Flow

The retail engine enters the shop from the field-VM shop-trigger opcode. The menu overlay dispatches on a sub-screen ID (pointer table at 0x801E4F40). The five phases are:

PhaseStateDescription
Buy listShopBuyShows available items + prices. Cursor selects an item.
Sell listShopSellShows player inventory. Cursor selects an item to sell.
QuantityShopQuantityNumeric selector 1..9. Confirms how many to buy/sell.
ConfirmShopConfirmYes / No prompt. Yes commits the transaction.
ExitShopExitClears session, returns to field.

On ShopConfirm slot 0 (Yes): try_buy deducts gold and credits inventory; try_sell credits gold and decrements inventory. Sell price is max(buy_price / 2, 1); items not in the shop's buy list sell for 1 gold.

ShopSession

ShopSession holds the cursor and pending-transaction state for one open shop visit. Installed on MenuRuntime by open_shop(ShopSession) before menu entry.

FieldTypeMeaning
inventoryShopInventoryItems the shop offers for purchase
pending_item_idOption<u8>Item selected at current sub-flow cursor
pending_quantityu8Quantity from ShopQuantity step
pending_is_buyingbooltrue = buy, false = sell

Key methods: select_buy_item(cursor), select_sell_item(cursor, items), set_quantity(slot) (quantity = slot + 1), try_buy(world_money), try_sell(held_count).

Render layout

Traced from FUN_801d5de0 (overlay_shop_save.bin). Each visible row (up to 8 with scroll) uses a 14 px stride:

ElementX offset (px)Notes
Cursor >+0Selected row only
Item name+20 (0x14)func_0x80036888
Price+112 (0x70)6-digit field; func_0x80034b78
Gold footer+0Below last row; 8-digit field

Row colour: white = affordable; dim = price exceeds gold or held count > 98; blue = equipped-comparison flag set. engine-render::shop_draws_for implements these constants. Cost prompt and Yes/No cursor render in legaia-engine play-window when MenuState::ShopConfirm is active.

Open items

  • Per-scene item tables. Retail shop stocks are in the menu overlay DATA segment at 0x801E4518 (8-byte strides, 0x60 bytes per scene; dispatched by FUN_801DC6B4). Scene-index to offset mapping is not yet traced.
  • Quantity cap. Retail caps held count at 98 before dimming; the current port allows unlimited stacking.

Full reference

Complete flow tables and provenance at docs/subsystems/shop.md. Source: crates/engine-core/src/shop.rs.