Autopilot · write-up
Shop autopilot and equipment compatibility
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:
$2BBCscans four six-byte code/pointer records at$C6C..$C7E. Laser installer$5BC2uses 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$2BD0gives horizontal offsets -26,+26,-44,+44: two on each side. The world model already captures every live Laser/Cannon offset.$5126chooses the lowest-grade upgradeable installed attachment and increments its power. Repeated Power Ups are useful until every eligible mount is maxed.$7766/$776Aclear 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..$7D50can 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.
- 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.
- 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. - 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.
- 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.
- 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.
- Expose the current mount layout, projected inventory, planned sales/purchases, expected cash, rejection reasons, and transaction phase in diagnostics and recordings.
- 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.savproduces 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.x2eventsvalidates the real transaction.