PROCITY/web/js/interiors/wallet.js

47 lines
2.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 ~$60200
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); },
};
}