Remplace le système de quêtes par des déclencheurs, ajoute l'action variable et le chaînage
Supprime le concept de "quête" au profit d'un onglet unique "Déclencheurs"
portant toute la logique (dialogue, condition, marquage terminé) directement
sur l'objet de scène. Ajoute une nouvelle action "Modifier une variable"
(réutilisant le vocabulaire du graphe de flow) utilisable après une
collision, une interaction ou une branche de condition, ainsi qu'un
chaînage d'actions ("then") permettant d'enchaîner plusieurs actions à la
suite et d'étendre un déclencheur déjà posé sans le recréer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c504ace167
commit
d664ed5637
@@ -6,9 +6,7 @@ from . import (
|
||||
scene_object_commands,
|
||||
scene_object_role,
|
||||
scene_object_collision,
|
||||
scene_object_collision_rules,
|
||||
scene_object_name,
|
||||
scene_object_dialogue_box_style,
|
||||
scene_collision_rule_objects,
|
||||
scene_object_names_list,
|
||||
)
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import screens
|
||||
|
||||
_DEFAULT_OBJECT_LABELS = {"personnage": "Personnage", "fond": "Fond"}
|
||||
_COLLISION_EXCLUDED_KINDS = ("fond", "dialogue_box", "quiz_box", "score_widget")
|
||||
|
||||
|
||||
def build_collision_rule_objects(objects):
|
||||
"""Une carte "🧩 Collision" (voir templates/scene_edit.html) par objet
|
||||
ÉLIGIBLE (jamais un "fond", jamais le personnage "joueur" — ce sont
|
||||
TOUJOURS les AUTRES objets qui réagissent à SA présence, voir
|
||||
screens/rendering/collision_rules.py) — factorisé ici plutôt que
|
||||
dupliqué : utilisé au premier rendu de la page (routes/scenes/
|
||||
scene_edit_view.py) ET par l'endpoint AJAX ci-dessous (appelé après
|
||||
ajout/suppression/changement de rôle ou de nom, voir static/js/scenes/
|
||||
scene-editor.js) pour reconstruire la liste SANS recharger la page.
|
||||
|
||||
`objects` doit déjà porter "rendered_html" (voir
|
||||
screens.render_scene_object) sur chaque élément.
|
||||
|
||||
resolve_personnage_role retombe sur "joueur" pour TOUT personnage sans
|
||||
rôle explicitement enregistré (voir screens/rendering/
|
||||
personnage_role.py — comportement voulu pour une scène à un seul
|
||||
personnage, posé avant l'ajout de ce réglage). Appliqué tel quel,
|
||||
ÇA CASSE dès qu'une scène a plusieurs personnages sans rôle explicite
|
||||
(le cas de toute scène créée avant ce réglage — un personnage ajouté
|
||||
depuis l'éditeur reçoit maintenant TOUJOURS un rôle "pnj" explicite,
|
||||
voir add_scene_object.py) : ils retomberaient TOUS sur "joueur" et
|
||||
disparaîtraient donc TOUS de cette liste. On ne considère donc comme
|
||||
"joueur" implicite QUE LE PREMIER personnage sans rôle explicite (le
|
||||
plus ancien, z_index croissant comme `objects`) — les suivants sans
|
||||
rôle explicite sont traités comme "pnj" ici, sans rien réécrire en
|
||||
base."""
|
||||
implicit_joueur_claimed = any(
|
||||
(o.get("attributes") or {}).get("_personnage_role") == "joueur"
|
||||
for o in objects if o["kind"] == "personnage"
|
||||
)
|
||||
result = []
|
||||
for o in objects:
|
||||
if o["kind"] in _COLLISION_EXCLUDED_KINDS:
|
||||
continue
|
||||
role = None
|
||||
if o["kind"] == "personnage":
|
||||
explicit_role = (o.get("attributes") or {}).get("_personnage_role")
|
||||
if explicit_role in screens.PERSONNAGE_ROLES:
|
||||
role = explicit_role
|
||||
elif not implicit_joueur_claimed:
|
||||
role = "joueur"
|
||||
implicit_joueur_claimed = True
|
||||
else:
|
||||
role = "pnj"
|
||||
if role == "joueur":
|
||||
continue
|
||||
result.append({
|
||||
"id": o["id"],
|
||||
"name": o.get("name") or _DEFAULT_OBJECT_LABELS.get(o["kind"], "Décor"),
|
||||
"kind": o["kind"],
|
||||
"role": role,
|
||||
"thumbnail_html": o["rendered_html"],
|
||||
"rules": screens.resolve_collision_rules(o),
|
||||
})
|
||||
return result
|
||||
@@ -1,24 +0,0 @@
|
||||
from flask import jsonify
|
||||
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
|
||||
from .collision_rule_objects import build_collision_rule_objects
|
||||
|
||||
|
||||
@app.route("/game/<slug>/screens/<int:screen_id>/collision-rule-objects", methods=["GET"])
|
||||
def scene_collision_rule_objects(slug, screen_id):
|
||||
"""Liste à jour des cartes "🧩 Collision" (voir COLLISION_RULE_OBJECTS,
|
||||
templates/scene_edit.html) — appelée en AJAX après un ajout/suppression
|
||||
d'objet, ou un changement de rôle/nom (voir static/js/scenes/
|
||||
scene-editor.js) qui peut faire apparaître/disparaître un objet de
|
||||
cette liste (rôle passé à/depuis "joueur", voir
|
||||
build_collision_rule_objects) ou changer son libellé affiché (nom).
|
||||
Recalculée entièrement plutôt que diffée : la liste reste petite (un
|
||||
objet de scène par carte, jamais un "fond"/widget d'UI) et cette même
|
||||
fonction est déjà appelée à chaque rendu complet de la page."""
|
||||
objects = screens.list_scene_objects(slug, screen_id)
|
||||
for o in objects:
|
||||
o["rendered_html"] = screens.render_scene_object(o)
|
||||
return jsonify(build_collision_rule_objects(objects))
|
||||
@@ -5,8 +5,6 @@ from flask import render_template, request, abort, g
|
||||
import db
|
||||
import screens
|
||||
|
||||
from .collision_rule_objects import build_collision_rule_objects
|
||||
|
||||
|
||||
def render_scene_edit(slug, screen_id, game):
|
||||
"""Vue de l'éditeur de scène 2D — appelée par routes/screens/
|
||||
@@ -63,12 +61,6 @@ def render_scene_edit(slug, screen_id, game):
|
||||
o["id"]: screens.resolve_personnage_animations(o) for o in objects if o["kind"] == "personnage"
|
||||
}
|
||||
|
||||
# "🧩 Collision" — voir build_collision_rule_objects() (routes/scenes/
|
||||
# collision_rule_objects.py, factorisé pour être réutilisé par
|
||||
# l'endpoint AJAX scene_collision_rule_objects.py, appelé après ajout/
|
||||
# suppression/changement de rôle ou de nom sans recharger la page).
|
||||
collision_rule_objects = build_collision_rule_objects(objects)
|
||||
|
||||
flow_blocks = screens.list_flow_blocks(slug, screen_id)
|
||||
flow_nodes = screens.list_flow_nodes(slug, screen_id)
|
||||
flow_edges = screens.list_flow_edges(slug, screen_id)
|
||||
@@ -125,24 +117,15 @@ def render_scene_edit(slug, screen_id, game):
|
||||
flow_blocks_json=json.dumps(flow_blocks), blocks_view=blocks_view,
|
||||
animation_clips=animation_clips, animation_clips_json=json.dumps(animation_clips),
|
||||
animate_css_catalog=screens.ANIMATE_CSS_CATALOG, animate_css_labels_json=json.dumps(screens.ANIMATE_CSS_LABELS),
|
||||
global_variables=global_variables,
|
||||
global_variables=global_variables, global_variable_types=db.GLOBAL_VARIABLE_TYPES,
|
||||
custom_events=custom_events, custom_event_usages=custom_event_usages,
|
||||
custom_events_map_json=json.dumps(custom_events_map),
|
||||
definitions=db.list_definitions(slug),
|
||||
definitions_json=json.dumps({str(d["id"]): screens.data_definition_options(slug, d["id"]) for d in db.list_definitions(slug)}),
|
||||
definitions_names_json=json.dumps({d["id"]: d["name"] for d in db.list_definitions(slug)}),
|
||||
collision_rule_objects_json=json.dumps(collision_rule_objects),
|
||||
collision_action_types=screens.ACTION_TYPES, collision_trigger_types=screens.TRIGGER_TYPES,
|
||||
collision_default_perimetre_px=screens.DEFAULT_PERIMETRE_PX,
|
||||
# Éditeur de quêtes (voir db/quests/) : préchargées ici pour que
|
||||
# collisionRuleActionSummary (collision-rules-editor.js) affiche
|
||||
# tout de suite le TITRE de la quête référencée par une règle
|
||||
# existante, sans attendre l'ouverture de l'assistant "+ Action"
|
||||
# (seul moment où questPickerHtml irait la chercher sinon).
|
||||
quests_json=json.dumps(db.list_quests(slug)),
|
||||
# "qui parle" dans le dialogue d'une quête (voir "ℹ️ Informations",
|
||||
# static/js/quests/quest-editor.js) : les noms donnés à N'IMPORTE
|
||||
# QUEL objet de scène (personnage, décor, fond), toutes scènes du
|
||||
# jeu confondues.
|
||||
# "qui parle" dans un dialogue de déclencheur (voir "ℹ️
|
||||
# Informations", static/js/triggers/trigger-editor.js) : les noms
|
||||
# donnés à N'IMPORTE QUEL objet de scène (personnage, décor,
|
||||
# fond), toutes scènes du jeu confondues.
|
||||
scene_object_names_json=json.dumps(screens.list_named_scene_object_names(slug)),
|
||||
)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
from flask import request, jsonify
|
||||
|
||||
import screens
|
||||
|
||||
from core.flask_app import app
|
||||
|
||||
|
||||
@app.route("/game/<slug>/scene-objects/<int:object_id>/collision-rules", methods=["POST"])
|
||||
def scene_object_collision_rules(slug, object_id):
|
||||
"""Liste complète des règles "déclencheur -> action" d'un objet (voir
|
||||
"🧩 Collision" dans templates/scene_edit.html) — le client poste
|
||||
toujours la liste ENTIÈRE (ajout/suppression déjà appliqués côté
|
||||
client), jamais une règle isolée, même patron que
|
||||
scene_object_commands.py pour "extra"."""
|
||||
body = request.get_json(silent=True) or {}
|
||||
obj = screens.get_scene_object(slug, object_id)
|
||||
if not obj:
|
||||
return jsonify({"error": "objet introuvable"}), 404
|
||||
rules = screens.sanitize_collision_rules(body.get("rules"))
|
||||
screens.set_scene_object_collision_rules(slug, object_id, rules)
|
||||
return jsonify({"ok": True, "rules": rules})
|
||||
@@ -9,12 +9,13 @@ from core.flask_app import app
|
||||
def scene_object_names_list(slug):
|
||||
"""Noms d'objets de scène à jour, pour repeupler le sélecteur "qui
|
||||
parle" de l'éditeur de dialogue (voir SCENE_OBJECT_NAMES_JSON,
|
||||
templates/scene_edit.html, questSpeakerOptions() dans static/js/
|
||||
quests/quest-editor.js) — cette variable n'est posée qu'une fois au
|
||||
chargement complet de la page (HORS de #builder3, jamais rafraîchie
|
||||
par une sélection d'objet sans rechargement, voir goToSelected()) :
|
||||
sans cet endpoint, renommer un personnage puis rouvrir la modale de
|
||||
dialogue dans la MÊME session ne faisait jamais apparaître son nouveau
|
||||
nom, tant qu'aucun vrai rechargement de page n'avait eu lieu entre
|
||||
temps — appelée en AJAX depuis saveSceneObjectName()."""
|
||||
templates/scene_edit.html, triggerSpeakerOptions() dans static/js/
|
||||
triggers/trigger-editor.js) — cette variable n'est posée qu'une fois
|
||||
au chargement complet de la page (HORS de #builder3, jamais
|
||||
rafraîchie par une sélection d'objet sans rechargement, voir
|
||||
goToSelected()) : sans cet endpoint, renommer un personnage puis
|
||||
rouvrir un dialogue de déclencheur dans la MÊME session ne faisait
|
||||
jamais apparaître son nouveau nom, tant qu'aucun vrai rechargement de
|
||||
page n'avait eu lieu entre temps — appelée en AJAX depuis
|
||||
saveSceneObjectName()."""
|
||||
return jsonify(screens.list_named_scene_object_names(slug))
|
||||
|
||||
Reference in New Issue
Block a user