import { createContext, useContext, useState, useCallback, useEffect, } from "react"; import { useSound } from "use-sound"; import { storyApi } from "../utils/api"; const SOUND_ENABLED_KEY = "sound_enabled"; // Définition des sons du jeu const SOUNDS = { page: { files: Array.from( { length: 7 }, (_, i) => `/sounds/page-flip-${i + 1}.mp3` ), volume: 0.5, }, writing: { files: Array.from({ length: 5 }, (_, i) => `/sounds/drawing-${i + 1}.mp3`), volume: 0.3, }, transition: { files: Array.from( { length: 3 }, (_, i) => `/sounds/transitional-swipe-${i + 1}.mp3` ), volume: 0.1, }, talkySarah: { on: "/sounds/talky-walky-on.mp3", off: "/sounds/talky-walky-off.mp3", volume: 0.5, }, tick: { files: Array.from({ length: 4 }, (_, i) => `/sounds/tick-${i + 1}.mp3`), volume: { normal: 0.05, // Volume normal à 50% du volume final final: 0.4, // Volume final (comme avant) }, }, lock: { files: ["/sounds/lock-1.mp3"], volume: 0.025, }, }; const SoundContext = createContext(null); export function SoundProvider({ children }) { const [isSoundEnabled, setIsSoundEnabled] = useState(() => { const stored = localStorage.getItem(SOUND_ENABLED_KEY); return stored === null ? true : stored === "true"; }); // Initialiser l'audio context après interaction utilisateur useEffect(() => { const handleInteraction = () => { storyApi.handleUserInteraction(); // Retirer les listeners une fois qu'on a eu une interaction window.removeEventListener("click", handleInteraction); window.removeEventListener("touchstart", handleInteraction); window.removeEventListener("keydown", handleInteraction); }; window.addEventListener("click", handleInteraction); window.addEventListener("touchstart", handleInteraction); window.addEventListener("keydown", handleInteraction); return () => { window.removeEventListener("click", handleInteraction); window.removeEventListener("touchstart", handleInteraction); window.removeEventListener("keydown", handleInteraction); }; }, []); // Initialiser tous les sons const soundInstances = {}; Object.entries(SOUNDS).forEach(([category, config]) => { if (category === "tick") { // Initialisation spéciale pour les ticks avec volumes différents soundInstances[category] = { normal: config.files.map((file) => { const [play] = useSound(file, { volume: config.volume.normal }); return play; }), final: config.files.map((file) => { const [play] = useSound(file, { volume: config.volume.final }); return play; }), }; } else if (Array.isArray(config.files)) { // Pour les sons avec plusieurs variations soundInstances[category] = config.files.map((file) => { const [play] = useSound(file, { volume: config.volume }); return play; }); } else if (typeof config.files === "string") { // Pour les sons uniques const [play] = useSound(config.files, { volume: config.volume }); soundInstances[category] = play; } else { // Pour les sons avec sous-catégories (comme talkySarah) soundInstances[category] = {}; Object.entries(config).forEach(([key, value]) => { if (key !== "volume" && typeof value === "string") { const [play] = useSound(value, { volume: config.volume }); soundInstances[category][key] = play; } }); } }); // Sauvegarder l'état du son dans le localStorage useEffect(() => { localStorage.setItem(SOUND_ENABLED_KEY, isSoundEnabled); }, [isSoundEnabled]); // Fonction pour jouer un son const playSound = useCallback( (category, subCategory = null) => { if (!isSoundEnabled) return; try { if (category === "tick") { // Pour les ticks avec volumes différents const type = subCategory || "normal"; const sounds = soundInstances[category][type]; const randomIndex = Math.floor(Math.random() * sounds.length); sounds[randomIndex]?.(); } else if (subCategory) { // Pour les sons avec sous-catégories (comme talkySarah.on) soundInstances[category][subCategory]?.(); } else if (Array.isArray(soundInstances[category])) { // Pour les sons avec variations, jouer un son aléatoire const randomIndex = Math.floor( Math.random() * soundInstances[category].length ); soundInstances[category][randomIndex]?.(); } else { // Pour les sons uniques soundInstances[category]?.(); } } catch (error) { console.warn(`Error playing sound ${category}:`, error); } }, [isSoundEnabled, soundInstances] ); const value = { isSoundEnabled, setIsSoundEnabled, playSound, }; return ( {children} ); } export const useSoundSystem = () => { const context = useContext(SoundContext); if (!context) { throw new Error("useSoundSystem must be used within a SoundProvider"); } return context; };