feat(rules): expose splash in observation attack reference + AttackResult.splash, document splash weapon rule and JSON schema in README (SRD Throw Splash Weapon)

This commit is contained in:
2026-09-20 19:23:15 +02:00
parent 2e60bbb419
commit a1b1c29ca3
2 changed files with 47 additions and 0 deletions
+42
View File
@@ -301,6 +301,13 @@ double l'allonge naturelle du porteur mais ne frappe pas à cette allonge
naturelle ou moins — anneau avec dead zone (conformance R1, voir « Mêlée »). naturelle ou moins — anneau avec dead zone (conformance R1, voir « Mêlée »).
Le `reach_ft` d'une attaque naturelle (morsure, sabots) n'est **pas** une arme Le `reach_ft` d'une attaque naturelle (morsure, sabots) n'est **pas** une arme
à allonge : il encode l'allonge naturelle de la créature, qui reste un disque. à allonge : il encode l'allonge naturelle de la créature, qui reste un disque.
L'objet `splash` (optionnel, défaut `null`) marque une arme de jet à
éclaboussures (SRD « Throw Splash Weapon ») : `{"damage": N, "type": "fire"}`
— dégâts d'éclaboussure plats (type énergétique, comme dans `damage`) infligés sans jet ni sauvegarde à toute créature
à 5 pieds du point d'impact (touche directe) ou d'atterrissage (dispersion au
raté, voir « Armes de jet à éclaboussures »). Une arme `splash` doit être
lançable (`kind: ranged`, ou `kind: touch` avec `range_increment_ft`) — le
schéma rejette `splash` sur une attaque de mêlée ou sans incrément.
`spell_resistance` (entier), `resistances` (dict type → montant) et `spell_resistance` (entier), `resistances` (dict type → montant) et
`immunities` (liste de types) sont optionnels. `immunities` (liste de types) sont optionnels.
Le tableau `carried_items` (optionnel, défaut vide) énumère les **objets Le tableau `carried_items` (optionnel, défaut vide) énumère les **objets
@@ -1093,6 +1100,40 @@ Règles modélisées :
touch attacks ») s'applique à **la touche** du contact de mêlée (pénalité −X touch attacks ») s'applique à **la touche** du contact de mêlée (pénalité −X
au jet d'attaque et de confirmation) mais son bonus de dégâts reste réservé au jet d'attaque et de confirmation) mais son bonus de dégâts reste réservé
aux armes de mêlée (le contact ne gagne pas le +2X/+3X). aux armes de mêlée (le contact ne gagne pas le +2X/+3X).
- Armes de jet à éclaboussures (SRD « Throw Splash Weapon », KB
`rules/prpg-core-rulebook/throw-splash-weapon.md` ; SRD « Alchemist's fire »,
« Acid », « Holy water ») : une attaque dont l'`AttackSpec` porte un marqueur
`splash` (`{"damage": 1, "type": "fire"}` dans le JSON — Alchemist's Fire sur
`oni.json` et `tammara.json` : 1 point d'éclaboussure de feu) se lance en
attaque de contact à distance (incréments de portée ; la maîtrise est
automatique en RAW — le moteur ne modélise aucune pénalité de maîtrise).
**Touche directe** : la cible subit les dégâts indiqués (1d6 feu) et
**toute créature à moins de 5 pieds de la case d'impact** (case adjacente ou
occupée — créatures mourantes/inconscientes incluses, cadavres exclus) subit
l'éclaboussure plate, sans jet d'attaque ni sauvegarde ; la cible elle-même
ne subit **pas** d'éclaboussure supplémentaire (SRD : « A hit deals direct
hit damage to the target and splash damage to all creatures within 5 feet of
the target »). **Échec** (jet raté ou dissimulation) : la fiole **disperse**
— d8 de direction (1 = trop court, en ligne vers le lanceur ; 2 à 8 en
rotation horaire autour de la cible), puis un nombre de cases égal à
l'**incrément de portée du jet** (Alchemist's Fire : 10 pieds = 2 cases) ;
la case d'atterrissage **et ses cases adjacentes** subissent **seulement**
l'éclaboussure — la cible d'origine comprise si elle est dans la zone.
L'éclaboussure est un dégât **énergétique** : résistance/immunité
énergétiques s'appliquent, la **RD non** ; le montant plat n'est **jamais**
multiplié au critique, et une arme à éclaboussures ne peut pas porter de
dégâts de précision — SRD : « Splash weapons cannot deal precision-based
damage (such as sneak attack) ». Le d8 de dispersion n'est jeté **que** pour
une arme à éclaboussures : le flux RNG de toute autre attaque est
bit-identique. `AttackResult.splash` (additif) rapporte le total
d'éclaboussure infligé, distinct de `damage` (cible uniquement) ; le
snapshot d'observation expose `splash` (`{damage, type}` ou `None`) par
arme. Simplifications et hors périmètre documentés : le ciblage d'une
intersection de grille (CA 5) n'est pas modélisé ; l'éclaboussure asperge
les cases adjacentes sans vérification de ligne d'effet ; le point d'impact
d'une cible multi-cases est sa case d'ancrage (le choix RAW d'une case n'est
pas offert) ; les dégâts persistants d'Alchemist's Fire (1d6 feu au round
suivant, extinction par Réflexes DD 15) ne sont **pas** modélisés.
- Jets de sauvegarde : `resolve_save(state, save_type, dc)` — fort/ref/will. - Jets de sauvegarde : `resolve_save(state, save_type, dc)` — fort/ref/will.
1 naturel = échec automatique, 20 naturel = succès automatique. Les 1 naturel = échec automatique, 20 naturel = succès automatique. Les
modificateurs d'effets (`StatModifier` avec `target` correspondant) sont modificateurs d'effets (`StatModifier` avec `target` correspondant) sont
@@ -1816,6 +1857,7 @@ Règles modélisées :
touch, flat_footed}, saves {fort, ref, will}, cmb, cmd, attacks touch, flat_footed}, saves {fort, ref, will}, cmb, cmd, attacks
(référentiel complet : id, name, kind, attack_bonus, damage, damage_bonus, (référentiel complet : id, name, kind, attack_bonus, damage, damage_bonus,
crit_range, crit_mult, reach_ft, range_increment_ft, count, firearm, crit_range, crit_mult, reach_ft, range_increment_ft, count, firearm,
splash ({damage, type} ou None — arme de jet à éclaboussures),
hardness, hit_points (stats d'objet effectives, Table 7-12) — hardness, hit_points (stats d'objet effectives, Table 7-12) —
y compris les armes broken/destroyed/stolen), features (noms des capacités), y compris les armes broken/destroyed/stolen), features (noms des capacités),
feature_details (C4 : tuple de {name, category, source_detail, effects: feature_details (C4 : tuple de {name, category, source_detail, effects:
+5
View File
@@ -1932,6 +1932,11 @@ class CombatEngine:
"range_increment_ft": attack.range_increment_ft, "range_increment_ft": attack.range_increment_ft,
"count": attack.count, "count": attack.count,
"firearm": attack.firearm, "firearm": attack.firearm,
"splash": (
{"damage": attack.splash.damage, "type": attack.splash.type}
if attack.splash is not None
else None
),
"hardness": attack.object_stats()[0], "hardness": attack.object_stats()[0],
"hit_points": attack.object_stats()[1], "hit_points": attack.object_stats()[1],
} }