Xenon 2

Autopilot · write-up

Shop autopilot and equipment compatibility

xenondoc/plan-shop-autopilot.md · 13 KB · updated 2026-09-17

Goal

Drive Xenon 2's post-level shop from the external autopilot using semantic RAM state rather than screen recognition. The controller must preserve valuable equipment, buy useful upgrades, handle incompatible ship mounts deliberately, and leave the shop without requiring human input.

Verified game behaviour

The purchase validator at $11024 rejects incompatible equipment with "THERE ISN'T ROOM FOR THAT ON YOUR SHIP." The sell menu runs before the buy menu, so any replacement sale must be planned before the buy grid is displayed. Rear Shot and Side Shot are additionally mutually exclusive: their installers remove the other weapon, without granting its resale value.

The attachment layout is:

  • primary $C66: Forward Shot, Double Shot, or Flamer;
  • left wing $C84: Rear Shot, either Mine, Electro Ball, Drone, or Homing Missile;
  • right wing $C8A: Side Shot, Bomb, or Homing Missile;
  • four shared auxiliary slots $C6C..$C7E: Cannon, Missile Launcher, and Laser.

Homing Missile uses either free wing mount. Rear and Side cannot coexist. A sale pays (base price + current power * 2000) / 2.

The original Atari/Amiga game visits the shop twice per level: once halfway through and once after the level guardian. The byte at $1178C is not a visit number; it only selects the final completion message. Normal visits are distinguished by the level scroll value used by the game itself at $7D56: values above $03C0 are visit 1 and values at or below $03C0 are visit 2.

The external guides are advisory inputs, not runtime truth. The Lemon Amiga shopping recipe matches the five-level Atari build and therefore supplies the equipment progression. The GameFAQs walkthrough is for the six-level Master System port, so its prices and one-shop-per-level schedule are not portable. Its tactical observations are still useful: off-axis weapons matter, level 2 rewards a Laser, center staging is safer against level-2 wall enemies, and ramming the boss is much more dangerous than its projectiles. The original instructions independently confirm that the original game offers two shop visits per level.

Equipment recipe

Spending and capacity correction (2026-09-02)

Recipes retain their equipment order and explicit replacement sales, but their finite purchase counts no longer cause an early exit with usable money left. After the recipe, ShopController enters purchase_policy=spend_remaining and rechecks live RAM after each purchase: emergency repair, speed, installed weapon grades, Power Ups, additional auxiliary weapons (Laser preferred), and other compatible permanent improvements. It checks the next merchandise page before exiting. It stops only when no allowed, affordable, useful purchase remains; Advice, Autofire, cosmetic shades and temporary Nashwan Power remain excluded. It does not sell protected weapons or replace Side Shot with Homing Missile just to spend a remainder. An unspendable remainder is possible.

Disassembly evidence, also annotated in ReVa:

  • $2BBC scans four six-byte code/pointer records at $C6C..$C7E. Laser installer $5BC2 uses this allocator; duplicate Lasers are legal up to four total auxiliary weapons. These slots are independent of the two wing records. The slot-offset table at $2BD0 gives horizontal offsets -26,+26,-44,+44: two on each side. The world model already captures every live Laser/Cannon offset.
  • $5126 chooses the lowest-grade upgradeable installed attachment and increments its power. Repeated Power Ups are useful until every eligible mount is maxed.
  • $7766/$776A clear current and respawn cash during level initialization. Ordinary mid-level shop return does not itself clear cash: run204 still reports 5100 after exit. Shop entry at $7D00..$7D50 can also top up low cash using the level's allowance. The policy nevertheless does not bank credits for later.

Preference and eligibility are separate: generic Rear preference must not reject an explicitly planned or already-installed Side Shot upgrade. Actual mount conflicts and current/maximum power still gate purchases.

The table below describes the first-pass loadout goals; its older finite limits are not a cap on the subsequent surplus-spending pass.

Representative explicit recipes (the complete set is in ATARI_SHOP_RECIPES):

Visit Mandatory target Desired target Conditional
Level 1, shop 1 Keep current equipment; trade nothing - None
Level 1, shop 2 Sell Rear; buy Double Shot 1 and Side Shot 1 Raise Side Shot to grade 3 One Power-up if cash remains; critical Health Power 2 last
Level 2, shop 1 Raise Side Shot to grade 3 - Critical Health Power 2 last
Level 2, shop 2 Sell Side; buy Laser 1 and Rear Shot 1 Raise Laser count to 2 One Power-up if cash remains; critical Health Power 2 last
Level 5, shop 1 Protection if not already active; keep existing equipment Additional Lasers within four auxiliary mounts Power Up, critical repair, then useful surplus purchases

Advice, Autofire, Bitmap Shades, Forward Shot, and temporary Super Nashwan Power remain excluded. The minimum column is funded before desired grades or optional purchases. A conflicting attachment is sold only when the complete plan proves that its replacement is present and affordable.

Implementation

MORE page (verified live 2026-09-02)

MORE is grid slot19, row3/column4 (bottom-right). Move there and press Fire once; it changes pages without a purchase confirmation or charge. $10D2C adds19 to the page base $10B16, wrapping back to0. Page0 contains types2..20; page19 contains types21..25 plus MORE back. The grid builder hides first-page MORE when the first next-page item exceeds the current cash/availability ceiling. A single confirmed page change is required: no repeated fire while waiting for its RAM acknowledgement. Initially reading just the $10D2C branch missed that its caller $11646 waits for a fire edge; live run207 exposed this and run208 verified the correction.

