fix(rules): harmless spells on willing targets forgo the save roll - SpellSpec gains a data-driven 'harmless' flag set on the 29 SRD '(harmless)' spells (verified one by one against the KB); a same-side/self target consumes NO save die (SRD saving-throw.md: '(harmless) ... can attempt a saving throw if it desires' + 'Voluntarily Giving up a Saving Throw'), while hostile targets and undead receiving a cure (harmful to them, Will half for undead damage) keep the roll; snapshot spell summaries expose 'harmless'; golden transcript unchanged (no harmless-save cast in it); +8 tests, 3 fixtures re-pinned for the removed die
This commit is contained in:
@@ -1137,7 +1137,24 @@ Règles modélisées :
|
||||
sur un échec et **aucun dégât sur un succès** (la sauvegarde annule) ; le
|
||||
demi-dégât sur sauvegarde réussie ne s'applique que là où l'effet le déclare
|
||||
(`half_on_save: true` pour les rayons/lignes/cônes, `AreaEffect.save_for_half`
|
||||
pour les explosions). Ciblage par point (U7b) : `Action(kind="cast_spell",
|
||||
pour les explosions). **Sorts « harmless » et cible consentante** (SRD
|
||||
« Spell Descriptions — Saving Throw » : « (harmless) : The spell is usually
|
||||
beneficial, not harmful, but a targeted creature can attempt a saving throw
|
||||
if it desires » ; « Voluntarily Giving up a Saving Throw : A creature can
|
||||
voluntarily forego a saving throw and willingly accept a spell's result ») :
|
||||
`SpellSpec` porte un booléen `harmless` (JSON `"harmless"`, défaut `false`)
|
||||
posés sur les 29 sorts dont la fiche SRD marque la sauvegarde « (harmless) »
|
||||
(vérifiés un à un contre le KB — les sorts SRD « save: none » comme Aid et
|
||||
Bless n'ont pas la marque et n'en ont pas besoin). Jeté sur une cible
|
||||
**consentante** (soi-même ou un même camp), le jet de sauvegarde primaire
|
||||
est **totalement sauté** — aucun dé consommé, journalisé `NO SAVE`
|
||||
(`_save_forgone`). Deux exceptions fidèles conservent le jet : une cible
|
||||
**hostile** n'est pas consentante, et un sort de soin sur un **mort-vivant**
|
||||
lui est **nuisible** (SRD cure-light-wounds.md : il « deals damage to them
|
||||
instead » avec « Will half » pour demi-dégâts). Simplification documentée :
|
||||
la « volonté » est approximée par le camp (le moteur n'a pas de concept
|
||||
d'intention de cible) ; un sort harmless jeté sur un ennemi garde donc son
|
||||
jet. Ciblage par point (U7b) : `Action(kind="cast_spell",
|
||||
target_pos=(r, c))` centre l'`AreaEffect` de niveau supérieur du sort sur la
|
||||
case `(r, c)` désignée au lieu de la position de la cible créature — poser un
|
||||
Fireball au sol, pas seulement sur une tête. Le point doit être dans la carte
|
||||
@@ -1653,7 +1670,8 @@ Règles modélisées :
|
||||
feature_details (C4 : tuple de {name, category, source_detail, effects:
|
||||
tuple de {target, value, bonus_type, condition, weapon_filter}}),
|
||||
spells (résumés enrichis du registre : name, level, school, range_ft,
|
||||
save, dc, summary, half_on_save, save_negates (E4), area {shape,
|
||||
save, dc, summary, half_on_save, save_negates (E4), harmless (sort «
|
||||
(harmless) » du SRD — sauvegarde sautée sur cible consentante), area {shape,
|
||||
radius_ft} | None (U7a : premier AreaEffect de niveau supérieur du sort,
|
||||
gabarit de zone structuré, None si le sort n'a pas de zone), cast_time
|
||||
(code de temps d'incantation, « standard » pour un sort inconnu du
|
||||
@@ -1908,7 +1926,8 @@ Limites de sorts (conformance D6-D9, documentées plutôt que bricolées) :
|
||||
`AbilitySpec` réels ou des « no-op » tracés.
|
||||
- `spells.py` — sorts : `SpellSpec` (dataclass avec niveau, école, portée,
|
||||
sauvegarde, DC de base, exigence de contact à distance `requires_ranged_touch`
|
||||
(rayons), temps d'incantation `cast_time`) et types d'effets
|
||||
(rayons), marque `harmless` (SRD « (harmless) » — sauvegarde sautée sur
|
||||
cible consentante), temps d'incantation `cast_time`) et types d'effets
|
||||
(`DamageEffect`, `ConditionEffect`,
|
||||
`HealEffect`, `BuffEffect`, `AreaEffect` — burst/cône/ligne, S1a). Un
|
||||
`DamageEffect` (et un `HealEffect`, S5b) porte des specs de scalage
|
||||
|
||||
Reference in New Issue
Block a user