95 lines
3.7 KiB
JavaScript
95 lines
3.7 KiB
JavaScript
// SWDBGData.js — data layer for Star Wars Deckbuilder.
|
|
// All card content lives in /data/swdbg-cards.json (user-editable); this module
|
|
// indexes the parsed JSON and exposes lookups. loadCardData() must be called
|
|
// before the engine is used: the Phaser scene feeds it the preloaded JSON and
|
|
// tools/verifySWDBG.js reads the file from disk.
|
|
|
|
export const FACTIONS = ['empire', 'rebel'];
|
|
|
|
export const FACTION_INFO = {
|
|
empire: { label: 'Galactic Empire', color: 0x4d7fd6, colorHex: '#4d7fd6', dark: 0x16233d, symbol: '◉' },
|
|
rebel: { label: 'Rebel Alliance', color: 0xd6604d, colorHex: '#d6604d', dark: 0x3d1a16, symbol: '✴' },
|
|
neutral: { label: 'Neutral', color: 0xc9a54a, colorHex: '#c9a54a', dark: 0x332a14, symbol: '◈' },
|
|
};
|
|
|
|
// Every op the engine understands. verifySWDBG.js checks each card in the JSON
|
|
// against this list so a data edit can't silently no-op.
|
|
export const OPS = [
|
|
'draw', 'gainResources', 'gainForce', 'gainAttack', 'damageBase', 'dealDamage',
|
|
'repairBase', 'oppDiscard', 'oppChoice', 'discardRow', 'destroyCapital',
|
|
'exileCards', 'freePurchase', 'buyGalaxyDiscard', 'topdeckNextPurchase',
|
|
'recoverDiscard', 'lookTop', 'lookTopSwap', 'lookOppHand', 'takeRowTemp',
|
|
'revealTop', 'choose', 'multi', 'purchaseToHand',
|
|
'traitBoost', 'typeBoost', 'rowBonus', 'selfBoostWhileForce',
|
|
'selfBoostWithTrait', 'selfBoostPerBaseLost',
|
|
'capitalDiscount', 'onPlayTraitAttack',
|
|
];
|
|
export const TIMINGS = ['action', 'constant', 'onPlay', 'onBounty', 'onPurchase', 'onReveal'];
|
|
// Ops that are passive modifiers — never activated as an action.
|
|
export const CONSTANT_OPS = ['traitBoost', 'typeBoost', 'rowBonus', 'selfBoostWhileForce', 'selfBoostWithTrait', 'selfBoostPerBaseLost', 'capitalDiscount', 'onPlayTraitAttack'];
|
|
|
|
let DATA = null;
|
|
|
|
export function loadCardData(json) {
|
|
if (!json || !json.cards) throw new Error('swdbg-cards.json missing or malformed');
|
|
const byId = new Map();
|
|
const add = (def) => {
|
|
if (byId.has(def.id)) throw new Error(`duplicate card id ${def.id}`);
|
|
byId.set(def.id, def);
|
|
};
|
|
for (const def of json.starterCards) add(def);
|
|
add(json.outerRimPilot);
|
|
for (const def of json.cards) add(def);
|
|
const bases = { rebel: new Map(), empire: new Map() };
|
|
for (const f of FACTIONS) for (const b of json.bases[f]) bases[f].set(b.id, b);
|
|
DATA = { json, byId, bases, meta: json.meta };
|
|
return DATA;
|
|
}
|
|
|
|
export function getData() {
|
|
if (!DATA) throw new Error('loadCardData() must be called before using the engine');
|
|
return DATA;
|
|
}
|
|
|
|
export function cardDef(idOrInst) {
|
|
const id = typeof idOrInst === 'string' ? idOrInst : idOrInst?.id;
|
|
const def = getData().byId.get(id);
|
|
if (!def) throw new Error(`unknown card id ${id}`);
|
|
return def;
|
|
}
|
|
|
|
export function baseDef(faction, id) {
|
|
const def = getData().bases[faction].get(id);
|
|
if (!def) throw new Error(`unknown ${faction} base ${id}`);
|
|
return def;
|
|
}
|
|
|
|
export function basesFor(faction) { return getData().json.bases[faction]; }
|
|
|
|
let uidCounter = 0;
|
|
export function makeInstance(id) { return { uid: ++uidCounter, id }; }
|
|
export function resetUids() { uidCounter = 0; }
|
|
|
|
// Deck construction ----------------------------------------------------------
|
|
|
|
export function buildGalaxyDeck() {
|
|
const out = [];
|
|
for (const def of getData().json.cards) {
|
|
for (let i = 0; i < def.count; i++) out.push(makeInstance(def.id));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export function buildStarterDeck(faction) {
|
|
const out = [];
|
|
for (const entry of getData().json.starters[faction]) {
|
|
for (let i = 0; i < entry.count; i++) out.push(makeInstance(entry.id));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export function buildOuterRim() {
|
|
const def = getData().json.outerRimPilot;
|
|
return Array.from({ length: def.count }, () => makeInstance(def.id));
|
|
}
|