Players can ask total-hand and primary-role card-count comparisons using the existing count controls and compound facts. Component presentation shares the same default-role classification, including canonical Richese cards, Ix alternate uses, and Ecaz slot-only specials. Only the respondent receives the verified aggregate answer; current facts do not impose future custody promises. Eight new tests cover all 60 catalog cards, real engine actions, malformed input, private worlds, all four bots, JSON continuation, and a legal custody transfer. Expanded production-room SQLite cases cover restored total/category/compound facts, suspended auction state, and one winning concurrent answer/discard. Independent review's two copy issues were fixed before broad verification. Validation: types, lint and 4,200 offline tests passed; production build passed; 40 HTTP tests passed. One stable broad run (check 123036 ms, build 6505 ms, integration 23467 ms). Browser room LC3E55GY verified combined role counts, total hand size, invalid-input feedback and refresh at 390px phone width. All 33 pre-integration rooms preserved unchanged; HTTP checks added 30 rooms. No complete-mode, full-game or publication gate opened. Private report: 20260913-hand-inventory-final/report.json Source fingerprint: c6a69a9e69941cdd1e5734d92afedbf10d31fda36c91d26ca7e15f4fb7c59b18 Efficiency pilot milestone 3: aggregate counter 58,695,053 to 59,144,653 at completed verification = 449,600 tokens, including context/coordination overhead. Two bounded workhorse-model helpers, reused UI and SQLite fixtures, one browser room. Counter is not monetary cost and this differently sized batch does not establish a savings percentage. Final Git/push overhead follows this sample.
41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
import type { Card } from './cards';
|
|
import { richeseCardDefinition } from './richese-cards';
|
|
|
|
export const CARD_CATEGORIES = [
|
|
'weapon',
|
|
'defense',
|
|
'worthless',
|
|
'hero',
|
|
'special',
|
|
] as const;
|
|
export type CardCategory = (typeof CARD_CATEGORIES)[number];
|
|
|
|
const PRIMARY_CATEGORY: Record<Card['kind'], CardCategory> = {
|
|
projectile: 'weapon',
|
|
poison: 'weapon',
|
|
lasgun: 'weapon',
|
|
poisonBlade: 'weapon',
|
|
poisonTooth: 'weapon',
|
|
artillery: 'weapon',
|
|
weirdingWay: 'weapon',
|
|
shield: 'defense',
|
|
snooper: 'defense',
|
|
shieldSnooper: 'defense',
|
|
chemistry: 'defense',
|
|
worthless: 'worthless',
|
|
hero: 'hero',
|
|
special: 'special',
|
|
};
|
|
|
|
/** Primary component role, independent of chosen battle slots or faction powers.
|
|
* Richese's physical definitions distinguish weapons/defenses stored as special.
|
|
* Weirding Way and Chemistry retain their defaults; Worthless remains separate.
|
|
*/
|
|
export function printedCardCategory(card: Card): CardCategory {
|
|
const definition = richeseCardDefinition(card);
|
|
if (definition?.behavior.battleCategory === 'weapon') return 'weapon';
|
|
if (definition?.behavior.battleCategory === 'poison-defense')
|
|
return 'defense';
|
|
return PRIMARY_CATEGORY[card.kind];
|
|
}
|