Première moitié de la fonctionnalité "événements" (NEED_ACTION et
autres) : une entité game-wide (nom, description, "a un paramètre
élément" oui/non), déclenchable comme nouvelle action du graphe de
logique depuis n'importe quelle scène/modèle, et écoutable comme
nouveau type de déclencheur depuis n'importe quel autre. L'UI (nouvel
onglet "Événements" dans screen_edit.html, formulaires de nœud, exécution
côté client dans play.html) suit dans un commit séparé.
- db/custom_events/ (calqué sur db/global_vars/) : CRUD de la table
_custom_events (nom unique, description, has_element_param).
create_custom_event est idempotent par nom (même convention que
create_global_variable) — sans risque en cas de double soumission.
- screens/flow/ : 3 nouvelles colonnes sur _flow_nodes
(trigger_custom_event_id/target_custom_event_id : quel événement un
nœud écoute/déclenche ; target_element_from_event : indicateur
réutilisable par n'importe quel nœud Action utilisant déjà
target_element_id, pour résoudre "l'élément transmis par l'événement
en cours" au lieu d'une cible fixe — contourne la contrainte de clé
étrangère de target_element_id, qui empêche d'y stocker un sentinel
comme EVENT_ROW_ID directement). Nouveau trigger_event "evenement" et
action_type "declencher_evenement".
- screens/custom_events/ (PAS dans db/, même séparation que
screens/elements/delete_element.py) : delete_custom_event, la SEULE
suppression d'entité game-wide du moteur à vraiment cascader (demande
explicite) — supprime tous les nœuds/arêtes qui référencent
l'événement, sur TOUTES les scènes ET tous les modèles à la fois
(aucun filtre screen_id nécessaire : un modèle est un écran caché,
même table _flow_nodes). list_custom_event_usages : où un événement
est écouté/déclenché, pour l'onglet Événements à venir.
- routes/custom_events/ : CRUD monté sous /game/<slug>/events/...,
redirige vers l'éditeur de scène/modèle d'origine (screen_id transmis
par le formulaire) avec l'onglet "events" à ouvrir.
tests/test_custom_events.py (nouveau) : idempotence à la création,
usages détectés sur deux écrans différents, suppression qui retire bien
les DEUX nœuds (un sur une vraie scène, un sur un modèle/écran caché)
en une seule opération, sans toucher aux écrans eux-mêmes. 207 tests au
total.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>