Files
Forge-Engine/static/js/play/dialogue-box-controller.js
T
williamandClaude Sonnet 5 2347a70c45
Build and deploy / test-python (push) Successful in 11m32s
Build and deploy / test-js (push) Successful in 1m12s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Quêtes/collision : personnages nommés, dialogues qui parlent, boîte de dialogue en jeu
- "ℹ️ Informations" (propriétés d'un personnage) : nom éditable, réutilisé
  comme "qui parle" dans l'éditeur de dialogue de quête (menu déroulant,
  plus "Joueur" toujours disponible) — remplace l'ancien choix binaire
  joueur/pnj. db.sanitize_quest_dialogues accepte maintenant un nom libre.

- Nouveau menu "🖥️ Interface" (palette d'objets) avec le premier widget :
  "💬 Boîte de dialogue" (kind="dialogue_box", screens/rendering/
  dialogue_box_style.py) — position/taille comme tout objet de scène,
  panneau "🎨 Style" dédié (police, taille, épaisseur, couleur du texte,
  couleur header/body/footer). Rendu en <div> à 3 zones, jamais soumis à
  la collision ni à l'éditeur de collision (exclu partout : obstacles,
  liste des règles, payload). Rendu côté jeu dans .sceneUI, une couche
  FIXE au viewport (jamais .sceneWorld, qui défile avec la caméra).

- static/js/play/dialogue-box-controller.js : fait le lien moteur entre
  l'action "quete" de l'éditeur de collision et ce widget — affiche la
  réplique en cours du dialogue correspondant au STATUT ACTUEL de la
  quête (gameData.quests, désormais exposé game-wide par
  full_game_payload.py), avance au clic sur "Suivant" (header = qui
  parle, body = texte, footer = bouton), se masque à la dernière réplique.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:20:58 +02:00

73 lines
3.1 KiB
JavaScript

// ---------- 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(<id>)").
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,
};
}