1 Commits

Author SHA1 Message Date
Nicolas Civade
569c0a73e4 Refactor cards into modular per-file definitions
Split the monolithic CARD_LIBRARY into one file per card under
cards/definitions/, aggregated by a barrel (definitions/index.ts).
card-library.ts now indexes ALL_CARDS by id with a duplicate-id guard.
Public API (CARD_LIBRARY, getCard, STARTER_DECK) and all card ids are
unchanged, so consumers and save data are unaffected.

Also ignore the .vite build cache.
2026-08-13 12:19:59 +02:00
10 changed files with 124 additions and 75 deletions

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ lerna-debug.log*
node_modules node_modules
dist dist
dist-ssr dist-ssr
.vite
*.local *.local
# Editor directories and files # Editor directories and files

View File

@@ -1,82 +1,21 @@
import type { CardData } from './card.types'; import type { CardData } from './card.types';
import { ALL_CARDS } from './definitions';
/** /**
* Central card library. All card definitions live here, keyed by id. * Central card library. Card *definitions* live one-per-file under ./definitions
* Content is data — add cards by adding entries, not code paths. * and are registered in ./definitions/index.ts; this module indexes them by id.
* Content is data — add cards by adding a file, not by editing code paths here.
*/ */
export const CARD_LIBRARY: Record<string, CardData> = { export const CARD_LIBRARY: Record<string, CardData> = buildLibrary();
strike: {
id: 'strike', function buildLibrary(): Record<string, CardData> {
name: 'Strike', const library: Record<string, CardData> = {};
type: 'attack', for (const card of ALL_CARDS) {
rarity: 'starter', if (library[card.id]) throw new Error(`Duplicate card id: ${card.id}`);
cost: 1, library[card.id] = card;
target: 'enemy', }
description: 'Deal 6 damage.', return library;
effect: { damage: 6 }, }
},
defend: {
id: 'defend',
name: 'Defend',
type: 'skill',
rarity: 'starter',
cost: 1,
target: 'self',
description: 'Gain 5 block.',
effect: { block: 5 },
},
bash: {
id: 'bash',
name: 'Bash',
type: 'attack',
rarity: 'starter',
cost: 2,
target: 'enemy',
description: 'Deal 10 damage.',
effect: { damage: 10 },
},
quick_slash: {
id: 'quick_slash',
name: 'Quick Slash',
type: 'attack',
rarity: 'common',
cost: 1,
target: 'enemy',
description: 'Deal 4 damage. Draw 1 card.',
effect: { damage: 4, draw: 1 },
},
cleave: {
id: 'cleave',
name: 'Cleave',
type: 'attack',
rarity: 'common',
cost: 1,
target: 'all-enemies',
description: 'Deal 8 damage to ALL enemies.',
effect: { damage: 8 },
},
flurry: {
id: 'flurry',
name: 'Flurry',
type: 'attack',
rarity: 'uncommon',
cost: 1,
target: 'enemy',
description: 'Deal 3 damage 3 times.',
effect: { damage: 3, hits: 3 },
},
adrenaline: {
id: 'adrenaline',
name: 'Adrenaline',
type: 'skill',
rarity: 'uncommon',
cost: 0,
target: 'none',
description: 'Gain 1 energy. Draw 2 cards. Exhaust.',
effect: { energy: 1, draw: 2 },
exhaust: true,
},
};
/** Look up a card definition by id; throws early on typos rather than failing silently. */ /** Look up a card definition by id; throws early on typos rather than failing silently. */
export function getCard(id: string): CardData { export function getCard(id: string): CardData {

View File

@@ -0,0 +1,13 @@
import type { CardData } from '../card.types';
export const adrenaline: CardData = {
id: 'adrenaline',
name: 'Adrenaline',
type: 'skill',
rarity: 'uncommon',
cost: 0,
target: 'none',
description: 'Gain 1 energy. Draw 2 cards. Exhaust.',
effect: { energy: 1, draw: 2 },
exhaust: true,
};

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const bash: CardData = {
id: 'bash',
name: 'Bash',
type: 'attack',
rarity: 'starter',
cost: 2,
target: 'enemy',
description: 'Deal 10 damage.',
effect: { damage: 10 },
};

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const cleave: CardData = {
id: 'cleave',
name: 'Cleave',
type: 'attack',
rarity: 'common',
cost: 1,
target: 'all-enemies',
description: 'Deal 8 damage to ALL enemies.',
effect: { damage: 8 },
};

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const defend: CardData = {
id: 'defend',
name: 'Defend',
type: 'skill',
rarity: 'starter',
cost: 1,
target: 'self',
description: 'Gain 5 block.',
effect: { block: 5 },
};

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const flurry: CardData = {
id: 'flurry',
name: 'Flurry',
type: 'attack',
rarity: 'uncommon',
cost: 1,
target: 'enemy',
description: 'Deal 3 damage 3 times.',
effect: { damage: 3, hits: 3 },
};

View File

@@ -0,0 +1,24 @@
import type { CardData } from '../card.types';
import { strike } from './strike';
import { defend } from './defend';
import { bash } from './bash';
import { quickSlash } from './quick-slash';
import { cleave } from './cleave';
import { flurry } from './flurry';
import { adrenaline } from './adrenaline';
/**
* Card manifest. Every card definition is registered here exactly once.
* Adding a card = create ./<card>.ts, then add one import + one array entry.
* The library (card-library.ts) keys these by id and enforces uniqueness.
*/
export const ALL_CARDS: readonly CardData[] = [
strike,
defend,
bash,
quickSlash,
cleave,
flurry,
adrenaline,
];

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const quickSlash: CardData = {
id: 'quick_slash',
name: 'Quick Slash',
type: 'attack',
rarity: 'common',
cost: 1,
target: 'enemy',
description: 'Deal 4 damage. Draw 1 card.',
effect: { damage: 4, draw: 1 },
};

View File

@@ -0,0 +1,12 @@
import type { CardData } from '../card.types';
export const strike: CardData = {
id: 'strike',
name: 'Strike',
type: 'attack',
rarity: 'starter',
cost: 1,
target: 'enemy',
description: 'Deal 6 damage.',
effect: { damage: 6 },
};