From 285d9929156fa64ca8eeee435ff50069745be985 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Wed, 27 May 2026 17:29:11 -0600 Subject: [PATCH] ``` feat(dominion): add recommended kingdom presets and update deck mode UI - Introduce four new recommended kingdom decks from the 2nd-edition rulebook: Size Distortion, Deck Top, Silver & Gold, and Helpful Actions. - Refactor `kingdomFor` to use a `KINGDOM_PRESETS` mapping for cleaner extensibility. - Update the Opponent Select Scene UI to display all deck mode options in a 3-column grid layout. ``` --- public/src/games/dominion/DominionCards.js | 29 +++++++++++++++++++++- public/src/scenes/OpponentSelectScene.js | 28 ++++++++++++++------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/public/src/games/dominion/DominionCards.js b/public/src/games/dominion/DominionCards.js index ce7b0b8..3f384b9 100644 --- a/public/src/games/dominion/DominionCards.js +++ b/public/src/games/dominion/DominionCards.js @@ -83,6 +83,32 @@ export const FIRST_GAME = [ 'moat', 'remodel', 'smithy', 'village', 'workshop', ]; +// Additional recommended kingdoms from the 2nd-edition rulebook. +export const SIZE_DISTORTION = [ + 'artisan', 'bandit', 'bureaucrat', 'gardens', 'harbinger', + 'laboratory', 'moneylender', 'throneroom', 'village', 'witch', +]; +export const DECK_TOP = [ + 'artisan', 'bureaucrat', 'councilroom', 'festival', 'harbinger', + 'laboratory', 'poacher', 'sentry', 'vassal', 'village', +]; +export const SILVER_AND_GOLD = [ + 'artisan', 'bandit', 'councilroom', 'mine', 'moneylender', + 'poacher', 'remodel', 'smithy', 'throneroom', 'vassal', +]; +export const HELPFUL_ACTIONS = [ + 'cellar', 'councilroom', 'festival', 'harbinger', 'laboratory', + 'library', 'merchant', 'militia', 'moat', 'sentry', +]; + +export const KINGDOM_PRESETS = { + 'standard': FIRST_GAME, + 'size-distortion': SIZE_DISTORTION, + 'deck-top': DECK_TOP, + 'silver-gold': SILVER_AND_GOLD, + 'helpful-actions': HELPFUL_ACTIONS, +}; + export function hasType(card, type) { return card.types.includes(type); } @@ -103,5 +129,6 @@ export function chooseRandomKingdom(rand) { export function kingdomFor(deckMode, rand) { if (deckMode === 'random') return chooseRandomKingdom(rand); - return FIRST_GAME.slice().sort((a, b) => getCard(a).cost - getCard(b).cost); + const preset = KINGDOM_PRESETS[deckMode] ?? FIRST_GAME; + return preset.slice().sort((a, b) => getCard(a).cost - getCard(b).cost); } diff --git a/public/src/scenes/OpponentSelectScene.js b/public/src/scenes/OpponentSelectScene.js index 0eecf66..5729070 100644 --- a/public/src/scenes/OpponentSelectScene.js +++ b/public/src/scenes/OpponentSelectScene.js @@ -531,13 +531,20 @@ export default class OpponentSelectScene extends Phaser.Scene { // ── Dominion: Kingdom deck mode toggle ───────────────────────────────────── buildDeckModeSection(centerX, centerY) { const options = [ - { id: 'standard', label: 'Standard' }, - { id: 'random', label: 'Random' }, + { id: 'standard', label: 'Standard' }, + { id: 'size-distortion', label: 'Size Distortion' }, + { id: 'deck-top', label: 'Deck Top' }, + { id: 'silver-gold', label: 'Silver & Gold' }, + { id: 'helpful-actions', label: 'Helpful Actions' }, + { id: 'random', label: 'Random' }, ]; const pillW = 150, pillH = 40, pillGap = 12; - const totalW = options.length * pillW + (options.length - 1) * pillGap; - const labelY = centerY - 28; - const pillY = centerY + 10; + const cols = 3; + const rowW = cols * pillW + (cols - 1) * pillGap; + // Two rows — shift the whole section up so both rows sit above y=1080. + const labelY = centerY - 53; + const row0Y = centerY - 12; + const row1Y = centerY + 38; const labelText = this.add.text(centerX, labelY, 'Kingdom', { fontFamily: '"Julius Sans One"', @@ -549,14 +556,17 @@ export default class OpponentSelectScene extends Phaser.Scene { this._deckModeBtns = []; options.forEach((opt, i) => { - const x = centerX - totalW / 2 + i * (pillW + pillGap) + pillW / 2; + const col = i % cols; + const row = Math.floor(i / cols); + const x = centerX - rowW / 2 + col * (pillW + pillGap) + pillW / 2; + const y = row === 0 ? row0Y : row1Y; const isSelected = this.selectedDeckMode === opt.id; - const bg = this.add.rectangle(x, pillY, pillW, pillH, COLORS.panel) + const bg = this.add.rectangle(x, y, pillW, pillH, COLORS.panel) .setStrokeStyle(3, isSelected ? COLORS.accent : COLORS.muted) .setInteractive({ useHandCursor: true }); - const pillBg = this.add.rectangle(x, pillY, pillW, pillH, 0x000000, 0.72); + const pillBg = this.add.rectangle(x, y, pillW, pillH, 0x000000, 0.72); this.children.moveBelow(pillBg, bg); - this.add.text(x, pillY, opt.label, { + this.add.text(x, y, opt.label, { fontFamily: '"Julius Sans One"', fontSize: '16px', color: COLORS.textHex,