Xenon 2

How it works · write-up

Shop item catalog (Xenon 2: Megablast)

xenondoc/shop-items-catalog.md · 6 KB · updated 2026-09-22

Extracted directly from the ROM via ReVa/Ghidra disassembly of the shop's sell-menu handler (FUN_0001122e), item-description printer (FUN_000114ce) and buy-cost printer (ShopPanel_PrintBuyCost, FUN_00011346). Names come from the pointer table at 0x00010ea8 and prices from the word table at 0x00010f7a; both are indexed by the one-based runtime item type stored in each grid slot (offset +6) and in attachment object +$44: runtime type 1 is FORWARD SHOT, 2 is ADVICE, 25 is BITMAP SHADES. Python and protocol code (pickup_catalog.py) use these runtime values end to end, and this table uses them too.

Both lookups are literally table + type * 4 / table + type * 2 with the one-based type (the cost code is lea $10f7c,a1; move.w -2(a1,d0.w),d0 after add.w d0,d0), so the word at 0x00010f7a itself (6128) and the pointer at 0x00010ea8 are never used -- they are whatever precedes the tables, not a "type 0" entry. An earlier version of this catalog indexed both tables zero-based, which shifted every price and the leveled-item list one row up (it made ADVICE look free and gave it power levels); the values below are re-verified against the disassembly and xenon_tools/pickup_catalog.py, which agree.

The game has no separate flavor-text blurb per item beyond its display name -- the name is the in-game description, printed via blitter_printSmallTextWrapped_FUN_000122d0 when you select an item to sell (or presumably an equivalent path on the buy side).

Catalog

The sprite column shows one frame of each item's shop-icon loop (icon table at 0x00010f0c, one looping sprite list per item), rendered from assets/stram.bin and the packed atlas by xenon_tools/render_shop_icons.py; the image files are named by the runtime type.

Type Sprite Name (as printed in-game) Price Notes
1 forward-shot FORWARD SHOT (0) The player's starting weapon: price slot is 0 and item type 0 means "empty slot" (the sell handler's != 0 guard), so it is never bought. Has power levels.
2 advice ADVICE 200 Crispin's hint. Not free: 200 credits.
3 speedup SPEEDUP 500
4 health-power-1 HEALTH\rPOWER 1 500 Displayed as "HEALTH / POWER 1" (embedded `
` line break).
5 autofire AUTOFIRE 500
6 super-nashwan-power SUPER NASHWAN POWER 600
7 health-power-2 HEALTH\rPOWER 2 1000 "HEALTH / POWER 2" -- second health tier.
8 rear-shot REAR SHOT 1000 Leveled item (gets a POWER <n> suffix, see below).
9 mine MINE 1000 Leveled item.
10 side-shot SIDE SHOT 1000 Leveled item.
11 electro-ball ELECTRO BALL 1200
12 powerup POWERUP 2000
13 mine MINE 3000 Second MINE entry (same display text, different type and price -- a second mine tier). Leveled item.
14 double-shot DOUBLE SHOT 3000 Leveled item.
15 cannon CANNON 4000
16 dive DIVE 4000
17 missile-launcher MISSILE LAUNCHER 4000
18 laser LASER 4000 Leveled item.
19 drone DRONE 4500 Leveled item.
20 flamer FLAMER 5000
21 bomb BOMB 5500
22 extra-life EXTRA LIFE 6000
23 homing-missile HOMING MISSILE 6000
24 protection PROTECTION 6000 Shield.
25 bitmap-shades BITMAP SHADES 6000 Bitmap Brothers in-joke / cosmetic item.

Prices are halved when $E1A (the current / just-completed level number) is 5, i.e. in the Level 5 shops (cmpi.w #5,$e1a; bne; lsr.w #1,d0 in FUN_00011346).

"Leveled" items

FUN_000114ce special-cases runtime item types {1, 8, 9, 10, 13, 14, 18, 19} (FORWARD SHOT, REAR SHOT, MINE, SIDE SHOT, MINE (second tier), DOUBLE SHOT, LASER, DRONE): after printing the base name, if DAT_00011788 is set it also prints "\rPOWER " (string at 0x0001163c) followed by the attachment's power level plus one (d1 = attachment object +$42, read by the sell handler from the grid slot's object pointer at +$c, incremented, then FUN_0001234e). These are exactly the weapons that can be upgraded in place.

Source addresses (for future reference)

  • Name table: 0x00010ea8 (4-byte pointer per runtime item type; the entry for type 1 is at 0x00010eac)
  • Price table: 0x00010f7a (2-byte unsigned cost per runtime item type; the entry for type 1 is at 0x00010f7c)
  • Icon table: 0x00010f0c (4-byte pointer per runtime item type to a {sprite...}, 0, loop list)
  • Sell-confirmation flow: FUN_0001122e -> FUN_000114ce (print name) -> ShopPanel_PlayHandPayAnimation_FUN_00011380 ("I WILL PAY ") -> next cursor-poll pass -> clr.w (0x6,A0) at 0x000112f0 finalizes the sale (see SHOP_ITEM_SOLD_PC in src/drawCommandStream.c)
  • Buy-side cost message: FUN_00011346 ("THAT WILL COST")