diff --git a/tools/re-capture/wait_flight.sh b/tools/re-capture/wait_flight.sh index a3b5b4c..6ee36f3 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