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>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
390ee831ca
commit
2347a70c45
@@ -27,6 +27,20 @@ var QUEST_STATUS_ORDER = ['nouvelle', 'en_cours', 'terminee'];
|
||||
// besoin (collisionRuleActionSummary).
|
||||
var QUESTS = (typeof QUESTS_JSON !== 'undefined') ? QUESTS_JSON : [];
|
||||
|
||||
// Noms de personnages nommés (voir "ℹ️ Informations", templates/
|
||||
// scene_edit.html) — proposés comme "qui parle" pour une réplique, en
|
||||
// plus de "Joueur" (toujours disponible, jamais un objet de scène).
|
||||
var PERSONNAGE_NAMES = (typeof PERSONNAGE_NAMES_JSON !== 'undefined') ? PERSONNAGE_NAMES_JSON : [];
|
||||
|
||||
// Une réplique n'a que deux COULEURS possibles (voir .questBubble-joueur/
|
||||
// .questBubble-pnj, static/style.css) même si le nom affiché est
|
||||
// n'importe quel personnage nommé — "Joueur" à droite en vert, n'importe
|
||||
// quel autre nom à gauche en bleu (voir demande utilisateur : "les bulles
|
||||
// du pnj et du joueur sont d'une couleur différente").
|
||||
function questBubbleKind(speaker) {
|
||||
return speaker === 'Joueur' ? 'joueur' : 'pnj';
|
||||
}
|
||||
|
||||
function questById(questId) {
|
||||
return QUESTS.find(function (q) { return q.id === questId; });
|
||||
}
|
||||
@@ -178,13 +192,26 @@ function renderQuestFieldsModalBody(questId) {
|
||||
'</div>';
|
||||
}
|
||||
|
||||
// Options du <select> "qui parle" — "Joueur" toujours en premier, puis
|
||||
// chaque personnage nommé (voir "ℹ️ Informations"), plus le speaker
|
||||
// ACTUEL de la réplique s'il n'est plus dans cette liste (personnage
|
||||
// renommé/supprimé depuis) pour ne jamais perdre silencieusement la
|
||||
// valeur déjà enregistrée.
|
||||
function questSpeakerOptions(currentSpeaker) {
|
||||
var options = ['Joueur'].concat(PERSONNAGE_NAMES);
|
||||
if (currentSpeaker && options.indexOf(currentSpeaker) === -1) options.push(currentSpeaker);
|
||||
return options;
|
||||
}
|
||||
|
||||
function questDialogueBubbleHtml(line, status, index) {
|
||||
var kind = questBubbleKind(line.speaker);
|
||||
var speakerSelect = questSpeakerOptions(line.speaker).map(function (name) {
|
||||
return '<option value="' + name.replace(/"/g, '"') + '"' + (name === line.speaker ? ' selected' : '') + '>' + (name === 'Joueur' ? '🧑 Joueur' : '🗨️ ' + name) + '</option>';
|
||||
}).join('');
|
||||
return (
|
||||
'<div class="questBubbleRow questBubbleRow-' + line.speaker + '">' +
|
||||
'<div class="questBubble questBubble-' + line.speaker + '">' +
|
||||
'<div class="questBubbleSpeaker" onclick="questToggleSpeaker(\'' + status + '\', ' + index + ')" title="Changer qui parle">' +
|
||||
(line.speaker === 'joueur' ? '🧑 Joueur' : '🗨️ PNJ') +
|
||||
'</div>' +
|
||||
'<div class="questBubbleRow questBubbleRow-' + kind + '">' +
|
||||
'<div class="questBubble questBubble-' + kind + '">' +
|
||||
'<select class="questBubbleSpeaker" title="Qui parle" onchange="questSetBubbleSpeaker(\'' + status + '\', ' + index + ', this.value)">' + speakerSelect + '</select>' +
|
||||
'<textarea class="questBubbleText" rows="1" placeholder="Réplique..." ' +
|
||||
'oninput="this.style.height=\'auto\'; this.style.height=this.scrollHeight+\'px\';" ' +
|
||||
'onchange="questUpdateBubbleText(\'' + status + '\', ' + index + ', this.value)">' + line.text.replace(/</g, '<') + '</textarea>' +
|
||||
@@ -292,22 +319,30 @@ function questSaveDialogues(quest) {
|
||||
.then(function (json) { if (json.dialogues) quest.dialogues = json.dialogues; });
|
||||
}
|
||||
|
||||
// Alterne "Joueur" <-> le premier personnage nommé (ou "PNJ" faute de
|
||||
// mieux, si aucun personnage n'a encore de nom — voir "ℹ️ Informations")
|
||||
// — juste un défaut de départ, l'auteur choisit ensuite librement dans
|
||||
// le menu déroulant de la réplique.
|
||||
function questNextDefaultSpeaker(lastSpeaker) {
|
||||
if (lastSpeaker === 'Joueur') return PERSONNAGE_NAMES[0] || 'PNJ';
|
||||
return 'Joueur';
|
||||
}
|
||||
|
||||
function questAddBubble(status) {
|
||||
var quest = questById(_currentQuestModalId());
|
||||
if (!quest) return;
|
||||
quest.dialogues = quest.dialogues || {};
|
||||
var lines = quest.dialogues[status] || (quest.dialogues[status] = []);
|
||||
var lastSpeaker = lines.length ? lines[lines.length - 1].speaker : 'pnj';
|
||||
lines.push({ speaker: lastSpeaker === 'pnj' ? 'joueur' : 'pnj', text: '' });
|
||||
var lastSpeaker = lines.length ? lines[lines.length - 1].speaker : 'PNJ';
|
||||
lines.push({ speaker: questNextDefaultSpeaker(lastSpeaker), text: '' });
|
||||
renderQuestDialogueModalBody(quest.id);
|
||||
questSaveDialogues(quest);
|
||||
}
|
||||
|
||||
function questToggleSpeaker(status, index) {
|
||||
function questSetBubbleSpeaker(status, index, speaker) {
|
||||
var quest = questById(_currentQuestModalId());
|
||||
if (!quest) return;
|
||||
var line = quest.dialogues[status][index];
|
||||
line.speaker = line.speaker === 'joueur' ? 'pnj' : 'joueur';
|
||||
quest.dialogues[status][index].speaker = speaker;
|
||||
renderQuestDialogueModalBody(quest.id);
|
||||
questSaveDialogues(quest);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user