Shop
Buy / sell / quantity / confirm flow for town shops. Lives inside the menu overlay (same 129-function binary as the save screen, inn, and status screens). Clean-room session state: engine-core::shop::ShopSession. Buy-list render layout confirmed from FUN_801d5de0 (overlay_shop_save.bin).
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:
| Phase | State | Description |
|---|---|---|
| Buy list | ShopBuy | Shows available items + prices. Cursor selects an item. |
| Sell list | ShopSell | Shows player inventory. Cursor selects an item to sell. |
| Quantity | ShopQuantity | Numeric selector 1..9. Confirms how many to buy/sell. |
| Confirm | ShopConfirm | Yes / No prompt. Yes commits the transaction. |
| Exit | ShopExit | Clears 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.
| Field | Type | Meaning |
|---|---|---|
inventory | ShopInventory | Items the shop offers for purchase |
pending_item_id | Option<u8> | Item selected at current sub-flow cursor |
pending_quantity | u8 | Quantity from ShopQuantity step |
pending_is_buying | bool | true = 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:
| Element | X offset (px) | Notes |
|---|---|---|
Cursor > | +0 | Selected row only |
| Item name | +20 (0x14) | func_0x80036888 |
| Price | +112 (0x70) | 6-digit field; func_0x80034b78 |
| Gold footer | +0 | Below 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,0x60bytes per scene; dispatched byFUN_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.