Where dead players' belongings come back into the economy โ and the kingdom's treasury takes its cut.
The Pawn Shop (in-game: Lombard) is the kingdom's second-hand market. When a player dies from any cause, every item they were carrying is transferred to the shop, where any other living non-king player can buy it for gold. Every sale funnels straight into the king's treasury.
It's the only recycling path in the game โ without it, a death would permanently remove weapon parts from the economy and dragon-slay paths could become unwinnable.
Items are deposited into the pawn shop whenever a player dies. The resolver tracks a deposit intent for every death event and the turn-scheduler processes them after the turn resolves.
| Cause of death | Items go to | Notes |
|---|---|---|
| Eaten by dragon | Pawn Shop | Both weapon parts and unique bow parts |
| Failed dragon-slay attempt | Pawn Shop | Attacker dies, all their parts drop |
| Assassinated | Pawn Shop | Plus gold โ treasury via the assassin's cut |
| Drained by a Vampire | Pawn Shop | Body joins the Vampire's ghoul pack |
| Hunted by a Werewolf | Pawn Shop | Wolf pack grows by one |
| Robbery gone wrong | Pawn Shop | Target survives robbery but drops via mutual kill |
| Vampire / Werewolf mutual kill | Pawn Shop (both) | Contested combat, both hunters die โ double drop |
All item drops use the same plumbing โ TurnResult.pawn_shop_deposits collects {player_id, reason} entries during resolution, and the persistence layer moves all that player's rows from player_items into pawn_shop in a single transaction.
dragon_victims) during resolution.
Here's how a single weapon part can move through the economy:
The item's type (knight weapon part, ACME kit part, unique bow string, etc.) is preserved, so Player B can continue assembling a dragon-kill weapon from where Player A left off.
Every item in the shop is listed at a flat price of 67 gold regardless of what it would cost to earn or craft directly:
pawn_shop:
part_price: 67 # game_config.yaml โ single source of truth
This is a balance lever. 67g is set just high enough to matter (about 4โ6 turns of peasant work) but well below what crafting a fresh part costs, so the pawn shop genuinely competes with the normal paths rather than being a pure last resort.
| Player state | Can buy? | Reason |
|---|---|---|
| Living peasant / citizen / knight / prince | โ Yes | Has gold, needs parts |
| The King | โ No | Kings don't haggle. Also, the king already owns the treasury โ buying would just move gold from their right pocket to their left |
| Dead players | โ No | Dead men buy no bows |
| Player with less gold than the item price | โ No (disabled button) | Can't afford โ shown greyed out |
| Any player if shop is empty | โ (shown as empty state) | See screenshot below |
The pawn shop panel lives inside the game screen, beneath the forest map. It renders as a list of item rows:
Acme Dragon Kit Part 1 (x2) when multiple players dropped the same kind of partClicking the buy button sends a DataStar POST to /games/{game_id}/buy_pawnshop with the item name. The server re-validates everything (item exists, player is alive, player is not king, player has enough gold) inside a transaction and broadcasts an SSE update to all players.
| Case | Behaviour |
|---|---|
| Unique bow parts (only one exists in the game) | Treated like any other item โ stacks into the shop on death. Since there's only one of each bow string / shaft / arrowhead, the pawn shop becomes the only way to acquire one without searching the forest yourself. |
| Multiple players dropped the same generic part | Quantity increments. One row, shown as "Item (x2)", "(x3)", etc. |
| An item is bought, leaving quantity = 0 | Row vanishes from the shop on next SSE refresh. Never shown with "(x0)". |
| Dead player had no inventory | Nothing is deposited โ the deposit intent is still recorded for logging but no rows are written. |
| Game ends with items still in shop | Items are lost. There's no rollover between games. |
| Piece | File |
|---|---|
| Schema | server/migrations/002_inventory.sql โ defines pawn_shop and player_items tables |
| Deposit intents (pure logic) | server/turn_resolver.py โ every death path appends to s.pawn_shop_deposits |
| Persistence (DB writes) | server/turn_scheduler.py โ after resolver returns, moves items row-by-row in a transaction |
| Buy API | POST /games/{game_id}/buy_pawnshop โ game_manager.buy_from_pawn_shop() |
| UI render | server/view_renderer.py::render_pawn_shop() โ SSE fragment targeting #pawn-shop |
| Target div | client/templates/game.html โ <div id="pawn-shop"></div> under the forest map region |
| Config | game_config.yaml โ pawn_shop.part_price |
#pawn-shop div was missing from game.html, and the SSE stream's initial full-sync didn't query pawn shop rows. Items were being created correctly in the database but never rendered. Fixed while writing this wiki page.