47 lines
2.2 KiB
JavaScript
47 lines
2.2 KiB
JavaScript
// 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); },
|
||
};
|
||
}
|