diff --git a/public/assets/fx/sword-hit.mp3 b/public/assets/fx/sword-hit.mp3 new file mode 100644 index 0000000..afb46c1 Binary files /dev/null and b/public/assets/fx/sword-hit.mp3 differ diff --git a/public/assets/fx/sword-slice.mp3 b/public/assets/fx/sword-slice.mp3 new file mode 100644 index 0000000..29d9cf7 Binary files /dev/null and b/public/assets/fx/sword-slice.mp3 differ diff --git a/public/assets/images/background-jewelquest.png b/public/assets/images/background-jewelquest.png new file mode 100644 index 0000000..50b9ce7 Binary files /dev/null and b/public/assets/images/background-jewelquest.png differ diff --git a/public/assets/images/background-jewelquest.psd b/public/assets/images/background-jewelquest.psd new file mode 100644 index 0000000..fb350ac Binary files /dev/null and b/public/assets/images/background-jewelquest.psd differ diff --git a/public/src/games/jewelquest/JewelQuestGame.js b/public/src/games/jewelquest/JewelQuestGame.js index 7d6df5d..de34089 100644 --- a/public/src/games/jewelquest/JewelQuestGame.js +++ b/public/src/games/jewelquest/JewelQuestGame.js @@ -57,7 +57,7 @@ export default class JewelQuestGame extends Phaser.Scene { if (music?.tracks) new MusicPlayer(this, music.tracks); } catch (_) { /* optional */ } - this.add.rectangle(GAME_WIDTH / 2, GAME_HEIGHT / 2, GAME_WIDTH, GAME_HEIGHT, FELT).setDepth(D.felt); + const raw = this.cache.json.get('jewelquest'); this.config = raw ?? this.config; @@ -83,6 +83,9 @@ export default class JewelQuestGame extends Phaser.Scene { } catch (_) { /* private mode */ } this.makeTextures(); + // Solid felt background for non-battle screens (class select, level select, intro) + this.add.rectangle(GAME_WIDTH / 2, GAME_HEIGHT / 2, GAME_WIDTH, GAME_HEIGHT, FELT).setDepth(D.felt); + this.layer = this.add.container(0, 0); if (this.playerClass) this.showLevelSelect(); else this.showClassSelect(); @@ -197,6 +200,7 @@ export default class JewelQuestGame extends Phaser.Scene { this.selected = null; this.dragFrom = null; this.layer.removeAll(true); + if (this.calloutText) { this.calloutText.destroy(); this.calloutText = null; } this.cellSprites = null; this.spellButtons = null; } @@ -540,6 +544,9 @@ export default class JewelQuestGame extends Phaser.Scene { } drawBattleChrome() { + // Battle-only background + this.add.image(GAME_WIDTH / 2, GAME_HEIGHT / 2, 'bg-jewelquest-battle').setDisplaySize(GAME_WIDTH, GAME_HEIGHT).setDepth(D.felt); + const cx = GAME_WIDTH / 2; const hud = this.add.text(cx, 52, `Level ${this.level} — vs ${this.opponent.name}`, { fontFamily: 'Righteous', fontSize: '36px', color: COLORS.goldHex, @@ -593,11 +600,10 @@ export default class JewelQuestGame extends Phaser.Scene { this.drawSpellPanel(); - // callout + // callout — not in container so it always renders above jewels/fx this.calloutText = this.add.text(cx, 540, '', { fontFamily: 'Righteous', fontSize: '54px', color: COLORS.goldHex, stroke: '#000000', strokeThickness: 6, - }).setOrigin(0.5).setDepth(D.fx).setAlpha(0); - this.layer.add(this.calloutText); + }).setOrigin(0.5).setDepth(D.ui + 5).setAlpha(0); const quit = new Button(this, 140, GAME_HEIGHT - 50, 'Levels', () => this.showLevelSelect(), { variant: 'ghost', width: 180, height: 52, fontSize: 22 }); @@ -894,7 +900,8 @@ export default class JewelQuestGame extends Phaser.Scene { this.flashCells([e.a, e.b], 0xffffff); break; case 'clear': { - playSound(this, SFX.MASTERMIND_MATCH ?? SFX.CARD_SHOW); + const hasSkullMatch = (e.groups ?? []).some((grp) => grp.cls === 'skull' && grp.cells.length >= 3); + playSound(this, hasSkullMatch ? SFX.SWORD_HIT : (SFX.MASTERMIND_MATCH ?? SFX.CARD_SHOW)); const actorPanel = PANEL_X[e.actor]; const foePanel = PANEL_X[1 - e.actor]; for (const grp of e.groups ?? []) { @@ -929,6 +936,7 @@ export default class JewelQuestGame extends Phaser.Scene { break; } case 'damage': + playSound(this, SFX.SWORD_SLICE); this.floatText(PANEL_X[e.target], 320, `-${e.amount}`, GEM_HEX.red, PANEL_X[e.target], 376); this.updateMetersFrom(e); break; diff --git a/public/src/scenes/PreloadScene.js b/public/src/scenes/PreloadScene.js index f84bfcc..bd2ce05 100644 --- a/public/src/scenes/PreloadScene.js +++ b/public/src/scenes/PreloadScene.js @@ -55,6 +55,7 @@ export default class PreloadScene extends Phaser.Scene { this.load.image('bg-menu', '/assets/images/background-menu.png'); this.load.image('bg-room', '/assets/images/background-room.png'); this.load.image('bg-casino', '/assets/images/background-casino.png'); + this.load.image('bg-jewelquest-battle', '/assets/images/background-jewelquest.png'); this.load.image('main-title', '/assets/images/main-title.png'); this.load.json('playfields', '/data/playfields.json'); this.load.json('card-backs', '/data/card-backs.json'); @@ -100,6 +101,8 @@ export default class PreloadScene extends Phaser.Scene { this.load.audio('sfx-battleship-miss', '/assets/fx/battleship-miss.mp3'); this.load.audio('sfx-battleship-launch', '/assets/fx/battleship-launch.mp3'); this.load.audio('sfx-victory-short', '/assets/fx/victory-short.mp3'); + this.load.audio('sfx-sword-hit', '/assets/fx/sword-hit.mp3'); + this.load.audio('sfx-sword-slice', '/assets/fx/sword-slice.mp3'); this.load.audio('sfx-scifi-launch', '/assets/fx/scifi-launch.mp3'); this.load.audio('sfx-scifi-explode', '/assets/fx/scifi-explode.mp3'); this.load.audio('sfx-scifi-riser', '/assets/fx/scifi-riser.mp3'); diff --git a/public/src/ui/Sounds.js b/public/src/ui/Sounds.js index 194a80b..7e42539 100644 --- a/public/src/ui/Sounds.js +++ b/public/src/ui/Sounds.js @@ -32,6 +32,8 @@ export const SFX = { SCIFI_RISER: 'sfx-scifi-riser', SCIFI_REVEAL: 'sfx-scifi-reveal', SCIFI_WOOSH: 'sfx-scifi-woosh', + SWORD_HIT: 'sfx-sword-hit', + SWORD_SLICE: 'sfx-sword-slice', MONOPOLY_PURCHASE: 'sfx-monopoly-purchase', MONOPOLY_EXPENSE: 'sfx-monopoly-expense', MONOPAY: 'sfx-monopoly-pay',