Two separate reasons the scripted route stopped, both measured rather than guessed: * LOAD -> READY ROOM is not 28 s. Both runs on 2026-08-23 overran it, so the next press was eaten by the transition and the run ended up in OPTIONS once and BRIEFINGS once. wait_screen.sh now waits for the screen, with an optional --tap that clears a dialog the caller cannot know about (a freshly restored profile inserts "Auto-Save is active. OK?" here). * The READY ROOM is DRAWN long before it is USABLE: it comes up with a "Preparing to Sortie" spinner and TAKE OFF greyed out. The two states differ by 1.7 units of blue whole-image, so screen_id.py cannot separate them and should not try. take_off_armed.py tests the label instead: 0.0000 bright pixels while preparing, 0.1633 once armed, on three captures from two runs. It carries its own position check - the always-enabled BRIEFINGS label below reads 0.1027 in all three, to four decimals, so if that reference is dark the boxes are off the labels and the answer is "unknown", not a confident wrong one. screen_id.py gains a "readyroom" class from the same measurements; nothing else reclassifies. Verified end to end and unattended: boot -> title -> LOAD GAME -> slot 01 -> READY ROOM -> TAKE OFF -> "IN FLIGHT at 34s", pilot bound and engaging. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
54 lines
2.1 KiB
Python
Executable File
54 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Is the READY ROOM's TAKE OFF item ARMED, or still `Preparing to Sortie`?
|
|
|
|
`screen_id.py` answers "which screen", by whole-image statistics, and that is the
|
|
right contract for it — but it cannot answer this, because the two states of the
|
|
READY ROOM differ by a spinner and a greyed word and are otherwise the same
|
|
image: measured (13.4, 38.2, 135.2) while preparing against (12.7, 36.5, 133.5)
|
|
when armed. Waiting on that 1.7-unit difference would be superstition.
|
|
|
|
The disabled state is unambiguous where it actually shows: the TAKE OFF label has
|
|
**no** pixel above 170 while preparing, and **16.3 %** of its pixels above 170
|
|
once armed. Measured on three captures from two independent runs.
|
|
|
|
This does use fixed boxes, which `screen_id.py`'s header warns about — so it
|
|
carries its own check: the BRIEFINGS label below it is always enabled, and reads
|
|
**0.1027 bright in all three captures**, to four decimal places, across those two
|
|
runs. If that reference is not bright, the boxes are not on the labels and the
|
|
answer is `unknown` rather than `not armed` — which is the failure mode the
|
|
warning is about.
|
|
|
|
Only meaningful ON the READY ROOM — ask `screen_id.py` first. The MAIN MENU has
|
|
its own text in these boxes and reads `armed` (0.1342), which is not a bug in
|
|
this test but the reason it is not a screen classifier.
|
|
|
|
Usage: take_off_armed.py <png> -> prints armed|preparing|unknown
|
|
exit 0 only when armed
|
|
"""
|
|
import sys
|
|
from PIL import Image
|
|
|
|
TAKE_OFF = (548, 140, 745, 182)
|
|
BRIEFINGS = (548, 196, 760, 238) # always enabled — the position self-check
|
|
BRIGHT = 170
|
|
|
|
|
|
def bright_fraction(im, box):
|
|
px = list(im.crop(box).getdata())
|
|
return sum(1 for v in px if v > BRIGHT) / len(px)
|
|
|
|
|
|
def state(path):
|
|
im = Image.open(path).convert("L")
|
|
ref = bright_fraction(im, BRIEFINGS)
|
|
if ref < 0.04:
|
|
return "unknown", 0.0, ref
|
|
tgt = bright_fraction(im, TAKE_OFF)
|
|
return ("armed" if tgt > 0.04 else "preparing"), tgt, ref
|
|
|
|
|
|
if __name__ == "__main__":
|
|
st, tgt, ref = state(sys.argv[1])
|
|
print(f"{st} take_off={tgt:.4f} briefings_ref={ref:.4f}")
|
|
sys.exit(0 if st == "armed" else 1)
|