Intègre un chat IA capable de manipuler la scène via les mêmes fonctions que l'éditeur manuel (objets, variables, déclencheurs, images générées), avec conversations multiples par écran façon Claude. Corrige au passage le rafraîchissement pjax hors-ordre, l'onglet IA/déclencheurs vide après sélection d'un objet, la comparaison de booléens dans les conditions, et le blocage du glisser-déposer hors du cadre caméra après un redimensionnement de fond par l'IA. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
111 lines
5.1 KiB
Python
111 lines
5.1 KiB
Python
from flask import jsonify, request
|
|
|
|
import screens
|
|
|
|
from core.flask_app import app
|
|
|
|
|
|
@app.route("/game/<slug>/triggers/objects-catalog", methods=["GET"])
|
|
def triggers_objects_catalog(slug):
|
|
"""Catalogue des objets de scène éligibles à un déclencheur, pour la
|
|
grille "choisis un objet" de la modale d'ajout (voir
|
|
screens.list_all_collision_objects)."""
|
|
return jsonify(screens.list_all_collision_objects(slug))
|
|
|
|
|
|
@app.route("/game/<slug>/triggers", methods=["GET"])
|
|
def triggers_get(slug):
|
|
"""TOUS les déclencheurs du jeu (voir screens.list_all_triggers) — plus
|
|
de recherche inversée par quête, la logique est portée directement par
|
|
chaque déclencheur."""
|
|
return jsonify(screens.list_all_triggers(slug))
|
|
|
|
|
|
@app.route("/game/<slug>/triggers", methods=["POST"])
|
|
def triggers_add(slug):
|
|
"""Ajoute un déclencheur sur l'objet choisi — body {object_id, rule},
|
|
`rule` construite par l'assistant "déclencheur -> action" (voir
|
|
openTriggerWizard, static/js/scenes/collision-rules-editor.js) :
|
|
n'importe quel type de déclencheur/action qu'il propose passe donc
|
|
déjà tel quel, sans changement à faire ici si de nouveaux types
|
|
apparaissent un jour. Même contrat "liste ENTIÈRE" que l'éditeur de
|
|
collision (routes/scenes/scene_object_collision_rules.py) : on
|
|
recharge les règles existantes de l'objet, on y ajoute la nouvelle, on
|
|
sauvegarde la liste complète."""
|
|
body = request.get_json(silent=True) or {}
|
|
try:
|
|
object_id = int(body.get("object_id"))
|
|
except (TypeError, ValueError):
|
|
return jsonify({"error": "object_id invalide"}), 400
|
|
obj = screens.get_scene_object(slug, object_id)
|
|
if obj is None:
|
|
return jsonify({"error": "objet introuvable"}), 404
|
|
new_rule = body.get("rule")
|
|
if not isinstance(new_rule, dict):
|
|
return jsonify({"error": "rule invalide"}), 400
|
|
|
|
rules = screens.resolve_collision_rules(obj)
|
|
rules.append(new_rule)
|
|
sanitized = screens.sanitize_collision_rules(rules)
|
|
screens.set_scene_object_collision_rules(slug, object_id, sanitized)
|
|
return jsonify({"ok": True})
|
|
|
|
|
|
@app.route("/game/<slug>/triggers/<int:object_id>", methods=["DELETE"])
|
|
def triggers_delete(slug, object_id):
|
|
"""Retire TOUTES les règles de collision de CET objet — sans quête
|
|
pour distinguer "cette règle-ci" d'une autre, un objet ne porte de
|
|
toute façon en pratique qu'un seul déclencheur à la fois (posé par
|
|
l'assistant, jamais cumulé)."""
|
|
obj = screens.get_scene_object(slug, object_id)
|
|
if obj is None:
|
|
return jsonify({"error": "objet introuvable"}), 404
|
|
screens.set_scene_object_collision_rules(slug, object_id, [])
|
|
return jsonify({"ok": True})
|
|
|
|
|
|
@app.route("/game/<slug>/triggers/<int:object_id>/dialogue", methods=["POST"])
|
|
def trigger_dialogue_update(slug, object_id):
|
|
"""Édition EN LIGNE des répliques d'UN dialogue précis (voir
|
|
screens/rendering/collision_rules.py::"dialogue".dialogue) — body
|
|
{dialogue_id, lines}. 404 si `dialogue_id` ne correspond à aucun
|
|
dialogue de CET objet (règle supprimée entre-temps, référence
|
|
orpheline)."""
|
|
obj = screens.get_scene_object(slug, object_id)
|
|
if obj is None:
|
|
return jsonify({"error": "objet introuvable"}), 404
|
|
body = request.get_json(silent=True) or {}
|
|
dialogue_id = body.get("dialogue_id")
|
|
if not isinstance(dialogue_id, str) or not dialogue_id.strip():
|
|
return jsonify({"error": "dialogue_id invalide"}), 400
|
|
|
|
rules = screens.resolve_collision_rules(obj)
|
|
if not screens.set_dialogue_lines_in_rules(rules, dialogue_id, body.get("lines")):
|
|
return jsonify({"error": "dialogue introuvable"}), 404
|
|
sanitized = screens.sanitize_collision_rules(rules)
|
|
screens.set_scene_object_collision_rules(slug, object_id, sanitized)
|
|
return jsonify({"ok": True})
|
|
|
|
|
|
@app.route("/game/<slug>/triggers/<int:object_id>/append-action", methods=["POST"])
|
|
def trigger_append_action(slug, object_id):
|
|
""""+ Ajouter une action" en bout de chaîne (voir screens/rendering/
|
|
collision_rules.py::set_then_action_in_rules, static/js/triggers/
|
|
trigger-editor.js) — body {after_id, action} : `after_id` est le
|
|
dialogue.id (feuille "dialogue") ou id (feuille "variable") de la
|
|
DERNIÈRE feuille d'une chaîne. 404 si `after_id` introuvable ou si
|
|
cette feuille a déjà un "then" (jamais écrasé par cette route — un
|
|
nouvel appel doit d'abord recharger la chaîne à jour)."""
|
|
if screens.get_scene_object(slug, object_id) is None:
|
|
return jsonify({"error": "objet introuvable"}), 404
|
|
body = request.get_json(silent=True) or {}
|
|
after_id = body.get("after_id")
|
|
if not isinstance(after_id, str) or not after_id.strip():
|
|
return jsonify({"error": "after_id invalide"}), 400
|
|
|
|
# Chemin d'écriture PARTAGÉ avec l'agent IA (voir ai/tools.py) —
|
|
# ni cette route ni l'agent n'écrivent _collision_rules directement.
|
|
if not screens.append_action_to_trigger(slug, object_id, after_id, body.get("action")):
|
|
return jsonify({"error": "action précédente introuvable ou déjà chaînée"}), 404
|
|
return jsonify({"ok": True})
|