fix(combat): evaluate conditional stat modifiers with action context
This commit is contained in:
@@ -346,6 +346,14 @@ Règles modélisées :
|
||||
modificateurs d'effets (`StatModifier` avec `target` correspondant) sont
|
||||
appliqués via `resolve_modifiers` (mêmes règles d'empilement que les
|
||||
attaques). Renvoie un `SaveResult` (success, roll, total, dc).
|
||||
- Modificateurs conditionnés : un `StatModifier` avec `condition=` n'est appliqué
|
||||
que si la condition tient au moment de la résolution (`_modifier_condition_holds`) :
|
||||
`target_within_30ft_ranged` (arme à distance à ≤ 30 ft), `axe` (arme dont le nom
|
||||
contient « axe »), et les descripteurs de sauvegarde (`fear`, `cold`,
|
||||
`electricity`, `fey`, `divination`, `poison`, `disease`, `mind_affecting`) — les
|
||||
descripteurs sont portés par l'aura de terreur, les sorts (types de dégâts,
|
||||
conditions de peur, écoles enchantement/divination) et les effets de zone. Toute
|
||||
condition inconnue ou non supportée reste exclue (False).
|
||||
- Incantation : chaque `CombatantState` porte `spell_slots_left` (initialisé depuis
|
||||
le champ `spell_slots` du JSON, ex. `{"1": 4, ...}`) ; `_cast_spell` dépense
|
||||
l'emplacement du niveau concerné (`spend_spell_slot`). Le DD vaut `10 + niveau du
|
||||
@@ -415,10 +423,8 @@ dans la résolution) :
|
||||
- Parmi les manœuvres, seules trip / disarm / bull_rush / sunder / grapple / escape
|
||||
sont câblées ; les autres (overrun, dirty trick, steal, reposition, drag) ne le
|
||||
sont pas. Une arme brisée ne peut pas être réparée en cours de combat.
|
||||
- Les modificateurs d'effets conditionnés par un `condition=` au runtime ne sont pas
|
||||
évalués (`_modifier_condition_holds` renvoie toujours False, le modificateur est
|
||||
alors exclu) ; la distribution des dégâts par type sur un sort n'envoie que des
|
||||
dégâts simples (sans plage « half on save » pour les effets ciblés).
|
||||
- La distribution des dégâts par type sur un sort n'envoie que des dégâts simples
|
||||
(sans plage « half on save » pour les effets ciblés).
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -439,7 +445,10 @@ dans la résolution) :
|
||||
des attaques (couvert, ligne d'effet, pénalités de portée, CA de contact
|
||||
pour les attaques touch et firearms), états de vie, incantation
|
||||
(emplacements, concentration par situation, AoO d'incantation), invocation,
|
||||
manœuvres, capacités de classe, transcripts, politique par défaut.
|
||||
manœuvres, capacités de classe, transcripts, politique par défaut. Les
|
||||
modificateurs conditionnés (`StatModifier.condition`) sont évalués via
|
||||
`_modifier_condition_holds` avec le contexte d'action (arme, portée,
|
||||
descripteurs de sauvegarde) ; les conditions inconnues restent exclues.
|
||||
- `effects.py` — système d'effets : `StatModifier` (modificateur de
|
||||
caractéristique avec type de bonus) et `resolve_modifiers` (application des
|
||||
règles d'empilement PF1e). Types de bonus cumulables (dodge, racial, trait,
|
||||
@@ -468,12 +477,15 @@ dans la résolution) :
|
||||
sauvegarde, DC de base) et types d'effets (`DamageEffect`, `ConditionEffect`,
|
||||
`HealEffect`, `BuffEffect`). Portées PF1e (personal, touch, close, medium,
|
||||
long) calculées par `spell_range_ft`. Chargeur JSON (`load_spell`,
|
||||
`load_spell_registry`) pour `data/spells/`. Le moteur intègre les sorts via
|
||||
`Action(kind="cast_spell")` et `_cast_spell` : résolution de sauvegarde,
|
||||
application des dégâts (demi-dégâts sur sauvegarde réussie ; la RD ne
|
||||
s'applique pas aux dégâts de sorts), conditions, soins (plafonnés à hp_max)
|
||||
et buffs. Le champ `spells` de `Combatant` contient les noms de sorts connus ;
|
||||
le `spell_registry` est passé au `CombatEngine`.
|
||||
`load_spell_registry`) pour `data/spells/`. Des descripteurs de sauvegarde
|
||||
(`spell_save_descriptors` / `save_descriptors_for_effects` : types de dégâts,
|
||||
conditions de peur, écoles enchantement/divination) sont dérivés des effets
|
||||
pour évaluer les modificateurs conditionnés lors d'une sauvegarde. Le moteur
|
||||
intègre les sorts via `Action(kind="cast_spell")` et `_cast_spell` :
|
||||
résolution de sauvegarde, application des dégâts (demi-dégâts sur sauvegarde
|
||||
réussie ; la RD ne s'applique pas aux dégâts de sorts), conditions, soins
|
||||
(plafonnés à hp_max) et buffs. Le champ `spells` de `Combatant` contient les
|
||||
noms de sorts connus ; le `spell_registry` est passé au `CombatEngine`.
|
||||
- `metrics.py` — statistiques en forme fermée : `win_rate`, `win_rate_sigma`,
|
||||
`win_rate_band` (bande 3σ bornée à [0, 1]).
|
||||
- `runner.py` — `EncounterSpec`/`Side`, `build_states` (placement en zone +
|
||||
|
||||
Reference in New Issue
Block a user