Plain command surface for V1 (Phase 3): /quests, /quests info, /quests cancel. Cheap to ship, works on mobile via the bridge. Quest Log book item in V2 (Phase 3.5) -- nicer surface, same backend. Sidebar HUD as V3 later, optional. Adds a 3-quest active slot cap so cancellation is meaningful: prevents accept-all/RNG-shop-cancel exploit, makes the cancel button a real choice. Quest moves to READY frees the slot. State storage schema documented (per-player JSON with active + completed/cooldown tracking). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
16 KiB
Brass and Sigil — Economy & Quest System Design
Status: design draft (v0.1). Not yet implemented. Owner: matt Last updated: 2026-06-06
1. Goals
- One unified currency — spurs (Numismatics).
- Multiple ways to earn, each one bounded. No infinite money printer.
- Multiple sinks that scale with progression. Money disappears as you advance, so wealth never dwarfs the cost of new ambitions.
- Spatial design that gives spawn personality. Themed guild buildings, each with a clear purpose, each tied to the same wallet.
- Forward-compat with a proper quest line via FTB Quests, while supporting daily/repeatable activities at spawn.
- Anti-automation by design, not by patches.
2. Core architecture
┌────── MONEY IN (bounded) ──────┐
│ │
Adventurer's Guild — Daily bounties (cooldowns, scaling)
Merchant's Bazaar — Sell shop (fixed + DR), dynamic exchange
Mint — Capped emerald → spur conversion *
First-time milestones — One-shot per player
FTB Quests — Progression milestone payouts
│
▼
┌───────────────────┐
│ Player wallet │ ← Numismatics
│ (spurs) │
└───────────────────┘
│
▼
┌────── MONEY OUT (scaling) ──────┐
│ │
Civic Office — Plot claim costs (FTB Chunks override)
Civic Office — Tier upgrades (FTB Ranks integration)
Merchant's Bazaar — Player-to-player job board (no minting)
Villagers — Re-priced trades, net sink
Custom services — Warps, sethomes, premium cosmetics
* Only if we keep emeralds; see §5 — we're moving villagers to spurs, which probably retires the Mint as a currency-conversion station and repurposes it as a wallet/info hub.
3. Spawn — themed guild buildings
Each guild is a destination. The guild's NPC is both the entry point (accept work) and exit point (return to claim reward). This pattern applies universally — see §4.
| Building | Purpose | Primary mechanics inside |
|---|---|---|
| Adventurer's Guild | Combat & exploration | Bounty board (daily mob hunts), boss-kill quests, dungeon-delve quests (future) |
| Merchant's Bazaar | Trade & raw-mat economy | Numismatics sell shop, dynamic exchange counter, player-driven job board |
| Civic Office | Land & status | Plot claim office, tier upgrades, sethome/warp services |
| Library / Academy | Knowledge & magic | FTB Quests anchor NPC, Ars Nouveau themed quests, lore terminals |
| Tavern | Social & onboarding | First-time newbie quests, casual NPCs, food/buff vendor |
| Foundry / Workshop | Crafting & commissions | Create-themed contracts, crafting orders, raw-material market |
| Mint | Currency information | Wallet info, currency tutorial, possibly emerald exchange |
Forward-compat with a full quest line
The architecture is naturally dual-track:
- FTB Quests = the progression backbone — chapter-by-chapter pack content, one-time rewards, story arcs. The campaign.
- Spawn-building NPCs (Easy NPC + KubeJS) = the daily/repeatable layer — bounties, sell shops, services. The live activities.
Both pay into the same wallet. Players run the campaign at their pace and the daily content for income/replay value. They reinforce each other rather than compete.
4. Quest & bounty flow (universal pattern)
Core principle: for any guild, the player accepts work from an NPC, completes it in the world, then returns to that NPC to turn it in and claim the reward. No instant payouts. This:
- Anchors guilds as destinations
- Creates risk/reward tension (die on the return, lose the reward)
- Encourages waypoint use and travel
- Lets the server centrally control payouts and detect cheating
State machine
Each quest, per player, lives in one of these states:
AVAILABLE ─[player accepts]─► ACTIVE ─[objective met]─► READY ─[turned in]─► COMPLETED
▲ │
└──────────────────────[cooldown elapses]───────────────────────────────────────────┘
- AVAILABLE — NPC offers the quest in dialog. Player has no current copy of it.
- ACTIVE — Player accepted. KubeJS tracks objective progress via relevant events (
EntityEvents.deathfor kills,ItemEvents.firstRightClickedfor explorations, etc.). - READY — Objective met. Reward is promised but not yet paid. NPC dialog now offers a turn-in option.
- COMPLETED — Reward paid out. Quest goes on cooldown for this player.
- AVAILABLE (again) — after the cooldown, the NPC will offer it again.
Worked example — daily bounty
- Adventurer's Guild NPC has 5 randomized daily quests (e.g. "Slay 10 Plunderers — 50 spurs").
- Player right-clicks NPC → Easy NPC dialog → "Accept: Slay 10 Plunderers."
- KubeJS writes
quest:plunderer_10to the player's quest state withcount: 0. - Player kills Plunderers in the world.
EntityEvents.deathforsupplementaries:plundererincrements the count. - At count=10, KubeJS flips state to READY and notifies the player ("Return to the Adventurer's Guild to claim your reward.").
- Player returns. Right-click NPC. Easy NPC dialog detects READY state and offers "Turn in: Slay 10 Plunderers."
- KubeJS pays 50 spurs into the player's Numismatics wallet, flips state to COMPLETED, sets cooldown to 24h.
Universal applicability
The same accept → complete → return pattern works for every guild:
| Guild | Accept | Complete | Return |
|---|---|---|---|
| Adventurer's | "Hunt 10 plunderers" | kill them | NPC pays bounty |
| Merchant's | "Procure 32 diamonds for our buyer" | gather them | NPC pays inflated price + completes |
| Civic | "Survey 5 unclaimed chunks" | walk through them | NPC pays survey fee |
| Library | "Recover this lost tome" | find the book in a structure | NPC pays + grants reputation |
| Foundry | "Craft 10 Andesite Casings" | craft them | NPC pays commission |
Player-facing tracking & cancellation
A quest engine that players can't inspect is worthless. The design ships with three layers of visibility:
V1 — command-driven (Phase 3, with the engine)
| Command | Effect |
|---|---|
/quests |
Lists all of your ACTIVE and READY quests with progress, source guild, and reward |
/quests info <id> |
Detail view for one quest — description, objective, progress, reward |
/quests cancel <id> |
Drops an active quest, freeing your slot. The quest goes on cooldown as if completed (prevents accept-cancel-accept RNG farming) |
Cheap to ship. Works on mobile via the Telegram bridge. Doesn't require any extra mods.
V2 — Quest Log book item (Phase 3.5)
Every new player joins with a Quest Log book in their inventory (KubeJS PlayerEvents.loggedIn grants it once). Right-click to open. Dynamic Patchouli-style pages list active/ready quests, with a "Cancel" button per quest. Same backend as the /quests commands — just a nicer surface.
V3 — Sidebar HUD (later)
Optional scoreboard sidebar showing 2-3 most recent quests + progress, always-on. Implemented via vanilla scoreboard objectives driven by KubeJS. Players can toggle on/off via /quests sidebar.
Quest slot limit
Players have a maximum of 3 active quests at a time. This is the friction that makes cancel meaningful:
- Forces players to pick which quests they actually want — no "accept all 5, see what's easiest, cancel the rest" RNG-shopping.
- Keeps the state files small.
- Makes ready-to-turn-in queues meaningful (you can hold 3 unrewarded quests in your back pocket).
A quest moving to READY frees the slot for accepting a new one even before turn-in.
KubeJS implementation sketch
- State storage: per-player JSON in
world/data/bns_quests/<uuid>.json, written via KubeJS persistent-data hooks. Schema:{ "active": [ { "id": "advg_plunderer_10", "acceptedAt": 1717684800, "progress": 7, "target": 10, "rewardSpurs": 50, "source": "adventurers_guild" } ], "completed": { "advg_plunderer_10": { "cooldownUntil": 1717771200, "completions": 3 } } } - Event tracking: standard KubeJS event handlers (
EntityEvents.death,ItemEvents.pickedUp,BlockEvents.broken) read the player's active quests and increment. - Dialog branching: Easy NPC dialog with conditions that call KubeJS to check quest state and route the dialog appropriately.
- Reward delivery: call Numismatics' wallet API to deposit spurs.
- Commands: registered via
ServerEvents.commandRegistryin KubeJS, scoped to the player who runs them.
5. Villager rebalance
Decision: move all villagers to spurs (not emeralds). Thematic consistency over preserving vanilla mental model.
Decision principles:
- Villagers are net money sinks — players spend more on villagers than they earn from them.
- Useful trades stay — enchanted books, tools, food, decorative blocks. Reasonable spur prices.
- Trash trades get deleted — no one ever wanted to sell rotten flesh or buy paper.
- Sell-to-villager trades exist but are bad —
64 wheat → 1 spur,16 leather → 1 spur. Farms still possible, but ~10× slower than any other income source.
Price guidance (initial calibration — tune via playtesting)
Buy-from-villager (player pays spurs)
| Item | Tier-1 | Tier-3 | Tier-5 |
|---|---|---|---|
| Standard enchanted book (random) | 50 spurs | 120 spurs | 250 spurs |
| Mending book | — | — | 800 spurs |
| Diamond tool (unenchanted) | — | 80 spurs | — |
| Diamond tool (enchanted) | — | — | 350 spurs |
| Bookshelf | 15 spurs | — | — |
Sell-to-villager (player gets spurs)
| Item | Spurs per unit |
|---|---|
| Wheat | 1 per 64 |
| Paper | 1 per 32 |
| Leather | 1 per 16 |
| Iron ingot | 2 per 1 |
| Diamond | 8 per 1 (matches sell-shop fixed price — players use whichever is closer) |
Scope
~60 trades × 5 profession tiers = ~300 trade entries to redesign. One-time data-design pass, implemented via ServerEvents.villagerTrades in KubeJS.
6. Money inflow sources (detailed)
| Source | Cap / DR mechanism | Rough rate |
|---|---|---|
| Daily bounties | Per-player per-quest cooldown (24h) | ~200-500 spurs/day for an active player |
| Sell shop (fixed price + DR) | Lifetime sales tracker per player, 10% price drop per 64 sold | ~50-200 spurs/hr while diamond stockpile lasts |
| Dynamic exchange | Global supply pool — price drops with sales | Self-balancing |
| First-time milestones | One-shot per player (hasFlag) |
5-50 spurs per milestone, ~10 milestones total |
| FTB Quest progression | One-time per quest | Varies; cluster rewards at chapter completion |
| Villager sell trades | Inherently slow + bad prices | ~50 spurs/hr from a serious villager farm |
7. Money outflow sinks (detailed)
| Sink | Cost curve | Why this scales right |
|---|---|---|
| Plot claims | Free up to 9 chunks. 50 spurs/chunk to 25. 200 spurs/chunk beyond. | New players claim free starter areas; ambitious players pay real money |
| Tier upgrades | Cumulative cost: 500 → 2k → 8k → 30k spurs | Endgame sink, status display |
| Buy-from-villager | See §5 | Constant outflow as you build up |
| Premium cosmetics | 100-2k spurs each | Optional sink for cash-flush players |
| Services | Sethome: 50 spurs, warp: 25 spurs, /back: 10 spurs | Convenience taxes |
8. Mod stack (we have what we need)
| Need | Mod | Status |
|---|---|---|
| Currency + wallets + shop blocks | Numismatics | ✅ In pack |
| NPC quest-givers + dialog | Easy NPC | ✅ In pack |
| Quest engine (progression) | FTB Quests | ⏳ Planned, not added |
| Plot claims | FTB Chunks | ✅ In pack |
| Tier system | FTB Ranks | ❓ Not in pack — add when we get to tiers |
| Glue & quest state | KubeJS | ✅ In pack |
Not adding: CustomNPCs (Easy NPC covers it), Citizens (Bukkit-only), PMMO (out of scope), generic "quest giver" mods (FTB Quests + KubeJS do it).
9. Phasing
Each phase is independently shippable. Earlier phases unlock value without depending on later ones.
| Phase | Deliverable | Why this order |
|---|---|---|
| 0 | Spawn skeleton built — 7 guild buildings placed (rough). | Locations have to exist before NPCs can stand in them. |
| 1 | Merchant's Bazaar V1: Numismatics sell shop (fixed prices, no DR yet) for diamonds & netherite. | Cheapest to ship, immediate economy unlock. |
| 2 | Civic Office V1: Plot claim cost via KubeJS /ftbchunks claim override. |
Real money sink. Tests FTB Chunks integration depth. |
| 3 | Adventurer's Guild V1: Bounty board engine. 5 daily quests, accept→complete→return flow, /quests commands, 3-slot cap. |
The biggest gameplay feature. Validates the universal quest pattern. |
| 3.5 | Quest Log book item (V2 of tracking surface). | Nicer UX surface on top of the same engine — non-blocking. |
| 4 | Villager rebalance: strip vanilla, ship the spur-priced trade table. | Closes the exploit. Big JSON pass. |
| 5 | Library / Academy: FTB Quests anchor + first chapter of progression quests. | Long-form content begins. |
| 6 | Civic Office V2: FTB Ranks integration + tier upgrades. | Endgame money sink. |
| 7 | Dynamic exchange rates (Bazaar V2). | Most engineering, biggest anti-farm payoff, ship last. |
| 8+ | Foundry, Tavern, deeper Library quests, dungeons-with-Lootr. | Beyond V1. |
10. Risk register
| Risk | Likelihood | Mitigation |
|---|---|---|
| Bounty engine bugs out, players lose progress | Medium | Atomic state writes; logs of every state transition |
| Villager farms still profitable after rebalance | Medium | Track player sell volumes; tune prices in patches |
| KubeJS-EasyNPC dialog branching has limits | Low-Med | Verify hooks in a test world before Phase 3; fall back to command-driven NPCs if needed |
FTB Chunks /claim command override gotchas |
Low | Test in dev world; FTB Chunks API is stable |
| Plot cost feels punishing | Med | First 9 chunks free is the safety valve; tune from playtest |
Players bypass the system via creative / /give |
Op-only | Document op responsibility; consider audit logs for op spur grants |
11. Open decisions
These need an actual call before implementation:
- Keep emeralds as a secondary collectible? Or fully retire them now that villagers don't use them?
- Sethomes / warps as paid services? Or free baseline?
- PvP bounties (players posting bounties on other players)? Probably no for V1, revisit later.
- Lootr — add for shared dungeon loot, or skip until structured dungeons exist?
- Daily quest count — start with 5? 8? Refresh window — true daily (00:00 UTC) or per-player 24h?
12. Implementation notes
- Document each phase's KubeJS scripts under
pack/overrides/kubejs/server_scripts/economy/<phase>.js - State data under
world/data/bns_economy/— readable JSON, easy to debug - All NPC dialog trees authored in Easy NPC's editor, exported as preset JSONs into
pack/overrides/world/datapacks/bns-fuel/data/easy_npc/ - Trade table for villager rebalance lives in a single
villager_trades.jsso one file is the source of truth
See also
MEMORY.mdentries:project-mc-player-economy.md— earlier higher-level notes on Numismatics + plot systemfeedback-kubejs-rhino-gotchas.md— KubeJS scripting constraintsfeedback-bns-pack-version-sync.md— pack version + sync workflow
- Existing tasks #20-#26 — to be reshuffled to mirror the phase plan above