import { create } from 'zustand' import { persist } from 'zustand/middleware' import type { ThemeName } from '../types' export type SoundEffect = | 'correct' | 'incorrect' | 'steal' | 'timer_tick' | 'timer_urgent' | 'victory' | 'defeat' | 'select' | 'game_start' | 'player_join' | 'question_reveal' | 'hover' | 'countdown' interface SoundState { volume: number muted: boolean soundsLoaded: boolean currentLoadedTheme: ThemeName | null setVolume: (volume: number) => void setMuted: (muted: boolean) => void toggleMute: () => void setSoundsLoaded: (loaded: boolean) => void setCurrentLoadedTheme: (theme: ThemeName | null) => void } export const useSoundStore = create()( persist( (set) => ({ volume: 0.7, muted: false, soundsLoaded: false, currentLoadedTheme: null, setVolume: (volume) => set({ volume: Math.max(0, Math.min(1, volume)) }), setMuted: (muted) => set({ muted }), toggleMute: () => set((state) => ({ muted: !state.muted })), setSoundsLoaded: (soundsLoaded) => set({ soundsLoaded }), setCurrentLoadedTheme: (currentLoadedTheme) => set({ currentLoadedTheme }), }), { name: 'trivia-sound', partialize: (state) => ({ volume: state.volume, muted: state.muted }), } ) ) // Sound file paths per theme // All themes share the same base sounds but can be customized per theme export const soundPaths: Record> = { drrr: { correct: '/sounds/drrr/correct.mp3', incorrect: '/sounds/drrr/incorrect.mp3', steal: '/sounds/drrr/steal.mp3', timer_tick: '/sounds/drrr/tick.mp3', timer_urgent: '/sounds/drrr/urgent.mp3', victory: '/sounds/drrr/victory.mp3', defeat: '/sounds/drrr/defeat.mp3', select: '/sounds/drrr/select.mp3', game_start: '/sounds/drrr/game_start.mp3', player_join: '/sounds/drrr/player_join.mp3', question_reveal: '/sounds/drrr/question_reveal.mp3', hover: '/sounds/drrr/hover.mp3', countdown: '/sounds/drrr/countdown.mp3', }, retro: { correct: '/sounds/retro/correct.mp3', incorrect: '/sounds/retro/incorrect.mp3', steal: '/sounds/retro/steal.mp3', timer_tick: '/sounds/retro/tick.mp3', timer_urgent: '/sounds/retro/urgent.mp3', victory: '/sounds/retro/victory.mp3', defeat: '/sounds/retro/defeat.mp3', select: '/sounds/retro/select.mp3', game_start: '/sounds/retro/game_start.mp3', player_join: '/sounds/retro/player_join.mp3', question_reveal: '/sounds/retro/question_reveal.mp3', hover: '/sounds/retro/hover.mp3', countdown: '/sounds/retro/countdown.mp3', }, minimal: { correct: '/sounds/minimal/correct.mp3', incorrect: '/sounds/minimal/incorrect.mp3', steal: '/sounds/minimal/steal.mp3', timer_tick: '/sounds/minimal/tick.mp3', timer_urgent: '/sounds/minimal/urgent.mp3', victory: '/sounds/minimal/victory.mp3', defeat: '/sounds/minimal/defeat.mp3', select: '/sounds/minimal/select.mp3', game_start: '/sounds/minimal/game_start.mp3', player_join: '/sounds/minimal/player_join.mp3', question_reveal: '/sounds/minimal/question_reveal.mp3', hover: '/sounds/minimal/hover.mp3', countdown: '/sounds/minimal/countdown.mp3', }, rgb: { correct: '/sounds/rgb/correct.mp3', incorrect: '/sounds/rgb/incorrect.mp3', steal: '/sounds/rgb/steal.mp3', timer_tick: '/sounds/rgb/tick.mp3', timer_urgent: '/sounds/rgb/urgent.mp3', victory: '/sounds/rgb/victory.mp3', defeat: '/sounds/rgb/defeat.mp3', select: '/sounds/rgb/select.mp3', game_start: '/sounds/rgb/game_start.mp3', player_join: '/sounds/rgb/player_join.mp3', question_reveal: '/sounds/rgb/question_reveal.mp3', hover: '/sounds/rgb/hover.mp3', countdown: '/sounds/rgb/countdown.mp3', }, anime: { correct: '/sounds/anime/correct.mp3', incorrect: '/sounds/anime/incorrect.mp3', steal: '/sounds/anime/steal.mp3', timer_tick: '/sounds/anime/tick.mp3', timer_urgent: '/sounds/anime/urgent.mp3', victory: '/sounds/anime/victory.mp3', defeat: '/sounds/anime/defeat.mp3', select: '/sounds/anime/select.mp3', game_start: '/sounds/anime/game_start.mp3', player_join: '/sounds/anime/player_join.mp3', question_reveal: '/sounds/anime/question_reveal.mp3', hover: '/sounds/anime/hover.mp3', countdown: '/sounds/anime/countdown.mp3', }, } // Fallback sounds using Web Audio API generated tones // These are used when actual sound files are not available export const fallbackSoundConfigs: Record = { correct: { frequency: 880, duration: 0.15, type: 'sine' }, incorrect: { frequency: 220, duration: 0.3, type: 'square' }, steal: { frequency: 660, duration: 0.2, type: 'sawtooth' }, timer_tick: { frequency: 440, duration: 0.05, type: 'sine' }, timer_urgent: { frequency: 880, duration: 0.1, type: 'square' }, victory: { frequency: 523, duration: 0.5, type: 'sine' }, defeat: { frequency: 196, duration: 0.5, type: 'sine' }, select: { frequency: 600, duration: 0.08, type: 'sine' }, game_start: { frequency: 440, duration: 0.4, type: 'sine' }, player_join: { frequency: 520, duration: 0.12, type: 'sine' }, question_reveal: { frequency: 700, duration: 0.2, type: 'triangle' }, hover: { frequency: 400, duration: 0.03, type: 'sine' }, countdown: { frequency: 600, duration: 0.15, type: 'square' }, }