fix(health): detect and close CENTRED panels — Chronicle blocked every template match

Bug 31 fixed the keypress that opened CHRONICLE but explicitly left the real
gap open: the panel guard matches only LeftPanel / RightPanel, and a centred
panel matches neither. Nothing closed it, and a centred panel blanks EVERY
later template search.

Recurred 2026-08-28 with the merc key never pressed at all
(resurrect_merc | skip | merc alive), so something else opened it and it simply
stayed. The error screenshot shows Chronicle filling the screen while the bot
hunted A5_RED_PORTAL for 66s:

    Traverse from a5_larzuk to a5_nihlathak_portal
    Wanted to select A5_RED_PORTAL, but could not find it
    random guess towards (96, -115)
    Wanted to select A5_RED_PORTAL, but could not find it

Why the existing guard missed it, measured on that frame: the Chronicle's close
button scores 1.000 against CLOSE_PANEL_2 at (952, 56). That x IS inside
right_panel_header (830,0,455,56) — but the ROI is 56px tall and the button's
centre sits exactly at y=56, so the match falls outside. Both header ROIs
scored 0.409 and 0.373.

Adds a center_panel_header ROI (400,0,620,92) and a CenterPanel ScreenObject,
and escapes it WITHOUT counting toward a chicken — a centred panel is
self-inflicted UI state like the waypoint panel, and chickening on it throws
away a healthy game. Bounded by the same _MAX_WP_PANEL_ESCAPES so one that
genuinely will not close still falls through.

Verified on the failure frame: CenterPanel True, LeftPanel False, RightPanel
False.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
alexpolo1
2026-08-28 13:28:57 +02:00
parent c8e63bc9fa
commit 1f440cfed2
21 changed files with 82 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -130,6 +130,13 @@ corpse=459,195,414,213
chat_icon=7,555,43,41
left_panel_header=0,0,455,56
right_panel_header=830,0,455,56
; A CENTRED panel (Chronicle, and anything else that opens mid-screen) puts its
; close button outside both header ROIs above — the Chronicle's X sits at
; (952, 56), inside right_panel_header's x-range but exactly at its 56px height
; boundary, so the match centre falls out. Nothing then closes it, and a
; centred panel blanks every later template search: measured as a 66s
; click_red_portal failure on 2026-08-28 (Bug 31's residual).
center_panel_header=400,0,620,92
npc_dialogue=456,0,30,150
bind_skill=516,619,251,29
quest_skill_btn=284,455,710,121

View File

@@ -37,6 +37,7 @@ class HealthManager:
self._last_chicken_screenshot = None
self._count_panel_detects = 0
self._count_wp_panel_detects = 0
self._count_center_panel_detects = 0
def stop_monitor(self):
self._do_monitor = False
@@ -202,6 +203,27 @@ class HealthManager:
self._last_merc_heal = time.time()
# Close any open panels that might block detection
# A CENTRED panel (Chronicle) matches neither header ROI, so
# nothing ever closed it — and a centred panel blanks every
# later template search. Measured 2026-08-28: Chronicle open,
# A5_RED_PORTAL unfindable, 66s approach failure. It is not a
# threat, so escape it without counting toward a chicken,
# bounded the same way as the waypoint panel.
if not self.get_panel_check_paused() and is_visible(ScreenObjects.CenterPanel, img):
self._count_center_panel_detects = getattr(self, "_count_center_panel_detects", 0) + 1
if self._count_center_panel_detects <= self._MAX_WP_PANEL_ESCAPES:
Logger.debug(
f"Centred panel open (blocks all template matching) — closing it "
f"({self._count_center_panel_detects}/{self._MAX_WP_PANEL_ESCAPES})"
)
from input_layer import keyboard as kb
kb.send("esc")
wait(0.1, 0.2)
fn_end = time.perf_counter()
wait(max(0.01, (1/15 - (fn_end - fn_start)) * random.uniform(0.8, 1.2)))
continue
Logger.warning("Centred panel would not close — treating as a blocking panel")
if not self.get_panel_check_paused() and (is_visible(ScreenObjects.LeftPanel, img) or is_visible(ScreenObjects.RightPanel, img)):
# A waypoint panel is self-inflicted: the pather walked the char
# over the WP stone. That is a navigation problem, not a threat,
@@ -237,6 +259,7 @@ class HealthManager:
else:
# Screen is clear, so any waypoint panel we escaped did close.
self._count_wp_panel_detects = 0
self._count_center_panel_detects = 0
fn_end = time.perf_counter()
# Target ~15 FPS polling with anti-cheat jitter

View File

@@ -225,6 +225,12 @@ class ScreenObjects:
threshold=0.8,
use_grayscale=True
)
CenterPanel=ScreenObject(
ref=["CLOSE_PANEL_2", "CLOSE_PANEL"],
roi="center_panel_header",
threshold=0.8,
use_grayscale=True
)
NPCDialogue=ScreenObject(
ref="NPC_DIALOGUE",
roi="npc_dialogue",

46
test/test_center_panel.py Normal file
View File

@@ -0,0 +1,46 @@
"""A centred panel must be detected and closed.
Bug 31 fixed the merc-panel keypress that opened CHRONICLE, but noted the real
gap was never closed: the health manager's guard matches only LeftPanel /
RightPanel, and a centred panel matches neither. Nothing closes it, and a
centred panel blanks EVERY later template search.
Measured 2026-08-28: Chronicle open, A5_RED_PORTAL unfindable, 66s
click_red_portal failure. The Chronicle's close button scores 1.000 against
CLOSE_PANEL_2 at (952, 56) — inside right_panel_header's x-range but exactly at
its 56px height boundary, so the match centre falls outside the ROI.
"""
import inspect
def test_center_panel_screenobject_exists():
from ui_manager import ScreenObjects
assert hasattr(ScreenObjects, "CenterPanel"), "no detection for a centred panel"
def test_center_panel_roi_covers_the_chronicle_close_button():
from config import Config
x, y, w, h = Config().ui_roi["center_panel_header"]
cx, cy = 952, 56 # measured Chronicle X position
assert x <= cx <= x + w, "ROI does not span the Chronicle close button in x"
assert y <= cy <= y + h, (
"ROI does not span it in y — this is exactly how right_panel_header "
"missed it, its 56px height ending at the button's centre"
)
def test_guard_checks_center_panel_before_chickening():
"""It must be escaped, not counted as a threat.
A centred panel is self-inflicted UI state, like the waypoint panel.
Chickening on it throws away a healthy game.
"""
from health_manager import HealthManager
src = inspect.getsource(HealthManager)
assert "ScreenObjects.CenterPanel" in src, "guard never checks for a centred panel"
center_at = src.index("ScreenObjects.CenterPanel")
chicken_at = src.index("Chickening to be safe")
assert center_at < chicken_at, "centred-panel escape must come before the chicken path"