fix(spells): apply a shaken effect when a fear save succeeds

ConditionEffect gains save_partial (JSON 'on_success': condition_name + duration_rounds). On a successful save that would otherwise negate, _apply_condition_effect now imposes the weaker condition (SRD fear.md: panicked on a failed Will save, shaken for 1 round on a success). Extended _metamagic_transform_sub to preserve/double it; extracted _impose_condition helper. Updated fear.json, added failed/successful-save and loader tests in test_spells.py, and the README.

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-13 12:32:45 +02:00
parent a59ebee37a
commit c96b36d3f9
5 changed files with 92 additions and 19 deletions
+15 -10
View File
@@ -1253,7 +1253,14 @@ Règles modélisées :
annule » (Sleep, Color Spray, Web) sauvent donc aussi. Une composante de
dégâts peut déclarer `save_negates: false` (conformance D1 — SRD
« Sound Burst » : « Fortitude partial » n'annule que l'étourdissement,
jamais les dés) : la sauvegarde réussie ne réduit alors pas ces dégâts.
jamais les dés) : la sauvegarde réussie ne réduit alors pas ces dégâts.
**Sauvegardes partielles (S2d)** : un `ConditionEffect` peut déclarer
`"on_success": {"condition_name": "shaken", "duration_rounds": 1}` (champ
`save_partial`) — sur une sauvegarde **réussie**, au lieu d'annuler
totalement l'effet, la cible subit la condition affaiblie indiquée (SRD
Fear : paniqué à l'échec, `shaken` 1 round au succès). Sans `on_success`,
le comportement reste « sauvegarde annule ». L'Extend Spell double aussi la
durée de la condition partielle.
- Dons : les 8 PJ portent 55 noms de dons uniques ; le chargeur résout chacun d'eux
soit vers un effet réel (Power Attack actif, Weapon Focus ciblé par arme, Toughness
lié au niveau, dons passifs via `_stat_modifiers`), soit vers un « no-op » tracé en
@@ -1431,16 +1438,14 @@ plutôt que bricolées) :
minuscules sur une même case) ne sont pas modélisées ; seule la substitution
Dextérité/Force du CMB (conformance L1) tient compte de leur taille.
Limites de sorts (conformance D6-D9, documentées plutôt que bricolées — le
moteur n'a pas encore de sauvegarde partielle) :
Limites de sorts (conformance D6-D9, documentées plutôt que bricolées) :
- **Fear — sauvegarde totale** (SRD spells/fear.md : « each
living creature in the area [...] becomes panicked unless it succeeds on a
Will save [...]. If the Will save succeeds, the creature is shaken for 1
round » ; cône de 30 ft — modélisé, S1a/S1c) : la condition appliquée est
bien `panicked` (conformance D8), mais le moteur n'a pas de sauvegarde
partielle pour les conditions — un succès annule totalement l'effet au lieu
de poser `shaken` 1 round ; la durée « 1 round/niveau » est fixée à 4 rounds.
- **Fear — durée figée** (SRD spells/fear.md : « each living creature in the
area [...] becomes panicked unless it succeeds on a Will save [...]. If the
Will save succeeds, the creature is shaken for 1 round » ; cône de 30 ft —
modélisé, S1a/S1c) : la sauvegarde partielle est désormais modélisée (panic
à l'échec, `shaken` 1 round au succès — voir « Sauvegardes partielles » plus
bas) ; seule la durée « 1 round/niveau » du `panicked` reste fixée à 4 rounds.
- **Résistance aux sorts appliquée à tout sort ciblé** : le moteur oppose la
SR du combattant à chaque sort qui le cible, sans drapeau par sort ; les
rares sorts dont la fiche SRD déclare « Spell Resistance: no » (ex. Acid