Fix #2452: Per-object cooldown for under-attack radar alarm#2845
Fix #2452: Per-object cooldown for under-attack radar alarm#2845secprentice wants to merge 1 commit into
Conversation
…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 <noreply@anthropic.com>
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/Common/GameDefines.h | Sets PRESERVE_RADAR_WARNING_SUPPRESSION to 0, disabling the old map-wide suppression hack in favour of the new per-object cooldown; accompanied by an explanatory comment. |
| Core/GameEngine/Include/Common/Radar.h | Adds m_lastUnderAttackAlarmFrame (UnsignedInt) to RadarObject; field placement and comment are consistent with surrounding members. |
| Core/GameEngine/Source/Common/System/Radar.cpp | Initializes m_lastUnderAttackAlarmFrame to 0xFFFFFFFF in the constructor and gates tryUnderAttackEvent on a per-object cooldown; the new field is not serialized in xfer, so the cooldown silently resets on save/load. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller
participant tryUnderAttackEvent
participant RadarObject
participant tryEvent
Caller->>tryUnderAttackEvent: obj attacked
tryUnderAttackEvent->>RadarObject: friend_getRadarData()
RadarObject-->>tryUnderAttackEvent: radarData (or null)
alt radarData exists AND cooldown not expired
tryUnderAttackEvent-->>Caller: return (silenced)
else cooldown expired or no radarData
tryUnderAttackEvent->>tryEvent: RADAR_EVENT_UNDER_ATTACK, pos
alt area suppression (within 250 units, within 10s)
tryEvent-->>tryUnderAttackEvent: false
else no recent nearby event
tryEvent->>tryEvent: createEvent()
tryEvent-->>tryUnderAttackEvent: true
tryUnderAttackEvent->>RadarObject: "m_lastUnderAttackAlarmFrame = currentFrame"
tryUnderAttackEvent->>Caller: UI feedback (glow, audio, message)
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller
participant tryUnderAttackEvent
participant RadarObject
participant tryEvent
Caller->>tryUnderAttackEvent: obj attacked
tryUnderAttackEvent->>RadarObject: friend_getRadarData()
RadarObject-->>tryUnderAttackEvent: radarData (or null)
alt radarData exists AND cooldown not expired
tryUnderAttackEvent-->>Caller: return (silenced)
else cooldown expired or no radarData
tryUnderAttackEvent->>tryEvent: RADAR_EVENT_UNDER_ATTACK, pos
alt area suppression (within 250 units, within 10s)
tryEvent-->>tryUnderAttackEvent: false
else no recent nearby event
tryEvent->>tryEvent: createEvent()
tryEvent-->>tryUnderAttackEvent: true
tryUnderAttackEvent->>RadarObject: "m_lastUnderAttackAlarmFrame = currentFrame"
tryUnderAttackEvent->>Caller: UI feedback (glow, audio, message)
end
end
Comments Outside Diff (1)
-
Core/GameEngine/Source/Common/System/Radar.cpp, line 139-171 (link)Per-object cooldown not persisted across save/load
m_lastUnderAttackAlarmFrameis initialized to0xFFFFFFFFin the constructor but is never written or read inRadarObject::xfer—m_colorand the object ID are xferred but this new field is omitted. On every save/load the cooldown silently resets, so an object that fired an alarm immediately before a save will be able to fire it again immediately after load. For a purely transient UI notification this may be intentional, but if so thexferversion comment is worth updating to document the deliberate omission, otherwise a future maintainer may assume it was overlooked.Prompt To Fix With AI
This is a comment left during a code review. Path: Core/GameEngine/Source/Common/System/Radar.cpp Line: 139-171 Comment: **Per-object cooldown not persisted across save/load** `m_lastUnderAttackAlarmFrame` is initialized to `0xFFFFFFFF` in the constructor but is never written or read in `RadarObject::xfer` — `m_color` and the object ID are xferred but this new field is omitted. On every save/load the cooldown silently resets, so an object that fired an alarm immediately before a save will be able to fire it again immediately after load. For a purely transient UI notification this may be intentional, but if so the `xfer` version comment is worth updating to document the deliberate omission, otherwise a future maintainer may assume it was overlooked. How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
Core/GameEngine/Source/Common/System/Radar.cpp:139-171
**Per-object cooldown not persisted across save/load**
`m_lastUnderAttackAlarmFrame` is initialized to `0xFFFFFFFF` in the constructor but is never written or read in `RadarObject::xfer` — `m_color` and the object ID are xferred but this new field is omitted. On every save/load the cooldown silently resets, so an object that fired an alarm immediately before a save will be able to fire it again immediately after load. For a purely transient UI notification this may be intentional, but if so the `xfer` version comment is worth updating to document the deliberate omission, otherwise a future maintainer may assume it was overlooked.
Reviews (1): Last reviewed commit: "Fix #2452: Per-object cooldown for under..." | Re-trigger Greptile
|
See guidelines for AI contributions https://github.com/TheSuperHackers/GeneralsGameCode/blob/main/CONTRIBUTING.md |
Summary
Fixes #2452.
PR #2368 correctly fixed the broken 2-D squared-distance formula in
Radar::tryEvent. A side effect was that the 10-second suppression window became area-local (250 world units), so simultaneous attacks on cargo planes at different map locations each triggered their own alarm — causing the reported spam.PR #2540 worked around this by adding
PRESERVE_RADAR_WARNING_SUPPRESSION, which forces map-wide 10-second suppression for allRADAR_EVENT_UNDER_ATTACKevents. This restores retail noise levels but introduces a new problem: a cargo plane alarm suppresses a legitimate base under attack warning for the same 10-second window, even though the two events are in completely different locations.This fix
Adds a
m_lastUnderAttackAlarmFramefield toRadarObject(initialized to0xFFFFFFFFso unsigned subtraction safely yields "never fired"). InRadar::tryUnderAttackEvent, the per-object frame is checked before callingtryEvent: if this specific object has already alarmed within the last 10 seconds, the call is skipped entirely.PRESERVE_RADAR_WARNING_SUPPRESSIONis set to0. The original area-based (250-unit radius) suppression intryEventhandles the case of multiple nearby units being attacked simultaneously.Result:
RadarObjectand its own cooldown.Files changed
Core/GameEngine/Include/Common/GameDefines.h—PRESERVE_RADAR_WARNING_SUPPRESSION→ 0Core/GameEngine/Include/Common/Radar.h— addm_lastUnderAttackAlarmFrametoRadarObjectCore/GameEngine/Source/Common/System/Radar.cpp— initialize field; add per-object cooldown check intryUnderAttackEventTest plan