Files
arcane-duels/server/cards.js
2026-03-13 16:01:39 -04:00

909 lines
26 KiB
JavaScript

// ============================================================================
// ARCANE DUELS — Complete Card Database
// An original TCG with 5 colors: Radiance, Tide, Shadow, Flame, Growth
// ============================================================================
const COLORS = {
RADIANCE: 'radiance', // White — order, healing, protection
TIDE: 'tide', // Blue — knowledge, control, illusion
SHADOW: 'shadow', // Black — death, sacrifice, power
FLAME: 'flame', // Red — chaos, destruction, speed
GROWTH: 'growth', // Green — nature, strength, growth
COLORLESS: 'colorless',
};
const TYPES = {
CREATURE: 'creature',
SORCERY: 'sorcery',
INSTANT: 'instant',
ENCHANTMENT: 'enchantment',
ARTIFACT: 'artifact',
LAND: 'land',
};
// Keywords mapping
const KEYWORDS = {
SWIFT: 'swift', // Can attack immediately (Haste)
VIGILANT: 'vigilant', // Doesn't tap to attack (Vigilance)
SOARING: 'soaring', // Can only be blocked by Soaring/Reaching (Flying)
GUARDIAN: 'guardian', // Deals damage first in combat (First Strike)
FORTIFIED: 'fortified', // Can't attack (Defender)
DRAINING: 'draining', // Gain life equal to damage dealt (Lifelink)
OVERWHELMING: 'overwhelming', // Excess combat damage hits player (Trample)
VENOMOUS: 'venomous', // Any damage is lethal (Deathtouch)
REACHING: 'reaching', // Can block Soaring creatures (Reach)
};
// Mana cost encoding: { radiance: N, tide: N, shadow: N, flame: N, growth: N, colorless: N }
// e.g. 2W = { colorless: 2, radiance: 1 }
let nextId = 1;
function card(props) {
return { id: nextId++, ...props };
}
// ============================================================================
// RADIANCE (White) — 12 cards
// ============================================================================
const radianceCards = [
card({
name: 'Sanctuary Guard',
type: TYPES.CREATURE,
cost: { colorless: 1, radiance: 1 },
color: COLORS.RADIANCE,
power: 2, toughness: 2,
keywords: [],
abilities: [],
flavor: 'The temple never falls while its guardians stand.',
rarity: 'common',
}),
card({
name: 'Dawn Priest',
type: TYPES.CREATURE,
cost: { colorless: 2, radiance: 1 },
color: COLORS.RADIANCE,
power: 1, toughness: 4,
keywords: [KEYWORDS.FORTIFIED],
abilities: [{ trigger: 'upkeep', effect: 'gainLife', amount: 1 }],
flavor: 'Each sunrise is a prayer answered.',
rarity: 'uncommon',
}),
card({
name: 'Shieldbearer',
type: TYPES.CREATURE,
cost: { radiance: 1 },
color: COLORS.RADIANCE,
power: 1, toughness: 1,
keywords: [KEYWORDS.VIGILANT],
abilities: [],
flavor: 'Always watching, never resting.',
rarity: 'common',
}),
card({
name: 'Radiant Champion',
type: TYPES.CREATURE,
cost: { colorless: 3, radiance: 2 },
color: COLORS.RADIANCE,
power: 4, toughness: 4,
keywords: [KEYWORDS.VIGILANT],
abilities: [],
flavor: 'She carries the light of a thousand dawns into battle.',
rarity: 'rare',
}),
card({
name: 'Lightbringer',
type: TYPES.CREATURE,
cost: { colorless: 2, radiance: 1 },
color: COLORS.RADIANCE,
power: 2, toughness: 2,
keywords: [],
abilities: [{ trigger: 'enters', effect: 'gainLife', amount: 3 }],
flavor: 'Where she walks, wounds close and despair lifts.',
rarity: 'common',
}),
card({
name: 'Angelic Sentinel',
type: TYPES.CREATURE,
cost: { colorless: 3, radiance: 2 },
color: COLORS.RADIANCE,
power: 3, toughness: 5,
keywords: [KEYWORDS.SOARING, KEYWORDS.VIGILANT],
abilities: [],
flavor: 'Its wings span the horizon, shielding the faithful below.',
rarity: 'rare',
}),
card({
name: 'Holy Wrath',
type: TYPES.SORCERY,
cost: { colorless: 2, radiance: 2 },
color: COLORS.RADIANCE,
abilities: [{ effect: 'destroyCreatureIf', condition: 'powerGte4' }],
flavor: 'The righteous need not fear judgment.',
rarity: 'uncommon',
}),
card({
name: 'Mending Light',
type: TYPES.INSTANT,
cost: { radiance: 1 },
color: COLORS.RADIANCE,
abilities: [{ effect: 'gainLife', amount: 4 }],
flavor: 'A warm glow that knits flesh and spirit alike.',
rarity: 'common',
}),
card({
name: 'Celestial Shield',
type: TYPES.INSTANT,
cost: { colorless: 1, radiance: 1 },
color: COLORS.RADIANCE,
abilities: [{ effect: 'pumpCreature', power: 0, toughness: 4, duration: 'endOfTurn' }],
flavor: 'The blow struck true—but found only light.',
rarity: 'common',
}),
card({
name: 'Divine Decree',
type: TYPES.ENCHANTMENT,
cost: { colorless: 2, radiance: 2 },
color: COLORS.RADIANCE,
abilities: [{ effect: 'anthemBuff', power: 1, toughness: 1 }],
flavor: 'By decree of the High Luminary, all shall stand firm.',
rarity: 'rare',
}),
card({
name: 'Purifying Light',
type: TYPES.SORCERY,
cost: { colorless: 3, radiance: 2 },
color: COLORS.RADIANCE,
abilities: [{ effect: 'destroyAllCreatures' }],
flavor: 'When the light burns too bright, nothing remains.',
rarity: 'rare',
}),
card({
name: 'Resolute Defender',
type: TYPES.CREATURE,
cost: { colorless: 1, radiance: 1 },
color: COLORS.RADIANCE,
power: 1, toughness: 3,
keywords: [KEYWORDS.GUARDIAN],
abilities: [],
flavor: 'His shield has turned a thousand blades.',
rarity: 'common',
}),
];
// ============================================================================
// TIDE (Blue) — 12 cards
// ============================================================================
const tideCards = [
card({
name: 'Reef Scholar',
type: TYPES.CREATURE,
cost: { colorless: 1, tide: 1 },
color: COLORS.TIDE,
power: 1, toughness: 2,
keywords: [],
abilities: [{ trigger: 'enters', effect: 'drawCards', amount: 1 }],
flavor: 'The coral libraries hold secrets older than the continents.',
rarity: 'common',
}),
card({
name: 'Tidal Serpent',
type: TYPES.CREATURE,
cost: { colorless: 4, tide: 2 },
color: COLORS.TIDE,
power: 5, toughness: 5,
keywords: [KEYWORDS.SOARING],
abilities: [],
flavor: 'It moves between sea and sky as if the boundary were a suggestion.',
rarity: 'rare',
}),
card({
name: 'Mistwalker',
type: TYPES.CREATURE,
cost: { colorless: 2, tide: 1 },
color: COLORS.TIDE,
power: 2, toughness: 1,
keywords: [KEYWORDS.SOARING],
abilities: [],
flavor: 'It drifts through the fog, never quite where you expect.',
rarity: 'common',
}),
card({
name: 'Arcane Student',
type: TYPES.CREATURE,
cost: { tide: 1 },
color: COLORS.TIDE,
power: 1, toughness: 1,
keywords: [],
abilities: [{ trigger: 'tap', effect: 'scry', amount: 1 }],
flavor: 'Every page reveals a new horizon.',
rarity: 'common',
}),
card({
name: 'Current Channeler',
type: TYPES.CREATURE,
cost: { colorless: 2, tide: 2 },
color: COLORS.TIDE,
power: 2, toughness: 4,
keywords: [],
abilities: [{ trigger: 'spellCast', effect: 'drawCards', amount: 1 }],
flavor: 'Magic flows through her like water through a delta.',
rarity: 'rare',
}),
card({
name: 'Mind Shatter',
type: TYPES.INSTANT,
cost: { tide: 2 },
color: COLORS.TIDE,
abilities: [{ effect: 'counterSpell' }],
flavor: 'Your incantation unravels before the last syllable.',
rarity: 'uncommon',
}),
card({
name: 'Essence Drain',
type: TYPES.INSTANT,
cost: { colorless: 1, tide: 1 },
color: COLORS.TIDE,
abilities: [{ effect: 'bounceCreature' }],
flavor: 'Returned to the aether, as if it had never been summoned.',
rarity: 'common',
}),
card({
name: 'Foresight',
type: TYPES.SORCERY,
cost: { tide: 1 },
color: COLORS.TIDE,
abilities: [{ effect: 'drawCards', amount: 2 }],
flavor: 'To see what comes is the first step to mastering it.',
rarity: 'common',
}),
card({
name: 'Mental Fortress',
type: TYPES.ENCHANTMENT,
cost: { colorless: 2, tide: 1 },
color: COLORS.TIDE,
abilities: [{ effect: 'extraDraw', amount: 1 }],
flavor: 'Within these walls, knowledge multiplies endlessly.',
rarity: 'rare',
}),
card({
name: 'Time Warp',
type: TYPES.SORCERY,
cost: { colorless: 3, tide: 2 },
color: COLORS.TIDE,
abilities: [{ effect: 'extraTurn' }],
flavor: 'Yesterday and tomorrow are merely pages to be turned.',
rarity: 'mythic',
}),
card({
name: 'Frost Barrier',
type: TYPES.INSTANT,
cost: { colorless: 1, tide: 1 },
color: COLORS.TIDE,
abilities: [{ effect: 'tapCreature' }],
flavor: 'Frozen mid-stride, locked in a prison of ice.',
rarity: 'common',
}),
card({
name: 'Thought Thief',
type: TYPES.CREATURE,
cost: { colorless: 1, tide: 1 },
color: COLORS.TIDE,
power: 2, toughness: 1,
keywords: [],
abilities: [{ trigger: 'dealsDamage', effect: 'drawCards', amount: 1 }],
flavor: 'What you know, he knows. What he knows, you never will.',
rarity: 'uncommon',
}),
];
// ============================================================================
// SHADOW (Black) — 12 cards
// ============================================================================
const shadowCards = [
card({
name: 'Graveborn Ghoul',
type: TYPES.CREATURE,
cost: { colorless: 1, shadow: 1 },
color: COLORS.SHADOW,
power: 2, toughness: 2,
keywords: [],
abilities: [],
flavor: 'It remembers nothing of its former life, only hunger.',
rarity: 'common',
}),
card({
name: 'Soul Collector',
type: TYPES.CREATURE,
cost: { colorless: 3, shadow: 2 },
color: COLORS.SHADOW,
power: 3, toughness: 4,
keywords: [KEYWORDS.DRAINING],
abilities: [],
flavor: 'Each soul taken makes it stronger, and its victims weaker.',
rarity: 'rare',
}),
card({
name: 'Plague Rat',
type: TYPES.CREATURE,
cost: { colorless: 1, shadow: 1 },
color: COLORS.SHADOW,
power: 1, toughness: 1,
keywords: [],
abilities: [{ effect: 'plagueRatBonus' }],
flavor: 'Where one scurries, a hundred follow.',
rarity: 'common',
}),
card({
name: 'Night Terror',
type: TYPES.CREATURE,
cost: { colorless: 2, shadow: 1 },
color: COLORS.SHADOW,
power: 2, toughness: 1,
keywords: [KEYWORDS.SOARING],
abilities: [],
flavor: 'It feeds on screams the way others feed on bread.',
rarity: 'common',
}),
card({
name: 'Bone Revenant',
type: TYPES.CREATURE,
cost: { colorless: 4, shadow: 2 },
color: COLORS.SHADOW,
power: 6, toughness: 5,
keywords: [KEYWORDS.VENOMOUS],
abilities: [],
flavor: 'Assembled from the bones of fallen champions.',
rarity: 'rare',
}),
card({
name: 'Vampiric Noble',
type: TYPES.CREATURE,
cost: { colorless: 2, shadow: 1 },
color: COLORS.SHADOW,
power: 3, toughness: 2,
keywords: [KEYWORDS.DRAINING],
abilities: [],
flavor: 'She attends the finest galas. Few guests leave alive.',
rarity: 'uncommon',
}),
card({
name: 'Raise Dead',
type: TYPES.SORCERY,
cost: { shadow: 1 },
color: COLORS.SHADOW,
abilities: [{ effect: 'returnFromGraveyard', type: 'creature' }],
flavor: 'Death is merely a temporary inconvenience.',
rarity: 'common',
}),
card({
name: 'Dark Pact',
type: TYPES.SORCERY,
cost: { shadow: 2 },
color: COLORS.SHADOW,
abilities: [{ effect: 'drawCards', amount: 2 }, { effect: 'loseLife', amount: 2 }],
flavor: 'Power has a price. The wise pay it willingly.',
rarity: 'uncommon',
}),
card({
name: 'Assassinate',
type: TYPES.INSTANT,
cost: { colorless: 1, shadow: 2 },
color: COLORS.SHADOW,
abilities: [{ effect: 'destroyCreature' }],
flavor: 'No spell, no blade—just silence, then nothing.',
rarity: 'uncommon',
}),
card({
name: 'Drain Life',
type: TYPES.SORCERY,
cost: { shadow: 2 },
color: COLORS.SHADOW,
abilities: [{ effect: 'drainLife', isX: true }],
flavor: 'Your loss is my gain, in the most literal sense.',
rarity: 'uncommon',
}),
card({
name: 'Cursed Ground',
type: TYPES.ENCHANTMENT,
cost: { colorless: 1, shadow: 1 },
color: COLORS.SHADOW,
abilities: [{ trigger: 'creatureDies', effect: 'opponentLosesLife', amount: 1 }],
flavor: 'Nothing rests peacefully here.',
rarity: 'uncommon',
}),
card({
name: 'Mind Rot',
type: TYPES.SORCERY,
cost: { colorless: 1, shadow: 1 },
color: COLORS.SHADOW,
abilities: [{ effect: 'opponentDiscards', amount: 2 }],
flavor: 'Thoughts dissolve like morning mist in the darkness.',
rarity: 'common',
}),
];
// ============================================================================
// FLAME (Red) — 12 cards
// ============================================================================
const flameCards = [
card({
name: 'Goblin Striker',
type: TYPES.CREATURE,
cost: { flame: 1 },
color: COLORS.FLAME,
power: 1, toughness: 1,
keywords: [KEYWORDS.SWIFT],
abilities: [],
flavor: 'Speed is a virtue. Thinking is not.',
rarity: 'common',
}),
card({
name: 'Fire Elemental',
type: TYPES.CREATURE,
cost: { colorless: 3, flame: 2 },
color: COLORS.FLAME,
power: 5, toughness: 4,
keywords: [],
abilities: [],
flavor: 'Born of the mountain\'s heart, it answers to no master.',
rarity: 'uncommon',
}),
card({
name: 'Lightning Imp',
type: TYPES.CREATURE,
cost: { colorless: 1, flame: 1 },
color: COLORS.FLAME,
power: 2, toughness: 1,
keywords: [KEYWORDS.SWIFT],
abilities: [],
flavor: 'It arrives with the thunder and leaves with the echo.',
rarity: 'common',
}),
card({
name: 'Lava Golem',
type: TYPES.CREATURE,
cost: { colorless: 2, flame: 1 },
color: COLORS.FLAME,
power: 3, toughness: 2,
keywords: [],
abilities: [],
flavor: 'Molten stone given purpose, if not grace.',
rarity: 'common',
}),
card({
name: 'Dragon of the Peaks',
type: TYPES.CREATURE,
cost: { colorless: 4, flame: 2 },
color: COLORS.FLAME,
power: 5, toughness: 5,
keywords: [KEYWORDS.SOARING, KEYWORDS.SWIFT],
abilities: [],
flavor: 'The mountain trembles when it wakes. The world trembles when it flies.',
rarity: 'mythic',
}),
card({
name: 'Berserker Ogre',
type: TYPES.CREATURE,
cost: { colorless: 2, flame: 2 },
color: COLORS.FLAME,
power: 4, toughness: 3,
keywords: [KEYWORDS.OVERWHELMING],
abilities: [],
flavor: 'Subtlety is a foreign concept. Destruction is its mother tongue.',
rarity: 'uncommon',
}),
card({
name: 'Lightning Bolt',
type: TYPES.INSTANT,
cost: { flame: 1 },
color: COLORS.FLAME,
abilities: [{ effect: 'dealDamage', amount: 3, target: 'any' }],
flavor: 'The sky cracks open and chooses its victim.',
rarity: 'common',
}),
card({
name: 'Fireball',
type: TYPES.SORCERY,
cost: { flame: 1 },
color: COLORS.FLAME,
abilities: [{ effect: 'dealDamage', target: 'any', isX: true }],
flavor: 'The equation is simple: more mana, more fire.',
rarity: 'uncommon',
}),
card({
name: 'Inferno',
type: TYPES.SORCERY,
cost: { colorless: 3, flame: 2 },
color: COLORS.FLAME,
abilities: [{ effect: 'dealDamageAll', amount: 3 }],
flavor: 'Everything burns eventually. This just speeds up the schedule.',
rarity: 'rare',
}),
card({
name: 'Battle Rage',
type: TYPES.INSTANT,
cost: { flame: 1 },
color: COLORS.FLAME,
abilities: [{ effect: 'pumpCreature', power: 3, toughness: 0, duration: 'endOfTurn' }],
flavor: 'Thought yields to instinct, instinct to fury.',
rarity: 'common',
}),
card({
name: 'Flame Barrage',
type: TYPES.INSTANT,
cost: { colorless: 1, flame: 1 },
color: COLORS.FLAME,
abilities: [{ effect: 'dealDamage', amount: 2, target: 'any' }],
flavor: 'One bolt for spite. Two for certainty.',
rarity: 'common',
}),
card({
name: 'Reckless Charge',
type: TYPES.SORCERY,
cost: { flame: 1 },
color: COLORS.FLAME,
abilities: [{ effect: 'giveKeyword', keyword: KEYWORDS.SWIFT }, { effect: 'pumpCreature', power: 2, toughness: 0, duration: 'endOfTurn' }],
flavor: 'Strategy is for cowards. Real warriors just run faster.',
rarity: 'common',
}),
];
// ============================================================================
// GROWTH (Green) — 12 cards
// ============================================================================
const growthCards = [
card({
name: 'Woodland Elf',
type: TYPES.CREATURE,
cost: { growth: 1 },
color: COLORS.GROWTH,
power: 1, toughness: 1,
keywords: [],
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'any' }],
flavor: 'The forest speaks through her, and she answers with magic.',
rarity: 'common',
}),
card({
name: 'Highland Bear',
type: TYPES.CREATURE,
cost: { colorless: 1, growth: 1 },
color: COLORS.GROWTH,
power: 2, toughness: 2,
keywords: [],
abilities: [],
flavor: 'It needs no magic. Teeth and claws suffice.',
rarity: 'common',
}),
card({
name: 'Ironbark Treant',
type: TYPES.CREATURE,
cost: { colorless: 3, growth: 2 },
color: COLORS.GROWTH,
power: 5, toughness: 7,
keywords: [],
abilities: [],
flavor: 'Centuries of growth have made it as unyielding as stone.',
rarity: 'rare',
}),
card({
name: 'Wild Stallion',
type: TYPES.CREATURE,
cost: { colorless: 2, growth: 1 },
color: COLORS.GROWTH,
power: 3, toughness: 3,
keywords: [],
abilities: [],
flavor: 'Untamed and untameable, it runs where it wills.',
rarity: 'common',
}),
card({
name: 'Ancient Wurm',
type: TYPES.CREATURE,
cost: { colorless: 4, growth: 2 },
color: COLORS.GROWTH,
power: 7, toughness: 7,
keywords: [KEYWORDS.OVERWHELMING],
abilities: [],
flavor: 'Older than the forests it burrows beneath.',
rarity: 'mythic',
}),
card({
name: 'Thornweaver',
type: TYPES.CREATURE,
cost: { colorless: 2, growth: 1 },
color: COLORS.GROWTH,
power: 2, toughness: 3,
keywords: [KEYWORDS.REACHING],
abilities: [],
flavor: 'Its thorny tendrils snatch birds from the sky.',
rarity: 'common',
}),
card({
name: 'Giant Growth',
type: TYPES.INSTANT,
cost: { growth: 1 },
color: COLORS.GROWTH,
abilities: [{ effect: 'pumpCreature', power: 3, toughness: 3, duration: 'endOfTurn' }],
flavor: 'Nature\'s fury compressed into a single heartbeat.',
rarity: 'common',
}),
card({
name: "Nature's Gift",
type: TYPES.SORCERY,
cost: { colorless: 1, growth: 1 },
color: COLORS.GROWTH,
abilities: [{ effect: 'searchLand' }],
flavor: 'The land provides for those who listen.',
rarity: 'common',
}),
card({
name: 'Regenerate',
type: TYPES.INSTANT,
cost: { growth: 1 },
color: COLORS.GROWTH,
abilities: [{ effect: 'preventDamage', target: 'creature' }],
flavor: 'What was broken, the forest mends.',
rarity: 'common',
}),
card({
name: 'Overrun',
type: TYPES.SORCERY,
cost: { colorless: 3, growth: 2 },
color: COLORS.GROWTH,
abilities: [{ effect: 'pumpAll', power: 3, toughness: 3, keyword: KEYWORDS.OVERWHELMING }],
flavor: 'The forest does not march. It stampedes.',
rarity: 'rare',
}),
card({
name: 'Vine Snare',
type: TYPES.INSTANT,
cost: { colorless: 1, growth: 1 },
color: COLORS.GROWTH,
abilities: [{ effect: 'preventCombatDamage' }],
flavor: 'Thorned vines erupt from the earth, halting all charge.',
rarity: 'common',
}),
card({
name: 'Feral Instinct',
type: TYPES.INSTANT,
cost: { growth: 1 },
color: COLORS.GROWTH,
abilities: [{ effect: 'pumpCreature', power: 1, toughness: 1, duration: 'endOfTurn' }, { effect: 'drawCards', amount: 1 }],
flavor: 'Trust the animal within.',
rarity: 'uncommon',
}),
];
// ============================================================================
// COLORLESS — Artifacts (7 cards)
// ============================================================================
const artifactCards = [
card({
name: 'Crystal Amulet',
type: TYPES.ARTIFACT,
cost: { colorless: 2 },
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'any' }],
flavor: 'It pulses with the light of every color, and none.',
rarity: 'uncommon',
}),
card({
name: 'War Golem',
type: TYPES.CREATURE,
subtype: 'artifact',
cost: { colorless: 5 },
color: COLORS.COLORLESS,
power: 4, toughness: 4,
keywords: [],
abilities: [],
flavor: 'Forged in the War of Five Suns, it still remembers how to fight.',
rarity: 'common',
}),
card({
name: 'Enchanted Blade',
type: TYPES.ARTIFACT,
subtype: 'equipment',
cost: { colorless: 3 },
color: COLORS.COLORLESS,
abilities: [{ effect: 'equipBuff', power: 2, toughness: 1 }],
flavor: 'Its edge never dulls, and its hunger never fades.',
rarity: 'uncommon',
}),
card({
name: 'Healing Draught',
type: TYPES.ARTIFACT,
cost: { colorless: 1 },
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap_sacrifice', effect: 'gainLife', amount: 3 }],
flavor: 'One sip restores what hours of rest cannot.',
rarity: 'common',
}),
card({
name: 'Mind Stone',
type: TYPES.ARTIFACT,
cost: { colorless: 2 },
color: COLORS.COLORLESS,
abilities: [
{ trigger: 'tap', effect: 'addMana', color: 'colorless' },
{ trigger: 'tap_sacrifice', effect: 'drawCards', amount: 1 },
],
flavor: 'It stores thoughts the way a gem stores light.',
rarity: 'uncommon',
}),
card({
name: 'Iron Shield',
type: TYPES.ARTIFACT,
subtype: 'equipment',
cost: { colorless: 2 },
color: COLORS.COLORLESS,
abilities: [{ effect: 'equipBuff', power: 0, toughness: 3 }],
flavor: 'Heavy, inelegant, and thoroughly reliable.',
rarity: 'common',
}),
card({
name: 'Arcane Compass',
type: TYPES.ARTIFACT,
cost: { colorless: 1 },
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'scry', amount: 1 }],
flavor: 'It always points toward what you need most.',
rarity: 'common',
}),
];
// ============================================================================
// LANDS — 5 Basic + 5 Dual
// ============================================================================
const landCards = [
// Basic Lands
card({
name: 'Sunlit Plains',
type: TYPES.LAND,
subtype: 'basic',
color: COLORS.RADIANCE,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'radiance' }],
rarity: 'basic',
}),
card({
name: 'Coral Reef',
type: TYPES.LAND,
subtype: 'basic',
color: COLORS.TIDE,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'tide' }],
rarity: 'basic',
}),
card({
name: 'Dark Swamp',
type: TYPES.LAND,
subtype: 'basic',
color: COLORS.SHADOW,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'shadow' }],
rarity: 'basic',
}),
card({
name: 'Volcanic Peak',
type: TYPES.LAND,
subtype: 'basic',
color: COLORS.FLAME,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'flame' }],
rarity: 'basic',
}),
card({
name: 'Verdant Forest',
type: TYPES.LAND,
subtype: 'basic',
color: COLORS.GROWTH,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'growth' }],
rarity: 'basic',
}),
// Dual Lands
card({
name: 'Dual Springs',
type: TYPES.LAND,
subtype: 'dual',
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'radiance|tide' }],
rarity: 'rare',
}),
card({
name: 'Ashen Moor',
type: TYPES.LAND,
subtype: 'dual',
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'shadow|flame' }],
rarity: 'rare',
}),
card({
name: 'Twilight Glade',
type: TYPES.LAND,
subtype: 'dual',
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'radiance|growth' }],
rarity: 'rare',
}),
card({
name: 'Molten Cavern',
type: TYPES.LAND,
subtype: 'dual',
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'flame|growth' }],
rarity: 'rare',
}),
card({
name: 'Frozen Depths',
type: TYPES.LAND,
subtype: 'dual',
color: COLORS.COLORLESS,
abilities: [{ trigger: 'tap', effect: 'addMana', color: 'tide|shadow' }],
rarity: 'rare',
}),
];
// ============================================================================
// ALL CARDS
// ============================================================================
const ALL_CARDS = [
...radianceCards,
...tideCards,
...shadowCards,
...flameCards,
...growthCards,
...artifactCards,
...landCards,
];
// Card lookup by ID
const CARD_DB = {};
ALL_CARDS.forEach((c) => { CARD_DB[c.id] = c; });
// Get the converted mana cost (total mana needed)
function getManaCost(cost) {
if (!cost) return 0;
return Object.values(cost).reduce((sum, v) => sum + v, 0);
}
// Build a starter deck for a given color (24 lands + 36 spells)
function buildStarterDeck(color) {
const colorCards = ALL_CARDS.filter(
(c) => c.color === color && c.type !== TYPES.LAND
);
const basicLand = ALL_CARDS.find(
(c) => c.type === TYPES.LAND && c.subtype === 'basic' && c.color === color
);
const deck = [];
// Add 4 copies of each color card (up to 9 unique cards = 36)
const spellCards = colorCards.slice(0, 9);
spellCards.forEach((c) => {
for (let i = 0; i < 4; i++) deck.push(c.id);
});
// Fill to 60 with basic lands
while (deck.length < 60) {
deck.push(basicLand.id);
}
return deck;
}
// Prebuilt starter decks
const STARTER_DECKS = {
radiance: { name: 'Dawn\'s Wrath', color: COLORS.RADIANCE },
tide: { name: 'Depths of Knowledge', color: COLORS.TIDE },
shadow: { name: 'Veil of Shadows', color: COLORS.SHADOW },
flame: { name: 'Infernal Fury', color: COLORS.FLAME },
growth: { name: 'Primal Might', color: COLORS.GROWTH },
};
module.exports = {
COLORS,
TYPES,
KEYWORDS,
ALL_CARDS,
CARD_DB,
getManaCost,
buildStarterDeck,
STARTER_DECKS,
};