Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -754,10 +754,11 @@ let positionTarget = cmpPositionTarget.GetPosition(); const heightDifference = positionSelf.y + this.GetAttackYOrigin(type) - positionTarget.y; - range.max = Math.sqrt(Math.square(range.max) + 2 * range.max * heightDifference); + const squaredRange = Math.square(range.max) + 2 * range.max * heightDifference; - if (range.max < 0) + if (squaredRange < 0) return false; + range.max = Math.sqrt(squaredRange); } let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false); Index: binaries/data/mods/public/simulation/components/BuildingAI.js =================================================================== --- binaries/data/mods/public/simulation/components/BuildingAI.js +++ binaries/data/mods/public/simulation/components/BuildingAI.js @@ -351,11 +351,12 @@ // Parabolic range compuation is the same as in UnitAI's MoveToTargetAttackRange. // h is positive when I'm higher than the target. const h = y - targetCmpPosition.GetPosition().y; - if (h > -range.max / 2 && cmpObstructionManager.IsInTargetRange( + const squaredRange = Math.square(range.max) + 2 * range.max * h; + if (squaredRange >= 0 && h > -range.max / 2 && cmpObstructionManager.IsInTargetRange( this.entity, selectedTarget, range.min, - Math.sqrt(Math.square(range.max) + 2 * range.max * h), false)) + Math.sqrt(squaredRange), false)) { cmpAttack.PerformAttack(attackType, selectedTarget); PlaySound("attack_" + attackType.toLowerCase(), this.entity);