From 402de88f2578abd53acd4e3998cf05fc3e9e5c42 Mon Sep 17 00:00:00 2001 From: Atrik Date: Mon, 18 May 2026 14:54:26 +0200 Subject: [PATCH] Filter out hidden targets in CanAttack Units should not be able to attack entities with "hidden" visibility. Visible and fogged (mirage/retainInFog) targets remain attackable. --- .../data/mods/public/simulation/components/Attack.js | 9 +++++++++ .../data/mods/public/simulation/components/UnitAI.js | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js index ea163f05a8..7af3ddf16a 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..8433ba7c59 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -6397,8 +6397,11 @@ UnitAI.prototype.GetQueryRange = function(iid) // before actually attacking. ret.parabolic = range.parabolic; } + // In other stances, don't make the range parabolic, since they use vision/approach ranges + // that are larger than attack range, so targets will be spotted as they chase/approach anyway. + // TODO: With large height differences, the effective parabolic attack range can exceed + // vision/approach ranges, causing targets to be spotted later than ideal. else if (this.GetStance().respondChase) - // Chase stances: use full vision range (unit will chase anything it sees) ret.max = visionRange; else if (this.GetStance().respondHoldGround) {