Quêtes : bulle "❓ Question" à choix multiples, à côté de "+ Réplique"
Build and deploy / test-python (push) Successful in 6m25s
Build and deploy / test-js (push) Successful in 58s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Nouveau type de ligne dans un dialogue de quête (voir
db/quests/sanitize_quest_dialogues.py) : une bulle JAUNE, dans la même
chaîne verticale que les répliques (même alignement, reliée par un
trait) — header : nombre de choix (2 à 8) + récompense (score, montant
en points) ; body : la question, ses choix et un bouton radio pour
désigner la bonne réponse. Aucune limite au nombre de questions par
colonne, comme pour une réplique.

Les lignes de dialogue portent maintenant explicitement
{"type": "dialogue", ...} (au lieu d'un objet sans type) pour
distinguer les deux formes — migration de forme, tests mis à jour.

Portée de ce commit : l'ÉDITEUR (créer/modifier une question). Le jeu
lui-même (afficher la question au joueur, vérifier la réponse,
attribuer la récompense) reste à construire — le widget "💬 Boîte de
dialogue" ne sait aujourd'hui afficher qu'une réplique.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-03 14:48:14 +02:00
co-authored by Claude Sonnet 5
parent f2ed602459
commit e972acf9e6
5 changed files with 242 additions and 34 deletions
+32 -6
View File
@@ -86,19 +86,45 @@ def test_sanitize_quest_dialogues_keeps_only_valid_lines_per_status():
}
cleaned = db.sanitize_quest_dialogues(raw)
assert cleaned == {
"nouvelle": [{"speaker": "Le Sorcier", "text": "Bonjour !"}],
"nouvelle": [{"type": "dialogue", "speaker": "Le Sorcier", "text": "Bonjour !"}],
"en_cours": [],
"terminee": [],
}
def test_sanitize_quest_dialogues_accepts_a_valid_question_and_rejects_malformed_ones():
""""❓ Question" (voir static/js/quests/quest-editor.js) : une bulle
jaune avec plusieurs choix, une seule bonne réponse, une récompense —
même chaîne qu'une réplique de dialogue, un autre "type" de ligne."""
raw = {
"nouvelle": [
{"type": "question", "text": "2+2 ?", "choices": ["3", "4", "5"], "correct_index": 1, "reward_type": "score", "reward_amount": 2},
{"type": "question", "text": "Une seule option", "choices": ["seule"], "correct_index": 0}, # < 2 choix -> rejetée
{"type": "question", "text": "index hors bornes", "choices": ["a", "b"], "correct_index": 5}, # rejetée
{"type": "question", "text": " ", "choices": ["a", "b"], "correct_index": 0}, # texte vide -> rejetée
{"type": "question", "text": "type de récompense inconnu", "choices": ["a", "b"], "correct_index": 0, "reward_type": "vie"},
],
"en_cours": [], "terminee": [],
}
cleaned = db.sanitize_quest_dialogues(raw)
assert cleaned["nouvelle"] == [
{"type": "question", "text": "2+2 ?", "choices": ["3", "4", "5"], "correct_index": 1, "reward_type": "score", "reward_amount": 2},
# reward_type invalide -> repli sur le premier type connu ("score"), jamais rejetée pour ça seul
{"type": "question", "text": "type de récompense inconnu", "choices": ["a", "b"], "correct_index": 0, "reward_type": "score", "reward_amount": 0},
]
def test_set_quest_dialogues_persists_all_three_columns(tmp_game_slug_cleanup):
slug = _make_game(tmp_game_slug_cleanup)
quest = db.create_quest(slug, "Trouver la clé")
dialogues = {
"nouvelle": [{"speaker": "pnj", "text": "Peux-tu m'aider ?"}, {"speaker": "joueur", "text": "Bien sûr !"}],
"en_cours": [{"speaker": "pnj", "text": "Alors, cette clé ?"}],
"terminee": [{"speaker": "pnj", "text": "Merci beaucoup !"}],
"nouvelle": [
{"type": "dialogue", "speaker": "pnj", "text": "Peux-tu m'aider ?"},
{"type": "dialogue", "speaker": "joueur", "text": "Bien sûr !"},
{"type": "question", "text": "2+2 ?", "choices": ["3", "4"], "correct_index": 1, "reward_type": "score", "reward_amount": 2},
],
"en_cours": [{"type": "dialogue", "speaker": "pnj", "text": "Alors, cette clé ?"}],
"terminee": [{"type": "dialogue", "speaker": "pnj", "text": "Merci beaucoup !"}],
}
db.set_quest_dialogues(slug, quest["id"], dialogues)
reloaded = db.get_quest(slug, quest["id"])
@@ -159,8 +185,8 @@ def test_quest_dialogues_route_sanitizes_and_persists(client, tmp_game_slug_clea
data='{"dialogues": {"nouvelle": [{"speaker": "pnj", "text": "Salut !"}], "en_cours": [], "terminee": []}}',
content_type="application/json",
)
assert resp.get_json()["dialogues"]["nouvelle"] == [{"speaker": "pnj", "text": "Salut !"}]
assert db.get_quest(slug, quest["id"])["dialogues"]["nouvelle"] == [{"speaker": "pnj", "text": "Salut !"}]
assert resp.get_json()["dialogues"]["nouvelle"] == [{"type": "dialogue", "speaker": "pnj", "text": "Salut !"}]
assert db.get_quest(slug, quest["id"])["dialogues"]["nouvelle"] == [{"type": "dialogue", "speaker": "pnj", "text": "Salut !"}]
def test_quest_dialogues_route_404s_for_missing_quest(client, game):