// PROCITY Lane C — buy loop v0 (round 8). In-memory wallet: seeded starting cash, purchases, inventory. // RUNTIME state only — reload resets, world generation is untouched (purchases never enter the plan or // the seeded room build). One wallet is shared across dig sessions + shops so F's shell can render the // same cash chip on the street. Economy is deliberately shallow (no persistence, no backend) — v0. import { mulberry32 } from '../core/prng.js'; export function createWallet(seed = 1) { const r = mulberry32(seed >>> 0); const start = 60 + ((r() * 140) | 0); // seeded starting cash ~$60–200 let cash = start; const inv = []; const listeners = new Set(); const notify = () => listeners.forEach(fn => { try { fn(); } catch (e) {} }); return { cash: () => cash, start: () => start, canBuy: (price) => (price || 0) <= cash, // buy(offer) — offer is a dig offer ({a:artist, t:title, price, ...}) or a pack item ({title,artist,price}). // Returns false (no state change) if broke. Deducts + records on success. buy(o) { const price = (o && o.price) || 0; if (price > cash) return false; cash -= price; inv.push({ title: o.t || o.title || '?', artist: o.a || o.artist || '', price, band: (o.s || o.price_band || '') }); notify(); return true; }, // [R30 §9.3] sell(item, offer) — the credit side of the counter, the exact mirror of buy(): adds the // offer (computed by sell.js sellOffer — this file never prices) and drops the matching v0-inventory // entry if one exists (by identity first, then title+artist). The GAME collection is NOT touched // here — that removal is the consumer's, via the game API (LANE_C_PUB §9.3). sell(o, offer) { const amt = Math.max(0, Math.floor(+offer || 0)); cash += amt; let i = inv.indexOf(o); if (i < 0) i = inv.findIndex((x) => x.title === (o.t || o.title) && x.artist === (o.a || o.artist || '')); if (i >= 0) inv.splice(i, 1); notify(); return true; }, inventory: () => inv.slice(), count: () => inv.length, onChange(fn) { listeners.add(fn); return () => listeners.delete(fn); }, }; }