import { config } from '../config/Config.js'; /** * The shared SFX voice (data/sfx.json). * * Scenes expose a `playSfx(name)` method (MenuScene / GameScene) that * delegates here, and UI components call it through the scene seam * (`this.scene.playSfx?.('ui_hover')`) — one voice, one place (the same * rule ConfirmOverlay follows for the construct ticks). * * Convention: `name` is the data/sfx.json key, and the asset is queued * as `sfx_` (the play name resolves to the cache key directly — * the same rule the existing construct/scan/… voices follow). * * Guards, in order: the master switch (sfx.enabled), the sound manager * (absent in headless), and the audio cache — v4 (Giedi) quirk: * `sound.play()` THROWS on a key that never loaded, and * `cache.hasAudio()` does not exist in this build, so we check * `cache.audio.has()` directly. The game never blocks or warns on sound. */ export function playSfxOn(scene, name, o = {}) { if (!scene || !config.get('sfx.enabled', true)) return; const snd = scene.sound; if (!snd || typeof snd.play !== 'function') return; const key = `sfx_${name}`; if (scene.cache && scene.cache.audio && typeof scene.cache.audio.has === 'function' && !scene.cache.audio.has(key)) return; snd.play(key, { volume: config.get('sfx.volume', 0.55), ...o }); } /** * Stop one of the configured SFX by its data/sfx.json key (a no-op when * it isn't playing). v4 (Giedi) API: the manager stops BY KEY — * `sound.stop()` does not exist in this build. */ export function stopSfxOn(scene, name) { const snd = scene && scene.sound; if (!snd || typeof snd.stopByKey !== 'function') return; snd.stopByKey(`sfx_${name}`); } /** Is one of the configured SFX playing right now? (false when unsure). */ export function sfxPlayingOn(scene, name) { const snd = scene && scene.sound; if (!snd || typeof snd.isPlaying !== 'function') return false; return snd.isPlaying(`sfx_${name}`) === true; }