Shops
games/tbs/src/shop/README.md on GitHub
This folder holds The Broken Seal's counters: shops that buy, sell and repair, the artifact counter and the Game Ticket gifts, the sanctum's healing services, the inn, and the item picker that asks which item to drop when an item is found with every bag full.
See also: Windows, the windows and messages the counters are made of; Menus, which share their work block; and Game rules, the items and their counters.
Files
| File | What it holds |
|---|---|
shop.c | the guide to the shop object: it includes shop_internal.h, then the parts in shop/ in ROM order |
shop_internal.h | the object's includes, the shop actions and sanctum services, and the values that differ by edition |
shopspr.s | the hand, gem, arrow, price and quantity sprite tiles |
The guide's comment says where to start, and each part's second line says
what it holds: head -2 shop/*.c lists them. A part includes the private
header, so it resolves when opened on its own, but it is compiled only through
shop.c. The ROM shows the counters as one object; the parts are ours, cut
where one family ends and the next begins. Link order is in
games/tbs/objects.tsv, from shop.
The work block's layout, struct ShopRuntime, is in
include/shop.h and the prototypes in
games/tbs/include/unit/shop/. Scene overlays import these functions by name (games/tbs/src/scene/import/), and code in other
banks calls them through the far-call table
games/tbs/src/system/far_call/SHOP.S (the ...Far names), so a rename
crosses folders.
Words
- work block:
struct ShopRuntime, heap slotHEAP_SLOT_MENU, reached asgMenuWorkwhile a counter is open;Shop_InitializeCursorWorksets it up andShop_ReleaseCursorWorkreleases it for every counter. - stock row: a row of
sStockTable(artifacts.c), one per shop: up to 24 item ids from column 0, ending with 0; up to 8 artifacts from column 24; and the shop's type in column 32 (SHOP_STOCK_names the columns). - artifact: an item a shop sells only while its shared stock counter is
not zero (
Item_AdjustCounter). A shop adds its row's artifacts to the counters once, on its first visit, and sets flag0x400 + stockRowto remember it (EventTable_ApplyRowAbilities). - action: what the player chose at a shop's counter: buy, sell, artifacts
or repair (
enum ShopAction). service: what the sanctum does for one party member: revive, cure poison, exorcise or remove a curse (enum SanctumService). - cursor duration:
shop->mode, the number of frames for the next hand cursor glide.Shop_PlaceCursorpasses it toShop_SetCursor, andShopCursor_Advanceinterpolates until that many frames have elapsed. - party row: the party members' icons across the window, which the
counters select and animate (
partyMemberIcons,Shop_PickUnit). unk<offset>: a field whose meaning is not known yet.
Prefixes
| Prefix | What it acts on |
|---|---|
Shop_ | the shops' screens, and anything every counter shares |
ShopCursor_ | the hand cursor |
UiMessage_ | the shopkeeper's messages: show, wait, choose |
EventTable_ | the stock rows |
Sanctum_ | the sanctum's services |
Inn_ | the inn |
Battle_, BattleUnit_, BattleFx_, AudioCommand_, NodeChain_ | things the engine names elsewhere |
The comment markers are in Matching.
Design
Artifacts are counted, not stocked
A shop's ordinary items are its row of sStockTable, always for sale. Its
artifacts work differently: they are not kept per shop at all. Each rare item
has one counter for the whole game (Item_AdjustCounter, in
../game/game/inventory.c), and a shop's artifact list is built when it
opens from every item of the shop's type whose counter is above zero
(shop/run.c). The counters move with the items:
- a shop's first visit adds one to the counter of each artifact in its row,
and sets flag
0x400 + stockRow(FLAG_SHOP_ARTIFACTS_STOCKEDplus the row) so it never does so again (EventTable_ApplyRowAbilities); - buying one takes one away, once the purchase is complete;
- a rare item the party drops, discards or sells goes back into circulation,
one up on its counter (
Inventory_Discard, the item screen).
So an artifact first stocked in one town is then sold by every shop of its type, and a rare item the party gives up turns up for sale again. The flag per row is what keeps a revisited shop from adding its artifacts a second time.
One work block for every counter
Every counter (shop, sanctum, inn, artifact counter) uses the same heap
block, HEAP_SLOT_MENU, as struct ShopRuntime: Shop_InitializeCursorWork
takes it and Shop_ReleaseCursorWork gives it back. The field menu's screens
use the same slot through their own views, so a counter and the field menu
are never open together.
How to change a counter
- A shop's stock is its row of
sStockTableinartifacts.c; each row's number is thestockRowits scene passes toShop_Run. - A value that differs by edition, such as a window moved for longer words,
is a named macro chosen in one
#ifblock at the top ofshop_internal.h, or of the part that uses it; change that edition's branch. - Messages are linker symbols (
MsgDeal); their text is in the PO catalogs ingames/tbs/text.
Limits
- A shop sells at most 24 items and 8 artifacts, the columns of its stock
row (
SHOP_STOCK_). - A shop adds its artifacts once, remembered by flag
0x400 + stockRow.
Evidence and open questions
The counters are named for what the player meets at them; the stock row's
columns (SHOP_STOCK_) from what artifacts.c reads at each place; the
actions and services from the choices their windows offer in the English
release.
Still unknown:
- XXX: why rows 16, 17 and 18 are the warrior's shops (
shop->warriorShop,shop/run.c) by number rather than by a column of the row. - XXX:
EventTable_ApplyRowAbilitiesand the otherEventTable_names say less than the functions do; they cross folders.
Source
Every file of this folder: src/shop.