Ajoute la fonctionnalite quiz autonome/plein ecran a la boite a quiz
Build and deploy / test-python (push) Successful in 12m10s
Build and deploy / test-js (push) Successful in 1m27s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Introduit la double categorie de modeles (boite de dialogue / page de
quiz plein ecran) avec plein ecran, minuteur, score integre et ecran de
resultat pour les modeles page ; ajoute les modeles "Manga" (boite et
page) et "Classique" (page), pilotables aussi par l'assistant IA Ruby.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-13 15:07:23 +02:00
co-authored by Claude Sonnet 5
parent 559331f9cf
commit 7db4803b93
26 changed files with 3173 additions and 60 deletions
+27
View File
@@ -161,6 +161,33 @@ _SYSTEM_PROMPT = (
"de l'écran (ex. centré, ou en haut) via set_object_geometry après "
"les avoir posés."
"\n\n"
"QUIZ AUTONOME (RH/formation, pas narratif) : quand le créateur décrit "
"un besoin de quiz \"tout seul\" (pas un personnage/dialogue de jeu), "
"utilise set_quiz_box_config sur l'objet kind=\"quiz_box\" pour régler "
"le PLEIN ÉCRAN (fullscreen) et un MINUTEUR pour répondre (timer_mode : "
"jamais imposé par défaut — demande TOUJOURS si le créateur en veut un "
"avant d'en activer un, \"question\" redémarre à chaque question, "
"\"quiz\" est un seul compte à rebours pour tout le quiz, timer_seconds "
"sa durée)."
"\n\n"
"MODÈLES VISUELS — DEUX catégories bien distinctes, jamais confondues : "
"dialog_template (modèles \"boîte de dialogue\" : \"defaut\" — Classique — "
"ou \"manga_dialogue\", le pendant en petite carte du thème manga) ne "
"s'affiche QUE si fullscreen=false. "
"page_template (modèles \"page de quiz\" : \"classique\" — sobre/"
"professionnel, couleurs reprises du modèle \"boîte de dialogue\" de "
"base — ou \"manga\", un thème dessiné/typographié entièrement à part) "
"ne s'affiche QUE si fullscreen=true — chacun un thème complet et "
"autonome (police, formes, couleurs ET structure entièrement propres à "
"ce modèle), pensé pour un quiz qui occupe tout l'écran. Les deux "
"réglages sont conservés "
"INDÉPENDAMMENT (jamais l'un n'écrase l'autre) : ne règle QUE celui qui "
"correspond au mode (plein écran ou non) réellement voulu par le "
"créateur, et demande le style souhaité s'il n'en a mentionné aucun "
"plutôt que d'en choisir un au hasard. En plein écran, le score choisi "
"via score_widget/reward_amount s'affiche automatiquement DANS la boîte "
"à quiz, sans réglage supplémentaire."
"\n\n"
"Ton professionnel, adapté à une formation d'entreprise. Réponds "
"toujours en français, de façon concise, en confirmant ce que tu as "
"posé."
+51
View File
@@ -40,6 +40,9 @@ _CONDITION_OPERATORS = sorted(CONDITION_OPERATOR_KEYS)
_DATA_OPERATIONS = sorted(DATA_OPERATION_LABELS)
_PERSONNAGE_ROLES = list(screens.PERSONNAGE_ROLES)
_COLLISION_SHAPES = list(screens.COLLISION_SHAPES)
_QUIZ_BOX_TIMER_MODES = list(screens.TIMER_MODES)
_QUIZ_BOX_DIALOG_TEMPLATES = list(screens.QUIZ_BOX_DIALOG_TEMPLATES)
_QUIZ_BOX_PAGE_TEMPLATES = list(screens.QUIZ_BOX_PAGE_TEMPLATES)
_GLOBAL_VARIABLE_TYPES = sorted(db.GLOBAL_VARIABLE_TYPES)
# Catalogue COMPLET (public + admin-only, voir core/sprite_gate.py) —
# Claude doit connaître les slugs valides pour ne jamais en deviner un
@@ -210,6 +213,32 @@ TOOLS = [
"required": ["object_id"],
},
},
{
"name": "set_quiz_box_config",
"description": (
"Règle les options d'une \"❓ Boîte à quiz\" pensées pour un quiz AUTONOME "
"(RH/formation) : plein écran, minuteur (jamais imposé — \"aucun\" par défaut, "
"au choix du créateur : \"question\" redémarre à chaque question, \"quiz\" est un "
"seul compte à rebours pour tout le quiz), et DEUX modèles visuels INDÉPENDANTS "
"(les deux réglages sont conservés en même temps, jamais l'un n'écrase l'autre) : "
"dialog_template (visible SEULEMENT hors plein écran — variantes de forme/couleur "
"sur une structure proche de \"Classique\") et page_template (visible SEULEMENT en "
"plein écran — thème complet et autonome, structure HTML propre à chaque modèle). "
"En plein écran, le score se retrouve affiché directement dans la boîte."
),
"input_schema": {
"type": "object",
"properties": {
"object_id": {"type": "integer"},
"fullscreen": {"type": "boolean"},
"timer_mode": {"type": "string", "enum": _QUIZ_BOX_TIMER_MODES},
"timer_seconds": {"type": "integer", "description": "Durée du minuteur (3 à 600s), ignorée si timer_mode=\"aucun\"."},
"dialog_template": {"type": "string", "enum": _QUIZ_BOX_DIALOG_TEMPLATES, "description": "Modèle \"boîte de dialogue\" — ne s'affiche que si fullscreen=false."},
"page_template": {"type": "string", "enum": _QUIZ_BOX_PAGE_TEMPLATES, "description": "Modèle \"page de quiz\" — ne s'affiche que si fullscreen=true."},
},
"required": ["object_id"],
},
},
{
"name": "create_global_variable",
"description": "Crée une variable globale (idempotent par nom) — utilisable ensuite dans les déclencheurs/conditions.",
@@ -502,6 +531,27 @@ def _dispatch_set_object_collision(slug, screen_id, user_id, object_id, enabled=
return {"ok": True}
def _dispatch_set_quiz_box_config(slug, screen_id, user_id, object_id, fullscreen=False,
timer_mode="aucun", timer_seconds=20,
dialog_template="defaut", page_template="classique"):
# Même forme que screens.set_scene_object_quiz_config (remplacement
# complet des réglages, jamais un merge partiel) — screens.py sanitize
# de toute façon toute valeur hors énumération, ce garde-fou ici sert
# juste à ne jamais transmettre None à sanitize_quiz_box_config.
# dialog_template/page_template sont conservés INDÉPENDAMMENT (voir
# screens/rendering/quiz_box_config.py) : Ruby peut en régler un seul
# sans jamais écraser l'autre.
config = {
"fullscreen": bool(fullscreen),
"timer_mode": timer_mode if timer_mode in _QUIZ_BOX_TIMER_MODES else "aucun",
"timer_seconds": timer_seconds or 20,
"dialog_template": dialog_template if dialog_template in _QUIZ_BOX_DIALOG_TEMPLATES else "defaut",
"page_template": page_template if page_template in _QUIZ_BOX_PAGE_TEMPLATES else "classique",
}
screens.set_scene_object_quiz_config(slug, object_id, config)
return {"ok": True}
def _dispatch_create_global_variable(slug, screen_id, user_id, name, var_type="texte", default_value="", per_player=True):
variable_id = db.create_global_variable(slug, name, var_type=var_type, default_value=default_value, per_player=per_player)
return {"variable_id": variable_id}
@@ -571,6 +621,7 @@ _DISPATCH = {
"set_object_name": _dispatch_set_object_name,
"set_object_role": _dispatch_set_object_role,
"set_object_collision": _dispatch_set_object_collision,
"set_quiz_box_config": _dispatch_set_quiz_box_config,
"create_global_variable": _dispatch_create_global_variable,
"set_collision_rules": _dispatch_set_collision_rules,
"append_action_to_trigger": _dispatch_append_action_to_trigger,