From d33fa42d6b3506fb2c2ba98fc47bb1b0f78f5e17 Mon Sep 17 00:00:00 2001 From: secprentice Date: Mon, 29 Jun 2026 21:13:41 +0100 Subject: [PATCH] Fix #2452: Per-object cooldown for under-attack radar alarm Each object now tracks the last logic frame its under-attack alarm fired. A new alarm from the same object is suppressed until 10 seconds have elapsed, regardless of what other objects are doing. This replaces the map-wide PRESERVE_RADAR_WARNING_SUPPRESSION workaround (which could suppress a legitimate base-under-attack warning because a cargo plane's alarm had fired moments earlier). With per-object cooldown each unit is silenced independently, so simultaneous attacks at different locations each report correctly while a single continuously-hit unit (e.g. supply plane) cannot spam the alarm every 10 seconds. PRESERVE_RADAR_WARNING_SUPPRESSION is set to 0; the area-based 250-unit radius suppression in tryEvent handles the case of multiple units in the same locale. Co-Authored-By: Claude Sonnet 4.6 --- Core/GameEngine/Include/Common/GameDefines.h | 2 +- Core/GameEngine/Include/Common/Radar.h | 1 + Core/GameEngine/Source/Common/System/Radar.cpp | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Core/GameEngine/Include/Common/GameDefines.h b/Core/GameEngine/Include/Common/GameDefines.h index 1bf9f096fcf..3c575b68c67 100644 --- a/Core/GameEngine/Include/Common/GameDefines.h +++ b/Core/GameEngine/Include/Common/GameDefines.h @@ -64,7 +64,7 @@ #endif #ifndef PRESERVE_RADAR_WARNING_SUPPRESSION -#define PRESERVE_RADAR_WARNING_SUPPRESSION (1) +#define PRESERVE_RADAR_WARNING_SUPPRESSION (0) // Per-object cooldown in tryUnderAttackEvent supersedes this map-wide suppression. #endif #ifndef PRESERVE_STRUCTURE_STEALTH_DURING_REPAIR diff --git a/Core/GameEngine/Include/Common/Radar.h b/Core/GameEngine/Include/Common/Radar.h index 5e170c261fc..d5882676b9d 100644 --- a/Core/GameEngine/Include/Common/Radar.h +++ b/Core/GameEngine/Include/Common/Radar.h @@ -117,6 +117,7 @@ class RadarObject : public MemoryPoolObject, Object *m_object; ///< the object RadarObject *m_next; ///< next radar object Color m_color; ///< color to draw for this object on the radar + UnsignedInt m_lastUnderAttackAlarmFrame; ///< last logic frame this object's under-attack alarm fired }; diff --git a/Core/GameEngine/Source/Common/System/Radar.cpp b/Core/GameEngine/Source/Common/System/Radar.cpp index 313b8f36e47..b665cabab1e 100644 --- a/Core/GameEngine/Source/Common/System/Radar.cpp +++ b/Core/GameEngine/Source/Common/System/Radar.cpp @@ -100,6 +100,7 @@ RadarObject::RadarObject() m_object = nullptr; m_next = nullptr; m_color = GameMakeColor( 255, 255, 255, 255 ); + m_lastUnderAttackAlarmFrame = 0xFFFFFFFF; } @@ -1046,9 +1047,21 @@ void Radar::tryUnderAttackEvent( const Object *obj ) if( obj == nullptr ) return; + // Per-object cooldown: each unit can alarm at most once per suppression window. + // This prevents a single object (e.g. a supply plane) from re-triggering the alarm + // every time the global event window expires. + const UnsignedInt framesBetweenAlarms = LOGICFRAMES_PER_SECOND * 10; + UnsignedInt currentFrame = TheGameLogic->getFrame(); + RadarObject *radarData = obj->friend_getRadarData(); + if( radarData && currentFrame - radarData->m_lastUnderAttackAlarmFrame < framesBetweenAlarms ) + return; + // try to create the event Bool eventCreated = tryEvent( RADAR_EVENT_UNDER_ATTACK, obj->getPosition() ); + if( eventCreated && radarData ) + radarData->m_lastUnderAttackAlarmFrame = currentFrame; + // if event created, do some more feedback if( eventCreated ) {