Money and shops

Usage guide of economy.money and trade.shop: the balance and its rules, shops, offers, stock and restock, settings and defaults, verbs, hooks (money.earn, money.spend, shop.open, shop.buy, shop.sell), engines.

Source: module-kits:kits/economy_money/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs economyMCP tool: gripforge_docs { "topic": "economy" }

Money and shops (economy.money, trade.shop) #

The player's balance and the merchants that exchange it for items. Readable offline: gripforge docs economy, or the MCP tool gripforge_docs (topic economy).

What it is for #

KitWhat it adds
economy.moneythe balance as the game variable economy.money: earn and spend with an optional debt, a transaction event for every change, mission rewards paid through it, verbs for scripts
trade.shopmerchants as data: offers with price and stock, what a merchant buys, a sell rate, restocking, interaction prompt, buy and sell rules

The rules live in the kits; the counter itself (the screen) is drawn by the interface layer from the events and services.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "economy.money" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "economy.money", config: { "startingMoney": 100, "currency": "gold" } }
gripforge_gamekit_install   { project_id: "gkp_…", id: "trade.shop" }

economy.money requires only game.engine. trade.shop requires economy.money and inventory.basic (see the Inventory guide), so installing a shop brings both.

Settings and defaults #

KitKeyDefaultMeaning
economy.moneystartingMoney0balance at the start, when the project does not seed one
economy.moneycurrency$symbol shown by the HUD (economy.currency)
economy.moneyallowDebtfalselet a spend go below zero
trade.shopbuyRate0.5share of an item's price paid when the player sells it
trade.shopbuysAnythingtruea merchant buys any item that has a price in any shop
trade.shoprestockMinutes0minutes before a sold-out offer comes back (0: never)
trade.shopinteractLabelTrade with {name}the prompt on a merchant; {name} is the shop name

A project may also seed the balance in its variables ({ "economy.money": 250 } wins over startingMoney); a set_var on it is simply the new balance.

Money rules #

  • add(amount, reason) credits a finite amount of 0 or more; 0 or an invalid amount changes nothing and emits nothing.
  • spend(amount, reason) debits when the balance covers it, or always with allowDebt; otherwise it answers false and the balance is untouched. Amounts are rounded to cents.
  • Mission rewards.money is paid through add(money, "mission:<id>"), once, just before mission.completed.
  • Service economy.money: balance(), currency(), canAfford(amount), add(amount, reason?) (the new balance), spend(amount, reason?). Verbs add_money, spend_money, condition money_at_least; in a script: { "add_money": 50 }.
  • Events: economy.transaction { amount, balance, reason } (signed: plus is a credit), economy.refused (a spend that could not be paid). Variables: economy.money, economy.currency. The balance is part of the saved game state.

Shops #

{ "shops": [{ "id": "blacksmith", "name": "Blacksmith", "greeting": "Steel for the road?",
  "offers": [{ "item": "iron_helmet", "price": 120, "stock": 1 }, { "item": "arrow", "price": 2 }] }] }

An offer with no stock is unlimited. A shop may also list the items the merchant buys (an id, or { item, price } with its own base price) and its own sell rate. A merchant in the world is an entity with the component shop: { id }: interacting opens the shop; open_shop does the same from a script.

  • buy(shop, item, n) checks the stock and the balance, takes the money and gives the units; a full inventory refuses with no_room. sell(shop, item, n) pays price times buyRate for items the merchant offers or buys, or any priced item when buysAnything.
  • Service trade.shop: shops(), open(id), close(), current(), offers(id) (with price, stock, affordable, sell price), priceOf, sellPriceOf, buy(...) and sell(...) answering { ok, reason?, paid? / earned? }.
  • Verbs open_shop { shop }, close_shop, condition shop_open { shop? }. Variable shop.open. Events shop.opened, shop.closed, shop.bought, shop.sold, shop.refused. The stock is saved.

Hooks and modding #

HookPayloadWhat a tap may do
money.earn{ amount, reason, balance }change amount, cancel (nothing is credited)
money.spend{ amount, reason, balance }change amount (before the balance check), cancel (refused like a short balance)
shop.open{ shop }cancel (a closed shop; shop.refused carries the reason)
shop.buy{ shop, item, count, price }change the total price (a discount, a tax), cancel; asked after the stock check and before the balance check
shop.sell{ shop, item, count, price }change the total price the merchant pays, cancel
{ "id": "half_rent", "hook": "money.spend", "match": { "reason": "rent" }, "mul": { "amount": 0.5 } }

Moddable: every setting above, and the shops collection (a registry: { "id": "new", "extends": "blacksmith" } inherits an entry, keys merged, the child wins). Quests and missions pay and check money through the same service (see the Quests guide).

Engines #

economy.money is the same Rust logic on the web and in the native player, and is delivered to Godot and Unity as files and to Unreal through the shared kit library. trade.shop runs on the web and in the native player. The hooks run in those two.

When it does not do what you expect #

SymptomCause and fix
A purchase is refusedread the reason: no_room (inventory full), not enough money, or sold out
spend_money fails at zeroallowDebt is false
A reward is not paidthe mission or quest was not completed through the kit, or a money.earn tap cancelled it
Selling pays littlebuyRate is 0.5 by default; raise it or set a rate on the shop
The HUD shows the wrong symbolset currency (or seed economy.currency)