fix(rules): consume the current turn's swift for an in-turn immediate

PF1e (SRD Immediate Actions): "Using an immediate action on your turn is the same as using a swift action and counts as your swift action for that turn." The engine now tracks the acting combatant (_turn_actor); an immediate fired during its OWN turn sets swift_used_this_turn instead of immediate_used, so swift actions later in the turn's sequence are dropped (downgraded:immediate_swift) and no second immediate fires that round, while the next turn's swift stays free. Off-turn immediates keep consuming the next swift. The off-turn consumption test was retargeted to a true off-turn event and an in-turn test added; README updated (Actions immediates + budget classification).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-12 10:00:25 +02:00
parent dde6bc1f5d
commit 1363bb7f06
3 changed files with 140 additions and 35 deletions
+17 -6
View File
@@ -367,7 +367,8 @@ Règles modélisées :
`default_policy` renvoie `(full_attack,)` si l'ennemi est en portée, `(charge,)`
si une ligne droite existe, `(5foot_step, full_attack)` si un seul pas
suffit à entrer en portée, ou `(move, attack)` sinon. Les actions immédiates
(hors-tour, consomment le prochain swift) sont modélisées via une politique
(hors-tour : prochain swift ; pendant son tour : swift du tour courant —
conformance L10) sont modélisées via une politique
de réaction opt-in (`reaction_policy`) — voir « Actions immédiates » ci-dessous.
**Application du budget (conformance X4)** : le moteur applique désormais le
budget d'action PF1e (CRB « Actions in Combat ») à TOUTE séquence renvoyée par
@@ -403,8 +404,9 @@ Règles modélisées :
`run` (round complet en RAW — il consacre le standard ET le mouvement, tout
en posant `moved_this_turn` et `running`) ;
**libre/conditionnel (hors budget)** = `wait`, `free`, `immediate` (hors-tour ;
il consomme le PROCHAIN swift via `immediate_used`, pas les compartiments du
tour courant), `5foot_step` (pas libre, exclusif avec tout autre mouvement via
il consomme le PROCHAIN swift via `immediate_used` ; pendant son propre tour,
il consomme le swift du tour courant via `swift_used_this_turn` — conformance
L10), `5foot_step` (pas libre, exclusif avec tout autre mouvement via
`moved_this_turn`), `drop_prone`, `activate_power_attack` et `fight_defensively`
(des déclarations de mode appliquées à l'attaque qui les suit, comme le
basculement Power Attack). Ordre de composition : le pré-filtre des temps
@@ -644,9 +646,18 @@ Règles modélisées :
`reaction_policy(engine, state, event)` (défaut : aucune) ; sur événement
(`attack_resolved`, `movement_step`, `spell_cast`, `damage_taken`) une
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). Les actions préparées (`ready`) sont traitées sur ces mêmes
événement — et consomme le prochain swift de l'état (`immediate_used`).
Conformance L10 (SRD « Immediate Actions ») : « Using an immediate action
on your turn is the same as using a swift action and counts as your swift
action for that turn » — une immédiate déclenchée **pendant le tour** du
combattant consomme le swift du **tour courant** (`swift_used_this_turn`,
posé par le moteur sur l'acteur du tour) : tout swift encore présent dans
la séquence est retiré (`downgraded:immediate_swift`) et aucune seconde
immédiate ne part ce round ; le swift du tour **suivant** reste disponible
(contrairement à l'immédiate hors-tour). Simplification documentée :
l'interdiction RAW d'une seconde immédiate s'étend jusqu'au début du tour
suivant, le moteur la borne au round en cours.
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