diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js index 9ea860167e..508475d4a5 100644 --- a/binaries/data/mods/public/simulation/components/Attack.js +++ b/binaries/data/mods/public/simulation/components/Attack.js @@ -271,6 +271,15 @@ Attack.prototype.CanAttack = function(target, wantedTypes) if (!cmpTargetPlayer || !cmpEntityPlayer) return false; + // Must be visible or miraged / with retainInFog flag, not completely hidden + const cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + if (cmpRangeManager) + { + const visibility = cmpRangeManager.GetLosVisibility(target, cmpEntityPlayer.GetPlayerID()); + if (visibility == "hidden") + return false; + } + const types = this.GetAttackTypes(wantedTypes); const entityOwner = cmpEntityPlayer.GetPlayerID(); const targetOwner = cmpTargetPlayer.GetPlayerID(); diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index 33467c0281..7c35c7652e 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -6386,7 +6386,10 @@ UnitAI.prototype.GetQueryRange = function(iid) if (!range) return ret; ret.min = range.min; - ret.max = Math.min(range.max, visionRange); + // Use full attack range (not capped by vision) for StandGround. + // Enemies visible through allied vision or as mirages are valid targets; + // completely hidden enemies are filtered out by Attack.CanAttack's visibility check. + ret.max = range.max; // For StandGround, the 'parabolic' flag is set so that the caller can create a // parabolic query instead of a flat one. This ensures elevation bonuses are // properly accounted for when detecting enemies.