from flask import jsonify, request from werkzeug.wrappers import Response import game_engine from core.flask_app import app @app.route("/game//screens//triggers", methods=["GET"]) def screen_triggers_get(slug: str, screen_id: int) -> Response | tuple[Response, int]: """Déclencheurs D'ÉCRAN de CET écran (voir "Déclencheurs de l'écran", game_engine/rendering/screen_triggers.py) — SANS objet requis, pour de la narration/cinématique dès l'affichage.""" screen = game_engine.get_screen(slug, screen_id) if screen is None: return jsonify({"error": "écran introuvable"}), 404 rules = game_engine.resolve_screen_triggers(screen) # Rétro-remplissage des feuilles sans id (voir game_engine/rendering/ # trigger_graph.py::list_all_triggers, même logique côté objet) — # persisté dès ce premier affichage. if game_engine.backfill_missing_leaf_ids(rules): game_engine.set_screen_triggers(slug, screen_id, rules) return jsonify(rules) @app.route("/game//screens//triggers", methods=["POST"]) def screen_triggers_add(slug: str, screen_id: int) -> Response | tuple[Response, int]: """Ajoute une règle "déclencheur d'écran -> action" — body {rule}, même contrat "liste ENTIÈRE" que routes/game/triggers/triggers.py::triggers_add : on recharge les règles existantes de l'écran, on y ajoute la nouvelle, on sauvegarde la liste complète.""" screen = game_engine.get_screen(slug, screen_id) if screen is None: return jsonify({"error": "écran introuvable"}), 404 body = request.get_json(silent=True) or {} new_rule = body.get("rule") if not isinstance(new_rule, dict): return jsonify({"error": "rule invalide"}), 400 rules = game_engine.resolve_screen_triggers(screen) rules.append(new_rule) sanitized = game_engine.sanitize_screen_triggers(rules) game_engine.set_screen_triggers(slug, screen_id, sanitized) return jsonify({"ok": True}) @app.route("/game//screens//triggers", methods=["DELETE"]) def screen_triggers_clear(slug: str, screen_id: int) -> Response | tuple[Response, int]: """Retire TOUTES les règles d'écran de CET écran.""" if game_engine.get_screen(slug, screen_id) is None: return jsonify({"error": "écran introuvable"}), 404 game_engine.set_screen_triggers(slug, screen_id, []) return jsonify({"ok": True}) @app.route("/game//screens//triggers/", methods=["DELETE"]) def screen_trigger_delete_one(slug: str, screen_id: int, index: int) -> Response | tuple[Response, int]: """Retire UNE SEULE règle d'écran (son index dans la liste) — contrairement aux déclencheurs d'objet (un seul par objet en pratique), un écran peut porter plusieurs règles "affichage" côte à côte : la suppression doit donc cibler l'une d'elles, pas tout vider (voir screen_triggers_clear ci-dessus, conservée pour un vidage complet).""" screen = game_engine.get_screen(slug, screen_id) if screen is None: return jsonify({"error": "écran introuvable"}), 404 rules = game_engine.resolve_screen_triggers(screen) if index < 0 or index >= len(rules): return jsonify({"error": "règle introuvable"}), 404 del rules[index] game_engine.set_screen_triggers(slug, screen_id, rules) return jsonify({"ok": True}) @app.route("/game//screens//triggers/action/", methods=["DELETE"]) def screen_trigger_remove_action(slug: str, screen_id: int, leaf_id: str) -> Response | tuple[Response, int]: """Retire UNE action précise d'un déclencheur d'écran — même contrat que routes/game/triggers/triggers.py::trigger_remove_action.""" if not game_engine.remove_action_from_screen_trigger(slug, screen_id, leaf_id): return jsonify({"error": "action introuvable"}), 404 return jsonify({"ok": True}) @app.route("/game//screens//triggers/action//move", methods=["POST"]) def screen_trigger_move_action(slug: str, screen_id: int, leaf_id: str) -> Response | tuple[Response, int]: """Déplace une action précise d'un cran ("up"/"down") dans sa chaîne, pour un déclencheur d'écran — même contrat que routes/game/triggers/triggers.py::trigger_move_action.""" body = request.get_json(silent=True) or {} direction = body.get("direction") if direction not in ("up", "down"): return jsonify({"error": "direction invalide"}), 400 if not game_engine.move_action_in_screen_trigger(slug, screen_id, leaf_id, direction): return jsonify({"error": "action introuvable"}), 404 return jsonify({"ok": True}) @app.route("/game//screens//triggers/dialogue", methods=["POST"]) def screen_trigger_dialogue_update(slug: str, screen_id: int) -> Response | tuple[Response, int]: """Édition EN LIGNE des répliques d'un dialogue porté par un déclencheur d'écran — même contrat que routes/game/triggers/triggers.py::trigger_dialogue_update.""" screen = game_engine.get_screen(slug, screen_id) if screen is None: return jsonify({"error": "écran 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 = game_engine.resolve_screen_triggers(screen) if not game_engine.set_dialogue_lines_in_rules(rules, dialogue_id, body.get("lines")): return jsonify({"error": "dialogue introuvable"}), 404 sanitized = game_engine.sanitize_screen_triggers(rules) game_engine.set_screen_triggers(slug, screen_id, sanitized) return jsonify({"ok": True}) @app.route("/game//screens//triggers/append-action", methods=["POST"]) def screen_trigger_append_action(slug: str, screen_id: int) -> Response | tuple[Response, int]: """ "+ Ajouter une action" en bout de chaîne, pour un déclencheur d'écran — même contrat que routes/game/triggers/triggers.py::trigger_append_action.""" if game_engine.get_screen(slug, screen_id) is None: return jsonify({"error": "écran 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 if not game_engine.append_action_to_screen_trigger(slug, screen_id, after_id, body.get("action")): return jsonify({"error": "action précédente introuvable"}), 404 return jsonify({"ok": True})