Compare commits
No commits in common. "d22f6ff902a221104c71bfeba39d02fdb26dd3a6" and "b7821c3bd8bb44d536956a356fa5817df723b076" have entirely different histories.
d22f6ff902
...
b7821c3bd8
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -64,21 +64,6 @@
|
|||
"file": "track13.mp3",
|
||||
"artist": "Dance All Night",
|
||||
"title": "Michael Jackson"
|
||||
},
|
||||
{
|
||||
"file": "track14.mp3",
|
||||
"artist": "Growin' Up in the Heartland",
|
||||
"title": "Bryan Adams"
|
||||
},
|
||||
{
|
||||
"file": "track15.mp3",
|
||||
"artist": "Synthetic Highway",
|
||||
"title": "The Midnight"
|
||||
},
|
||||
{
|
||||
"file": "track16.mp3",
|
||||
"artist": "Surf Sundown",
|
||||
"title": "Khruangbin"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -538,7 +538,7 @@ export default class BoggleGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
buildControls() {
|
||||
const y = ORIGIN_Y + SPAN + 110;
|
||||
const y = ORIGIN_Y + SPAN + 150;
|
||||
const submit = new Button(this, TRAY_CX + 120, y, 'Submit Word',
|
||||
() => this.submitWord(), { width: 220, height: 64, fontSize: 26 });
|
||||
submit.setDepth(D.ui);
|
||||
|
|
|
|||
|
|
@ -69,10 +69,6 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
this.skill = data.opponents?.[0]?.skill ?? 3;
|
||||
this.playfield = data.playfield ?? null;
|
||||
|
||||
this.humanWins = data.humanWins ?? 0;
|
||||
this.aiWins = data.aiWins ?? 0;
|
||||
this.roundNum = data.roundNum ?? 1;
|
||||
|
||||
this.blockers = null;
|
||||
this.humanBoard = null;
|
||||
this.aiBoard = null;
|
||||
|
|
@ -117,7 +113,6 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
this._buildGridGraphics();
|
||||
this._buildLabels();
|
||||
this._buildPortraits();
|
||||
this._buildRoundDisplay();
|
||||
this._buildTray();
|
||||
this._buildHints();
|
||||
|
||||
|
|
@ -149,30 +144,24 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
const OFF = 4;
|
||||
|
||||
this._pulseGfx.clear();
|
||||
this._pulseGfx.lineStyle(5, color, alpha);
|
||||
|
||||
const drawEdges = () => {
|
||||
for (const [r, c] of cells) {
|
||||
const x0 = HGX + c * CELL, y0 = HGY + r * CELL;
|
||||
const x1 = x0 + CELL, y1 = y0 + CELL;
|
||||
if (!ghostSet.has(`${r - 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y0 - OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r + 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y1 + OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c - 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x0 - OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c + 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x1 + OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
for (const [r, c] of cells) {
|
||||
const x0 = HGX + c * CELL, y0 = HGY + r * CELL;
|
||||
const x1 = x0 + CELL, y1 = y0 + CELL;
|
||||
if (!ghostSet.has(`${r - 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y0 - OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
};
|
||||
|
||||
this._pulseGfx.lineStyle(14, color, alpha * 0.4);
|
||||
drawEdges();
|
||||
this._pulseGfx.lineStyle(3, color, alpha);
|
||||
drawEdges();
|
||||
if (!ghostSet.has(`${r + 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y1 + OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c - 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x0 - OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c + 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x1 + OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Scene construction ────────────────────────────────────────────────────────
|
||||
|
|
@ -255,35 +244,6 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
}
|
||||
}
|
||||
|
||||
_buildRoundDisplay() {
|
||||
const cx = GAME_WIDTH / 2;
|
||||
const py = 74;
|
||||
|
||||
this.add.text(cx, py, `ROUND ${this.roundNum} OF 3`, {
|
||||
fontFamily: '"Julius Sans One"', fontSize: '17px', color: COLORS.mutedHex,
|
||||
}).setOrigin(0.5).setDepth(D.ui);
|
||||
|
||||
// Human win pips (left of center)
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const filled = i < this.humanWins;
|
||||
const gfx = this.add.graphics().setDepth(D.ui);
|
||||
gfx.fillStyle(filled ? 0x45d17a : 0x2a2a4a, 1);
|
||||
gfx.fillCircle(700 + i * 24, py, 8);
|
||||
gfx.lineStyle(2, filled ? 0x45d17a : 0x444466, 1);
|
||||
gfx.strokeCircle(700 + i * 24, py, 8);
|
||||
}
|
||||
|
||||
// AI win pips (right of center)
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const filled = i < this.aiWins;
|
||||
const gfx = this.add.graphics().setDepth(D.ui);
|
||||
gfx.fillStyle(filled ? COLORS.danger : 0x2a2a4a, 1);
|
||||
gfx.fillCircle(1196 + i * 24, py, 8);
|
||||
gfx.lineStyle(2, filled ? COLORS.danger : 0x444466, 1);
|
||||
gfx.strokeCircle(1196 + i * 24, py, 8);
|
||||
}
|
||||
}
|
||||
|
||||
_buildTray() {
|
||||
const trayLeft = HCX - (SLOT_W * 1.5); // left edge of 3-column tray
|
||||
|
||||
|
|
@ -408,12 +368,7 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
const allValid = ghostCells.every(([r, c]) =>
|
||||
r >= 0 && r < 6 && c >= 0 && c < 6 && board[r * 6 + c] === null
|
||||
);
|
||||
gfx.fillStyle(0x000000, 0.35);
|
||||
for (const [r, c] of ghostCells) {
|
||||
if (r < 0 || r >= 6 || c < 0 || c >= 6) continue;
|
||||
gfx.fillRoundedRect(gx + c * CELL + 8, gy + r * CELL + 9, CELL - 6, CELL - 6, 7);
|
||||
}
|
||||
gfx.fillStyle(allValid ? color : 0xff4444, allValid ? 0.78 : 0.4);
|
||||
gfx.fillStyle(color, allValid ? 0.5 : 0.2);
|
||||
for (const [r, c] of ghostCells) {
|
||||
if (r < 0 || r >= 6 || c < 0 || c >= 6) continue;
|
||||
gfx.fillRoundedRect(gx + c * CELL + 3, gy + r * CELL + 3, CELL - 6, CELL - 6, 7);
|
||||
|
|
@ -578,13 +533,7 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
const allValid = cells.every(([r, c]) =>
|
||||
r >= 0 && r < 6 && c >= 0 && c < 6 && this.humanBoard[r * 6 + c] === null
|
||||
);
|
||||
gfx.fillStyle(0x000000, 0.35);
|
||||
for (const [r, c] of cells) {
|
||||
const lx = (c - cc) * CELL - CELL / 2;
|
||||
const ly = (r - cr) * CELL - CELL / 2;
|
||||
gfx.fillRoundedRect(lx + 8, ly + 9, CELL - 6, CELL - 6, 7);
|
||||
}
|
||||
gfx.fillStyle(allValid ? color : 0xff4444, allValid ? 0.78 : 0.4);
|
||||
gfx.fillStyle(color, allValid ? 0.55 : 0.2);
|
||||
for (const [r, c] of cells) {
|
||||
const lx = (c - cc) * CELL - CELL / 2;
|
||||
const ly = (r - cr) * CELL - CELL / 2;
|
||||
|
|
@ -709,7 +658,6 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
label.setText(steps[i]).setScale(1.6).setAlpha(1);
|
||||
playSound(this, steps[i] === 'GO!' ? SFX.COUNTDOWN_GO : SFX.COUNTDOWN_TICK);
|
||||
|
||||
this.tweens.add({
|
||||
targets: label, scaleX: 1, scaleY: 1,
|
||||
|
|
@ -767,116 +715,59 @@ export default class GeniusSquareGame extends Phaser.Scene {
|
|||
this.gameOver = true;
|
||||
this._stopAI();
|
||||
this.opponentPortrait?.playEmotion('upset');
|
||||
this._endRound(true);
|
||||
playSound(this, SFX.UI_CHIME);
|
||||
playSound(this, SFX.VICTORY_SHORT);
|
||||
this._recordResult('win');
|
||||
this._showOverlay(true);
|
||||
}
|
||||
|
||||
_onAIWin() {
|
||||
if (this.gameOver) return;
|
||||
this.gameOver = true;
|
||||
this._stopAI();
|
||||
this.opponentPortrait?.playEmotion('happy');
|
||||
this._endRound(false);
|
||||
this._recordResult('loss');
|
||||
this._showOverlay(false);
|
||||
}
|
||||
|
||||
_endRound(humanWon) {
|
||||
if (humanWon) this.humanWins++;
|
||||
else this.aiWins++;
|
||||
|
||||
const matchOver = this.humanWins >= 2 || this.aiWins >= 2;
|
||||
if (matchOver) {
|
||||
const playerWon = this.humanWins > this.aiWins;
|
||||
playSound(this, playerWon ? SFX.VICTORY_SHORT : SFX.SCIFI_RISER);
|
||||
api.post('/history/single-player', {
|
||||
slug: 'geniussquare', score: playerWon ? 1 : 0, result: playerWon ? 'win' : 'loss',
|
||||
}).catch(() => {});
|
||||
this._showMatchOverlay(playerWon);
|
||||
} else {
|
||||
playSound(this, humanWon ? SFX.CASINO_WIN : SFX.CASINO_LOSE);
|
||||
this._showInterRoundOverlay(humanWon);
|
||||
}
|
||||
_recordResult(result) {
|
||||
api.post('/history/single-player', {
|
||||
slug: 'geniussquare', score: result === 'win' ? 1 : 0, result,
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
_showInterRoundOverlay(humanWon) {
|
||||
_showOverlay(humanWon) {
|
||||
const cx = GAME_WIDTH / 2, cy = GAME_HEIGHT / 2;
|
||||
const borderColor = humanWon ? 0x45d17a : COLORS.danger;
|
||||
const headline = humanWon ? 'Round Win!' : 'Round Loss!';
|
||||
const headline = humanWon ? 'You Win!' : 'Opponent Wins!';
|
||||
const headColor = humanWon ? '#45d17a' : COLORS.dangerHex;
|
||||
const subline = humanWon ? 'You filled the grid first!' : 'The opponent finished first.';
|
||||
|
||||
// Dim background
|
||||
this.add.rectangle(cx, cy, GAME_WIDTH, GAME_HEIGHT, 0x000000, 0.6)
|
||||
.setDepth(D.overlay).setInteractive();
|
||||
|
||||
// Panel
|
||||
const panel = this.add.graphics().setDepth(D.overlay + 1);
|
||||
panel.fillStyle(0x1a1828, 0.97);
|
||||
panel.fillRoundedRect(cx - 340, cy - 220, 680, 440, 18);
|
||||
panel.fillRoundedRect(cx - 340, cy - 190, 680, 380, 18);
|
||||
panel.lineStyle(3, borderColor, 1);
|
||||
panel.strokeRoundedRect(cx - 340, cy - 220, 680, 440, 18);
|
||||
panel.strokeRoundedRect(cx - 340, cy - 190, 680, 380, 18);
|
||||
|
||||
this.add.text(cx, cy - 150, headline, {
|
||||
this.add.text(cx, cy - 110, headline, {
|
||||
fontFamily: 'Righteous', fontSize: '68px', color: headColor,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy - 70, subline, {
|
||||
this.add.text(cx, cy - 26, subline, {
|
||||
fontFamily: '"Julius Sans One"', fontSize: '26px', color: COLORS.mutedHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy - 12, `${this.humanWins} — ${this.aiWins}`, {
|
||||
fontFamily: 'Righteous', fontSize: '56px', color: COLORS.textHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy + 50, `ROUND ${this.roundNum + 1} NEXT`, {
|
||||
fontFamily: '"Julius Sans One"', fontSize: '20px', color: COLORS.mutedHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
const nextData = {
|
||||
game: this.gameDef, opponents: this.opponents, playfield: this.playfield,
|
||||
humanWins: this.humanWins, aiWins: this.aiWins, roundNum: this.roundNum + 1,
|
||||
};
|
||||
new Button(this, cx, cy + 130, 'Next Round',
|
||||
() => this.scene.restart(nextData),
|
||||
{ width: 280, height: 58, fontSize: 22 }
|
||||
).setDepth(D.overlayUI);
|
||||
}
|
||||
|
||||
_showMatchOverlay(playerWon) {
|
||||
const cx = GAME_WIDTH / 2, cy = GAME_HEIGHT / 2;
|
||||
const borderColor = playerWon ? 0x45d17a : COLORS.danger;
|
||||
const headline = playerWon ? 'You Win!' : 'Opponent Wins!';
|
||||
const headColor = playerWon ? '#45d17a' : COLORS.dangerHex;
|
||||
const subline = playerWon ? 'You won the best of 3!' : 'The opponent won the best of 3.';
|
||||
|
||||
this.add.rectangle(cx, cy, GAME_WIDTH, GAME_HEIGHT, 0x000000, 0.6)
|
||||
.setDepth(D.overlay).setInteractive();
|
||||
|
||||
const panel = this.add.graphics().setDepth(D.overlay + 1);
|
||||
panel.fillStyle(0x1a1828, 0.97);
|
||||
panel.fillRoundedRect(cx - 340, cy - 220, 680, 440, 18);
|
||||
panel.lineStyle(3, borderColor, 1);
|
||||
panel.strokeRoundedRect(cx - 340, cy - 220, 680, 440, 18);
|
||||
|
||||
this.add.text(cx, cy - 150, headline, {
|
||||
fontFamily: 'Righteous', fontSize: '68px', color: headColor,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy - 70, subline, {
|
||||
fontFamily: '"Julius Sans One"', fontSize: '26px', color: COLORS.mutedHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy - 12, `${this.humanWins} — ${this.aiWins}`, {
|
||||
fontFamily: 'Righteous', fontSize: '56px', color: COLORS.textHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
this.add.text(cx, cy + 50, 'BEST OF 3', {
|
||||
fontFamily: '"Julius Sans One"', fontSize: '20px', color: COLORS.mutedHex,
|
||||
}).setOrigin(0.5).setDepth(D.overlayUI);
|
||||
|
||||
const freshData = { game: this.gameDef, opponents: this.opponents, playfield: this.playfield };
|
||||
new Button(this, cx - 170, cy + 130, 'Play Again',
|
||||
() => this.scene.restart(freshData),
|
||||
const data = { game: this.gameDef, opponents: this.opponents, playfield: this.playfield };
|
||||
new Button(this, cx - 170, cy + 100, 'Play Again',
|
||||
() => this.scene.restart(data),
|
||||
{ width: 280, height: 58, fontSize: 22 }
|
||||
).setDepth(D.overlayUI);
|
||||
|
||||
new Button(this, cx + 170, cy + 130, 'Menu',
|
||||
new Button(this, cx + 170, cy + 100, 'Menu',
|
||||
() => this.scene.start('GameMenu'),
|
||||
{ variant: 'ghost', width: 280, height: 58, fontSize: 22 }
|
||||
).setDepth(D.overlayUI);
|
||||
|
|
|
|||
|
|
@ -121,30 +121,24 @@ export default class KataminoGame extends Phaser.Scene {
|
|||
const bx = this._boardX;
|
||||
|
||||
this._pulseGfx.clear();
|
||||
this._pulseGfx.lineStyle(5, color, alpha);
|
||||
|
||||
const drawEdges = () => {
|
||||
for (const [r, c] of cells) {
|
||||
const x0 = bx + c * CELL, y0 = BOARD_Y + r * CELL;
|
||||
const x1 = x0 + CELL, y1 = y0 + CELL;
|
||||
if (!ghostSet.has(`${r - 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y0 - OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r + 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y1 + OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c - 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x0 - OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c + 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x1 + OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
for (const [r, c] of cells) {
|
||||
const x0 = bx + c * CELL, y0 = BOARD_Y + r * CELL;
|
||||
const x1 = x0 + CELL, y1 = y0 + CELL;
|
||||
if (!ghostSet.has(`${r - 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y0 - OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
};
|
||||
|
||||
this._pulseGfx.lineStyle(14, color, alpha * 0.4);
|
||||
drawEdges();
|
||||
this._pulseGfx.lineStyle(3, color, alpha);
|
||||
drawEdges();
|
||||
if (!ghostSet.has(`${r + 1},${c}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y1 + OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c - 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x0 - OFF, y0 - OFF); this._pulseGfx.lineTo(x0 - OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
if (!ghostSet.has(`${r},${c + 1}`)) {
|
||||
this._pulseGfx.beginPath(); this._pulseGfx.moveTo(x1 + OFF, y0 - OFF); this._pulseGfx.lineTo(x1 + OFF, y1 + OFF); this._pulseGfx.strokePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Screen management ──────────────────────────────────────────────────────
|
||||
|
|
@ -584,12 +578,7 @@ export default class KataminoGame extends Phaser.Scene {
|
|||
const ok = this._ghostCells.every(([r, c]) =>
|
||||
r >= 0 && r < ROWS && c >= 0 && c < cols && this._board[r * cols + c] === null
|
||||
);
|
||||
gfx.fillStyle(0x000000, 0.35);
|
||||
for (const [r, c] of this._ghostCells) {
|
||||
if (r < 0 || r >= ROWS || c < 0 || c >= cols) continue;
|
||||
gfx.fillRoundedRect(bx + c*CELL + 8, by + r*CELL + 9, CELL - 6, CELL - 6, 9);
|
||||
}
|
||||
gfx.fillStyle(ok ? clr : 0xff4444, ok ? 0.78 : 0.4);
|
||||
gfx.fillStyle(clr, ok ? 0.55 : 0.2);
|
||||
for (const [r, c] of this._ghostCells) {
|
||||
if (r < 0 || r >= ROWS || c < 0 || c >= cols) continue;
|
||||
gfx.fillRoundedRect(bx + c*CELL + 3, by + r*CELL + 3, CELL - 6, CELL - 6, 9);
|
||||
|
|
@ -738,13 +727,7 @@ export default class KataminoGame extends Phaser.Scene {
|
|||
const allValid = cells.every(([r, c]) =>
|
||||
r >= 0 && r < ROWS && c >= 0 && c < this._cols && this._board[r * this._cols + c] === null
|
||||
);
|
||||
gfx.fillStyle(0x000000, 0.35);
|
||||
for (const [r, c] of cells) {
|
||||
const lx = (c - cc) * CELL - CELL / 2;
|
||||
const ly = (r - cr) * CELL - CELL / 2;
|
||||
gfx.fillRoundedRect(lx + 8, ly + 9, CELL - 6, CELL - 6, 9);
|
||||
}
|
||||
gfx.fillStyle(allValid ? color : 0xff4444, allValid ? 0.78 : 0.4);
|
||||
gfx.fillStyle(color, allValid ? 0.55 : 0.2);
|
||||
for (const [r, c] of cells) {
|
||||
const lx = (c - cc) * CELL - CELL / 2;
|
||||
const ly = (r - cr) * CELL - CELL / 2;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
import { evaluateGuess } from './WordleLogic.js';
|
||||
|
||||
const SKILL_PROFILES = {
|
||||
1: { openerTier: 0, useFilter: true, blunder: 0.85, maxCandidates: 0, delay: [5500, 9000] },
|
||||
2: { openerTier: 1, useFilter: true, blunder: 0.52, maxCandidates: 0, delay: [4500, 7000] },
|
||||
3: { openerTier: 2, useFilter: true, blunder: 0.22, maxCandidates: 10, delay: [3200, 5500] },
|
||||
4: { openerTier: 3, useFilter: true, blunder: 0.08, maxCandidates: 35, delay: [2000, 3500] },
|
||||
5: { openerTier: 4, useFilter: true, blunder: 0.03, maxCandidates: 150, delay: [1200, 2200] },
|
||||
1: { openerTier: 0, useFilter: true, blunder: 0.85, maxCandidates: 0, delay: [3800, 6500] },
|
||||
2: { openerTier: 1, useFilter: true, blunder: 0.52, maxCandidates: 0, delay: [3000, 5000] },
|
||||
3: { openerTier: 2, useFilter: true, blunder: 0.22, maxCandidates: 10, delay: [2000, 3600] },
|
||||
4: { openerTier: 3, useFilter: true, blunder: 0.08, maxCandidates: 35, delay: [1100, 2000] },
|
||||
5: { openerTier: 4, useFilter: true, blunder: 0.03, maxCandidates: 150, delay: [450, 950] },
|
||||
};
|
||||
|
||||
// Opener tiers — ordered by expected information gain.
|
||||
|
|
|
|||
|
|
@ -110,8 +110,9 @@ export default class WordleGame extends Phaser.Scene {
|
|||
this.buildStatusText();
|
||||
this.buildScoreDisplay();
|
||||
this.buildControls();
|
||||
this.setupInput();
|
||||
|
||||
this._startCountdown();
|
||||
this.scheduleAITurn();
|
||||
}
|
||||
|
||||
// ── Build ──────────────────────────────────────────────────────────────────
|
||||
|
|
@ -278,53 +279,6 @@ export default class WordleGame extends Phaser.Scene {
|
|||
}).setDepth(DEPTH.ui);
|
||||
}
|
||||
|
||||
// ── Countdown ─────────────────────────────────────────────────────────────
|
||||
|
||||
_startCountdown() {
|
||||
const steps = ['3', '2', '1', 'GO!'];
|
||||
const cx = GAME_WIDTH / 2;
|
||||
const cy = GAME_HEIGHT / 2;
|
||||
const OVERLAY_D = DEPTH.ui + 5;
|
||||
|
||||
const dim = this.add.rectangle(cx, cy, GAME_WIDTH, GAME_HEIGHT, 0x000000, 0.50)
|
||||
.setDepth(OVERLAY_D);
|
||||
|
||||
const label = this.add.text(cx, cy, '', {
|
||||
fontFamily: 'Righteous',
|
||||
fontSize: '240px',
|
||||
color: '#f7c948',
|
||||
stroke: '#b08800',
|
||||
strokeThickness: 8,
|
||||
}).setOrigin(0.5).setDepth(OVERLAY_D + 1).setAlpha(0);
|
||||
|
||||
const runStep = (i) => {
|
||||
if (i >= steps.length) {
|
||||
dim.destroy();
|
||||
label.destroy();
|
||||
this.setupInput();
|
||||
this.scheduleAITurn();
|
||||
return;
|
||||
}
|
||||
|
||||
label.setText(steps[i]).setScale(1.6).setAlpha(1);
|
||||
playSound(this, steps[i] === 'GO!' ? SFX.COUNTDOWN_GO : SFX.COUNTDOWN_TICK);
|
||||
|
||||
this.tweens.add({
|
||||
targets: label, scaleX: 1, scaleY: 1,
|
||||
duration: 260, ease: 'Back.easeOut',
|
||||
});
|
||||
|
||||
this.time.delayedCall(steps[i] === 'GO!' ? 560 : 740, () => {
|
||||
this.tweens.add({
|
||||
targets: label, alpha: 0, duration: 180,
|
||||
onComplete: () => runStep(i + 1),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
runStep(0);
|
||||
}
|
||||
|
||||
// ── Input ──────────────────────────────────────────────────────────────────
|
||||
|
||||
setupInput() {
|
||||
|
|
@ -382,7 +336,7 @@ export default class WordleGame extends Phaser.Scene {
|
|||
|
||||
await this.animateTileFlip(this.playerTiles[row], word, this.gs.guesses[row].evaluation);
|
||||
this.updateKeyboardColors(this.gs);
|
||||
playSound(this, SFX.UI_ACTIVATE);
|
||||
playSound(this, SFX.PENCIL_WRITE);
|
||||
|
||||
const { over } = isGameOver(this.gs);
|
||||
if (over) {
|
||||
|
|
@ -559,11 +513,8 @@ export default class WordleGame extends Phaser.Scene {
|
|||
|
||||
this.time.delayedCall(700, () => {
|
||||
if (this.playerWins >= 3 || this.aiWins >= 3) {
|
||||
const playerWon = this.playerWins >= 3;
|
||||
playSound(this, playerWon ? SFX.VICTORY_SHORT : SFX.SCIFI_RISER);
|
||||
this.showVictoryScreen(playerWon);
|
||||
this.showVictoryScreen(this.playerWins >= 3);
|
||||
} else {
|
||||
if (!isDraw) playSound(this, roundWon ? SFX.CASINO_WIN : SFX.CASINO_LOSE);
|
||||
this.showRoundResult(roundWon, isDraw);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -125,8 +125,6 @@ export default class PreloadScene extends Phaser.Scene {
|
|||
this.load.audio('sfx-woosh', '/assets/fx/woosh.mp3');
|
||||
this.load.spritesheet('jello-items', '/assets/images/jello-items.png', { frameWidth: 132, frameHeight: 132 });
|
||||
this.load.audio('sfx-jello-monsters','/assets/fx/jello-monsters.mp3');
|
||||
this.load.audio('sfx-countdown-tick', '/assets/fx/countdown-01.mp3');
|
||||
this.load.audio('sfx-countdown-go', '/assets/fx/countdown-02.mp3');
|
||||
this.load.audio('sfx-ui-pick', '/assets/fx/ui-pick.mp3');
|
||||
this.load.audio('sfx-ui-activate', '/assets/fx/ui-activate.mp3');
|
||||
this.load.audio('sfx-ui-flip', '/assets/fx/ui-flip.mp3');
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ export const SFX = {
|
|||
SQUASH: 'sfx-squash',
|
||||
WOOSH: 'sfx-woosh',
|
||||
JELLO_MONSTERS: 'sfx-jello-monsters',
|
||||
COUNTDOWN_TICK: 'sfx-countdown-tick',
|
||||
COUNTDOWN_GO: 'sfx-countdown-go',
|
||||
UI_PICK: 'sfx-ui-pick',
|
||||
UI_ACTIVATE: 'sfx-ui-activate',
|
||||
UI_FLIP: 'sfx-ui-flip',
|
||||
|
|
|
|||
Loading…
Reference in New Issue