P12's core — the meta-layer John asked for on day one. Tips scale with
the grade because that is how it works: an S pays, a D pays in abuse,
and the scorecard says so ('They left you $18.' / 'No tip. He watched
them not leave one.'). The money is deliberately gentle. This is a
kitchen, not a roguelike economy.
And then the tier rule, which is the entire design: CHEAP GEAR ADDS
NOISE AND EVENTS, NEVER A FLAT SCORE TAX. The small board you start on
does not subtract points anywhere. It does two things:
- it SHIFTS under a sawing knife, as literal lateral noise added to the
stroke, so the wedge and the CV it produces are earned by the hardware
the way a thin pan's hot spots are;
- it cannot hold a whole diced onion, so past about eight pieces the
outer ones are balanced on the rim and go on the floor.
Buy the big maple board off the catalogue and both simply stop. That is
the feel the atlas asked for and it is now measurable: the SAME drill,
the same cuts, went 10 of 12 with two on the floor and no medal on the
small board, and 12 of 12 with an S on the maple.
One bug that only existed because of this feature: the drill's short
verdict said 'Finish the cut before you stop the clock' — which is a
plain lie to a cook who DID finish and watched the board throw two
pieces away. It now names the floor when the floor is the reason.
Verified: an S tips $18; $42 buys the maple through the real catalogue
UI leaving $18; the board tier reaches both service prep and drills;
brûlée 7.5, mandoline 9.6, curry 10.0, chips 10.0, grill 9.4.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
90 lines
3.1 KiB
TypeScript
90 lines
3.1 KiB
TypeScript
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<string, number> = { 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';
|
|
}
|