From 033b1b3784fd3bc274991f9022842f296fc02db4 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Sun, 23 Aug 2026 18:02:27 +0000 Subject: [PATCH] tools: wait_flight was testing a pixel that is 40 rows outside the HUD It tested one named pixel, (450,640), described as "inside the SHIELD bar". It is not inside anything. `screenshot` crops to the GAME SURFACE, 1279x675, while those constants were chosen for a 1280x720 window: measured on a frame that was unmistakably in flight (TIME 01:18.05, REMAINING OB 004), the SHIELD bar's green rows are 590-605 and the ARMOR bar's are 650-670, and (450,640) sits in the gap between them reading (64,66,116) - blue. That is why the corpus already carried "wait_flight.sh reported NEVER REACHED FLIGHT while the game was plainly in flight" as an unexplained note, and it is exactly the failure screen_id.py's own header warns about. Reproduced live here: the script sat for five minutes reporting nothing while tapping A into the cockpit every six seconds. Now classified by whole-image statistics - screen_id.py's "flight" class, green fraction 1.3-1.5% against <0.1% on every menu - which no crop or scale can move. Two consecutive frames are required so an explosion in a cutscene cannot pass, and the A tapping (which dismisses the objective card) STOPS once flight is seen, because in the cockpit A is a weapon press and not a "continue". Tested against the running game before being believed: 0 with "IN FLIGHT at 19s" on the same session the old test had been failing on, and then in the unattended launch. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE --- tools/re-capture/wait_flight.sh | 53 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/tools/re-capture/wait_flight.sh b/tools/re-capture/wait_flight.sh index a3b5b4c9..6ee36f3c 100755 --- a/tools/re-capture/wait_flight.sh +++ b/tools/re-capture/wait_flight.sh @@ -5,23 +5,34 @@ # stage load and the objective card. Under lavapipe that is not a constant: one # run needed 75 s, the next was still in Raymond's dialogue at 140 s, so the A # meant for the OBJECTIVE card was swallowed by the cutscene and the card sat -# there forever. +# there forever. So poll, and tap A every few seconds until the HUD appears +# (which dismisses the objective card whenever it happens to be up). # -# The in-flight HUD is unmistakable: the SHIELD bar is a solid bright green -# block at the bottom of the screen, and no cutscene or menu has anything green -# there. So poll that pixel, and tap A every few seconds until it appears (which -# dismisses the objective card whenever it happens to be up). +# 🔴 REWRITTEN 2026-08-23. This script used to test ONE NAMED PIXEL, (450,640), +# "inside the SHIELD bar". It is not inside anything: `screenshot` crops to the +# GAME SURFACE, which is **1279x675**, while those constants were picked for a +# 1280x720 window — (450,640) lands in the gap between the SHIELD bar (green rows +# 590-605) and the ARMOR bar (650-670) and reads (64,66,116), blue. Measured on a +# frame that was unmistakably in flight, `TIME 01:18.05`, while this script sat +# there reporting nothing and tapping A into the cockpit every six seconds. That +# is exactly the failure `screen_id.py`'s own header warns about, and it is why +# the corpus already carried "wait_flight.sh reported NEVER REACHED FLIGHT while +# the game was plainly in flight" as an unexplained note. +# +# So classify by WHOLE-IMAGE statistics instead, which no crop or scale can move: +# the flight HUD paints green over the entire frame (green fraction 1.3-1.5 %, +# against <0.1 % on every menu), and that is `screen_id.py`'s `flight` class. # # Same liveness rule as skip_intro.sh, for the same reason: a failed screenshot -# leaves r/g/b unset, they default to 0, the green test fails, and waiting for -# the HUD becomes indistinguishable from waiting for a dead emulator. +# leaves the classification unset and waiting for the HUD becomes +# indistinguishable from waiting for a dead emulator. set -u export HOME=/sylph-home/re DISP="${DISPLAY:-:98}" +SD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" alive(){ ps -o pid=,stat= -C xenia_canary 2>/dev/null | awk '$2 !~ /^Z/ {print $1}'; } DEADLINE=$(( SECONDS + ${1:-240} )) -PX=450; PY=640 # inside the SHIELD bar of the flight HUD -last_tap=0 +hits=0; last_tap=0 while [ $SECONDS -lt $DEADLINE ]; do rm -f /tmp/wf.png if ! screenshot /tmp/wf.png >/dev/null 2>&1 || [ ! -s /tmp/wf.png ]; then @@ -30,16 +41,20 @@ while [ $SECONDS -lt $DEADLINE ]; do sleep 2; continue fi [ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s"; exit 4; } - read -r r g b < <(convert /tmp/wf.png -format \ - "%[fx:int(255*p{$PX,$PY}.r)] %[fx:int(255*p{$PX,$PY}.g)] %[fx:int(255*p{$PX,$PY}.b)]" info:) - if [ "${g:-0}" -gt 140 ] && [ $(( g - r )) -gt 60 ] && [ $(( g - b )) -gt 60 ]; then - echo "IN FLIGHT at ${SECONDS}s (HUD shield bar visible)" - exit 0 - fi - if [ $(( SECONDS - last_tap )) -ge 6 ]; then - python3 "$(dirname "${BASH_SOURCE[0]}")/pad.py" tap A 0.3 - last_tap=$SECONDS + cls="$(python3 "$SD/screen_id.py" /tmp/wf.png | awk '{print $1}')" + if [ "$cls" = "flight" ]; then + hits=$(( hits + 1 )) + # Two consecutive frames: one green-heavy frame could be an explosion in a + # cutscene. Do not tap A once flight has been seen — in the cockpit that is + # a weapon/target press, not a "continue". + [ $hits -ge 2 ] && { echo "IN FLIGHT at ${SECONDS}s (screen_id: flight)"; exit 0; } + else + hits=0 + if [ $(( SECONDS - last_tap )) -ge 6 ]; then + python3 "$SD/pad.py" tap A 0.3 + last_tap=$SECONDS + fi fi sleep 2 done -echo "NO FLIGHT HUD within ${1:-240}s"; exit 1 +echo "NO FLIGHT HUD within ${1:-240}s (last: ${cls:-none})"; exit 1