feat(combat): add ready action with triggers

This commit is contained in:
2026-09-10 12:39:28 +02:00
parent f83e4b8016
commit ab02597bc4
3 changed files with 547 additions and 13 deletions
+26 -3
View File
@@ -306,6 +306,24 @@ Règles modélisées :
round est rejeté (`already_delayed`), et le drapeau se réinitialise au début
de chaque round. `default_policy` ne choisit pas le retard (disponible via
une politique personnalisée).
- Préparation (`Action(kind="ready", ready_trigger=...)`, action standard) : le
combattant se prépare à agir quand un événement déclencheur survient. Le
payload est encodé dans les champs porteurs de l'action, comme l'immédiate :
`spell_name` → incantation, `maneuver` → manœuvre (avec `direction` /
`trick_condition`), sinon attaque simple sur `target_id` (les capacités de
classe en payload ne sont pas modélisées). Quatre déclencheurs, mappés aux
événements de réaction existants : `enemy_enters_reach` ← pas de mouvement
d'un ennemi (simplification documentée : la portée menacée n'est pas
recalculée, tout pas ennemi déclenche), `enemy_casts` ← incantation d'un
ennemi, `enemy_attacks` ← attaque résolue d'un ennemi, `enemy_hits_ally` ←
dégâts subis par un allié du préparant infligés par un ennemi. Quand
l'événement correspond, le moteur exécute le payload **hors-tour, sans coût
de swift** (au plus une action préparée par événement, sans cascade), puis
l'action préparée est **consommée** (one-shot). Une nouvelle préparation
remplace la précédente ; le reste du tour (action de mouvement) reste
exécutable. Le snapshot expose l'état via la clé `readied`
(`{kind, trigger}` ou `None`). `default_policy` ne se prépare pas
(disponible via une politique personnalisée).
- Retour d'exécution des actions : chaque action produit un `ActionResult`
explicite (kind, ok, reason) consigné dans le snapshot (`last_turn_results`
au tour suivant). Les actions invalides sont rejetées et journalisées au lieu
@@ -315,7 +333,8 @@ Règles modélisées :
par les filtres staggered/nauseated (ou swift consommé par une immédiate) →
`downgraded:staggered` / `downgraded:nauseated` / `downgraded:immediate_swift` ;
retard valide → `ok=True, reason="delayed"`, second retard du même round →
`ok=False, reason="already_delayed"`.
`ok=False, reason="already_delayed"` ; préparation valide →
`ok=True, reason="ready"`.
- Attaques multiples par action : une arme avec `count` > 1 (« 2x Talons »)
résout `count` balayages indépendants dans la même action ; les balayages
restants sont perdus si la cible tombe (inconsciente ou morte) en cours de
@@ -350,7 +369,9 @@ Règles modélisées :
réaction `Action(kind="immediate")` peut être exécutée hors tour — une par
événement — et consomme le prochain swift de l'état (immédiate pendant le
tour : exécutée, consomme aussi le prochain swift — simplification
documentée).
documentée). Les actions préparées (`ready`) sont traitées sur ces mêmes
événements **avant** et indépendamment de la politique de réaction (voir
« Préparation » plus haut).
- Ligne d'effet : une cible entièrement derrière un terrain `blocks_los` ne
peut pas être attaquée — la politique se déplace jusqu'à gagner une ligne de
visée.
@@ -570,7 +591,9 @@ Règles modélisées :
inconsciente), stabilized (bool — stabilisée pendant son agonie, ne perd
plus de pv tant qu'aucune nouvelle blessure ne la remet en agonie),
last_turn_results (tuple de {kind, ok, reason} — résultat d'exécution du
dernier tour, pour que la policy apprenne les actions rejetées/dégradées).
dernier tour, pour que la policy apprenne les actions rejetées/dégradées),
readied ({kind, trigger} de l'action préparée ou None — préparation en
cours, consommée quand le déclencheur la fait tirer).
- Par paire combattant actif × cible : target_index, distance_ft, weapon_for,
range_penalty, can_charge, can_step5_to_attack, has_line_of_effect,
flanking, movement_cost_ft, target_threatens_me, enemies_threatening_me.