Compare commits
No commits in common. "25d29c0f86bf3bb41f068963c30517632b4553d9" and "9363fc3848fd5c6ae324cebd8de642f08eaddc32" have entirely different histories.
25d29c0f86
...
9363fc3848
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -515,16 +515,6 @@ export const MANIFEST = {
|
||||||
{ type: 'audio', key: 'sfx-zuma-win', path: 'assets/fx/zuma-win.mp3' },
|
{ type: 'audio', key: 'sfx-zuma-win', path: 'assets/fx/zuma-win.mp3' },
|
||||||
{ type: 'audio', key: 'sfx-zuma-lose', path: 'assets/fx/zuma-lose.mp3' },
|
{ type: 'audio', key: 'sfx-zuma-lose', path: 'assets/fx/zuma-lose.mp3' },
|
||||||
],
|
],
|
||||||
tents: [
|
|
||||||
// Tent placement/removal cues and the win jingle (played by TentsGame
|
|
||||||
// via the SFX.TENTS_* keys in src/ui/Sounds.js).
|
|
||||||
{ type: 'audio', key: 'sfx-tents-place', path: 'assets/fx/tents-place.mp3' },
|
|
||||||
{ type: 'audio', key: 'sfx-tents-remove', path: 'assets/fx/tents-remove.mp3' },
|
|
||||||
{ type: 'audio', key: 'sfx-tents-win', path: 'assets/fx/tents-win.mp3' },
|
|
||||||
// Puzzle-start intro jingle — TentsGame.startGame ducks the soundtrack
|
|
||||||
// for its duration (same pattern as Zuma's level-start fanfare).
|
|
||||||
{ type: 'audio', key: 'sfx-tents-intro', path: 'assets/music/tents-intro.mp3' },
|
|
||||||
],
|
|
||||||
'2048': [
|
'2048': [
|
||||||
// hacker soundtrack (see services/soundtrack.js) — lazy-loaded here so
|
// hacker soundtrack (see services/soundtrack.js) — lazy-loaded here so
|
||||||
// its audio only downloads once 2048 is actually entered.
|
// its audio only downloads once 2048 is actually entered.
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
create() {
|
create() {
|
||||||
try {
|
try {
|
||||||
const { tracks, volume } = getGameSoundtrack(this);
|
const { tracks, volume } = getGameSoundtrack(this);
|
||||||
if (tracks.length) this.music = new MusicPlayer(this, tracks, volume);
|
if (tracks.length) new MusicPlayer(this, tracks, volume);
|
||||||
} catch (_) { /* no soundtrack available */ }
|
} catch (_) { /* no soundtrack available */ }
|
||||||
|
|
||||||
this.input.mouse?.disableContextMenu?.();
|
this.input.mouse?.disableContextMenu?.();
|
||||||
|
|
@ -318,9 +318,6 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
this.tweens.killTweensOf(this.sky);
|
this.tweens.killTweensOf(this.sky);
|
||||||
this.sky.t = 0;
|
this.sky.t = 0;
|
||||||
|
|
||||||
// Puzzle-start intro — ducks the soundtrack for its own length.
|
|
||||||
this.playJingle(SFX.TENTS_INTRO);
|
|
||||||
|
|
||||||
const def = DIFFICULTIES[difficultyKey] ?? DIFFICULTIES.porch;
|
const def = DIFFICULTIES[difficultyKey] ?? DIFFICULTIES.porch;
|
||||||
this.view = 'play';
|
this.view = 'play';
|
||||||
this.selectLayer.setVisible(false);
|
this.selectLayer.setVisible(false);
|
||||||
|
|
@ -396,11 +393,11 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
|
|
||||||
if (res.placed) {
|
if (res.placed) {
|
||||||
this.pop.set(keyOf(c, r), this.time.now);
|
this.pop.set(keyOf(c, r), this.time.now);
|
||||||
playSoundEx(this, SFX.TENTS_PLACE, { volume: 0.8 });
|
playSoundEx(this, SFX.UI_ACTIVATE, { volume: 0.8 });
|
||||||
this.checkViolationFeedback();
|
this.checkViolationFeedback();
|
||||||
} else {
|
} else {
|
||||||
this.pop.delete(keyOf(c, r));
|
this.pop.delete(keyOf(c, r));
|
||||||
playSoundEx(this, SFX.TENTS_REMOVE, { volume: 0.7 });
|
playSoundEx(this, SFX.UI_PICK, { volume: 0.7 });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
|
|
@ -440,7 +437,7 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
this.flash.until = 0;
|
this.flash.until = 0;
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
playSoundEx(this, SFX.TENTS_REMOVE, { volume: 0.6 });
|
playSoundEx(this, SFX.UI_PICK, { volume: 0.6 });
|
||||||
}
|
}
|
||||||
|
|
||||||
revealAnswer() {
|
revealAnswer() {
|
||||||
|
|
@ -454,7 +451,7 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
this.g.tents.add(k);
|
this.g.tents.add(k);
|
||||||
this.pop.set(k, this.time.now);
|
this.pop.set(k, this.time.now);
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
playSoundEx(this, SFX.TENTS_PLACE, { volume: 0.55 });
|
playSoundEx(this, SFX.UI_ACTIVATE, { volume: 0.55 });
|
||||||
}));
|
}));
|
||||||
this.time.delayedCall(75 * missing.length + 180, () => {
|
this.time.delayedCall(75 * missing.length + 180, () => {
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
|
|
@ -463,25 +460,10 @@ export default class TentsGame extends Phaser.Scene {
|
||||||
this.btnAnswer.setEnabled(false);
|
this.btnAnswer.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duck the soundtrack for a one-shot jingle (puzzle-start intro, win),
|
|
||||||
// then hand playback back to MusicPlayer when the jingle ends — not a
|
|
||||||
// fixed delay, since the jingle's own length is what decides when the
|
|
||||||
// music comes back (same pattern as Zuma's start/lose fanfares).
|
|
||||||
playJingle(key, volume = 0.9) {
|
|
||||||
this.music?.pause();
|
|
||||||
try {
|
|
||||||
const sfx = this.sound.add(key, { volume });
|
|
||||||
sfx.once(Phaser.Sound.Events.COMPLETE, () => this.music?.resume());
|
|
||||||
sfx.play();
|
|
||||||
} catch (_) {
|
|
||||||
this.music?.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startWin() {
|
startWin() {
|
||||||
if (this.won) return;
|
if (this.won) return;
|
||||||
this.won = true;
|
this.won = true;
|
||||||
this.playJingle(SFX.TENTS_WIN);
|
playSoundEx(this, SFX.VICTORY_SHORT, { volume: 0.9 });
|
||||||
this.toast('Every tent is pitched… the sun is going down.', 950);
|
this.toast('Every tent is pitched… the sun is going down.', 950);
|
||||||
|
|
||||||
// Nightfall: ~6.5s, then the cozy panel.
|
// Nightfall: ~6.5s, then the cozy panel.
|
||||||
|
|
|
||||||
|
|
@ -99,12 +99,6 @@ export const SFX = {
|
||||||
KART_SHELL: 'sfx-kart-shell',
|
KART_SHELL: 'sfx-kart-shell',
|
||||||
KART_STAR: 'sfx-kart-star',
|
KART_STAR: 'sfx-kart-star',
|
||||||
KART_SPINNER: 'sfx-kart-spinner',
|
KART_SPINNER: 'sfx-kart-spinner',
|
||||||
// Tents & Trees cues (lazy-loaded via the `tents` entry in
|
|
||||||
// data/assetManifest.js when the game room is entered).
|
|
||||||
TENTS_PLACE: 'sfx-tents-place',
|
|
||||||
TENTS_REMOVE: 'sfx-tents-remove',
|
|
||||||
TENTS_WIN: 'sfx-tents-win',
|
|
||||||
TENTS_INTRO: 'sfx-tents-intro',
|
|
||||||
VEGA_SELECT: 'sfx-vega-select',
|
VEGA_SELECT: 'sfx-vega-select',
|
||||||
VEGA_BUILD: 'sfx-vega-build',
|
VEGA_BUILD: 'sfx-vega-build',
|
||||||
VEGA_CLOSE: 'sfx-vega-close',
|
VEGA_CLOSE: 'sfx-vega-close',
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,13 @@ function stub() {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfxPlayed = []; // keys passed to scene.sound.play
|
|
||||||
const sfxAdded = []; // keys passed to scene.sound.add (one-shot jingles)
|
|
||||||
const s = new TentsGame();
|
const s = new TentsGame();
|
||||||
|
|
||||||
// Wire up scene services.
|
// Wire up scene services.
|
||||||
s.add = stub();
|
s.add = stub();
|
||||||
s.scale = { setZoom() {} };
|
s.scale = { setZoom() {} };
|
||||||
s.input = { mouse: { disableContextMenu() {} } };
|
s.input = { mouse: { disableContextMenu() {} } };
|
||||||
s.sound = {
|
s.sound = { play() {} };
|
||||||
play(key) { sfxPlayed.push(key); },
|
|
||||||
add(key) { sfxAdded.push(key); return { once() {}, play() {} }; },
|
|
||||||
};
|
|
||||||
s.cache = { json: { get: () => null } };
|
s.cache = { json: { get: () => null } };
|
||||||
s.scene = { start() {} };
|
s.scene = { start() {} };
|
||||||
s.events = { on() {}, once() {} };
|
s.events = { on() {}, once() {} };
|
||||||
|
|
@ -68,7 +63,6 @@ check('select screen built', Array.isArray(s.selectLayer) === false && s.selectL
|
||||||
// ── Start a game ──
|
// ── Start a game ──
|
||||||
s.startGame('porch');
|
s.startGame('porch');
|
||||||
check('game state exists', s.g && s.g.puzzle && s.g.tents instanceof Set);
|
check('game state exists', s.g && s.g.puzzle && s.g.tents instanceof Set);
|
||||||
check('intro jingle queued on start', sfxAdded.includes('sfx-tents-intro'), `added=${sfxAdded}`);
|
|
||||||
check('board layout computed', typeof s.cell === 'number' && s.cell > 20 && s.cell < 140);
|
check('board layout computed', typeof s.cell === 'number' && s.cell > 20 && s.cell < 140);
|
||||||
check('zones built', s.cellZones.length === s.g.puzzle.size ** 2);
|
check('zones built', s.cellZones.length === s.g.puzzle.size ** 2);
|
||||||
check('labels built', s.colLabels.length === s.g.puzzle.size && s.rowLabels.length === s.g.puzzle.size);
|
check('labels built', s.colLabels.length === s.g.puzzle.size && s.rowLabels.length === s.g.puzzle.size);
|
||||||
|
|
@ -94,9 +88,7 @@ for (let r = 0; r < p.size; r++) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check('all solution tents placed', s.g.tents.size === p.trees.length && placed === p.trees.length, `tents=${s.g.tents.size} placed=${placed} trees=${p.trees.length}`);
|
check('all solution tents placed', s.g.tents.size === p.trees.length && placed === p.trees.length, `tents=${s.g.tents.size} placed=${placed} trees=${p.trees.length}`);
|
||||||
check('place cue played', sfxPlayed.includes('sfx-tents-place'), `played=${sfxPlayed}`);
|
|
||||||
check('win triggered', s.won === true);
|
check('win triggered', s.won === true);
|
||||||
check('win jingle queued', sfxAdded.includes('sfx-tents-win'), `added=${sfxAdded}`);
|
|
||||||
check('sky tween scheduled', s.tweens.tweens.some((t) => t.targets === s.sky));
|
check('sky tween scheduled', s.tweens.tweens.some((t) => t.targets === s.sky));
|
||||||
|
|
||||||
// ── Nightfall: animate sky to night and render ──
|
// ── Nightfall: animate sky to night and render ──
|
||||||
|
|
@ -134,7 +126,6 @@ for (const [c, r] of half) s.onCellClick(c, r);
|
||||||
check('partial placement ok', s.g.tents.size === 4, `tents=${s.g.tents.size}`);
|
check('partial placement ok', s.g.tents.size === 4, `tents=${s.g.tents.size}`);
|
||||||
s.resetTents();
|
s.resetTents();
|
||||||
check('reset clears tents', s.g.tents.size === 0);
|
check('reset clears tents', s.g.tents.size === 0);
|
||||||
check('remove cue played', sfxPlayed.includes('sfx-tents-remove'), `played=${sfxPlayed}`);
|
|
||||||
|
|
||||||
// ── All difficulties generate + solve ──
|
// ── All difficulties generate + solve ──
|
||||||
for (const key of ['porch', 'clearing', 'meadow', 'deepwoods']) {
|
for (const key of ['porch', 'clearing', 'meadow', 'deepwoods']) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue