diff --git a/public/assets/speech/croc-happy-01.mp3 b/public/assets/speech/croc-happy-01.mp3 new file mode 100644 index 0000000..5ad0253 Binary files /dev/null and b/public/assets/speech/croc-happy-01.mp3 differ diff --git a/public/assets/speech/croc-happy-02.mp3 b/public/assets/speech/croc-happy-02.mp3 new file mode 100644 index 0000000..77b3b9d Binary files /dev/null and b/public/assets/speech/croc-happy-02.mp3 differ diff --git a/public/assets/speech/croc-happy-03.mp3 b/public/assets/speech/croc-happy-03.mp3 new file mode 100644 index 0000000..e05c29c Binary files /dev/null and b/public/assets/speech/croc-happy-03.mp3 differ diff --git a/public/assets/speech/croc-happy-04.mp3 b/public/assets/speech/croc-happy-04.mp3 new file mode 100644 index 0000000..c7bf51f Binary files /dev/null and b/public/assets/speech/croc-happy-04.mp3 differ diff --git a/public/assets/speech/croc-happy-05.mp3 b/public/assets/speech/croc-happy-05.mp3 new file mode 100644 index 0000000..66eab78 Binary files /dev/null and b/public/assets/speech/croc-happy-05.mp3 differ diff --git a/public/assets/speech/croc-intro-01.mp3 b/public/assets/speech/croc-intro-01.mp3 new file mode 100644 index 0000000..687fe43 Binary files /dev/null and b/public/assets/speech/croc-intro-01.mp3 differ diff --git a/public/assets/speech/croc-intro-02.mp3 b/public/assets/speech/croc-intro-02.mp3 new file mode 100644 index 0000000..99b42f3 Binary files /dev/null and b/public/assets/speech/croc-intro-02.mp3 differ diff --git a/public/assets/speech/croc-upset-01.mp3 b/public/assets/speech/croc-upset-01.mp3 new file mode 100644 index 0000000..a18079b Binary files /dev/null and b/public/assets/speech/croc-upset-01.mp3 differ diff --git a/public/assets/speech/croc-upset-02.mp3 b/public/assets/speech/croc-upset-02.mp3 new file mode 100644 index 0000000..f50de65 Binary files /dev/null and b/public/assets/speech/croc-upset-02.mp3 differ diff --git a/public/assets/speech/croc-upset-03.mp3 b/public/assets/speech/croc-upset-03.mp3 new file mode 100644 index 0000000..be8a1f3 Binary files /dev/null and b/public/assets/speech/croc-upset-03.mp3 differ diff --git a/public/assets/speech/croc-upset-04.mp3 b/public/assets/speech/croc-upset-04.mp3 new file mode 100644 index 0000000..bc718df Binary files /dev/null and b/public/assets/speech/croc-upset-04.mp3 differ diff --git a/public/assets/speech/croc-upset-05.mp3 b/public/assets/speech/croc-upset-05.mp3 new file mode 100644 index 0000000..5e30bb1 Binary files /dev/null and b/public/assets/speech/croc-upset-05.mp3 differ diff --git a/public/assets/speech/cybro-happy-01.mp3 b/public/assets/speech/cybro-happy-01.mp3 new file mode 100644 index 0000000..71f399d Binary files /dev/null and b/public/assets/speech/cybro-happy-01.mp3 differ diff --git a/public/assets/speech/cybro-happy-02.mp3 b/public/assets/speech/cybro-happy-02.mp3 new file mode 100644 index 0000000..fac3e5d Binary files /dev/null and b/public/assets/speech/cybro-happy-02.mp3 differ diff --git a/public/assets/speech/cybro-happy-03.mp3 b/public/assets/speech/cybro-happy-03.mp3 new file mode 100644 index 0000000..c37026f Binary files /dev/null and b/public/assets/speech/cybro-happy-03.mp3 differ diff --git a/public/assets/speech/cybro-happy-04.mp3 b/public/assets/speech/cybro-happy-04.mp3 new file mode 100644 index 0000000..a14ea3c Binary files /dev/null and b/public/assets/speech/cybro-happy-04.mp3 differ diff --git a/public/assets/speech/cybro-happy-05.mp3 b/public/assets/speech/cybro-happy-05.mp3 new file mode 100644 index 0000000..2bc962e Binary files /dev/null and b/public/assets/speech/cybro-happy-05.mp3 differ diff --git a/public/assets/speech/cybro-intro-01.mp3 b/public/assets/speech/cybro-intro-01.mp3 new file mode 100644 index 0000000..0706673 Binary files /dev/null and b/public/assets/speech/cybro-intro-01.mp3 differ diff --git a/public/assets/speech/cybro-intro-02.mp3 b/public/assets/speech/cybro-intro-02.mp3 new file mode 100644 index 0000000..4fba7b8 Binary files /dev/null and b/public/assets/speech/cybro-intro-02.mp3 differ diff --git a/public/assets/speech/cybro-upset-01.mp3 b/public/assets/speech/cybro-upset-01.mp3 new file mode 100644 index 0000000..f978e7a Binary files /dev/null and b/public/assets/speech/cybro-upset-01.mp3 differ diff --git a/public/assets/speech/cybro-upset-02.mp3 b/public/assets/speech/cybro-upset-02.mp3 new file mode 100644 index 0000000..0fddfd8 Binary files /dev/null and b/public/assets/speech/cybro-upset-02.mp3 differ diff --git a/public/assets/speech/cybro-upset-03.mp3 b/public/assets/speech/cybro-upset-03.mp3 new file mode 100644 index 0000000..c62bebf Binary files /dev/null and b/public/assets/speech/cybro-upset-03.mp3 differ diff --git a/public/assets/speech/cybro-upset-04.mp3 b/public/assets/speech/cybro-upset-04.mp3 new file mode 100644 index 0000000..4b76740 Binary files /dev/null and b/public/assets/speech/cybro-upset-04.mp3 differ diff --git a/public/assets/speech/cybro-upset-05.mp3 b/public/assets/speech/cybro-upset-05.mp3 new file mode 100644 index 0000000..b72df66 Binary files /dev/null and b/public/assets/speech/cybro-upset-05.mp3 differ diff --git a/public/assets/speech/victor-happy-01.mp3 b/public/assets/speech/victor-happy-01.mp3 new file mode 100644 index 0000000..76d2ab4 Binary files /dev/null and b/public/assets/speech/victor-happy-01.mp3 differ diff --git a/public/assets/speech/victor-happy-02.mp3 b/public/assets/speech/victor-happy-02.mp3 new file mode 100644 index 0000000..b91536b Binary files /dev/null and b/public/assets/speech/victor-happy-02.mp3 differ diff --git a/public/assets/speech/victor-happy-03.mp3 b/public/assets/speech/victor-happy-03.mp3 new file mode 100644 index 0000000..49c5e74 Binary files /dev/null and b/public/assets/speech/victor-happy-03.mp3 differ diff --git a/public/assets/speech/victor-happy-04.mp3 b/public/assets/speech/victor-happy-04.mp3 new file mode 100644 index 0000000..7118595 Binary files /dev/null and b/public/assets/speech/victor-happy-04.mp3 differ diff --git a/public/assets/speech/victor-happy-05.mp3 b/public/assets/speech/victor-happy-05.mp3 new file mode 100644 index 0000000..2ed64f9 Binary files /dev/null and b/public/assets/speech/victor-happy-05.mp3 differ diff --git a/public/assets/speech/victor-intro-01.mp3 b/public/assets/speech/victor-intro-01.mp3 new file mode 100644 index 0000000..cdcd7cc Binary files /dev/null and b/public/assets/speech/victor-intro-01.mp3 differ diff --git a/public/assets/speech/victor-intro-02.mp3 b/public/assets/speech/victor-intro-02.mp3 new file mode 100644 index 0000000..78bdae9 Binary files /dev/null and b/public/assets/speech/victor-intro-02.mp3 differ diff --git a/public/assets/speech/victor-upset-01.mp3 b/public/assets/speech/victor-upset-01.mp3 new file mode 100644 index 0000000..9c22a73 Binary files /dev/null and b/public/assets/speech/victor-upset-01.mp3 differ diff --git a/public/assets/speech/victor-upset-02.mp3 b/public/assets/speech/victor-upset-02.mp3 new file mode 100644 index 0000000..9efdfee Binary files /dev/null and b/public/assets/speech/victor-upset-02.mp3 differ diff --git a/public/assets/speech/victor-upset-03.mp3 b/public/assets/speech/victor-upset-03.mp3 new file mode 100644 index 0000000..71f9057 Binary files /dev/null and b/public/assets/speech/victor-upset-03.mp3 differ diff --git a/public/assets/speech/victor-upset-04.mp3 b/public/assets/speech/victor-upset-04.mp3 new file mode 100644 index 0000000..2c4a17b Binary files /dev/null and b/public/assets/speech/victor-upset-04.mp3 differ diff --git a/public/assets/speech/victor-upset-05.mp3 b/public/assets/speech/victor-upset-05.mp3 new file mode 100644 index 0000000..4ebe19f Binary files /dev/null and b/public/assets/speech/victor-upset-05.mp3 differ diff --git a/public/data/opponents.json b/public/data/opponents.json index 1547908..dcb30b2 100644 --- a/public/data/opponents.json +++ b/public/data/opponents.json @@ -4,7 +4,27 @@ "id": "cybro", "spriteIndex": 0, "name": "Cy-Bro", - "bio": "AI Bro sent from the future to show the superiority of the future." + "bio": "AI Bro sent from the future to show the superiority of the future.", + "speech": { + "intro": [ + "cybro-intro-01", + "cybro-intro-02" + ], + "happy": [ + "cybro-happy-01", + "cybro-happy-02", + "cybro-happy-03", + "cybro-happy-04", + "cybro-happy-05" + ], + "upset": [ + "cybro-upset-01", + "cybro-upset-02", + "cybro-upset-03", + "cybro-upset-04", + "cybro-upset-05" + ] + } }, { "id": "brad", @@ -16,13 +36,53 @@ "id": "victor", "spriteIndex": 2, "name": "Victor", - "bio": "Patient and calculating. Moves are made using ancient technology." + "bio": "Patient and calculating. Moves are made using ancient technology.", + "speech": { + "intro": [ + "victor-intro-01", + "victor-intro-02" + ], + "happy": [ + "victor-happy-01", + "victor-happy-02", + "victor-happy-03", + "victor-happy-04", + "victor-happy-05" + ], + "upset": [ + "victor-upset-01", + "victor-upset-02", + "victor-upset-03", + "victor-upset-04", + "victor-upset-05" + ] + } }, { "id": "croc", "spriteIndex": 3, "name": "Croc", - "bio": "Wassssuppp everybody! I'm here for the party!!" + "bio": "Wassssuppp everybody! I'm here for the party!!", + "speech": { + "intro": [ + "croc-intro-01", + "croc-intro-02" + ], + "happy": [ + "croc-happy-01", + "croc-happy-02", + "croc-happy-03", + "croc-happy-04", + "croc-happy-05" + ], + "upset": [ + "croc-upset-01", + "croc-upset-02", + "croc-upset-03", + "croc-upset-04", + "croc-upset-05" + ] + } }, { "id": "mario", diff --git a/public/src/ui/MusicPlayer.js b/public/src/ui/MusicPlayer.js index c88b84b..646087c 100644 --- a/public/src/ui/MusicPlayer.js +++ b/public/src/ui/MusicPlayer.js @@ -1,9 +1,9 @@ import * as Phaser from 'phaser'; import { COLORS, GAME_WIDTH } from '../config.js'; -const BTN = 32; -const GAP = 6; -const PAD = 12; +const BTN = 32; +const GAP = 6; +const PAD = 12; const DEPTH = 90; function shuffle(arr) { @@ -17,25 +17,25 @@ function shuffle(arr) { export class MusicPlayer { constructor(scene, tracks) { - this.scene = scene; + this.scene = scene; this.tracks = shuffle(tracks); - this.idx = 0; - this.muted = false; + this.idx = 0; + this.muted = false; this._audio = null; - this._objs = []; + this._objs = []; this._buildUI(); this._play(0); scene.events.once('shutdown', () => this.destroy()); - scene.events.once('destroy', () => this.destroy()); + scene.events.once('destroy', () => this.destroy()); } _buildUI() { - const s = this.scene; + const s = this.scene; const muteX = GAME_WIDTH - PAD - BTN / 2; const skipX = muteX - GAP - BTN; - const btnY = PAD + BTN / 2; + const btnY = PAD + BTN / 2; const infoY = PAD + BTN + GAP + 8; this._muteX = muteX; @@ -48,9 +48,9 @@ export class MusicPlayer { Phaser.Geom.Rectangle.Contains, ); skipBg.input.cursor = 'pointer'; - skipBg.on('pointerover', () => this._drawBg(skipBg, skipX, btnY, true)); - skipBg.on('pointerout', () => this._drawBg(skipBg, skipX, btnY, false)); - skipBg.on('pointerdown', () => this.next()); + skipBg.on('pointerover', () => this._drawBg(skipBg, skipX, btnY, true)); + skipBg.on('pointerout', () => this._drawBg(skipBg, skipX, btnY, false)); + skipBg.on('pointerdown', () => this.next()); const skipIcon = s.add.text(skipX, btnY, '⏭', { fontFamily: 'sans-serif', fontSize: '17px', color: COLORS.textHex, @@ -63,9 +63,9 @@ export class MusicPlayer { Phaser.Geom.Rectangle.Contains, ); muteBg.input.cursor = 'pointer'; - muteBg.on('pointerover', () => this._drawBg(muteBg, muteX, btnY, true)); - muteBg.on('pointerout', () => this._drawBg(muteBg, muteX, btnY, false)); - muteBg.on('pointerdown', () => this.toggleMute()); + muteBg.on('pointerover', () => this._drawBg(muteBg, muteX, btnY, true)); + muteBg.on('pointerout', () => this._drawBg(muteBg, muteX, btnY, false)); + muteBg.on('pointerdown', () => this.toggleMute()); this._muteIcon = s.add.text(muteX, btnY, '♪', { fontFamily: 'sans-serif', fontSize: '17px', color: COLORS.textHex, @@ -97,9 +97,9 @@ export class MusicPlayer { } const track = this.tracks[idx]; this._audio = new Audio(`/assets/music/${track.file}`); - this._audio.muted = this.muted; - this._audio.volume = 0.7; - this._audio.play().catch(() => {}); + this._audio.muted = this.muted; + this._audio.volume = 0.15; + this._audio.play().catch(() => { }); this._audio.onended = () => this.next(); this._updateInfo(); } @@ -139,7 +139,7 @@ export class MusicPlayer { this._audio.onended = null; this._audio = null; } - for (const o of this._objs) { try { o.destroy(); } catch (_) {} } + for (const o of this._objs) { try { o.destroy(); } catch (_) { } } this._objs = []; } } diff --git a/public/src/ui/Portrait.js b/public/src/ui/Portrait.js index 7d53f91..eb6dc83 100644 --- a/public/src/ui/Portrait.js +++ b/public/src/ui/Portrait.js @@ -1,6 +1,7 @@ import { COLORS } from '../config.js'; import { auth } from '../services/auth.js'; import { api } from '../services/api.js'; +import { enqueue as enqueueSpeech, resetQueue as resetSpeechQueue } from './SpeechQueue.js'; // ── Shared portrait utility ─────────────────────────────────────────────────── // Both factories add elements directly to the scene at world coordinates so @@ -97,6 +98,11 @@ export function createOpponentPortrait(scene, opponent, worldX, worldY, radius, videoEl.play().catch(returnToIdle); videoEl.onended = returnToIdle; videoEl.onerror = returnToIdle; + + const speechClips = opponent?.speech?.[emotion]; + if (speechClips?.length && Math.random() < 0.6) { + enqueueSpeech(speechClips[Math.floor(Math.random() * speechClips.length)]); + } } function hide() { @@ -114,10 +120,16 @@ export function createOpponentPortrait(scene, opponent, worldX, worldY, radius, function destroy() { videoEl.pause(); videoEl.src = ''; + resetSpeechQueue(); } scene.events.once('shutdown', destroy); + if (opponent?.speech?.intro?.length) { + const clips = opponent.speech.intro; + enqueueSpeech(clips[Math.floor(Math.random() * clips.length)]); + } + return { playEmotion, hide, show, destroy }; } diff --git a/public/src/ui/SpeechQueue.js b/public/src/ui/SpeechQueue.js new file mode 100644 index 0000000..6e94ca7 --- /dev/null +++ b/public/src/ui/SpeechQueue.js @@ -0,0 +1,27 @@ +let _queue = []; +let _playing = false; +let _currentAudio = null; +const MAX = 4; + +export function enqueue(filename) { + if (_queue.length + (_playing ? 1 : 0) >= MAX) return; + _queue.push(filename); + _playNext(); +} + +function _playNext() { + if (_playing || !_queue.length) return; + _playing = true; + _currentAudio = new Audio(`/assets/speech/${_queue.shift()}.mp3`); + _currentAudio.volume = 0.8; + const done = () => { _playing = false; _currentAudio = null; _playNext(); }; + _currentAudio.onended = done; + _currentAudio.onerror = done; + _currentAudio.play().catch(done); +} + +export function resetQueue() { + if (_currentAudio) { _currentAudio.pause(); _currentAudio = null; } + _queue = []; + _playing = false; +}