How to make a shop in Godot
Sell from an Item Vault inventory with DropTable stock, atomic buys, and game-owned prices: the vault owns counts, your game owns the gold.
This recipe builds a shop that sells from an Item Vault inventory: stocked shelves, prices, atomic buys, and save-safe stock. The split is the whole recipe. Item Vault owns every count (definitions, stock, atomic mutation); your game owns every meaning (prices, gold, who may buy). A sale applies gold and goods only after the vault commits — never before.
1. Stock the shelves with a drop table
A shop shelf is a DropTable: each DropEntry points at an ItemDefinition
with a quantity and odds, and the table rolls opening stock. The definition
owns the stable id and world scene; the table only decides what can appear
and how many units show up:
var sword_drop := DropEntry.new()
sword_drop.item = sword_definition
sword_drop.quantity = 2
sword_drop.odds = 1.0 # always stocked; use lower odds for rare stock
var shelf := DropTable.new()
shelf.possible_drops = [sword_drop, potion_drop]
shelf.guaranteed_drops = 1
shelf.combined_odds = false # each entry rolls independentlycombined_odds = false rolls each entry on its own; true weights entries
against each other and picks one. Restocking is just re-rolling the same
table. Full roll behavior — including DropsGenerator for deciding drops
before spawning anything — is in the
Drop Tables
guide.
2. Price in the game, never in the vault
Prices, discounts, and reputation effects live in your game rules, next to the gold purse. Item Vault never sees a price: it moves stacks, your code moves gold, and the two meet only after a committed mutation. That separation is what keeps a failed sale from eating the player's money.
3. Sell on commit, not on click
Follow the consequence-follows-commit rule: game rules first, atomic vault mutation second, gold and effects last. A rejected mutation — no stock, no gold, no capacity for the bought stack — must leave both inventories and the purse untouched:
# 1) Game rules FIRST — a rejection never touches inventory.
if player_gold < price:
return {"committed": false, "reason": "not enough gold"}
# 2) Atomic vault mutation (remove from shelf, add to player).
var result := _move_stock(shelf_inventory, player_inventory, item_id, 1)
if not result.committed:
return result
# 3) Consequence ONLY after commit.
player_gold -= price
_play_cash_sound()This is the ItemUseAuthority pattern — gate, transact, then consequence —
documented with a runnable example in
Game-Owned Gameplay Integration.
Buy, sell-back, and repair are all the same shape: the direction of the stack
move changes, the commit ordering never does.