Autopilot · write-up
Level-5 tank: model, experiments, and handoff
Originally updated 2026-09-02; the C-only result below was added 2026-09-29.
See AUTOPILOT.MD for
the general controller and PROFILING.MD for offline analysis.
The older checkpoint and recording basenames below live in xenon_tools/run_logs.
C-only validation, 2026-09-29
The native C pilot defeated the tank in an uninterrupted visible run from the
pre-tank checkpoint, without shield cheats or a lost life. The current recording
is E:\xenon_runs\level5-tank-flank-r60.validation\level5-tank-flank-r60.x2events;
the same directory contains -original.avi, -sprite.avi, and 150-frame
checkpoints. All four cannons were gone at frame 77325, the core at 77570,
and the shop opened at 77659. Shield fell from 39 to 31 through one homing hit
at 77557. The previous level5-tank-full-r54 run cleared the last cannon at
78589, destroyed the core at 78997, and reached the shop with 11 shield. Its
long wait at the far-right edge was the regression addressed here.
The C tactic clears the nearby side emplacement, uses same-side weapon lanes
against the cannons, then fires the left-offset laser from the right flank at
the inner left cannon. It crosses only for the remaining outer cannon. Cannon
and core aiming hold a lower screen band, preserving dodge room; the core can
also request a small backscroll while it remains visible. Once the cannons and
far emplacement are gone, the installed left laser attacks the core from the
right of the central pulse. The core hit handler at Level-5 $50722 has no
cannon-count gate: live recordings show
core HP falling while cannons remain. Clearing cannons first is a survival
tactic, not a requirement for making the core vulnerable.
The active core collision rectangle is X=152..159 (7 pixels wide). With this loadout the forward, two laser, and cannon lanes are separated by at least 18 pixels; no fixed ship X can put two vertical streams inside that rectangle. The forward lane has higher estimated point damage, but repeatedly entering and leaving the central pulse cut its actual uptime and exposed the ship to homing fire. The right-side laser station is calculated from the observed core rectangle and attachment offset (about X=199 for the tested equipment). In a focused continuation from frame 77315, it destroyed the core with one hit and 31 shield remaining; the uninterrupted run above reproduced that result.
Verified object model
Level loading replaces code at these addresses. Interpret them only with a
Level-5 memory image. Symbolic names are in xenon_tools/xenon_symbols.py and
semantic fields/classification are in world_state.py. Object identities are
session/namespace-specific; an address or recorded identity is not a strategy key.
| Component | Update / hit handler | Meaning |
|---|---|---|
| Tank controller | $508E0 |
Non-damageable parent; attack phase and allocation timing. |
| Four mounted cannons | $507DA / $50870 |
40 initial health each, unsigned word at object +$32. |
| Four armor objects | $5078C |
Non-damageable; contact hazards, not firing targets. |
| Central core | $506DE / $50722 |
200 initial health; its hit handler accepts damage even while cannons remain. Clearing cannons first lowers projectile pressure. A checkpoint can contain a partly damaged core. |
| Central column | $50B38 |
Non-damageable grow-then-fall projectile, not a normal velocity sprite. |
| Curved homing missile | $4FA1E / ordinary damage callback $0E2A |
Six initial health; can be destroyed by ordinary Side Shot bullets. |
| Straight shots | $4180 |
Direction comes from object state; not necessarily horizontal and not safely removable by Side Shot. |
The central column occupies X=150..160. Its extent is at +$28, vertical step
at +$2A; it grows by 16 to a 48-pixel extent before descending. Its allocation
can be predicted from the parent's attack phase/accumulator. Subsequent screen
movement must be translated through the candidate camera trajectory into world
coordinates. Recent core runs took no central-column damage; it was not the main
reason they stayed at the edges.
Homing is path dependent. The model advances the missile each canonical frame and retargets on the game's eight-frame cadence, using the prospective player position. A fixed path predicted against a stationary ship is not valid after the ship dodges. Age, direction, opposite-turn X parity, health, and live collision bounds matter. All collision comparisons are in world coordinates; screen-domain counters in the original routine are converted at its boundary.
Forward/side projectile geometry uses object collision bounds, not the full rendered sprite. Installed attachments do not enlarge the ship's hull merely because their graphics overlap a wall. Walls still obstruct firing lanes.
Current encounter policy
- Cross the nearest already-cleared entrance quickly. Entrance groups are semantic Level-5 map cells/rows, not historical object IDs. Do not redirect to the opposite corridor because a pending tank spawn appears mid-crossing.
- Destroy the two side emplacements promptly, keeping the arena near the upper edge until this is done. Use the nearest reachable equipped firing lane.
- Reveal the actual cannon collision rectangles. An off-screen tank can launch missiles before our bullets can damage it; indefinitely holding at the bottom is therefore a losing one-sided engagement.
- Retain a productive station for nearby cannons. Once the right cannons die, use the left laser from a right-flank station to destroy the inner left cannon before attempting the shorter crossing for the outer one.
- With no cannons left, use a left-mounted laser from beyond the central column when installed. Its station follows the observed core hitbox and attachment offset. Without that laser, use the forward lane and its pulse refuge.
Combat phases are attack -> evade -> return. The tank contact trigger is 12
frames; the broader missile search can examine 32. Survival selects a bounded
safe prefix, revalidates it, then returns to the retained firing objective.
Navigation/aiming are preferences, never permission to accept a predicted hit.
The forward and attachment damage rates used for ordinary station ranking are
rough estimates. The core's narrow hitbox and periodic pulse make uninterrupted
firing time more important than nominal point damage. The current loadout's
right laser lane was verified by actual core health loss. Telemetry exports the
ordinary projectile damage bonus from $7AF4; attachment rate/damage
assumptions remain a validation risk for other loadouts.
The released Homing Missile pickup is intentionally skipped when it would replace Side Shot. Losing the two lateral streams can make this encounter harder. This is a replacement-cost rule, not a claim that Homing Missile is always undesirable.
Side-shot defense evolves live and scheduled bullets with missile health. A bullet is consumed by one target, and a missile disappears from a branch only after enough predicted damage. Fire commands become visible bullets after a modeled delay; merely pointing a side cannon at a missile does not make it harmless.
What failed, and what was actually fixed
Entering late and replaying an already saturated arena
Many tests began after the tank had accumulated homing missiles while out of range. Improvements to aiming were judged against an already poor state. Run 198 returned to the earlier pre-arena checkpoint, destroyed both emplacements before damage, then all four cannons. Future whole-encounter validation must use that earlier start, not a dying core checkpoint.
Station correctness did not imply station execution
The UI often showed the right aim X while survival owned nearly every command. Changing scores or reselecting the same target did not fix this. The explicit combat phase and retained target group separate intent from applied movement. Regional relatching fixed forced returns to a distant station after a cross-column dodge. The latest core runs still spend excessive time at the edges: this is not solved simply because the displayed firing lane is correct.
Revelation and camera hold fought each other
A tank weak point barely entering the viewport immediately left it on DOWN or
its vertical bob. Reveal now requires depth and can align horizontally while
advancing, rather than waiting for exact X first. Core reveal/attack switches
still occur under evasion. A dedicated core acquisition latch was considered but
not implemented or validated; a previous overly broad latch experiment made
results worse. Do not silently resurrect it as an established fix.
Exact contact was reported one action too late
The next missile hull could overlap during the current transition, but one path
reported it at frame + 1. The corrected next-hull contact timing has a synthetic
regression. It improves the safety gate; it does not prove the whole planner safe.
A committed escape was discarded every frame
Run 200 supplied a concrete counterexample: at 92580 a safe sequence began
DOWN-LEFT, DOWN-LEFT, then hold; at 92581 it was replaced by LEFT, and by 92582
all candidates predicted immediate contact. Cleanup in _formation_escape_decision
checked generic homing presence but omitted level5_homing_nearby, erasing the
Level-5 plan. The fix retains those prefixes; run 201 retained queued plans on
361 frames. Regression: test_level5_tank_curved_missile_keeps_committed_escape_prefix.
Missile-defense model versus proactive interception
Recent runs lose health mainly to homing missiles and some objects already in their destruction state, not the central column. The planner includes retargeting, but it still often waits until evasive motion dominates firing. The user's next tactical suggestion is valuable and not yet implemented as a dedicated policy: when a missile approaches horizontally a few pixels above the ship, move slightly up to align Side Shot early, then return to the core lane. Test this against the full retargeting/damage/delay model, not a frozen missile line. An eight-frame retarget can invalidate a presumed interception. No new scoring layer was added during this handoff/cheat task.
Checkpoints and recordings
Use the accompanying .sav.autoplay.json and identity sidecar where available.
record_run.py loads the controller sidecar automatically. --fresh-controller
is a deliberately different experiment and must be labeled as such.
Basename (append .sav) |
Use / known state |
|---|---|
level5-diagonal-exact-source-route-0831-40 |
Earlier route, around frame 91179; suitable full arena entry baseline. |
level5-tank-fast-egress-validation-0901-106 |
Entry cleared; later tank state already contains missile pressure. Not a clean start. |
level5-tank-one-step-reacquisition-validation-0901-160 |
Final cannon nearly destroyed; shield 15. Useful focused transition only. |
level5-tank-early-regional-validation-0902-198 |
Frame 92079; all four cannons gone, core HP160, shield19, lives1. Recommended focused core start. |
level5-tank-core-regional-final-0902-199 |
Core HP65, shield3. Dangerous continuation, not a fair survival baseline. |
level5-tank-core-committed-escape-validation-0902-201 |
Core HP57, shield3. Exposes remaining core reacquisition limitation. |
Run 198: 900 canonical frames, both emplacements and all four cannons destroyed, shield35 to19, no life loss, two hit events. Run 199: 500 core frames, HP160 to65, shield19 to3, two homing hits. Run 200: continuation died almost immediately, revealing the discarded-prefix bug. Run 201 after that fix: 600 core frames, HP160 to57, shield19 to3, two hits; not a tank kill. Runs 199--201 have paired original and Sprite Stream AVIs. Run 198 did not record AVI.
Commands (PowerShell, repository root)
Build/launch using HATARI_BUILD_RUN.MD. Do not run a stale executable or hide the window from the user. The current development endpoint is 6902; a manually launched instance normally uses 6802.
powershell -ExecutionPolicy Bypass -File xenon_tools\hatari_dev.ps1 build -BuildDirectory build2
powershell -ExecutionPolicy Bypass -File xenon_tools\hatari_dev.ps1 run -BuildDirectory build2 -ControlPort 6902 -Snapshot xenon_tools\run_logs\level5-tank-early-regional-validation-0902-198.sav
# Normal bounded comparison, full replayable evidence:
python xenon_tools\record_run.py tank-comparison.x2events --mode autopilot --port 6902 --snapshot xenon_tools\run_logs\level5-tank-early-regional-validation-0902-198.sav --frames 600 --trace --avi
# Exploration only; stop automatically at shop, or Ctrl+C for graceful cleanup:
python xenon_tools\record_run.py tank-cheat.x2events --mode autopilot --port 6902 --snapshot xenon_tools\run_logs\level5-tank-early-regional-validation-0902-198.sav --cheat-shield --trace --avi --stop-at-shop
python xenon_tools\replay_ui.py xenon_tools\run_logs\level5-tank-core-committed-escape-validation-0902-201.x2events
python xenon_tools\analyze_hits.py xenon_tools\run_logs\level5-tank-core-committed-escape-validation-0902-201.x2events
Cheat mode is off by default. Protocol v15 command 23 carries one big-endian
16-bit shield value, restricted to 0..39; it cannot write arbitrary RAM. The
autopilot requests a refill at 0 < shield <= 12, to39 by default. Options
--cheat-shield-threshold and --cheat-shield-value change those bounds. It does
not revive a dead ship or change any enemy state. JSONL shield_cheat records
every requested refill. The original frame shield remains untouched in the trace;
the following actual frame observes the RAM change. Cheat-assisted progress must
never be reported as a successful no-damage or normal-survival validation.
Acceptance and next owner
For a normal fix, compare identical checkpoint, controller sidecar, equipment, fire cadence, and frame budget. Report core/cannon HP lost, life/health loss, damage source, time on a productive lane, and decision latency. Prove a model change with synthetic transition tests plus live recorded contact/health changes. Do not keep rerunning slight scoring changes when actual movement ownership is wrong. The open non-cheat problem is sustained core damage while controlling path-dependent missile pressure and reliably returning from a committed dodge.
Completed cheat exploration (2026-09-02)
level5-tank-shield-cheat-0902-202.x2events starts from checkpoint198 at
frame92080. The last tracked core frame is93219 with one health, followed by
the core disappearing and the reward sequence; shop detection stops the run at
93325. The run took five eight-point contacts (one destroying object and four
curved homing missiles), no central-column hits, and no life loss. Refills were
requested at92256 (11 to39) and93055 (7 to39). Initial shield19, final39;
the two refills added60 total energy. This is a cheat-assisted tank kill.
Both AVIs, JSONL, native events, identity sidecar and checkpoint were finalized.
Shop shutdown emitted two additional canonical transition frames; the saved
event log/checkpoint ends at 93327, although the stop predicate fired at 93325.
The first shop attempt, level5-post-tank-cheat-0902-203, revealed that an
unconfigured Level-5 shop fell back to generic equipment trading and tried to
replace Side Shot with Homing Missile. That attempt was discarded. The new
explicit (5,1) shop recipe preserves attachments, permits at most one affordable
Power Up and critical-health repair, and plans no equipment sales. It is a
conservative exploration recipe, not an optimal final-level shopping claim.
level5-post-tank-preserve-side-cheat-0902-204.x2events restarted from the
untouched shop checkpoint202. It bought one Power Up (cash6100 to5100), preserved
the forward/Side Shot/Laser/Cannon loadout, and left the shop at94305. Over the
following222 gameplay frames it destroyed one wall shooter, advanced scroll to
2032, retained shield39 and its one life, and needed no refill. The bounded run
ended at94527 and released input. It is the recommended next exploration
checkpoint, with the same basename plus .sav and .sav.autoplay.json.
It inherits the cheated tank state even though this segment took no damage.
python xenon_tools\replay_ui.py xenon_tools\run_logs\level5-tank-shield-cheat-0902-202.x2events
python xenon_tools\replay_ui.py xenon_tools\run_logs\level5-post-tank-preserve-side-cheat-0902-204.x2events
python xenon_tools\record_run.py level5-next-cheat.x2events --mode autopilot --port 6902 --snapshot xenon_tools\run_logs\level5-post-tank-preserve-side-cheat-0902-204.sav --cheat-shield --trace --avi --frames 600
The handoff test pass is 549 autoplay tests plus the focused protocol, shop,
replay and profiling/cheat tests. During that pass an older constructor regression
was found: player_projectile_damage_bonus had been inserted before shop in
GameMemoryState, silently breaking positional callers and15 tests. Appending
the new field restored the existing constructor contract; live decoding already
used keyword arguments. No tactics were changed to make those tests pass.
Six-step handoff checklist
Later shop correction and MORE inspection (2026-09-02)
Run206 (level5-shop-spend-remaining-0902-206) is the older, unprotected fully
shopped continuation checkpoint: it bought3 Power Ups,1 Side Shot upgrade and1
Laser for5500 total, left600 unspendable on useful compatible items, and exited
at94600. End94727, shield39/lives1, no damage. Its events, paired AVIs, .sav
and controller sidecar are under xenon_tools/run_logs.
Run208 (level5-shop-more-page-0902-208) is an unshopped inspection checkpoint
at93966 on the second Buy page with6100 credits intact. MORE reveals Bomb,
Extra Life, Homing Missile, Protection and Bitmap Shades. Protection halves
incoming shield damage and costs3000 at Level5. The revised policy reserves this
first, then buys additional Lasers within the four auxiliary slots and Power Up.
Runs209/210 validate Protection3000 + Laser2000 + Power Up1000, leaving100 and
preserving Side Shot. Run209 exposed a MORE input-acknowledgement failure;210
continued after that fix, bought the remaining items and selected Exit. The new
continuation is level5-shop-protection-0902-210.sav with its controller sidecar,
at94802 during closing, shield39/lives1/Protection active. Paired AVIs and events
were recorded, with no damage or cheat refills during these shop runs. Do not
confuse this closing checkpoint with unshopped208 or post-exit206. See
plan-shop-autopilot.md for the budget and menu acknowledgement details.
- Tank evidence/checkpoints consolidated: this document.
- Current architecture, tactics and operator instructions: AUTOPILOT.MD handoff section.
- Opt-in bounded shield command/client/recorder and tests: implemented, C built, protocol v15 verified live.
- Tank killed and next area explored: runs 202/204, both with native events and paired AVIs.
- Offline frame ranking/function profiler and instructions: profile_autoplay.py and PROFILING.MD, exercised on run 201.
- Validation: 599 tests across autoplay/protocol/shop/replay/profiling/cheat helpers passed; both AVI pairs decoded at first/last frame. Hatari left paused at 94527 with input released.