import type { Grade } from './judging'; /** * THE CATALOGUE — money, and gear that changes your hands. * * Tips scale with the grade, because that is how it works: an S pays, a D * pays in abuse. The money is gentle on purpose. This is a kitchen, not a * roguelike economy, and nothing here is a stat stick. * * THE TIER RULE, which is the whole design: cheap gear adds NOISE and * EVENTS, never a flat score tax. The small board does not subtract points — * it WOBBLES under the knife and lets the outer pieces roll onto the floor. * You feel the upgrade in your hands, not in a stat sheet, and the day you * buy the big maple board the first thing you notice is the silence of * nothing rolling off the edge. */ export interface CatalogueItem { id: string; slot: 'board'; label: string; /** The catalogue's own patter, in the house voice. */ blurb: string; price: number; /** Higher is better. The slot's tier is the best item you own in it. */ tier: number; } export const CATALOGUE: CatalogueItem[] = [ { id: 'board_maple', slot: 'board', label: 'THE BIG MAPLE BOARD', blurb: 'Twice the room and it does not budge. Dice a whole onion on it and every piece is still on the board when you look up.', price: 42, tier: 1, }, { id: 'board_endgrain', slot: 'board', label: 'THE END-GRAIN BLOCK', blurb: 'The fibres stand up to meet the blade instead of lying across it. Heavy as a small dog. Kind to knives.', price: 120, tier: 2, }, ]; /** What you start with: a small board that wobbles and loses things. */ export const STARTER_TIERS: Record = { board: 0 }; /** * The tip. An S is worth having; below a C he is not paying you for it, and * the number is small enough that money never becomes the point. */ export function tipFor(grade: Grade, total: number): number { const base = grade === 'S' ? 14 : grade === 'A' ? 9 : grade === 'B' ? 5 : grade === 'C' ? 2 : 0; // A whisker of scaling inside the band so a 9.9 beats a 9.0. return Math.round(base + total * 0.4); } /** The best tier owned in a slot — what the bench should actually hand you. */ export function tierOf(slot: string, owned: string[]): number { let best = STARTER_TIERS[slot] ?? 0; for (const id of owned) { const it = CATALOGUE.find((c) => c.id === id); if (it && it.slot === slot && it.tier > best) best = it.tier; } return best; } /** How much a board of this tier shakes under a sawing knife. */ export function boardWobble(tier: number): number { return tier === 0 ? 0.055 : 0; // the cheap one is the only one that moves } /** * Odds a finished piece rolls off the edge, per piece past what the board can * hold. The small board holds about eight; everything after that is balanced * on the rim, and the floor is right there. */ export function rollOffChance(tier: number, pieceIndex: number): number { if (tier > 0) return 0; const over = pieceIndex - 8; return over <= 0 ? 0 : Math.min(0.5, over * 0.12); } export function boardName(tier: number): string { return tier === 0 ? 'the small board' : tier === 1 ? 'the big maple board' : 'the end-grain block'; }