#!/usr/bin/env bash # Wait until the game is actually FLYING, then return — do not guess with sleeps. # # `launch_mission.sh` used to allow a fixed 75 s for the launch cinematic, the # 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. So poll, and tap A every few seconds until the HUD 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 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} )) 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 xdpyinfo -display "$DISP" >/dev/null 2>&1 \ || { echo "DISPLAY LOST at ${SECONDS}s"; exit 3; } sleep 2; continue fi [ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s"; exit 4; } 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 (last: ${cls:-none})"; exit 1