From ff8a84937fd1a13e025a8f2e7b61a43bd5cbe044 Mon Sep 17 00:00:00 2001 From: andreasw Date: Wed, 14 Jan 2026 18:10:00 +0100 Subject: [PATCH 1/3] improved limited turret angle --- .../GameEngine/Include/Common/GameCommon.h | 9 +- .../GameEngine/Include/GameLogic/TurretAI.h | 3 + .../Source/Common/System/GameCommon.cpp | 13 +- .../GameEngine/Source/GameClient/Drawable.cpp | 2 +- .../Source/GameLogic/AI/TurretAI.cpp | 113 ++++++++++++++++-- 5 files changed, 126 insertions(+), 14 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h index 63061b8b47f..728c229c355 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h @@ -503,10 +503,13 @@ inline Real stdAngleDiff(Real a1, Real a2) return normalizeAngle(a1 - a2); } +// ------------------------------------------------------------------------ // normalized angle difference between a1 and a2, respecting negative values and wraparound -inline Real stdAngleDiffMod(Real a1, Real a2) { - return normalizeAngle(nmod(a1 - a2, 2 * PI)); -} +extern Real stdAngleDiffMod(Real a1, Real a2); + +// ------------------------------------------------------------------------ +// normalize an angle between 0 and 2PI +extern Real normalizeAngle2PI(Real angle); // ------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/TurretAI.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/TurretAI.h index ef4ecc6e81c..f4d1e05b03a 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/TurretAI.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/TurretAI.h @@ -353,6 +353,9 @@ class TurretAI : public MemoryPoolObject, public Snapshot, public NotifyWeaponFi void stopRotOrPitchSound(); ///< stop turret rotation sound void removeSelfAsTargeter(); + Bool getTurretRotationDir(Real desiredAngle, Real minAngle, Real maxAngle); ///< Min/Max turn angle checks + + #ifdef INTER_TURRET_DELAY void getOtherTurretWeaponInfo(Int& numSelf, Int& numSelfReloading, Int& numSelfReady, Int& numOther, Int& numOtherReloading, Int& numOtherReady) const; #endif diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/GameCommon.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/GameCommon.cpp index d5e35075774..6d32e39f3e6 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/GameCommon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/GameCommon.cpp @@ -67,5 +67,16 @@ Real normalizeAngle(Real angle) return angle; } +// ---------------------------------------------------------- +Real normalizeAngle2PI(Real angle) +{ + angle = nmod(angle, TWO_PI); + if (angle < 0) angle += TWO_PI; + return angle; +} - +//------------------------------------------------------------------------------------------------- +extern Real stdAngleDiffMod(Real a1, Real a2) { + return WWMath::Normalize_Angle(nmod(a1 - a2, TWO_PI)); + //return normalizeAngle(nmod(a1 - a2, 2 * PI)); +} diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 8c32f2ffbb6..470374fa8b6 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -886,7 +886,7 @@ Bool Drawable::getCurrentWorldspaceClientBonePositions(const char* boneName, Mat //------------------------------------------------------------------------------------------------- void Drawable::setTerrainDecal(TerrainDecalType type) { - DEBUG_LOG(("Drawable::setTerrainDecal - type = %d\n", type)); + //DEBUG_LOG(("Drawable::setTerrainDecal - type = %d\n", type)); if (m_terrainDecalType == type) return; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp index 3605a3a5356..e6dc02ec4c0 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp @@ -393,10 +393,88 @@ void TurretAI::loadPostProcess( void ) } } +//---------------------------------------------------------------------------------------------------------- +static bool IsInArc(Real a, Real min, Real max) +{ + if (min <= max) + return a >= min && a <= max; + else + return a >= min || a <= max; +} +// -- +static Real CCWDistance(Real from, Real to) +{ + Real d = to - from; + if (d < 0) d += TWO_PI; + return d; +} +// -- +static bool ccwLeavesAllowedArc(Real from, Real to, Real min, Real max) +{ + if (min > max) { // simplify + max += TWO_PI; + } + if (from > to) { + to += TWO_PI; + } + + Real disallowedCenter = normalizeAngle2PI(((max + min) / 2.0) + PI); + //DEBUG_LOG((">>> ccw check: from = %f, to = %f, min = %f, max = %f. disCenter = %f", + from * 180 / PI, to * 180 / PI, min * 180 / PI, max * 180 / PI, disallowedCenter * 180 / PI)); + + return (from < disallowedCenter && to > disallowedCenter); +} +// ------- +// return True if CCW, False if CW +Bool TurretAI::getTurretRotationDir(Real desiredAngle, Real minAngle, Real maxAngle) +{ + Real origAngle = getTurretAngle(); + + origAngle = normalizeAngle2PI(origAngle); + desiredAngle = normalizeAngle2PI(desiredAngle); + + Bool wantCCW = stdAngleDiffMod(desiredAngle, origAngle) > 0; + + // If allowed arc < 180°, shortest path is always safe + Real diff = maxAngle - minAngle; + if (abs(diff) < PI) + //if (stdAngleDiffMod(maxAngle, minAngle) < PI) + return wantCCW; + + minAngle = normalizeAngle2PI(minAngle); + maxAngle = normalizeAngle2PI(maxAngle); + + //minAngle = WWMath::Normalize_Angle(minAngle); + //maxAngle = WWMath::Normalize_Angle(maxAngle); + + // Check if preferred direction leaves allowed arc + //DEBUG_LOG((">>> curAngle = %f, targetAngle = %f, shortest dir = %d", + // origAngle*180/PI, desiredAngle*180/PI, wantCCW)); + + if (wantCCW) + { + if (ccwLeavesAllowedArc(origAngle, desiredAngle, minAngle, maxAngle)) { + //DEBUG_LOG((">>> >>> CCW check failed -> must turn CW")); + return false; // must go CW + } + } + else + { + // CW is reverse CCW + if (ccwLeavesAllowedArc(desiredAngle, origAngle, minAngle, maxAngle)) { + //DEBUG_LOG((">>> >>> CW check failed -> must turn CCW")); + return true; // must go CCW + } + } + + return wantCCW; +} + //---------------------------------------------------------------------------------------------------------- Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Real relThresh) { - desiredAngle = normalizeAngle(desiredAngle); + // desiredAngle = normalizeAngle(desiredAngle); + desiredAngle = WWMath::Normalize_Angle(desiredAngle); // rotate turret back to zero angle Real origAngle = getTurretAngle(); @@ -405,11 +483,11 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea // Real angleDiff = normalizeAngle(desiredAngle - actualAngle); Real angleDiff = stdAngleDiffMod(desiredAngle, actualAngle); + Real minAngle = getMinTurretAngle(); + Real maxAngle = getMaxTurretAngle(); + // --- if (hasLimitedTurretAngle()) { - Real minAngle = getMinTurretAngle(); - Real maxAngle = getMaxTurretAngle(); - if (maxAngle < minAngle) { // This might be a backwards facing configuration maxAngle = nmod(maxAngle, 2.0 * PI); desiredAngle = nmod(desiredAngle, 2.0 * PI); @@ -432,6 +510,7 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea if (!isWithinLimit) { // angleDiff = normalizeAngle(desiredAngle - actualAngle); angleDiff = stdAngleDiffMod(desiredAngle, actualAngle); + // Are we close enough to the desired angle to just snap there? if (fabs(angleDiff) < turnRate) { @@ -442,7 +521,13 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea } else { - if (angleDiff > 0) + bool rotate_ccw = false; + if (hasLimitedTurretAngle()) + rotate_ccw = getTurretRotationDir(desiredAngle, minAngle, maxAngle); + else + rotate_ccw = (angleDiff > 0); + + if (rotate_ccw) actualAngle += turnRate; else actualAngle -= turnRate; @@ -451,7 +536,8 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea m_playRotSound = true; } - m_angle = normalizeAngle(actualAngle); + //m_angle = normalizeAngle(actualAngle); + m_angle = WWMath::Normalize_Angle(actualAngle); if (m_angle != origAngle) getOwner()->reactToTurretChange(m_whichTurret, origAngle, m_pitch); @@ -460,7 +546,8 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea } } // ----- - desiredAngle = normalizeAngle(desiredAngle); + //desiredAngle = normalizeAngle(desiredAngle); + //desiredAngle = WWMath::Normalize_Angle(desiredAngle); // Are we close enough to the desired angle to just snap there? if (fabs(angleDiff) < turnRate) @@ -472,7 +559,14 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea } else { - if (angleDiff > 0) + // for limited angle check if we need to take the longer route to the target + bool rotate_ccw = false; + if (hasLimitedTurretAngle()) + rotate_ccw = getTurretRotationDir(desiredAngle, minAngle, maxAngle); + else + rotate_ccw = (angleDiff > 0); + + if (rotate_ccw) actualAngle += turnRate; else actualAngle -= turnRate; @@ -481,7 +575,8 @@ Bool TurretAI::friend_turnTowardsAngle(Real desiredAngle, Real rateModifier, Rea m_playRotSound = true; } - m_angle = normalizeAngle(actualAngle); + //m_angle = normalizeAngle(actualAngle); + m_angle = WWMath::Normalize_Angle(actualAngle); if( m_angle != origAngle ) getOwner()->reactToTurretChange( m_whichTurret, origAngle, m_pitch ); From a99a9d52215d66a86063f686e827ca9517bf6a8f Mon Sep 17 00:00:00 2001 From: andreasw Date: Wed, 14 Jan 2026 21:46:15 +0100 Subject: [PATCH 2/3] fix dynamic pitch for units and add dynamic height scale for DumbProjectile --- .../GameLogic/Module/DumbProjectileBehavior.h | 3 +++ .../Source/GameLogic/AI/TurretAI.cpp | 11 ++++++-- .../Behavior/DumbProjectileBehavior.cpp | 25 ++++++++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DumbProjectileBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DumbProjectileBehavior.h index baaf1196784..c9af29de118 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DumbProjectileBehavior.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DumbProjectileBehavior.h @@ -64,6 +64,9 @@ class DumbProjectileBehaviorModuleData : public UpdateModuleData Real m_flightPathAdjustDistPerFrame; Bool m_applyLauncherBonus; + Real m_dynamicHeightMinScale; + Real m_dynamicHeightMinRange; + DumbProjectileBehaviorModuleData(); static void buildFieldParse(MultiIniFieldParse& p); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp index e6dc02ec4c0..182970f22ae 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp @@ -420,7 +420,7 @@ static bool ccwLeavesAllowedArc(Real from, Real to, Real min, Real max) Real disallowedCenter = normalizeAngle2PI(((max + min) / 2.0) + PI); //DEBUG_LOG((">>> ccw check: from = %f, to = %f, min = %f, max = %f. disCenter = %f", - from * 180 / PI, to * 180 / PI, min * 180 / PI, max * 180 / PI, disallowedCenter * 180 / PI)); + // from * 180 / PI, to * 180 / PI, min * 180 / PI, max * 180 / PI, disallowedCenter * 180 / PI)); return (from < disallowedCenter && to > disallowedCenter); } @@ -1315,7 +1315,14 @@ StateReturnType TurretAIAimTurretState::update() Real dist = v.length(); if (range<1) range = 1; // paranoia. jba. // As the unit gets closer, reduce the pitch so we don't shoot over him. - Real groundPitch = turret->getGroundUnitPitch() * (dist/range); + + Real groundPitch; + if (dist > range) { + groundPitch = turret->getGroundUnitPitch(); + } + else { + groundPitch = turret->getGroundUnitPitch() * (dist / range); + } desiredPitch = actualPitch+groundPitch; if (desiredPitch < turret->getMinPitch()) { desiredPitch = turret->getMinPitch(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp index be90acd23b0..bb2c5becc32 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp @@ -67,7 +67,9 @@ DumbProjectileBehaviorModuleData::DumbProjectileBehaviorModuleData() : m_garrisonHitKillCount(0), m_garrisonHitKillFX(NULL), m_flightPathAdjustDistPerFrame(0.0f), - m_applyLauncherBonus(FALSE) + m_applyLauncherBonus(FALSE), + m_dynamicHeightMinScale(1.0), + m_dynamicHeightMinRange(1.0) { } @@ -97,6 +99,9 @@ void DumbProjectileBehaviorModuleData::buildFieldParse(MultiIniFieldParse& p) { "ApplyLauncherBonus", INI::parseBool, NULL, offsetof(DumbProjectileBehaviorModuleData, m_applyLauncherBonus) }, + { "DynamicHeightMinScale", INI::parseReal, NULL, offsetof(DumbProjectileBehaviorModuleData, m_dynamicHeightMinScale) }, + { "DynamicHeightMinRange", INI::parseReal, NULL, offsetof(DumbProjectileBehaviorModuleData, m_dynamicHeightMinRange) }, + { 0, 0, 0, 0 } }; @@ -430,6 +435,20 @@ Bool DumbProjectileBehavior::calcFlightPath(Bool recalcNumSegments) targetVector.Z = controlPoints[3].z - controlPoints[0].z; Real targetDistance = targetVector.Length(); + + Real heightScale = 1.0; + if (d->m_dynamicHeightMinScale != 1.0 && m_detonationWeaponTmpl != NULL) { + //Object* launcher = TheGameLogic->findObjectByID(m_launcherID); + //if (launcher) + WeaponBonus bonus; + bonus.clear(); + Real attackRange = m_detonationWeaponTmpl->getAttackRange(bonus); + Real clippedDistance = MIN(targetDistance, attackRange) - d->m_dynamicHeightMinRange; + Real distFactor = clippedDistance / (attackRange - d->m_dynamicHeightMinRange); + heightScale = 1.0 - (1.0 - distFactor) * (1.0 - d->m_dynamicHeightMinScale); + DEBUG_LOG(("DumbProjectileBehavior::calcFlightPath -- distFactor = %f, heightScale = %f", distFactor, heightScale)); + } + targetVector.Normalize(); Vector3 firstPointAlongLine = targetVector * (targetDistance * d->m_firstPercentIndent ); Vector3 secondPointAlongLine = targetVector * (targetDistance * d->m_secondPercentIndent ); @@ -442,8 +461,8 @@ Bool DumbProjectileBehavior::calcFlightPath(Bool recalcNumSegments) // Z's are determined using the highest intervening height so they won't hit hills, low end bounded by current Zs highestInterveningTerrain = max( highestInterveningTerrain, controlPoints[0].z ); highestInterveningTerrain = max( highestInterveningTerrain, controlPoints[3].z ); - controlPoints[1].z = highestInterveningTerrain + d->m_firstHeight; - controlPoints[2].z = highestInterveningTerrain + d->m_secondHeight; + controlPoints[1].z = highestInterveningTerrain + d->m_firstHeight * heightScale; + controlPoints[2].z = highestInterveningTerrain + d->m_secondHeight * heightScale; // With four control points, we have a curve. We will decide how many frames we want to take to get to the target, // and fill our vector with those curve points. From d803fb78aef403e5e34f503da74d656e238843ed Mon Sep 17 00:00:00 2001 From: andreasw Date: Thu, 15 Jan 2026 21:20:35 +0100 Subject: [PATCH 3/3] add surface limitations for Sound effect FXNuggets --- .../GameEngine/Source/GameClient/FXList.cpp | 94 +++++++++++++++---- .../Behavior/DumbProjectileBehavior.cpp | 2 +- 2 files changed, 79 insertions(+), 17 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp index 3e9a5410844..ff74c69f7a7 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp @@ -128,6 +128,21 @@ void FXNugget::doFXObj(const Object* primary, const Object* secondary) const doFXPos(p, mtx, speed, s); } +//------------------------------------------------------------------------------------------------- +static const char* const AllowedSurfaceNames[] = +{ + "ALL", + "LAND", + "WATER", + NULL +}; + +enum AllowedSurfaceType CPP_11(: Int) { + SURFACE_ALL = 0, + SURFACE_LAND, + SURFACE_WATER +}; + //------------------------------------------------------------------------------------------------- class SoundFXNugget : public FXNugget { @@ -135,8 +150,19 @@ class SoundFXNugget : public FXNugget public: + SoundFXNugget() + { + m_soundName.clear(); + m_maxAllowedHeight = INFINITY; + m_minAllowedHeight = -INFINITY; + m_allowedSurfaceType = SURFACE_ALL; + } + virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const { + if (!isValidSurface(primary)) + return; + AudioEventRTS sound(m_soundName); if (primary) @@ -149,6 +175,9 @@ class SoundFXNugget : public FXNugget virtual void doFXObj(const Object* primary, const Object* secondary = NULL) const { + if (!isValidSurface(primary->getPosition())) + return; + AudioEventRTS sound(m_soundName); if (primary) { @@ -159,12 +188,15 @@ class SoundFXNugget : public FXNugget TheAudio->addAudioEvent(&sound); } - static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/) { static const FieldParse myFieldParse[] = { { "Name", INI::parseAsciiString, NULL, offsetof( SoundFXNugget, m_soundName ) }, + { "MinAllowedHeight", INI::parseReal, NULL, offsetof(SoundFXNugget, m_minAllowedHeight) }, + { "MaxAllowedHeight", INI::parseReal, NULL, offsetof(SoundFXNugget, m_maxAllowedHeight) }, + { "AllowedSurface", INI::parseIndexList, AllowedSurfaceNames, offsetof(SoundFXNugget, m_allowedSurfaceType) }, + { 0, 0, 0, 0 } }; @@ -174,7 +206,52 @@ class SoundFXNugget : public FXNugget } private: + + + bool isValidSurface(const Coord3D* primary) const //@TODO unify code with ParticleSystemFXNugget + { + if (!primary) + return false; + + // Evaluate Height and allowed surfaces first. + if ((TheTerrainLogic != NULL) && (m_minAllowedHeight > -INFINITY || m_maxAllowedHeight < INFINITY || m_allowedSurfaceType != SURFACE_ALL )) { + + Real groundHeight = 0; + PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(primary); + + if (layer != LAYER_GROUND) { // Bridge + if (m_allowedSurfaceType == SURFACE_WATER) return false; // No water effects over bridges. + groundHeight = TheTerrainLogic->getLayerHeight(primary->x, primary->y, layer); + } + else { // Ground (Water or Land) + Real waterZ = 0; + Real terrainZ = 0; + if (m_allowedSurfaceType != SURFACE_ALL || TheGlobalData->m_heightAboveTerrainIncludesWater) { // Do water check + Bool isWater = TheTerrainLogic->isUnderwater(primary->x, primary->y, &waterZ, &terrainZ); + + if (isWater) { + if (m_allowedSurfaceType == SURFACE_LAND) return false; + groundHeight = waterZ; + } + else { + if (m_allowedSurfaceType == SURFACE_WATER) return false; + groundHeight = terrainZ; + } + } + } + + Real zOffset = primary->z - groundHeight; + if (zOffset < m_minAllowedHeight || zOffset > m_maxAllowedHeight) return false; + } + + return true; + } + AsciiString m_soundName; + + Real m_maxAllowedHeight; + Real m_minAllowedHeight; + AllowedSurfaceType m_allowedSurfaceType; }; EMPTY_DTOR(SoundFXNugget) @@ -566,21 +643,6 @@ class TerrainScorchFXNugget : public FXNugget }; EMPTY_DTOR(TerrainScorchFXNugget) -//------------------------------------------------------------------------------------------------- -static const char* const AllowedSurfaceNames[] = -{ - "ALL", - "LAND", - "WATER", - NULL -}; - -enum AllowedSurfaceType CPP_11(: Int) { - SURFACE_ALL = 0, - SURFACE_LAND, - SURFACE_WATER -}; - //------------------------------------------------------------------------------------------------- class ParticleSystemFXNugget : public FXNugget { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp index bb2c5becc32..dfc2cc000cf 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp @@ -446,7 +446,7 @@ Bool DumbProjectileBehavior::calcFlightPath(Bool recalcNumSegments) Real clippedDistance = MIN(targetDistance, attackRange) - d->m_dynamicHeightMinRange; Real distFactor = clippedDistance / (attackRange - d->m_dynamicHeightMinRange); heightScale = 1.0 - (1.0 - distFactor) * (1.0 - d->m_dynamicHeightMinScale); - DEBUG_LOG(("DumbProjectileBehavior::calcFlightPath -- distFactor = %f, heightScale = %f", distFactor, heightScale)); + // DEBUG_LOG(("DumbProjectileBehavior::calcFlightPath -- distFactor = %f, heightScale = %f", distFactor, heightScale)); } targetVector.Normalize();