// === CHARGEUR DE JEUX DYNAMIQUE === const GameLoader = { currentGame: null, contentScanner: new ContentScanner(), jsonLoader: new JSONContentLoader(), loadedModules: { games: {}, content: {} }, async loadGame(gameType, contentType) { try { // Nettoyage du jeu précédent this.cleanup(); // Chargement parallèle du module de jeu et du contenu const [gameModule, contentModule] = await Promise.all([ this.loadGameModule(gameType), this.loadContentModule(contentType) ]); // Initialisation du jeu this.initGame(gameType, gameModule, contentModule); } catch (error) { logSh(`❌ Erreur lors du chargement du jeu: ${error.message}`, 'ERROR'); logSh(`❌ Stack trace: ${error.stack}`, 'ERROR'); throw error; } }, async loadGameModule(gameType) { // Vérifier si le module est déjà chargé if (this.loadedModules.games[gameType]) { return this.loadedModules.games[gameType]; } try { // Chargement dynamique du script await this.loadScript(`js/games/${gameType}.js`); // Récupération du module depuis l'objet global const module = window.GameModules?.[this.getModuleName(gameType)]; if (!module) { throw new Error(`Module de jeu ${gameType} non trouvé`); } // Cache du module this.loadedModules.games[gameType] = module; return module; } catch (error) { logSh(`Erreur chargement module jeu ${gameType}:`, error, 'ERROR'); throw error; } }, async loadContentModule(contentType) { // Utiliser le ContentScanner pour récupérer le contenu découvert try { // Récupérer le contenu déjà découvert par le scanner const contentInfo = await this.contentScanner.getContentById(contentType); if (!contentInfo) { throw new Error(`Contenu ${contentType} non trouvé par le scanner`); } // Charger le module JavaScript correspondant await this.loadScript(`js/content/${contentInfo.filename}`); // Récupérer le module depuis l'objet global const moduleName = this.getContentModuleName(contentType); const rawModule = window.ContentModules?.[moduleName]; if (!rawModule) { throw new Error(`Module ${moduleName} non trouvé après chargement`); } // NOUVEAU: Utiliser le JSONContentLoader pour adapter le contenu ultra-modulaire const adaptedContent = this.jsonLoader.loadContent(rawModule); logSh(`🔄 Contenu adapté pour ${contentType}: ${adaptedContent._adapted ? 'JSON ultra-modulaire' : 'format legacy'}`, 'INFO'); // Combiner les informations du scanner avec le contenu adapté const enrichedContent = { ...adaptedContent, ...contentInfo, // S'assurer que le contenu brut du module est disponible rawContent: rawModule, adaptedContent: adaptedContent }; this.loadedModules.content[contentType] = enrichedContent; return enrichedContent; } catch (error) { logSh(`Erreur chargement contenu ${contentType}:`, error, 'ERROR'); // Fallback: essayer de charger directement le fichier JSON if (contentType.includes('json') || contentType.includes('ultra') || contentType.includes('exemple')) { try { logSh(`🔄 Tentative de chargement JSON direct pour ${contentType}...`, 'INFO'); const jsonResponse = await fetch(`${contentType}.json`); if (jsonResponse.ok) { const jsonContent = await jsonResponse.json(); const adaptedContent = this.jsonLoader.adapt(jsonContent); this.loadedModules.content[contentType] = adaptedContent; return adaptedContent; } } catch (jsonError) { logSh(`⚠️ Fallback JSON échoué: ${jsonError.message}`, 'WARN'); } } throw error; } }, loadScript(src) { return new Promise((resolve, reject) => { // Vérifier si le script est déjà chargé const existingScript = document.querySelector(`script[src="${src}"]`); if (existingScript) { resolve(); return; } const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = () => reject(new Error(`Impossible de charger ${src}`)); document.head.appendChild(script); }); }, initGame(gameType, GameClass, contentData) { logSh(`🎮 Initializing game: ${gameType}`, 'DEBUG'); try { const gameContainer = document.getElementById('game-container'); const gameTitle = document.getElementById('game-title'); const scoreDisplay = document.getElementById('current-score'); logSh('🎮 DOM elements found, adapting content...', 'DEBUG'); // Adapter le contenu avec le JSON Loader pour compatibilité avec les jeux const adaptedContent = this.jsonLoader.loadContent(contentData); logSh('🎮 Content adapted, updating UI...', 'DEBUG'); // Mise à jour du titre const contentName = adaptedContent.name || contentType; gameTitle.textContent = this.getGameTitle(gameType, contentName); // Réinitialisation du score scoreDisplay.textContent = '0'; logSh('🎮 Creating game instance...', 'DEBUG'); // Création de l'instance de jeu avec contenu enrichi this.currentGame = new GameClass({ container: gameContainer, content: adaptedContent, contentScanner: this.contentScanner, // Passer le scanner pour accès aux métadonnées onScoreUpdate: (score) => this.updateScore(score), onGameEnd: (finalScore) => this.handleGameEnd(finalScore) }); logSh('🎮 Game instance created successfully', 'DEBUG'); // Démarrage du jeu (seulement si la méthode start existe) if (typeof this.currentGame.start === 'function') { logSh('🎮 Starting game with start() method...', 'DEBUG'); this.currentGame.start(); } else { logSh('🎮 Game auto-started in constructor (no start() method)', 'DEBUG'); } logSh('✅ Game initialization completed successfully', 'DEBUG'); } catch (error) { logSh(`❌ Error in initGame: ${error.message}`, 'ERROR'); logSh(`❌ initGame stack: ${error.stack}`, 'ERROR'); throw error; } }, updateScore(score) { const scoreDisplay = document.getElementById('current-score'); scoreDisplay.textContent = score.toString(); // Animation du score Utils.animateElement(scoreDisplay, 'pulse', 200); }, handleGameEnd(finalScore) { // Sauvegarde du score this.saveScore(finalScore); // Affichage du résultat Utils.showToast(`Jeu terminé ! Score final: ${finalScore}`, 'success'); // Afficher les options de fin de jeu this.showGameEndOptions(finalScore); }, showGameEndOptions(finalScore) { const gameContainer = document.getElementById('game-container'); // Créer l'overlay de fin de jeu const endOverlay = document.createElement('div'); endOverlay.className = 'game-end-overlay'; endOverlay.innerHTML = `