const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)(); const sounds: Record = {}; async function loadSound(name: string): Promise { const response = await fetch(`./sounds/${name}.ogg`); const arrayBuffer = await response.arrayBuffer(); return audioCtx.decodeAudioData(arrayBuffer); } export async function initSounds() { const names = ['fireball', 'explosion', 'sword_hit1', 'teleport', 'damage', 'spiderwalking', 'spawn', 'gameover']; for (const name of names) { try { sounds[name] = await loadSound(name); } catch { console.warn(`Sound ${name} not found`); } } } export function resumeContext() { if (audioCtx.state === 'suspended') { audioCtx.resume(); } } export function playSound(name: string, volume = 1) { const buffer = sounds[name]; if (!buffer) return; if (audioCtx.state === 'suspended') return; const source = audioCtx.createBufferSource(); source.buffer = buffer; const gain = audioCtx.createGain(); gain.gain.value = volume; source.connect(gain); gain.connect(audioCtx.destination); source.start(0); } export function playLoopingSound(name: string, volume = 1): (() => void) | null { const buffer = sounds[name]; if (!buffer) return null; if (audioCtx.state === 'suspended') return null; const source = audioCtx.createBufferSource(); source.buffer = buffer; source.loop = true; const gain = audioCtx.createGain(); gain.gain.value = volume; source.connect(gain); gain.connect(audioCtx.destination); source.start(0); return () => { try { source.stop(); } catch { // already stopped } source.disconnect(); }; }