// ---------- Widget "💬 Boîte de dialogue" — moteur d'exécution ---------- // Fait le lien entre l'éditeur de collision (action "quete", voir // static/js/play/collision-rules-controller.js) et le widget d'interface // posé par l'auteur (voir "🖥️ Interface", templates/scene_edit.html, // screens/rendering/dialogue_box_style.py) : à l'exécution d'une action // "quete", affiche la réplique en cours du dialogue correspondant au // STATUT ACTUEL de la quête (gameData.quests, voir full_game_payload.py), // avance d'une réplique à chaque clic sur "Suivant", se masque à la fin. // Silencieux (aucun effet) si la quête est introuvable, n'a aucune // réplique pour son statut, ou si l'auteur n'a posé aucun widget sur // l'écran — même esprit que le reste du moteur (jamais planter). var forgeDialogueBoxState = {}; function forgeQuestById(questId) { return (gameData.quests || []).find(function (q) { return q.id === questId; }); } function forgeDialogueBoxWidgetOnCurrentScreen() { return document.querySelector('.playScreen[data-screen-id="' + window.currentScreenId + '"] .dialogueBoxWidget'); } function forgeDialogueBoxWidgetById(objectId) { return document.querySelector('.dialogueBoxWidget[data-object-id="' + objectId + '"]'); } function forgeRenderDialogueBoxLine(widget, line) { var header = widget.querySelector('[data-dialogue-role="header"]'); var body = widget.querySelector('[data-dialogue-role="body"]'); if (header) header.textContent = line.speaker; if (body) body.textContent = line.text; } // Appelée par l'action "quete" (collision-rules-controller.js) — trouve // le widget posé sur l'écran ACTUELLEMENT affiché (un seul à la fois, // comme le reste du moteur 2D). function forgeShowDialogueBox(questId) { var quest = forgeQuestById(questId); if (!quest) return; var lines = (quest.dialogues && quest.dialogues[quest.status]) || []; if (!lines.length) return; var widget = forgeDialogueBoxWidgetOnCurrentScreen(); if (!widget) return; var objectId = widget.getAttribute('data-object-id'); forgeDialogueBoxState[objectId] = { lines: lines, index: 0 }; forgeRenderDialogueBoxLine(widget, lines[0]); widget.classList.add('is-active'); } // Appelée par le bouton "Suivant →" rendu dans le widget lui-même (voir // render_scene_object.py, onclick="forgeDialogueBoxAdvance()"). function forgeDialogueBoxAdvance(objectId) { var state = forgeDialogueBoxState[objectId]; var widget = forgeDialogueBoxWidgetById(objectId); if (!state || !widget) return; state.index += 1; if (state.index >= state.lines.length) { widget.classList.remove('is-active'); delete forgeDialogueBoxState[objectId]; return; } forgeRenderDialogueBoxLine(widget, state.lines[state.index]); } // static/js/play/__tests__/ (node:test) — même garde que les autres // contrôleurs de ce dossier. if (typeof module !== 'undefined' && module.exports) { module.exports = { forgeQuestById, forgeShowDialogueBox, forgeDialogueBoxAdvance, forgeDialogueBoxWidgetOnCurrentScreen, forgeDialogueBoxWidgetById, forgeRenderDialogueBoxLine, }; }