Second-page item Base price Level-5 price Use with the current loadout
Bomb 5500 2750 Right-wing mount occupied by Side Shot; do not replace it casually.
Extra Life 6000 3000 Adds one life, capped at9. Valuable with only one life left.
Homing Missile 6000 3000 Both wing records occupied; would require a replacement. Keep the established Side Shot policy.
Protection 6000 3000 Halves incoming shield damage. Installer $517E sets $D99; damage routine $65AA..$65B6 shifts damage right once. Cleared on ship reset and next shop entry.
Bitmap Shades 6000 3000 Cosmetic; excluded.

Run208 (level5-shop-more-page-0902-208.x2events, paired AVIs and .sav) inspected this page at frame93966 with all6100 credits intact and made no purchases. It remains the unshopped second-page inspection checkpoint. The revised planner budgets and ranks targets across both pages, independent of the currently visible grid. Level-5 shop1 prioritizes Protection, then additional Lasers (four auxiliary slots total, including existing Cannons), then Power Up and useful surplus buys. An active Protection flag prevents buying it again after a mid-shop restore. The twenty-cell first page contains19 merchandise records and MORE, not Bomb.

Page navigation requires an acknowledgement, not a second purchase confirmation. Run209 bought Protection but exposed a lost initial Fire edge on MORE after cursor movement. The controller now retries while the page base remains unchanged, releasing between edges; after acknowledgement it waits for the rebuilt grid and does not fire again into the new page. The original180-frame timeout still applies.

The original/sprite AVI comparison from run208 shows that static shop chrome was already missing before MORE. This is a restore-only host-cache limitation, not evidence that MORE clears the chrome. Per user direction, leave that rendering limitation unfixed; recovering shop-active state does not recover static visuals.

Spending validation

Run206 (level5-shop-spend-remaining-0902-206.x2events) bought3 Power Ups (3000), 1 Side Shot grade (500), and1 extra Laser (2000), leaving600. It sold nothing, retained Side Shot, and left two max-grade Lasers plus a Cannon installed (three of four auxiliary slots). No useful compatible item was affordable with600. Shop exit was94600; the bounded run stopped at94727 with shield39/lives1 and no hits. Both original/sprite AVIs decode first and last640x400 frames. This is inherited cheat-assisted progress from the tank, but no cheat/refills were enabled in this shop validation. The607-test handoff suite passes after the additional MORE acknowledgement regression.

Runs209/210 (level5-shop-protection-0902-209/210) validate the new policy: 209 purchased Protection3000, then stopped on the page-handshake timeout above. 210 resumed that saved RAM with a fresh controller, returned to page0, purchased Laser2000 and Power Up1000, and selected Exit. It stopped at94802 during closing, with100 cash, Protection active, Side Shot intact, shield39/lives1 and no damage. Both runs include .x2events, decision trace, paired AVIs and a .sav checkpoint; 210 also includes its controller sidecar. No shield cheat was enabled during either shop run (the inherited tank checkpoint was cheat-assisted). The handoff suite now contains612 passing tests, including off-page budgeting, four-slot capacity, already-owned Protection, and unacknowledged MORE recovery.

  1. Extend canonical frame events with exact shop activity/mode, cursor, cash, level, input-repeat and confirmation state, buy-page/availability state, all twenty grid records, and attachment item type/current power/maximum power.
  2. Extract shop names, prices, compatibility flags, handlers, and mount semantics from assets/stram.bin, keeping the game's one-based runtime item codes end to end.
  3. Before leaving Sell mode, reproduce the game's buy-grid construction and calculate a complete sell/buy transaction. Sell only when a confirmed available and affordable higher-priority item needs the occupied mount.
  4. Execute the transaction as a verified menu state machine. Every cursor move, selection, sale, purchase, phase switch, and exit waits for the corresponding RAM change before continuing.
  5. Ignore Advice, Autofire, Bitmap Shades, and Forward Shot. Super Nashwan Power is also skipped by default because its complete weapon set expires after roughly ten seconds; it can only be enabled by an encounter-aware policy with explicit evidence that major combat is imminent. Use the level-and-visit recipe above; unknown later visits fall back to the conservative semantic equipment planner rather than guessing a guide sequence.
  6. Expose the current mount layout, projected inventory, planned sales/purchases, expected cash, rejection reasons, and transaction phase in diagnostics and recordings.
  7. Install claimed input at the shop's blocking selector reader $11646, synthesize the fire edge expected at $A01, and preserve one directional action across the selector's redraw call until its dispatcher at $1167A. This prevents a canonical-frame input release from erasing a menu action midway through the same 68000 selector call.

Acceptance tests

  • Extracted compatibility groups and prices match the original tables.
  • Rear/Side replacement always sells the old weapon first and never allows silent removal.
  • No equipment is sold unless its replacement is projected available and affordable.
  • Full auxiliary slots and both wing slots produce deterministic higher-value replacement choices.
  • assets/beforeshop2.sav produces the same predicted and actual buy grid.
  • The autopilot completes level-1 shop 1, preserves Rear, buys nothing unless shield is critical, skips excluded and short-lived items, and exits cleanly.
  • A full level-1 run reaches shop 2 with the real accumulated cash and validates the Rear-to-Side replacement before entering level 2. Both authentic and Sprite Stream AVI recordings are kept for this acceptance run.
  • The observed level-2 end shop with 4,400 cash keeps Side Shot because the complete Rear replacement is not funded, buys one permanent 4,000-credit Laser, skips Nashwan Power, exits, and reaches a playable Level 3. A synthetic test reproduces that exact cash/equipment state; level2-left-route-boss-shop-acceptance-0824-05.x2events validates the real transaction.