// ---------- Éditeur de quêtes ----------
// Module partagé entre templates/quests.html (page dédiée : liste de
// cartes + "+ Nouvelle quête") et static/js/scenes/collision-rules-editor.js
// (l'assistant "+ Action" de l'éditeur de collision ouvre CETTE MÊME
// modale de dialogue quand l'auteur choisit "Déclencher une quête",
// plutôt qu'un simple champ texte pour un id). La modale (arbre de
// dialogue) est créée dynamiquement (ensureQuestDialogueModal) plutôt que
// dupliquée dans deux templates.
//
// Une quête (voir db/quests/) : id, title, objectif, recompense_score,
// status (nouvelle/en_cours/terminee — statut COURANT, informatif),
// resultat (reussi/echoue), dialogues (une liste de répliques PAR
// STATUT — 3 colonnes dans l'éditeur : quel dialogue jouer selon l'état
// de la quête au moment où le joueur parle au PNJ).
var QUEST_STATUS_LABELS = { nouvelle: 'Nouvelle', en_cours: 'En cours', terminee: 'Terminée' };
var QUEST_RESULT_LABELS = { reussi: '✅ Réussi', echoue: '❌ Échoué' };
var QUEST_STATUS_ORDER = ['nouvelle', 'en_cours', 'terminee'];
// Quêtes connues côté client — préremplies par QUESTS_JSON (quests.html)
// si présent, sinon vide tant qu'on n'a pas encore fetch (contexte
// éditeur de collision, voir questPickerEnsureLoaded).
var QUESTS = (typeof QUESTS_JSON !== 'undefined') ? QUESTS_JSON : [];
function questById(questId) {
return QUESTS.find(function (q) { return q.id === questId; });
}
function questCardHtml(quest, i) {
var resultatHtml = quest.resultat ? '' + QUEST_RESULT_LABELS[quest.resultat] + '' : '';
return (
'
'
);
}
function renderQuestListPage() {
var container = document.getElementById('questsGrid');
if (!container) return;
if (!QUESTS.length) {
container.innerHTML = '
Aucune quête pour l\'instant — crée-en une avec le bouton ci-dessus.
';
return;
}
container.innerHTML = QUESTS.map(questCardHtml).join('');
}
function createQuestFromListPage() {
fetch('/game/' + GAME_SLUG + '/quests/new', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
})
.then(function (r) { return r.json(); })
.then(function (json) {
QUESTS.unshift(json.quest);
renderQuestListPage();
openQuestDialogueModal(json.quest.id);
});
}
// ---------- Modale "arbre de dialogue" ----------
// Créée une seule fois (au premier appel), réutilisée ensuite — partagée
// entre la page dédiée et l'assistant "+ Action" de l'éditeur de
// collision, jamais dupliquée dans les templates.
var _questModalOnUse = null;
function ensureQuestDialogueModal() {
var modal = document.getElementById('questDialogueModal');
if (modal) return modal;
modal = document.createElement('div');
modal.className = 'modal';
modal.id = 'questDialogueModal';
modal.innerHTML =
'' +
'
' +
'' +
'
';
document.body.appendChild(modal);
return modal;
}
// `onUse(quest)` optionnel : posé par collisionWizardChooseAction('quete', ...)
// pour finaliser la règle de collision avec cette quête, affiche alors un
// bouton "✓ Utiliser cette quête" épinglé en haut de la modale.
function openQuestDialogueModal(questId, onUse) {
_questModalOnUse = onUse || null;
var modal = ensureQuestDialogueModal();
modal.classList.add('is-active');
renderQuestDialogueModalBody(questId);
}
function closeQuestDialogueModal() {
var modal = document.getElementById('questDialogueModal');
if (modal) modal.classList.remove('is-active');
_questModalOnUse = null;
_questModalCurrentId = null;
}
function questUseThisQuest(questId) {
var quest = questById(questId);
if (_questModalOnUse && quest) _questModalOnUse(quest);
closeQuestDialogueModal();
}
function questFieldRowHtml(quest) {
return (
'
';
}
var _questPickerOnUse = null;
function renderQuestPickerStep(onUse) {
_questPickerOnUse = onUse;
var body = collisionWizardBodyEl();
body.innerHTML = '