Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9aee4f6f6b | |||
| 5afe495c4a | |||
| 1ca5aed758 | |||
| 543da6a931 | |||
| 07e0d83300 | |||
| 91f70f19ca | |||
| b3bff85215 | |||
| 79ac190728 | |||
| ec0397351a | |||
| 582b6c60d1 | |||
| f637f87a8c | |||
| 06555f7b49 | |||
| 26f86f416d | |||
| 7fafbe43cf | |||
| 61c9b7fa47 | |||
| 6abd29cbc5 | |||
| 8f3bd0d0e0 | |||
| ed04052244 | |||
| b91e1ac215 | |||
| 468c22ff57 | |||
| ebdff4f7e5 | |||
| ab02597bc4 | |||
| f83e4b8016 | |||
| c5cfa78f87 | |||
| 4e115f9176 | |||
| e6125b04f6 | |||
| 2eed752f7f | |||
| 97f4429c2b | |||
| a1c43e83af | |||
| a9ccdd3a56 | |||
| e29c472a67 |
@@ -164,7 +164,8 @@ legend: # un caractère = un type de terrain
|
|||||||
".": { type: floor, move_cost: 1 }
|
".": { type: floor, move_cost: 1 }
|
||||||
"T": { type: rubble, move_cost: 2 } # terrain difficile
|
"T": { type: rubble, move_cost: 2 } # terrain difficile
|
||||||
"~": { type: water, move_cost: 2 }
|
"~": { type: water, move_cost: 2 }
|
||||||
"C": { type: pillar, move_cost: null, cover: true } # bloque le pas, couvert
|
"C": { type: pillar, move_cost: null, cover: true } # bloque le pas, couvert (+4)
|
||||||
|
"W": { type: ruin, move_cost: null, cover_bonus: 2 } # couvert partiel (+2) ; 4 = standard, 8 = amélioré
|
||||||
|
|
||||||
elevation: | # optionnel : chiffres = hauteur (appliqué : coût de pas + high ground)
|
elevation: | # optionnel : chiffres = hauteur (appliqué : coût de pas + high ground)
|
||||||
....................
|
....................
|
||||||
@@ -189,7 +190,10 @@ deployment: # obligatoire si zones : nom de camp -> lettre de zone
|
|||||||
Valeur du `move_cost` : entier > 0 pour un terrain praticable, `null` pour un
|
Valeur du `move_cost` : entier > 0 pour un terrain praticable, `null` pour un
|
||||||
terrain infranchissable (mur, pilier). `blocks_los` et `cover` sont appliqués
|
terrain infranchissable (mur, pilier). `blocks_los` et `cover` sont appliqués
|
||||||
par la résolution des attaques (module `los.py`, règle des coins) : pas de
|
par la résolution des attaques (module `los.py`, règle des coins) : pas de
|
||||||
ligne d'effet ⇒ l'attaque est impossible ; couvert ⇒ bonus de +4 CA.
|
ligne d'effet ⇒ l'attaque est impossible ; couvert ⇒ bonus de CA. Le champ
|
||||||
|
optionnel `cover_bonus` (`2`, `4` ou `8`) encode le niveau de couvert PF1e
|
||||||
|
(partiel +2, standard +4, amélioré +8) ; `cover: true` sans `cover_bonus`
|
||||||
|
vaut couvert standard (+4), idem pour un terrain `blocks_los`.
|
||||||
|
|
||||||
### Monstre (JSON)
|
### Monstre (JSON)
|
||||||
|
|
||||||
@@ -237,6 +241,8 @@ Champ `range_increment_ft` (optionnel, uniquement pour `kind: ranged` ou
|
|||||||
par incrément complet au-delà du premier ; une arme `ranged` reste utilisable
|
par incrément complet au-delà du premier ; une arme `ranged` reste utilisable
|
||||||
jusqu'à 10 incréments, une arme `touch` jusqu'à 5 (jet/firearm), au-delà elle
|
jusqu'à 10 incréments, une arme `touch` jusqu'à 5 (jet/firearm), au-delà elle
|
||||||
n'est pas sélectionnable. `damage_bonus` et `dr` sont optionnels.
|
n'est pas sélectionnable. `damage_bonus` et `dr` sont optionnels.
|
||||||
|
`spell_resistance` (entier), `resistances` (dict type → montant) et
|
||||||
|
`immunities` (liste de types) sont optionnels.
|
||||||
Deux monstres d'exemple sont fournis : gobelin et orc.
|
Deux monstres d'exemple sont fournis : gobelin et orc.
|
||||||
|
|
||||||
### Fiches de personnages (PJ)
|
### Fiches de personnages (PJ)
|
||||||
@@ -263,9 +269,37 @@ vers la fiche Foundry d'origine.
|
|||||||
Règles modélisées :
|
Règles modélisées :
|
||||||
|
|
||||||
- 1 naturel = échec automatique ; 20 naturel = touche + menace de critique.
|
- 1 naturel = échec automatique ; 20 naturel = touche + menace de critique.
|
||||||
- Critique : (dés + bonus) × multiplicateur ; la RD s'applique après
|
- Critique : (dés + bonus) × multiplicateur ; le 20 naturel au jet de
|
||||||
multiplication, les types perforants annulent la RD, les dégâts plancher à 0.
|
confirmation confirme automatiquement la critique (conformance P2 — le jet
|
||||||
- Mort quand `hp < min(-10, -CON)` ; `hp ≤ 0` = inactif.
|
de confirmation est un jet d'attaque) ; la RD s'applique après
|
||||||
|
multiplication, un type de contournement annule la RD — une RD à plusieurs
|
||||||
|
composants (« DR X/Y and Z », conformance P2) exige que l'attaque porte
|
||||||
|
TOUS les composants (le contournement n'est plus traité comme un OU), les
|
||||||
|
dégâts plancher à 0.
|
||||||
|
- Critique améliorée (« Improved Critical ») : le don double la plage de
|
||||||
|
menace — plage effective = `21 - 2 × (21 - crit_range)` (20 → 19-20,
|
||||||
|
19 → 17-20, 18 → 15-20). Il n'affecte que le jet de menace, jamais le jet de
|
||||||
|
confirmation. Simplification moteur : le don s'applique à toutes les armes
|
||||||
|
de l'attaquant (pas de sélection par type d'arme comme sur table).
|
||||||
|
- Mourir et stabilisation : une créature à `hp < 0` mais pas morte est
|
||||||
|
mourante — inconsciente (inactive), elle perd 1 pv par tour si elle échoue
|
||||||
|
son jet de Constitution DD 10 à son tour d'initiative : `d20 + mod de CON −
|
||||||
|
|pv négatifs|` contre 10 ; un 20 naturel réussit automatiquement. En cas d'échec, elle
|
||||||
|
perd 1 pv de plus ; en cas de réussite, elle est stabilisée (plus de perte de
|
||||||
|
pv, reste inconsciente). Une nouvelle blessure sous le seuil de stabilisation
|
||||||
|
(`hp < stabilized_hp`) fait reprendre l'agonie (nouveau jet) ; un soin
|
||||||
|
ramenant à `hp ≥ 0` réinitialise la stabilisation pour toute chute future.
|
||||||
|
La mort survient quand les pv négatifs atteignent le score de CON
|
||||||
|
(`hp ≤ -CON`) — conformance P2 : la règle du −10 de D&D 3.5 n'existe pas
|
||||||
|
en PF1e et n'est plus modélisée.
|
||||||
|
- Invalide (conformance P2, CRB « Effects of Death ») : à `hp = 0`
|
||||||
|
exactement, une créature est **invalide** — elle reste active mais
|
||||||
|
**staggered** (une action de mouvement OU une action standard par tour, pas
|
||||||
|
d'action à round complet), se déplace à **moitié vitesse**, et achever une
|
||||||
|
action non-mouvement (standard ou pénible) lui coûte **1 pv** à la fin de
|
||||||
|
cette action (pv → −1, agonie). Simplification documentée : si l'action
|
||||||
|
elle-même soigne la créature au-dessus de 0 pv, ce coût n'est pas appliqué.
|
||||||
|
- `hp < 0` = inactive (mourante ou morte) ; `hp = 0` = active mais invalide.
|
||||||
- Initiative : triée sur (total, modificateur, ordre de liste), sans re-jet.
|
- Initiative : triée sur (total, modificateur, ordre de liste), sans re-jet.
|
||||||
- Économie d'action : un tour normal donne une action standard + une action de
|
- Économie d'action : un tour normal donne une action standard + une action de
|
||||||
mouvement (ou une action à round complet), plus swift/free/immediate. La
|
mouvement (ou une action à round complet), plus swift/free/immediate. La
|
||||||
@@ -275,6 +309,103 @@ Règles modélisées :
|
|||||||
suffit à entrer en portée, ou `(move, attack)` sinon. Les actions immédiates
|
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, consomment le prochain swift) sont modélisées via une politique
|
||||||
de réaction opt-in (`reaction_policy`) — voir « Actions immédiates » ci-dessous.
|
de réaction opt-in (`reaction_policy`) — voir « Actions immédiates » ci-dessous.
|
||||||
|
- Retard (`Action(kind="delay")`, action standard) : le combattant renonce à
|
||||||
|
agir maintenant et agit plus tard dans le **même round** — en fin d'ordre si
|
||||||
|
`target_id` est absent, sinon juste avant le combattant désigné. La nouvelle
|
||||||
|
position est encodée dans la clé d'initiative par un total égal à celui de la
|
||||||
|
cible − 0,5 (ou au minimum des totaux − 0,5 sans cible) et **persiste aux
|
||||||
|
rounds suivants** ; le reste du tour est perdu, un second retard dans le même
|
||||||
|
round est rejeté (`already_delayed`), et le drapeau se réinitialise au début
|
||||||
|
de chaque round. `default_policy` ne choisit pas le retard (disponible via
|
||||||
|
une politique personnalisée).
|
||||||
|
- Préparation (`Action(kind="ready", ready_trigger=...)`, action standard) : le
|
||||||
|
combattant se prépare à agir quand un événement déclencheur survient. Le
|
||||||
|
payload est encodé dans les champs porteurs de l'action, comme l'immédiate :
|
||||||
|
`spell_name` → incantation, `maneuver` → manœuvre (avec `direction` /
|
||||||
|
`trick_condition`), sinon attaque simple sur `target_id` (les capacités de
|
||||||
|
classe en payload ne sont pas modélisées). Quatre déclencheurs, mappés aux
|
||||||
|
événements de réaction existants : `enemy_enters_reach` ← pas de mouvement
|
||||||
|
d'un ennemi (simplification documentée : la portée menacée n'est pas
|
||||||
|
recalculée, tout pas ennemi déclenche), `enemy_casts` ← incantation d'un
|
||||||
|
ennemi, `enemy_attacks` ← attaque résolue d'un ennemi, `enemy_hits_ally` ←
|
||||||
|
dégâts subis par un allié du préparant infligés par un ennemi. Quand
|
||||||
|
l'événement correspond, le moteur exécute le payload **hors-tour, sans coût
|
||||||
|
de swift** (au plus une action préparée par événement, sans cascade), puis
|
||||||
|
l'action préparée est **consommée** (one-shot). Une nouvelle préparation
|
||||||
|
remplace la précédente ; le reste du tour (action de mouvement) reste
|
||||||
|
exécutable. Le snapshot expose l'état via la clé `readied`
|
||||||
|
(`{kind, trigger}` ou `None`). `default_policy` ne se prépare pas
|
||||||
|
(disponible via une politique personnalisée).
|
||||||
|
- Défense totale (`Action(kind="total_defense")`, action standard) : le
|
||||||
|
combattant se couvre entièrement et gagne **+4 d'esquive à la CA** jusqu'au
|
||||||
|
début de son prochain tour (champ runtime `defensive_ac_bonus`, réinitialisé
|
||||||
|
avec les autres drapeaux de tour). Le kind ne requiert pas de cible.
|
||||||
|
Simplification documentée : la progression d'Acrobatie (+6 avec 3 rangs)
|
||||||
|
n'est pas modélisée. `default_policy` ne la choisit pas (disponible via une
|
||||||
|
politique personnalisée).
|
||||||
|
- Combat défensif (`Action(kind="fight_defensively")`, action standard) : le
|
||||||
|
combattant se bat avec prudence — **−4 à ses jets d'attaque et de
|
||||||
|
confirmation de critique**, et **+2 d'esquive à la CA** jusqu'au début de son
|
||||||
|
prochain tour (drapeaux runtime `fight_defensively` + `defensive_ac_bonus`).
|
||||||
|
Simplification documentée : la progression d'Acrobatie (−2 / +3 avec 3
|
||||||
|
rangs) n'est pas modélisée. `default_policy` ne le choisit pas (disponible
|
||||||
|
via une politique personnalisée).
|
||||||
|
- Se relever (`Action(kind="stand_up")`, action de mouvement) : le combattant à
|
||||||
|
plat ventre (renversé par trip/overrun ou après s'être jeté à terre) retire la
|
||||||
|
condition `prone` des **deux** représentations (`active_conditions` durée,
|
||||||
|
`conditions` sans durée) et redevient valide. Le relèvement **provoque une
|
||||||
|
attaque d'opportunité** de chaque ennemi menaçant (résolue via la mécanique de
|
||||||
|
mouvement `_check_move_aoo`, pendant qu'il est encore à plat ventre, CA −4).
|
||||||
|
Sans condition `prone`, l'action est rejetée (`not_prone`). Le kind ne requiert
|
||||||
|
pas de cible. `default_policy` ne la choisit pas (disponible via une politique
|
||||||
|
personnalisée).
|
||||||
|
- Se jeter à terre (`Action(kind="drop_prone")`, action libre) : le combattant
|
||||||
|
ajoute `prone` à la liste `conditions` **sans durée**, donc la condition
|
||||||
|
persiste jusqu'à `stand_up` (contrairement à trip/overrun qui posent
|
||||||
|
`active_conditions` avec 1 round). Les modificateurs de `prone` s'appliquent
|
||||||
|
immédiatement : l'attaquant à plat ventre subit −4 à ses attaques (de mêlée
|
||||||
|
selon le CRB ; les armes à distance sont traitées comme des arbalètes —
|
||||||
|
utilisables à −4, simplification documentée), la cible à plat ventre subit
|
||||||
|
−4 CA contre les attaques de mêlée et gagne +4 CA contre les attaques à
|
||||||
|
distance. Si la condition est déjà
|
||||||
|
présente, l'action est rejetée (`already_prone`). Le kind ne requiert pas de
|
||||||
|
cible. `default_policy` ne la choisit pas (disponible via une politique
|
||||||
|
personnalisée).
|
||||||
|
- Aider autrui (`Action(kind="aid_another", aid_mode=...)`, action standard,
|
||||||
|
U5e) : l'aidant **doit avoir une arme de mêlée utilisable** ; il fait un jet
|
||||||
|
d'attaque `d20 + bonus d'attaque de sa première arme de mêlée utilisable`
|
||||||
|
contre le CA 10 (20 naturel réussit toujours, 1 naturel échoue toujours —
|
||||||
|
convention des jets d'attaque du moteur). Sur succès, la cible empile **+2**
|
||||||
|
soit à son prochain jet d'attaque (`aid_mode="attack"` ou absent — consommé
|
||||||
|
one-shot par `resolve_attack`, attaque et confirmation de critique), soit à
|
||||||
|
sa CA contre la prochaine attaque la ciblant (`aid_mode="ac"`). Plusieurs
|
||||||
|
aides s'additionnent (le bonus s'ajoute, ne se remplace pas) ; tout bonus
|
||||||
|
inutilisé expire au début du prochain tour du bénéficiaire. Simplifications
|
||||||
|
documentées : pas de vérification d'adjacence/ligne d'effet vers l'allié,
|
||||||
|
toute cible résolue peut être aidée, et la progression de compétence d'aide
|
||||||
|
(+5 avec 5 rangs, +8 avec 10) n'est pas modélisée. Sans cible →
|
||||||
|
`missing_target` ; sans arme de mêlée utilisable → `no_weapon`.
|
||||||
|
`default_policy` ne la choisit pas (disponible via une politique
|
||||||
|
personnalisée).
|
||||||
|
- Retour d'exécution des actions : chaque action produit un `ActionResult`
|
||||||
|
explicite (kind, ok, reason) consigné dans le snapshot (`last_turn_results`
|
||||||
|
au tour suivant). Les actions invalides sont rejetées et journalisées au lieu
|
||||||
|
d'être des no-op silencieux : cible absente → `missing_target` ; kinds
|
||||||
|
déclarés mais non implémentés (`swift`, `free`, `full_round` — leur
|
||||||
|
implémentation générique reste à faire) → `unsupported_kind` ; dégradation
|
||||||
|
par les filtres staggered/nauseated (ou swift consommé par une immédiate) →
|
||||||
|
`downgraded:staggered` / `downgraded:nauseated` / `downgraded:immediate_swift` ;
|
||||||
|
retard valide → `ok=True, reason="delayed"`, second retard du même round →
|
||||||
|
`ok=False, reason="already_delayed"` ; préparation valide →
|
||||||
|
`ok=True, reason="ready"` ; relèvement sans `prone` → `ok=False,
|
||||||
|
reason="not_prone"` ; se jeter à terre déjà `prone` → `ok=False,
|
||||||
|
reason="already_prone"` ; attaque avec un `weapon_id` choisi inutilisable →
|
||||||
|
`ok=False, reason="weapon_unavailable"` ; incantation avec un `target_pos`
|
||||||
|
hors carte ou sans ligne d'effet → `ok=False, reason="invalid_destination"`
|
||||||
|
(U7b) ; course ou aide sans cible **et** sans destination →
|
||||||
|
`missing_target` ; aide sans arme de mêlée utilisable → `no_weapon` ;
|
||||||
|
course vers une `destination` hors du budget 4× →
|
||||||
|
`unreachable_destination` (U5e).
|
||||||
- Attaques multiples par action : une arme avec `count` > 1 (« 2x Talons »)
|
- Attaques multiples par action : une arme avec `count` > 1 (« 2x Talons »)
|
||||||
résout `count` balayages indépendants dans la même action ; les balayages
|
résout `count` balayages indépendants dans la même action ; les balayages
|
||||||
restants sont perdus si la cible tombe (inconsciente ou morte) en cours de
|
restants sont perdus si la cible tombe (inconsciente ou morte) en cours de
|
||||||
@@ -282,6 +413,16 @@ Règles modélisées :
|
|||||||
attaques supplémentaires à -5/-10/-15 ; les armes naturelles (`count` > 1)
|
attaques supplémentaires à -5/-10/-15 ; les armes naturelles (`count` > 1)
|
||||||
ne gagnent pas d'itératifs. Plusieurs armes naturelles en une seule attaque
|
ne gagnent pas d'itératifs. Plusieurs armes naturelles en une seule attaque
|
||||||
à outrance ne sont pas modélisées.
|
à outrance ne sont pas modélisées.
|
||||||
|
Choix de l'arme : `Action(kind="attack", weapon_id=...)` et
|
||||||
|
`Action(kind="full_attack", weapon_id=...)` frappent avec l'arme désignée
|
||||||
|
(l'arc plutôt que l'épée, l'arme principale plutôt que la secondaire) au
|
||||||
|
lieu de l'arme auto-sélectionnée par `weapon_for` (première arme utilisable
|
||||||
|
capable de toucher la cible à cette distance avec ligne d'effet).
|
||||||
|
L'`id` doit désigner une arme utilisable (non brisée, non volée) pouvant
|
||||||
|
atteindre la cible ; sinon l'action est rejetée (`weapon_unavailable`) et
|
||||||
|
aucun jet n'est effectué. Sans `weapon_id`, la sélection automatique est
|
||||||
|
inchangée. `default_policy` ne choisit pas d'arme (disponible via une
|
||||||
|
politique personnalisée).
|
||||||
- Mêlée : allonge effective = max(allonge naturelle du gabarit (Small/Medium
|
- Mêlée : allonge effective = max(allonge naturelle du gabarit (Small/Medium
|
||||||
5 ft, Large 10 ft, Huge 15 ft, Gargantuan 20 ft, Colossal 30 ft), `reach_ft`
|
5 ft, Large 10 ft, Huge 15 ft, Gargantuan 20 ft, Colossal 30 ft), `reach_ft`
|
||||||
de l'arme). Une arme à allonge (`reach_ft` > 5) menace l'anneau de cases à
|
de l'arme). Une arme à allonge (`reach_ft` > 5) menace l'anneau de cases à
|
||||||
@@ -292,6 +433,27 @@ Règles modélisées :
|
|||||||
coût Dijkstra depuis la cible, diagonales 5-10-5), en s'arrêtant adjacent à
|
coût Dijkstra depuis la cible, diagonales 5-10-5), en s'arrêtant adjacent à
|
||||||
l'ennemi le plus proche — les combattants contournent les murs au lieu
|
l'ennemi le plus proche — les combattants contournent les murs au lieu
|
||||||
d'osciller contre eux.
|
d'osciller contre eux.
|
||||||
|
Vitesse de déplacement (V4) : le budget de tout mouvement (déplacement,
|
||||||
|
charge 2×, retraite 2×, course 4×) est le **meilleur entre la vitesse au
|
||||||
|
sol (`speed_land_ft`) et la vitesse de vol (`speed_fly_ft`)** — une créature
|
||||||
|
dotée d'une vitesse de vol (harvie : vol 80 vs sol 30, ierlieth : vol 40)
|
||||||
|
se déplace donc à sa vitesse de vol. Simplification documentée : voler
|
||||||
|
PAR-DESSUS les obstacles ou le terrain difficile n'est PAS modélisé — la
|
||||||
|
praticabilité et les coûts de terrain de la grille s'appliquent à tout le
|
||||||
|
budget (pas de vol 3D ni de maniabilité) ; le snapshot expose ce budget
|
||||||
|
sous la clé additive `speed_effective_ft`.
|
||||||
|
Destination explicite : `Action(kind="move", destination=(r, c))` et
|
||||||
|
`Action(kind="5foot_step", destination=(r, c))` déplacent le combattant vers
|
||||||
|
la case `(r, c)` désignée (monter au couvert, quitter un défilé, se
|
||||||
|
désengager) au lieu de auto-diriger vers `target_id`. Pour `move`, la case
|
||||||
|
doit être praticable, libre et atteignable dans le budget de vitesse (sinon
|
||||||
|
rejet `unreachable_destination`) ; le trajet réutilise la mécanique pas à pas
|
||||||
|
avec provocation d'AoO. Pour `5foot_step`, la case doit être exactement
|
||||||
|
adjacente (sinon `unreachable_destination`) et le pas ne provoque jamais
|
||||||
|
d'AoO. Sans `destination`, le comportement auto-dirigé est inchangé ; avec
|
||||||
|
`target_id` et `destination` absents, rejet `missing_target` (U1).
|
||||||
|
`default_policy` ne choisit pas de destination (disponible via une politique
|
||||||
|
personnalisée).
|
||||||
- Tailles et occupation multi-cases : une créature occupe un footprint carré à
|
- Tailles et occupation multi-cases : une créature occupe un footprint carré à
|
||||||
son ancre (`pos`) selon sa taille — Small/Medium 1×1, Large 2×2, Huge 3×3,
|
son ancre (`pos`) selon sa taille — Small/Medium 1×1, Large 2×2, Huge 3×3,
|
||||||
Gargantuan 4×4, Colossal 6×6 (taille inconnue → 1×1). Distance, ligne
|
Gargantuan 4×4, Colossal 6×6 (taille inconnue → 1×1). Distance, ligne
|
||||||
@@ -299,6 +461,16 @@ Règles modélisées :
|
|||||||
manœuvres et invocation sont généralisés aux cellules occupées (distance =
|
manœuvres et invocation sont généralisés aux cellules occupées (distance =
|
||||||
minimum entre cellules, LoS/couvert = meilleure paire) ; le comportement 1×1
|
minimum entre cellules, LoS/couvert = meilleure paire) ; le comportement 1×1
|
||||||
reste bit-identique.
|
reste bit-identique.
|
||||||
|
- Taille et attaques/CA : les valeurs `ac` (total/touch/flat_footed) et
|
||||||
|
`attack_bonus` des JSON de créatures sont des valeurs FINALES, déjà majorées
|
||||||
|
du modificateur de taille PF1e aux attaques/CA (Small +1, Medium 0, Large −1,
|
||||||
|
Tiny +2…) — vérifié sur toutes les fiches (`data/monsters/*.json`,
|
||||||
|
`data/pcs/*.json`, verrouillé par `tests/test_size_is_baked_in.py`). Le
|
||||||
|
moteur n'applique donc JAMAIS de bonus de taille aux jets d'attaque ni à la
|
||||||
|
CA (ce serait un double comptage) ; la taille n'intervient dans la
|
||||||
|
résolution que pour les manœuvres de combat (CMB/CMD, table
|
||||||
|
`_SIZE_MODIFIERS` Small −1 … Colossal +8 — colonne distincte de la table
|
||||||
|
attaques/CA), l'allonge naturelle, le footprint et l'occupation.
|
||||||
- Élévation : monter d'un niveau de hauteur coûte +1 case de mouvement par
|
- Élévation : monter d'un niveau de hauteur coûte +1 case de mouvement par
|
||||||
niveau (la descente est gratuite) ; une créature située plus haut que sa
|
niveau (la descente est gratuite) ; une créature située plus haut que sa
|
||||||
cible gagne +1 à ses jets d'attaque de mêlée et à la confirmation de
|
cible gagne +1 à ses jets d'attaque de mêlée et à la confirmation de
|
||||||
@@ -309,18 +481,24 @@ Règles modélisées :
|
|||||||
réaction `Action(kind="immediate")` peut être exécutée hors tour — une par
|
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
|
événement — et consomme le prochain swift de l'état (immédiate pendant le
|
||||||
tour : exécutée, consomme aussi le prochain swift — simplification
|
tour : exécutée, consomme aussi le prochain swift — simplification
|
||||||
documentée).
|
documentée). 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
|
- Ligne d'effet : une cible entièrement derrière un terrain `blocks_los` ne
|
||||||
peut pas être attaquée — la politique se déplace jusqu'à gagner une ligne de
|
peut pas être attaquée — la politique se déplace jusqu'à gagner une ligne de
|
||||||
visée.
|
visée.
|
||||||
- Couvert (règle des coins) : la cible gagne +4 CA sur la touche et la
|
- Couvert (règle des coins) : la cible gagne le bonus de couvert du terrain
|
||||||
|
(+2 partiel, +4 standard, +8 amélioré via `cover_bonus`) sur la touche et la
|
||||||
confirmation de critique ; couvert mou : une créature active entre
|
confirmation de critique ; couvert mou : une créature active entre
|
||||||
l'attaquant et la cible octroie aussi +4 CA aux attaques à distance (les
|
l'attaquant et la cible octroie aussi +4 CA aux attaques à distance (les
|
||||||
attaques de mêlée ignorent les créatures).
|
attaques de mêlée ignorent les créatures).
|
||||||
- Flanquement : +2 au jet d'attaque de mêlée si un allié actif (doté d'une arme
|
- Flanquement : +2 au jet d'attaque de mêlée (toucher de mêlée inclus, voir
|
||||||
de mêlée) menace la cible depuis la bordure ou le coin opposé. Les attaques à
|
« Touch AC ») si un allié actif menace réellement la cible depuis la
|
||||||
distance ignorent le flanquement ; un allié désarmé ou à distance ne compte
|
bordure ou le coin opposé — conformance P2 : l'allié doit **menacer** une
|
||||||
pas pour le flanquement.
|
case de la cible avec une arme de mêlée utilisable (la « dead zone » de 5 ft
|
||||||
|
d'une arme allongée ne menace pas) et ne pas être incapable d'agir
|
||||||
|
(étourdi/paralysé ne flanque pas). Les attaques à distance ignorent le
|
||||||
|
flanquement ; un allié désarmé ou à distance ne compte pas.
|
||||||
- Attaques d'opportunité : un combattant actif doté d'une arme de mêlée menace
|
- Attaques d'opportunité : un combattant actif doté d'une arme de mêlée menace
|
||||||
les cases à distance de son allonge effective (les 8 cases adjacentes pour
|
les cases à distance de son allonge effective (les 8 cases adjacentes pour
|
||||||
une arme sans allonge ; l'anneau à son allonge pour une arme reach — la
|
une arme sans allonge ; l'anneau à son allonge pour une arme reach — la
|
||||||
@@ -329,7 +507,9 @@ Règles modélisées :
|
|||||||
la case actuelle porte une AoO avant que le mouvant ne la quitte ; (2) tirer
|
la case actuelle porte une AoO avant que le mouvant ne la quitte ; (2) tirer
|
||||||
avec une arme à distance depuis une case menacée — chaque ennemi menaçant
|
avec une arme à distance depuis une case menacée — chaque ennemi menaçant
|
||||||
porte une AoO avant chaque tir. Une AoO par combattant par round (piste
|
porte une AoO avant chaque tir. Une AoO par combattant par round (piste
|
||||||
`_aoo_used`, réinitialisée au début du round) ; les AoO sont toujours portées
|
`_aoo_used`, réinitialisée au début du round) ; le budget restant est exposé
|
||||||
|
dans l'Observation via la clé `aoo_remaining` par combattant ; les AoO sont
|
||||||
|
toujours portées
|
||||||
(PF1e permet de les décliner, le simulateur ne le fait pas). Le pas de
|
(PF1e permet de les décliner, le simulateur ne le fait pas). Le pas de
|
||||||
placement (5 ft) ne provoque jamais d'AoO (voir ci-dessous) ; la retraite ne
|
placement (5 ft) ne provoque jamais d'AoO (voir ci-dessous) ; la retraite ne
|
||||||
protège que la case de départ (voir ci-dessous).
|
protège que la case de départ (voir ci-dessous).
|
||||||
@@ -347,6 +527,18 @@ Règles modélisées :
|
|||||||
ultérieures provoquent des AoO normalement (résolues pas à pas, comme pour
|
ultérieures provoquent des AoO normalement (résolues pas à pas, comme pour
|
||||||
le mouvement). `default_policy` ne choisit pas la retraite (disponible via
|
le mouvement). `default_policy` ne choisit pas la retraite (disponible via
|
||||||
une politique personnalisée).
|
une politique personnalisée).
|
||||||
|
- Course (`Action(kind="run")`, action à round complet, U5e) : le combattant
|
||||||
|
se déplace jusqu'à **4× sa vitesse** vers `target_id` (auto-dirigé,
|
||||||
|
s'arrête adjacent à la cible) ou vers une `destination` explicite (U5c), en
|
||||||
|
réutilisant exactement la mécanique de `move` (descente du champ de coût
|
||||||
|
Dijkstra, pas à pas avec provocation d'AoO — courir ne protège pas des
|
||||||
|
AoO). À l'achèvement, le combattant est `running` jusqu'au début de son
|
||||||
|
prochain tour : il **perd son bonus de Dextérité à la CA** (résolu par le
|
||||||
|
même chemin flat-footed/`denies_dex_to_ac` que les conditions). Une
|
||||||
|
`destination` hors budget 4× (ou invalide) est rejetée
|
||||||
|
(`unreachable_destination`) ; sans cible ni destination, rejet
|
||||||
|
(`missing_target`). `default_policy` ne choisit pas la course (disponible
|
||||||
|
via une politique personnalisée).
|
||||||
- Pas de placement (5-foot step) : action libre qui déplace le combattant d'une
|
- Pas de placement (5-foot step) : action libre qui déplace le combattant d'une
|
||||||
case vers l'ennemi le plus proche sans provoquer d'AoO. Exclusivité mutuelle
|
case vers l'ennemi le plus proche sans provoquer d'AoO. Exclusivité mutuelle
|
||||||
avec tout autre mouvement (move, charge, retraite) dans le même tour —
|
avec tout autre mouvement (move, charge, retraite) dans le même tour —
|
||||||
@@ -366,7 +558,11 @@ Règles modélisées :
|
|||||||
avec incrément est une attaque à distance : elle provoque des attaques
|
avec incrément est une attaque à distance : elle provoque des attaques
|
||||||
d'opportunité depuis une case menacée, subit −4 si l'attaquant est à plat
|
d'opportunité depuis une case menacée, subit −4 si l'attaquant est à plat
|
||||||
ventre et bénéficie du couvert mou ; un contact de mêlée (sans incrément,
|
ventre et bénéficie du couvert mou ; un contact de mêlée (sans incrément,
|
||||||
ex. le contact paralysant du liche) n'en fait rien.
|
ex. le contact paralysant du liche) n'en fait rien. Conformance P2 : le
|
||||||
|
contact de mêlée (touch sans incrément) est une **attaque de mêlée** — il
|
||||||
|
bénéficie du flanquement, de la hauteur (+1), du +4 contre une cible inerme
|
||||||
|
et peut porter une attaque sournoise ; Power Attack reste réservé aux armes
|
||||||
|
de mêlée (le contact n'en bénéficie pas).
|
||||||
- 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
|
||||||
@@ -382,34 +578,156 @@ Règles modélisées :
|
|||||||
condition inconnue ou non supportée reste exclue (False).
|
condition inconnue ou non supportée reste exclue (False).
|
||||||
- Incantation : chaque `CombatantState` porte `spell_slots_left` (initialisé depuis
|
- Incantation : chaque `CombatantState` porte `spell_slots_left` (initialisé depuis
|
||||||
le champ `spell_slots` du JSON, ex. `{"1": 4, ...}`) ; `_cast_spell` dépense
|
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
|
l'emplacement du niveau concerné (`spend_spell_slot`) — **sans emplacement
|
||||||
|
disponible, l'incantation est refusée** (journalisée `NO SPELL SLOT`, aucun
|
||||||
|
jet consommé) ; les cantrips (niveau 0) s'incantent librement. Le DD vaut `10 + niveau du
|
||||||
sort + mod de la caractéristique d'incantation` (`casting_ability`), la sauvegarde
|
sort + mod de la caractéristique d'incantation` (`casting_ability`), la sauvegarde
|
||||||
est résolue par `resolve_save`, et la RD ne réduit pas les dégâts des sorts
|
est résolue par `resolve_save`, et la RD ne réduit pas les dégâts des sorts
|
||||||
(`test_dr_does_not_reduce_spell_damage`). Incanter dans une
|
(`test_dr_does_not_reduce_spell_damage`). Incanter dans une
|
||||||
case menacée provoque des AoO ; tout dégât subi pendant l'incantation impose un
|
case menacée provoque des AoO ; tout dégât subi pendant l'incantation impose un
|
||||||
jet de concentration dont le DD dépend de la situation (`_concentration_dc`) :
|
jet de concentration dont le DD dépend de la situation (`_concentration_dc`) :
|
||||||
`10 + dégâts + niveau` si blessé, `10 + CMB de l'adversaire + niveau` si agrippé,
|
`10 + dégâts + niveau` si blessé, `10 + CMB de l'adversaire + niveau` si agrippé,
|
||||||
sinon `15 + 2×niveau` (incantation défensive), jet = d20 + niveau + mod de CON
|
sinon `15 + 2×niveau` (incantation défensive), jet = d20 + niveau + mod de
|
||||||
(+4 avec le don Combat Casting). Un sort ciblé avec sauvegarde fait pleins dégâts
|
la caractéristique d'incantation (Int/Wis/Cha — jamais Constitution, CRB) ;
|
||||||
|
le don Combat Casting n'accorde son +4 qu'en incantation défensive ou quand
|
||||||
|
on est agrippé, jamais pour les dégâts subis pendant l'incantation. Un sort ciblé avec sauvegarde fait pleins dégâts
|
||||||
sur un échec et **aucun dégât sur un succès** (la sauvegarde annule) ; le
|
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
|
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`
|
(`half_on_save: true` pour les rayons/lignes/cônes, `AreaEffect.save_for_half`
|
||||||
pour les explosions). `default_policy` choisit soin / offensif / buff via
|
pour les explosions). 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
|
||||||
|
et avoir une ligne d'effet depuis le jeteur (sinon rejet `invalid_destination`,
|
||||||
|
aucun sort lancé). Avec `target_pos` et pas de cible résolue, l'incantation se
|
||||||
|
fait sur le point : la sauvegarde primaire est sautée et chaque créature de la
|
||||||
|
zone effectue sa propre sauvegarde (SR incluse). `target_pos` n'a de sens que
|
||||||
|
pour un sort à zone : pour un sort ciblé sans `AreaEffect`, il est ignoré et
|
||||||
|
la cible résolue est utilisée normalement. Sans `target_pos`, le comportement
|
||||||
|
centré sur la créature est inchangé. `default_policy` ne choisit pas de point
|
||||||
|
(disponible via une politique personnalisée). `default_policy` choisit soin / offensif / buff via
|
||||||
`_find_heal_spell`, `_find_offensive_spell` et `_find_ally_needing_heal`.
|
`_find_heal_spell`, `_find_offensive_spell` et `_find_ally_needing_heal`.
|
||||||
|
- Résistance aux sorts (SR) et résistances/immunités énergétiques : un combattant
|
||||||
|
avec `spell_resistance > 0` oppose sa SR à chaque sort qui le cible — jet
|
||||||
|
`d20 + niveau du jeteur` contre la SR ; si le total est inférieur, le sort est
|
||||||
|
résisté (journalisé, tous les effets annulés pour cette cible). Pour les sorts à
|
||||||
|
zone, la SR est résolue par créature touchée (pas seulement sur la cible
|
||||||
|
primaire). Les dégâts énergétiques (feu, froid, électricité, acide, son…) sont
|
||||||
|
annulés par l'immunité (`immunities`) ou réduits par la résistance du type
|
||||||
|
correspondant (`resistances` : soustraction du maximum parmi les types du dégât,
|
||||||
|
plancher 0) ; les types physiques (contondant/perforant/tranchant) restent sur le
|
||||||
|
chemin de la RD. La résistance énergétique s'applique au dégât final (même étape
|
||||||
|
que la RD), y compris aux dégâts de sorts et aux composantes énergétiques des
|
||||||
|
armes.
|
||||||
|
- Concealment (chance de rater) : les conditions `blurred` (20 %, sort flou),
|
||||||
|
`displaced` (50 %, concealment total) et `invisible` (50 %, concealment total)
|
||||||
|
portent un champ `miss_chance` ; quand la
|
||||||
|
cible en porte une, après la touche et la confirmation de critique, le moteur
|
||||||
|
tire un d100 : si `d100 ≤ miss_chance`, l'attaque rate complètement (aucun
|
||||||
|
dégât, pas de critique, deed non consommé — journalisé « concealment »). Une
|
||||||
|
cible avec concealment ne peut pas être la victime d'une attaque sournoise.
|
||||||
|
Attaquant aveugle (V5a) : un attaquant portant `blinded` considère tous ses
|
||||||
|
adversaires comme ayant un concealment total — le même jet unique de d100 est
|
||||||
|
tiré avec `miss_chance = max(concealment de la cible, 50)` et journalisé
|
||||||
|
« attacker blinded » ; l'attaque peut donc rater même contre une cible sans
|
||||||
|
concealment.
|
||||||
|
- Attaquant invisible (V5a) : un attaquant portant `invisible` gagne **+2 à ses
|
||||||
|
jets d'attaque et de confirmation de critique** et sa cible **perd son bonus
|
||||||
|
de Dextérité à la CA** (même chemin `denies_dex_to_ac` que flat-footed/course).
|
||||||
|
L'invisibilité est symétrique : subi comme cible, la condition accorde le
|
||||||
|
concealment total de 50 % ci-dessus.
|
||||||
|
- Cible inerme (helpless, V5a + conformance P1) : sont traitées comme
|
||||||
|
**inertes** les conditions `helpless`, `paralyzed`, `asleep` et
|
||||||
|
`unconscious` (CRB : inerme = paralysé, immobilisé, ligoté, endormi,
|
||||||
|
inconscient — `stunned` **ne** rend **pas** inerme). Les attaques de
|
||||||
|
**mêlée** contre une cible inerme gagnent **+4 au jet d'attaque et à la
|
||||||
|
confirmation** (aucun bonus à distance) ; la cible a une **Dextérité
|
||||||
|
effective de 0** : son modificateur de Dextérité est entièrement remplacé
|
||||||
|
par la pénalité Dex 0 (−5), en plus de la perte du bonus de Dextérité
|
||||||
|
(CA flat-footed via `denies_dex_to_ac`).
|
||||||
|
Simplification documentée : l'attaque sournoise automatique du roublard sur
|
||||||
|
cible inerme n'est pas modélisée (la cible, privée de Dextérité, la déclenche
|
||||||
|
déjà via le chemin `denies_dex_to_ac`).
|
||||||
|
- Attaque sournoise : un combattant avec la capacité « Sneak Attack » inflige des
|
||||||
|
d6 de dégâts de précision ((niveau + 1) // 2 dés : 1d6 au niveau 1, 2d6 au
|
||||||
|
niveau 3…) si la cible est flanquée (attaque de mêlée uniquement — toucher de
|
||||||
|
mêlée inclus, conformance P2) ou privée de
|
||||||
|
son bonus de Dextérité à la CA (condition `denies_dex_to_ac` ; mêlée, ou
|
||||||
|
attaque à distance à ≤ 30 ft). Les dés sont jetés avec le RNG du moteur et
|
||||||
|
ajoutés APRÈS le multiplicateur de critique (la précision n'est jamais
|
||||||
|
multipliée) et AVANT la RD et les résistances énergétiques ; jamais contre une
|
||||||
|
cible avec concealment. Conformance P2 : les morts-vivants (`undead`) et les
|
||||||
|
constructeurs (`construct`) sont immunisés aux dégâts de précision — la cible
|
||||||
|
ne peut pas être la victime d'une attaque sournoise ; les autres immunités RAW
|
||||||
|
(vase, plante) ne sont pas modélisées (pas de tels types dans le modèle).
|
||||||
|
- Tirer dans une mêlée / Precise Shot : toute attaque à distance (kind `ranged`
|
||||||
|
ou `touch` avec incrément) contre une cible engagée dans une mêlée subit −4 au
|
||||||
|
jet d'attaque ET au jet de confirmation (la cible est « engagée » quand un
|
||||||
|
ennemi actif autre que l'attaquant, doté d'une arme de mêlée, menace ses
|
||||||
|
cases) ; la pénalité tombe à −2 si la cible ou l'adversaire menaçant est à
|
||||||
|
≥ 10 ft (2 cases) de l'attaquant. Le don « Precise Shot » annule la pénalité.
|
||||||
|
Les attaques de mêlée ne sont pas concernées.
|
||||||
|
- Couvert : les trois niveaux PF1e sont modélisés via `cover_bonus` sur le
|
||||||
|
terrain — partiel +2, standard +4 (ou `cover: true`), amélioré +8 ; le
|
||||||
|
couvert mou des créatures reste +4 (couvert standard).
|
||||||
- Invocation : les créatures invoquées agissent (calées sur la case d'initiative de
|
- Invocation : les créatures invoquées agissent (calées sur la case d'initiative de
|
||||||
leur conjurateur via `_build_round_order`) puis expirent après leur `summon_duration`
|
leur conjurateur via `_build_round_order`) puis expirent après leur `summon_duration`
|
||||||
(`_expire_summons` décrémente puis retire).
|
(`_expire_summons` décrémente puis retire).
|
||||||
- Conditions effectives : 18 conditions prédéfinies (`conditions.py`). Leurs drapeaux
|
- Conditions effectives : 28 conditions prédéfinies (`conditions.py`). Leurs drapeaux
|
||||||
comportementaux sont appliqués par le moteur : `cant_act` (étourdi, paralysé, dazed,
|
comportementaux sont appliqués par le moteur : `cant_act` (étourdi, paralysé, dazed,
|
||||||
endormi) annule le tour ; `cant_attack` (nauséeux) n'autorise qu'une unique action
|
endormi, inerme, fasciné) annule le tour ; `cant_attack` (nauséeux) n'autorise qu'une unique action
|
||||||
simple et bloque toute attaque / manœuvre ; `staggered` restreint à une action
|
de mouvement (`move`, `5foot_step`, `stand_up`, `drop_prone`) et bloque toute
|
||||||
|
attaque, manœuvre **et incantation** (CRB : un nauséeux ne peut ni attaquer,
|
||||||
|
ni incanter, ni se concentrer) ; `staggered` restreint à une action
|
||||||
simple (pas d'attaque à outrance) ; `cant_move` bloque le déplacement ;
|
simple (pas d'attaque à outrance) ; `cant_move` bloque le déplacement ;
|
||||||
`denies_dex_to_ac` (à plat ventre, paralysé…) fait perdre le bonus de Dextérité à
|
`denies_dex_to_ac` (flat-footed, paralysé, aveuglé…) fait perdre le bonus de Dextérité à
|
||||||
la CA (CA flat-footed). À plat ventre : −4 CA et −4 aux attaques à distance.
|
la CA (CA flat-footed) ; `miss_chance` (flou 20 %, déplacement 50 %, invisible
|
||||||
Agrippé : −4 Dextérité, −2 attaque/CA/Réflexes, sans déplacement ni AoO.
|
50 %) impose la
|
||||||
|
chance de rater du concealment. À plat ventre : l'attaquant à plat ventre
|
||||||
|
subit −4 à ses attaques (mêlée selon le CRB ; distance traitée arbalète à
|
||||||
|
−4, simplification documentée) ; la cible à plat ventre subit −4 CA contre
|
||||||
|
la mêlée et gagne +4 CA contre la distance (le CRB inverse du « −4 CA
|
||||||
|
contre tout » précédemment modélisé).
|
||||||
|
Agrippé : −4 Dextérité — le modificateur cible `dex_skills` s'applique
|
||||||
|
désormais réellement aux compétences de Dexterity (Acrobaties, Escalade,
|
||||||
|
Équilibre, Évasion, Vol, Équitation, Manipulation de corde, Discrétion,
|
||||||
|
Natation, Désamorçage — conformance P2) —, −2 attaque/CA/Réflexes, sans
|
||||||
|
déplacement ni AoO. Épinglé : même −4 `dex_skills`.
|
||||||
|
Aveuglé (conformance P2) : −2 CA, perte du bonus de Dextérité à la CA, −4
|
||||||
|
aux compétences de Dexterity (`dex_skills`) et **aucun malus plat
|
||||||
|
d'attaque** — la pénalité RAW est la dissimulation totale (50 % d'échec,
|
||||||
|
modélisée) ; le −2 d'attaque non-RAW qui s'y superposait a été supprimé.
|
||||||
|
Simplification documentée : la moitié Force du −4 RAW (compétences de
|
||||||
|
Force) n'est pas modélisée (pas de cible `str_skills`).
|
||||||
|
Inerme (`helpless`, `paralyzed`, `asleep`, `unconscious`) : ne peut pas agir,
|
||||||
|
Dextérité effective 0 (−5 CA en plus de la perte du bonus), +4 en mêlée
|
||||||
|
contre lui (voir « Cible inerme ») ; `stunned` ne rend pas inerte. Fasciné (`fascinated`) : ne peut pas agir.
|
||||||
|
Invisible (`invisible`) : concealment total subi +2 attaquant / perte de Dex
|
||||||
|
de la cible (voir « Attaquant invisible »).
|
||||||
|
Saignement (`bleeding`, V5b) : une créature qui saigne subit `bleed_damage`
|
||||||
|
points de dégâts au **début de son tour** (avant politique et flags) ; tout
|
||||||
|
effet restaurant des points de vie (sort de soin, channel energy) stoppe le
|
||||||
|
saignement (`bleed_damage = 0`) et retire la condition. Simplification
|
||||||
|
documentée : le jet de compétence Soin DD 15 n'est pas modélisé (le moteur
|
||||||
|
n'a pas d'action Soin).
|
||||||
|
Confus (`confused`, V5b) : au début de chaque tour, jet d% — 01-25 agit
|
||||||
|
normalement (le tour se poursuit) ; 26-50 bave incohéremment (tour perdu) ;
|
||||||
|
51-75 se inflige 1d8 + modificateur de Force avec l'objet tenu ; 76-100
|
||||||
|
attaque d'une seule attaque de mêlée la créature la plus proche (allié OU
|
||||||
|
ennemi, une seule si en allonge ; sinon le tour est perdu, journalisé).
|
||||||
|
Simplification documentée : la clause « si elle est blessée, riposte
|
||||||
|
l'agresseur » est réduite à « attaque la créature la plus proche » ; le coup
|
||||||
|
de grâce n'est pas modélisé.
|
||||||
- Manœuvres de combat : trip, disarm, bull_rush, sunder, grapple, escape,
|
- Manœuvres de combat : trip, disarm, bull_rush, sunder, grapple, escape,
|
||||||
overrun, dirty trick, steal, reposition et drag sont modélisées, chacune
|
overrun, dirty trick, steal, reposition et drag sont modélisées, chacune
|
||||||
comme une tentative unique (1d20 + CMB contre CMD) :
|
comme une tentative unique (1d20 + CMB contre CMD) : le jet de manœuvre est
|
||||||
|
un jet d'attaque — 20 naturel réussit toujours, 1 naturel échoue toujours
|
||||||
|
(conformance P2). Conformance P2 : tenter une manœuvre (sauf `escape`)
|
||||||
|
**provoque une attaque d'opportunité** de la cible, résolue **avant** le jet
|
||||||
|
de CMB ; le don « Improved <Maneuver> » correspondant (Improved Trip, …)
|
||||||
|
annule cette provocation ; si l'AoO fait passer l'attaquant sous 0 pv, la
|
||||||
|
manœuvre est perdue. L'AoO de manœuvre consomme le budget d'AoO du round de
|
||||||
|
la cible (Combat Reflexes inclus).
|
||||||
trip → `prone` ; disarm → `disarmed` (−4 attaque) ; bull_rush → pousse la
|
trip → `prone` ; disarm → `disarmed` (−4 attaque) ; bull_rush → pousse la
|
||||||
cible (direction sélectionnable via `Action.direction`) ;
|
cible (direction sélectionnable via `Action.direction`) ;
|
||||||
grapple → `grappled`/`pinned` ; escape → **une** sauvegarde (bonus statique de la
|
grapple → `grappled`/`pinned` ; escape → **une** sauvegarde (bonus statique de la
|
||||||
@@ -433,8 +751,12 @@ Règles modélisées :
|
|||||||
- Sortilèges du sorcier (witch hex) : le DD vaut `10 + niveau//2 + mod d'Intelligence`
|
- Sortilèges du sorcier (witch hex) : le DD vaut `10 + niveau//2 + mod d'Intelligence`
|
||||||
(evil_eye, slumber, cackle) ; `cackle` prolonge d'un round les sortilèges déjà
|
(evil_eye, slumber, cackle) ; `cackle` prolonge d'un round les sortilèges déjà
|
||||||
actifs, sur une liste instantanée pour ne pas s'étendre à l'infini. Les sorts à
|
actifs, sur une liste instantanée pour ne pas s'étendre à l'infini. Les sorts à
|
||||||
zone (AoE) utilisent le DD d'incantation du jeteur et, sur une sauvegarde réussie,
|
zone (AoE) utilisent le DD d'incantation du jeteur et chaque créature de la
|
||||||
ne font que la moitié des dégâts.
|
zone effectue la sauvegarde listée par le sort (Volonté / Réflexes /
|
||||||
|
Constitution — le sort primaire réutilise son jet déjà effectué) ; un succès
|
||||||
|
annule ou divise par deux selon ce que l'effet déclare (`save_negates` /
|
||||||
|
`half_on_save` / `AreaEffect.save_for_half`) — les zones « sauvegarde
|
||||||
|
annule » (Sleep, Color Spray, Web) sauvent donc aussi.
|
||||||
- Dons : les 8 PJ portent 55 noms de dons uniques ; le chargeur résout chacun d'eux
|
- 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
|
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
|
lié au niveau, dons passifs via `_stat_modifiers`), soit vers un « no-op » tracé en
|
||||||
@@ -446,12 +768,18 @@ Règles modélisées :
|
|||||||
moins 2 morts-vivants ennemis sont groupés à 30 ft → les blesse en 2d6 ; le camp de la
|
moins 2 morts-vivants ennemis sont groupés à 30 ft → les blesse en 2d6 ; le camp de la
|
||||||
cible n'est pas pris en compte — seul `creature_type` compte, `selective_channeling` non
|
cible n'est pas pris en compte — seul `creature_type` compte, `selective_channeling` non
|
||||||
modélisé), sortilège `evil_eye` (nairda), deed `up_close_and_deadly`
|
modélisé), sortilège `evil_eye` (nairda), deed `up_close_and_deadly`
|
||||||
(tammara, action bonus +1d6 à ≤ 30 ft), `inspire_courage` + `spell_combat` (misty)
|
(tammara, action bonus +1d6 à ≤ 30 ft — consommé sur la première attaque
|
||||||
|
résolue : si elle est à distance ET à ≤ 30 ft, +1d6 s'ajoute aux dégâts ;
|
||||||
|
sinon le bonus est perdu ; le drapeau est réinitialisé dans tous les cas),
|
||||||
|
`inspire_courage` + `spell_combat` (misty)
|
||||||
— couvertes par `tests/test_class_abilities.py`.
|
— couvertes par `tests/test_class_abilities.py`.
|
||||||
- Le Liche (`data/monsters/lich.json`) : `creature_type: "undead"` (sensible à l'énergie
|
- Le Liche (`data/monsters/lich.json`) : `creature_type: "undead"` (sensible à l'énergie
|
||||||
positive canalisée), aura de terreur (30 ft, Volonté DD 22 ou
|
positive canalisée), aura de terreur (30 ft, Volonté DD 22 ou
|
||||||
`shaken` 1 round, au début de son tour) et contact paralysant (au toucher,
|
`shaken` 1 round, au début de son tour) et contact paralysant (au toucher,
|
||||||
`paralysé` 1d4+1 rounds), RD 15/magie+contondant ; son JSON porte un dictionnaire
|
`paralysé` 1d4+1 rounds), RD 15/contondant **et** magie (conformance P2 :
|
||||||
|
les deux composants sont requis — une arme contondante non magique ne
|
||||||
|
contourne plus la RD ; lacune documentée : le modèle d'arme n'expose pas de
|
||||||
|
propriété « magique », donc aucun équipement ne contourne cette RD) ; son JSON porte un dictionnaire
|
||||||
`spell_slots` sans clés dupliquées.
|
`spell_slots` sans clés dupliquées.
|
||||||
- Snapshot d'observation (contrat LLM, Phase 2) : avant chaque appel de
|
- Snapshot d'observation (contrat LLM, Phase 2) : avant chaque appel de
|
||||||
politique, le moteur construit une `Observation` sérialisable (`to_dict()` →
|
politique, le moteur construit une `Observation` sérialisable (`to_dict()` →
|
||||||
@@ -460,21 +788,86 @@ Règles modélisées :
|
|||||||
se branche via `CombatEngine(..., llm_policy=...)` (`LLMPolicy(observation,
|
se branche via `CombatEngine(..., llm_policy=...)` (`LLMPolicy(observation,
|
||||||
state) -> tuple[Action, ...]`). Schéma enrichi (E1-E5) :
|
state) -> tuple[Action, ...]`). Schéma enrichi (E1-E5) :
|
||||||
- Par combattant : id, side, pos, occupied_cells, hp/hp_max, active/dead,
|
- Par combattant : id, side, pos, occupied_cells, hp/hp_max, active/dead,
|
||||||
conditions (noms + rounds_left), resources_left (+ `spell_slot_{level}`),
|
dying/stabilized, conditions (noms + rounds_left), resources_left (+ `spell_slot_{level}`),
|
||||||
weapon_broken/weapon_stolen, grappled_with, moved_this_turn, power_attack,
|
weapon_broken/weapon_stolen, grappled_with, moved_this_turn, power_attack,
|
||||||
name, level, size, speed_land_ft, speed_fly_ft, ac {total, touch,
|
name, level, size, dr {amount, bypass} ou None (C1), creature_type (C3),
|
||||||
flat_footed}, saves {fort, ref, will}, cmb, cmd, attacks (référentiel
|
bab (E1), initiative_mod (E2) et initiative_total (U2 : total du jet
|
||||||
complet : id, name, kind, attack_bonus, damage, damage_bonus, crit_range,
|
d'initiative courant = d20 + mod, 0 si pas encore de clé — invocation
|
||||||
crit_mult, reach_ft, range_increment_ft, count, firearm — y compris les
|
fraîche), casting_ability ou None pour non-jeteur
|
||||||
armes broken/stolen), features (noms des capacités), spells (résumés
|
(E3), abilities {str/dex/con/int/wis/cha: score brut} (Medium), skills
|
||||||
enrichis du registre : name, level, school, range_ft, save, dc, summary).
|
{nom: {rank, class_skill, armor_penalty}} uniquement rank > 0 (Medium),
|
||||||
|
metamagic_feats (tuple trié), weapon_damage {weapon_id: dégâts courants},
|
||||||
|
summon_duration (int ou None), immediate_used, deed_up_close_and_deadly
|
||||||
|
(flags actuels), active_buffs {source, rounds_left, mods: tuple de
|
||||||
|
{target, value, bonus_type}} (E5), speed_land_ft, speed_fly_ft,
|
||||||
|
speed_effective_ft (V4 : budget de déplacement effectif = max(land, fly),
|
||||||
|
en pieds), ac {total,
|
||||||
|
touch, flat_footed}, saves {fort, ref, will}, cmb, cmd, attacks
|
||||||
|
(référentiel complet : id, name, kind, attack_bonus, damage, damage_bonus,
|
||||||
|
crit_range, crit_mult, reach_ft, range_increment_ft, count, firearm —
|
||||||
|
y compris les armes broken/stolen), features (noms des capacités),
|
||||||
|
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,
|
||||||
|
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)),
|
||||||
|
spell_resistance (int), resistances {type: montant}, immunities
|
||||||
|
(tuple triée des types immunisés), sneak_dice (dés de précision disponibles :
|
||||||
|
(niveau + 1) // 2 avec « Sneak Attack », sinon 0), engaged_in_melee (bool —
|
||||||
|
une cible engagée dans une mêlée, signal pour le tir dans la mêlée et
|
||||||
|
l'attaque sournoise), dying (bool — `hp < 0` et pas morte : agonisante,
|
||||||
|
inconsciente), stabilized (bool — stabilisée pendant son agonie, ne perd
|
||||||
|
plus de pv tant qu'aucune nouvelle blessure ne la remet en agonie),
|
||||||
|
last_turn_results (tuple de {kind, ok, reason} — résultat d'exécution du
|
||||||
|
dernier tour, pour que la policy apprenne les actions rejetées/dégradées),
|
||||||
|
readied ({kind, trigger} de l'action préparée ou None — préparation en
|
||||||
|
cours, consommée quand le déclencheur la fait tirer),
|
||||||
|
defensive_ac_bonus (int — bonus d'esquive à la CA de la défense totale
|
||||||
|
(+4) ou du combat défensif (+2), réinitialisé au début du tour du
|
||||||
|
combattant), fight_defensively (bool — combat défensif actif : −4 aux
|
||||||
|
jets d'attaque et de confirmation jusqu'au prochain tour), aoo_remaining
|
||||||
|
(int — attaques d'opportunité restantes ce round : `_aoo_allowance`
|
||||||
|
(1 par défaut, 1 + mod de Dex avec Combat Reflexes, plancher 1) moins les
|
||||||
|
AoO déjà consommées, réinitialisé à chaque nouveau round, jamais négatif),
|
||||||
|
aid_attack_bonus (int — bonus d'aide autrui (+2 par aide réussie, cumulatif)
|
||||||
|
ajouté au prochain jet d'attaque du combattant puis consommé, expiré au
|
||||||
|
début de son tour s'il est inutilisé), aid_ac_bonus (int — bonus d'aide
|
||||||
|
autrui (+2 par aide réussie, cumulatif) ajouté à sa CA, expiré au début de
|
||||||
|
son tour), running (bool — course en cours jusqu'au prochain tour du
|
||||||
|
combattant : il perd son bonus de Dextérité à la CA), bleed_damage (int —
|
||||||
|
dégâts de saignement subis au début du tour du combattant, 0 = ne saigne
|
||||||
|
pas ; V5b ; `bleeding`/`confused` sont visibles via `conditions`).
|
||||||
- Par paire combattant actif × cible : target_index, distance_ft, weapon_for,
|
- Par paire combattant actif × cible : target_index, distance_ft, weapon_for,
|
||||||
range_penalty, can_charge, can_step5_to_attack, has_line_of_effect,
|
range_penalty, can_charge, can_step5_to_attack, has_line_of_effect,
|
||||||
flanking, movement_cost_ft, target_threatens_me, enemies_threatening_me.
|
flanking, movement_cost_ft, target_threatens_me, enemies_threatening_me,
|
||||||
|
cover_bonus (int — bonus de couvert que la cible gagne contre une attaque
|
||||||
|
de l'acteur, calculé comme dans `resolve_attack` : terrain +2/+4/+8 via la
|
||||||
|
règle des coins, couvert mou +4 des créatures interposées pour les seules
|
||||||
|
attaques à distance ; 0 si `weapon_for` est None), weapon_reason (str |
|
||||||
|
None — None si `weapon_for` a choisi une arme ; sinon la raison normalisée
|
||||||
|
de l'indisponibilité d'attaque, dans le vocabulaire `ACTION_RESULT_REASONS` :
|
||||||
|
`no_weapon` (aucune arme utilisable), `no_line_of_effect` (ligne d'effet
|
||||||
|
bloquée), `out_of_range` (arme existante mais cible hors de portée)),
|
||||||
|
charge_reason (str | None — None si `can_charge` est vrai ; sinon la
|
||||||
|
raison de `ChargeResult` verbatim (`no_line_of_effect` / `no_charge_path`)
|
||||||
|
ou `no_weapon` si aucune arme de mêlée utilisable).
|
||||||
- Top-level : round, acting_combatant, combatants, pairs, terrain, elevation,
|
- Top-level : round, acting_combatant, combatants, pairs, terrain, elevation,
|
||||||
threatened (grille bool des cases menacées par les ennemis),
|
threatened (grille bool des cases menacées au contact par les ennemis —
|
||||||
|
AoO), ranged_threatened (U6d : grille bool des cases sous tir ennemi à
|
||||||
|
distance — champ de tir des armes à distance utilisables des ennemis
|
||||||
|
actifs (portée maximale + ligne d'effet, bornée à la carte) ; les armes à
|
||||||
|
distance ne menacent pas pour les AoO en PF1e : c'est une carte de champ
|
||||||
|
de tir, pas une menace d'AoO ; la grille `threatened` de mêlée reste
|
||||||
|
inchangée),
|
||||||
|
initiative_order (U2 : tuple d'ids dans l'ordre d'initiative du round
|
||||||
|
courant — le premier est le prochain à agir ; les invocations héritent de la
|
||||||
|
case de leur conjurateur),
|
||||||
terrain_semantics (un dict par type de terrain : type, move_cost,
|
terrain_semantics (un dict par type de terrain : type, move_cost,
|
||||||
blocks_los, cover).
|
blocks_los, cover, cover_bonus), condition_definitions (C2 : tuple trié de (nom,
|
||||||
|
{mods, flags, speed_mult, miss_chance}) — définitions complètes des 28
|
||||||
|
conditions de CONDITIONS_BY_NAME pour que la LLM interprète les drapeaux,
|
||||||
|
les modificateurs et les chances de rater (concealment)).
|
||||||
Les helpers publics du moteur (L5) sont désormais embarqués EN DONNÉES dans
|
Les helpers publics du moteur (L5) sont désormais embarqués EN DONNÉES dans
|
||||||
le snapshot (`threatened`, `terrain_semantics`, `movement_cost_ft`,
|
le snapshot (`threatened`, `terrain_semantics`, `movement_cost_ft`,
|
||||||
`target_threatens_me`, `enemies_threatening_me`) — une `LLMPolicy` ne peut
|
`target_threatens_me`, `enemies_threatening_me`) — une `LLMPolicy` ne peut
|
||||||
@@ -483,11 +876,16 @@ Règles modélisées :
|
|||||||
`channel_energy`, `hexes`, `grit`, `arcane_pool`, `bardic_rounds`, plus
|
`channel_energy`, `hexes`, `grit`, `arcane_pool`, `bardic_rounds`, plus
|
||||||
`spell_slot_{level}` ajouté par le snapshot). Limites documentées : pas de
|
`spell_slot_{level}` ajouté par le snapshot). Limites documentées : pas de
|
||||||
grille `reachable_ft` budget=speed (délibérément rejetée —
|
grille `reachable_ft` budget=speed (délibérément rejetée —
|
||||||
`movement_cost_ft` par paire + `terrain_semantics` + `speed_land_ft`
|
`movement_cost_ft` par paire + `terrain_semantics` + `speed_effective_ft`
|
||||||
suffisent), pas de couvert par paire (déductible via `has_line_of_effect` +
|
suffisent). Le couvert par paire est exposé via la clé `cover_bonus`
|
||||||
`terrain_semantics` + positions). Les API de décision exposées (items L1-L8)
|
(calcul identique à `resolve_attack`, couvert mou des créatures inclus).
|
||||||
|
Les API de décision exposées (items L1-L8)
|
||||||
s'y retrouvent : `direction`/`trick_condition`/`weapon_id` sur `Action`,
|
s'y retrouvent : `direction`/`trick_condition`/`weapon_id` sur `Action`,
|
||||||
`can_charge` → `ChargeResult`, kinds `retrieve_weapon`/`repair_weapon`.
|
`can_charge` → `ChargeResult`, kinds `retrieve_weapon`/`repair_weapon`.
|
||||||
|
Le kind `activate_power_attack` (action libre) active le don Power Attack
|
||||||
|
(`state.power_attack = True`) si le combattant possède le don ; sans le don,
|
||||||
|
c'est un no-op journalisé. Le snapshot expose l'état courant via la clé
|
||||||
|
`power_attack` (bool) par combattant.
|
||||||
|
|
||||||
Non modélisé : la couche `markers` (points nommés de la carte) est validée à
|
Non modélisé : la couche `markers` (points nommés de la carte) est validée à
|
||||||
la lecture mais non appliquée dans la résolution.
|
la lecture mais non appliquée dans la résolution.
|
||||||
@@ -506,8 +904,8 @@ la lecture mais non appliquée dans la résolution.
|
|||||||
règle des coins (`diagonal_allowed`), Dijkstra `reachable` avec ou sans
|
règle des coins (`diagonal_allowed`), Dijkstra `reachable` avec ou sans
|
||||||
budget.
|
budget.
|
||||||
- `los.py` — ligne d'effet et couvert par la règle des coins : gate de ligne
|
- `los.py` — ligne d'effet et couvert par la règle des coins : gate de ligne
|
||||||
d'effet dans `weapon_for`, bonus de couvert +4 CA (terrain et couvert mou
|
d'effet dans `weapon_for`, bonus de couvert par niveau (+2/+4/+8 terrain via
|
||||||
des créatures) dans `resolve_attack`.
|
`cover_bonus`, +4 couvert mou des créatures) dans `resolve_attack`.
|
||||||
- `combat.py` — `CombatEngine` déterministe : initiative, actions, résolution
|
- `combat.py` — `CombatEngine` déterministe : initiative, actions, résolution
|
||||||
des attaques (couvert, ligne d'effet, pénalités de portée, CA de contact
|
des attaques (couvert, ligne d'effet, pénalités de portée, CA de contact
|
||||||
pour les attaques touch et firearms), tailles et allonges (occupation
|
pour les attaques touch et firearms), tailles et allonges (occupation
|
||||||
@@ -527,10 +925,12 @@ la lecture mais non appliquée dans la résolution.
|
|||||||
enhancement…) gardent la valeur la plus élevée. Les pénalités suivent les
|
enhancement…) gardent la valeur la plus élevée. Les pénalités suivent les
|
||||||
mêmes règles. Fondation pour sorts, conditions, dons et capacités de classe.
|
mêmes règles. Fondation pour sorts, conditions, dons et capacités de classe.
|
||||||
- `conditions.py` — conditions PF1e : `Condition` (dataclass avec
|
- `conditions.py` — conditions PF1e : `Condition` (dataclass avec
|
||||||
modificateurs + flags comportementaux) et 18 conditions prédéfinies
|
modificateurs + flags comportementaux + `miss_chance`) et 28 conditions prédéfinies
|
||||||
(shaken, sickened, fatigued, exhausted, entangled, dazzled, blinded,
|
(shaken, sickened, fatigued, exhausted, entangled, dazzled, blinded,
|
||||||
deafened, flat-footed, prone, stunned, paralyzed, nauseated, dazed,
|
deafened, flat-footed, prone, stunned, paralyzed, nauseated, dazed,
|
||||||
staggered, frightened, panicked, cowering). Les modificateurs sont intégrés
|
staggered, frightened, panicked, cowering, helpless, fascinated, invisible,
|
||||||
|
bleeding, confused).
|
||||||
|
Les modificateurs sont intégrés
|
||||||
à `resolve_attack` (attaque, dégâts, CA) et `resolve_save` (jets de
|
à `resolve_attack` (attaque, dégâts, CA) et `resolve_save` (jets de
|
||||||
sauvegarde) via `_stat_modifiers` qui collecte effets + conditions ; les
|
sauvegarde) via `_stat_modifiers` qui collecte effets + conditions ; les
|
||||||
drapeaux comportementaux (`cant_act`, `cant_attack`, `cant_move`, staggered,
|
drapeaux comportementaux (`cant_act`, `cant_attack`, `cant_move`, staggered,
|
||||||
@@ -538,8 +938,9 @@ la lecture mais non appliquée dans la résolution.
|
|||||||
- `abilities.py` — dons et capacités : `AbilitySpec` (dataclass avec
|
- `abilities.py` — dons et capacités : `AbilitySpec` (dataclass avec
|
||||||
catégorie feat/class/racial/trait) et fabriques de dons (Weapon Focus ciblé
|
catégorie feat/class/racial/trait) et fabriques de dons (Weapon Focus ciblé
|
||||||
par arme, Toughness lié au niveau, Power Attack actif −X attaque / +2X
|
par arme, Toughness lié au niveau, Power Attack actif −X attaque / +2X
|
||||||
dégâts, X = BAB//4 + 1, mêlée uniquement, declared as free action at turn
|
dégâts, X = BAB//4 + 1, mêlée uniquement, activé comme action libre via le
|
||||||
start via `state.power_attack`). Les modificateurs sont collectés par
|
kind `activate_power_attack` qui pose `state.power_attack`). Les
|
||||||
|
modificateurs sont collectés par
|
||||||
`_stat_modifiers` avec filtrage par arme (`weapon_filter`). Le champ
|
`_stat_modifiers` avec filtrage par arme (`weapon_filter`). Le champ
|
||||||
`features` de `Combatant` contient les aptitudes permanentes ; le chargeur
|
`features` de `Combatant` contient les aptitudes permanentes ; le chargeur
|
||||||
(`loaders/combatant.py`) résout les noms de dons des fiches vers des
|
(`loaders/combatant.py`) résout les noms de dons des fiches vers des
|
||||||
@@ -589,7 +990,7 @@ uv run basedpyright src # mode strict
|
|||||||
## Feuille de route
|
## Feuille de route
|
||||||
|
|
||||||
- **Phase 1** — magie et états : largement réalisée. Sorts par emplacements
|
- **Phase 1** — magie et états : largement réalisée. Sorts par emplacements
|
||||||
(`spells.py` + base `data/spells/`, 11 sorts), DD et sauvegardes, RD non
|
(`spells.py` + base `data/spells/`, 107 sorts), DD et sauvegardes, RD non
|
||||||
appliquée aux dégâts de sorts, concentration par situation, invocation,
|
appliquée aux dégâts de sorts, concentration par situation, invocation,
|
||||||
conditions effectives (`conditions.py`), manœuvres de combat, dons (55 noms
|
conditions effectives (`conditions.py`), manœuvres de combat, dons (55 noms
|
||||||
résolus, `abilities.py` + chargeur) et capacités de classe (channel energy,
|
résolus, `abilities.py` + chargeur) et capacités de classe (channel energy,
|
||||||
@@ -602,6 +1003,11 @@ uv run basedpyright src # mode strict
|
|||||||
- **Phase 2** — couche tactique LLM : stratégies en langage naturel traduites
|
- **Phase 2** — couche tactique LLM : stratégies en langage naturel traduites
|
||||||
en politiques, balayage de matrices de positionnement. Le contrat
|
en politiques, balayage de matrices de positionnement. Le contrat
|
||||||
d'observation (snapshot sérialisable `Observation` + wrapper `LLMPolicy`)
|
d'observation (snapshot sérialisable `Observation` + wrapper `LLMPolicy`)
|
||||||
est en place ; la couche LLM elle-même reste à implémenter.
|
est en place ; la couche LLM elle-même reste à implémenter. Les capacités
|
||||||
|
désormais débloquées du moteur (ready, delay, défense totale, destination
|
||||||
|
de déplacement, choix d'arme, boucle de feedback) sont démontrées par une
|
||||||
|
politique lisant uniquement l'`Observation` dans
|
||||||
|
`tests/test_llm_engine_capabilities.py` (démo de capacités, pas une
|
||||||
|
implémentation de la couche LLM).
|
||||||
- **Phase 3** — rapporteur LLM local : agrégation des statistiques et
|
- **Phase 3** — rapporteur LLM local : agrégation des statistiques et
|
||||||
rédaction du rapport d'équilibrage en français. (Non implémentée.)
|
rédaction du rapport d'équilibrage en français. (Non implémentée.)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Abundant Ammunition",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that conjures duplicate ammunition: attacks with the affected ammunition do not expend it. No combat-mechanical effect in the engine (ammunition is not tracked)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Acid Splash",
|
||||||
|
"level": 0,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d3",
|
||||||
|
"types": ["acid"],
|
||||||
|
"half_on_save": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "You fire a small orb of acid at the target, dealing 1d3 points of acid damage (ranged touch attack, no save)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Aid",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "long",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "attack", "value": 1, "bonus_type": "morale" },
|
||||||
|
{ "target": "will", "value": 1, "bonus_type": "morale" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The subject gains a +1 morale bonus on attack rolls and on saving throws against fear effects (modeled as Will). Duration 10 min/level approximated as 10 rounds."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Air Bubble",
|
||||||
|
"level": 1,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You create a sphere of air around your head (or a touched creature's) that lasts 10 min/level, allowing breathing underwater. No combat-mechanical effect in the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Alarm",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Wards a area (20-ft radius, 20 ft high) against intrusion for 2 hours/level, alerting you mentally. No combat-mechanical effect in the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Arcane Mark",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Creates a permanent visible inscribed mark of your choosing on an object or surface, optionally invisible and keyed to you. Utility cantrip, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Bane",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "shaken",
|
||||||
|
"duration_rounds": 10,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Enemies within range take a -1 penalty on attack rolls and saving throws (approximated with the shaken condition, -2). Will negates. Concentration 1 min/level approximated as 10 rounds."
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Bear's Endurance",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "fort", "value": 2, "bonus_type": "enhancement" },
|
||||||
|
{ "target": "hp", "value": 2, "bonus_type": "enhancement" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The subject gains a +4 enhancement bonus to Constitution, granting +2 Fortitude and +2 hit points (approximated as +2/+2). Fortitude negates (harmless). Duration 10 min/level approximated as 60 rounds."
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "Bladed Dash",
|
||||||
|
"level": 1,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "speed_ft", "value": 30, "bonus_type": "enhancement" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "You move up your speed as a move action and make one melee attack at the end. Simplified as a +30 ft speed buff for 1 round; the extra attack is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Bleed",
|
||||||
|
"level": 0,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "close",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "bleeding",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cantrip that causes a wound to bleed: the target takes 1 point of damage per round until healed. Fortitude negates. Modeled as the bleeding condition for 1 round."
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "Bless",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 20,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "attack", "value": 1, "bonus_type": "morale" },
|
||||||
|
{ "target": "will", "value": 1, "bonus_type": "morale" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "All allies within 20 ft/level (modeled as a 20-ft burst applied to all creatures in area) gain a +1 morale bonus on attack rolls and on saving throws against fear effects (modeled as Will). Duration 1 min/level approximated as 10 rounds."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Blindness/Deafness",
|
||||||
|
"level": 2,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "blinded",
|
||||||
|
"duration_rounds": 100,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The target becomes blind or deaf (modeled as blinded) until removed by a caster of higher level. Permanent duration approximated as 100 rounds. Will negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Charm Person",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "fascinated",
|
||||||
|
"duration_rounds": 100,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The charmed person regards the caster as a trusted friend (modeled as the fascinated condition; the charmed condition is not in the engine). Duration 1 hour/level approximated as 100 rounds. Will negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "Color Spray",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 15,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "stunned",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cone of chaotic colors (modeled as a 15-ft burst) blinds and stuns creatures with fewer HD than your level for 1d4 rounds (approximated as 1 round of stunned). Will negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Comprehend Languages",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that lets you understand the meaning of any spoken or written language you encounter for 1 min/level. Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Create Alcool",
|
||||||
|
"level": 0,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip (Create Alcohol, spelled as on the PC sheet) that transforms one liquid per level into an alcoholic drink of equal volume. Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Create Water",
|
||||||
|
"level": 1,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Conjures 4 gallons of clean water per level in an open space or container. Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Dancing Lights",
|
||||||
|
"level": 0,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that creates up to four flickering torch-like lights you move as desired (concentration, 1 min/level). Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Darkness",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 20,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "All light in a 20-ft radius (spread from the touched point) becomes supernatural darkness; creatures inside lose visual sight-based advantages for 10 min/level. The engine does not model area concealment, so the burst carries no mechanical effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Daze",
|
||||||
|
"level": 0,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "dazed",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cantrip that clouds the mind of a humanoid creature with 5 or fewer HD, making it unable to act for 1 round. Will negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Deja Vu",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that lets you reroll one attack roll, saving throw, or skill check made in the past round (once per casting). Not modeled by the engine's action flow, so it carries no mechanical effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Delay Disease",
|
||||||
|
"level": 3,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You suppress the progression of one disease the subject carries for 1 hour/level, keeping it dormant. Utility spell, no combat-mechanical effect in the engine. Fortitude negates (harmless)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Delay Poison",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You temporarily stave off incoming poison or eliminate one already in the subject's system for 1 hour/level. Utility spell, no combat-mechanical effect in the engine. Fortitude negates (harmless)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Detect Fiendish Presence",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that reveals whether a creature of the outsider (evil) subtype has been in the area within 10 minutes/HD, and hints at its nature. Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Detect Magic",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that detects magical auras in a 60-ft cone (2 rounds to identify strength and school). Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Detect Poison",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip that determines whether a creature, object, or area is poisoned, venomous, or afflicted by acid. Utility spell, no combat effect."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Disrupt Undead",
|
||||||
|
"level": 0,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d6",
|
||||||
|
"types": ["force"],
|
||||||
|
"half_on_save": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cantrip: a line of crackling energy strikes one undead creature, dealing 1d6 points of damage (ranged touch attack, no save). The engine does not restrict the damage to undead targets."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Divine Favor",
|
||||||
|
"level": 1,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You draw upon divine power for 1 round/level: a +1 luck bonus on attack rolls and weapon damage per 4 caster levels. Simplified: the engine has no luck-bonus self-buff that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Doom",
|
||||||
|
"level": 1,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "shaken",
|
||||||
|
"duration_rounds": 10,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The target is paralyzed with fear and becomes shaken (-2 on attacks and saves; on a successful save it takes -1 instead, not modeled). Will negates. Duration 1 min/level approximated as 10 rounds."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Drunkard's Breath",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "For 1 hour/level you gain DR 5/- against alcohol effects and cannot become drunk. The engine has no DR buff target, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Endure Elements",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "For 24 hours you tolerate comfortable extremes of heat and cold (from -50 to 140 degrees F) without ill effect. Environmental protection, no combat-mechanical effect in the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Enhance Water",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You purify and bless 1 gallon/level of water (or one vial of holy/unholy water). Utility spell, no combat-mechanical effect in the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Enhanced Diplomacy",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: the subject gains a +2 competence bonus on a single Diplomacy or Intimidate check, declared before the roll (duration 1 minute or until discharged). Will negates (harmless). Social skill effect only: the engine does not model skill-check modifiers, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Face of the Devourer",
|
||||||
|
"level": 1,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "The target's face becomes hideous: it gains a +4 circumstance bonus on Intimidate checks and, if it lacks one, a bite attack (1d6 for Medium) for 1 min/level. Fortitude negates (harmless). The skill bonus and the granted natural attack are not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "Flurry of Snowballs",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "ref",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 20,
|
||||||
|
"save_for_half": true,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "4d6",
|
||||||
|
"types": ["cold"],
|
||||||
|
"half_on_save": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A flurry of snowballs hurtles at your foes: any creature in the area takes 4d6 points of cold damage. Reflex half. The RAW 30-ft cone-shaped burst is approximated as a 20-ft burst centered on the target point."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Forbid Action",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "dazed",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "You forbid the target a single course of action (attack, cast, communicate, draw, or move), which it avoids to the best of its ability for 1 round. Will negates. Simplification: the chosen-category restriction is approximated as dazed (the target loses its next turn); the specific forbidden action is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Grasp",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip cast as an immediate action when you fail a Climb check and would fall: you immediately retry the Climb check at a -2 penalty (increasing by 2 per successive use in the same situation); on success you don't fall. Climbing is not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Guidance",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: the subject gains a +1 competence bonus on a single attack roll, saving throw, or skill check, declared before the roll (duration 1 minute or until discharged). Will negates (harmless). Single-roll discharge is not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "Heroism",
|
||||||
|
"level": 2,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "attack", "value": 2, "bonus_type": "morale" },
|
||||||
|
{ "target": "fort", "value": 2, "bonus_type": "morale" },
|
||||||
|
{ "target": "ref", "value": 2, "bonus_type": "morale" },
|
||||||
|
{ "target": "will", "value": 2, "bonus_type": "morale" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The subject gains a +2 morale bonus on attack rolls, saving throws, and skill checks. Duration 10 min/level approximated as 10 rounds; the skill-check bonus has no engine-wide target and is not modeled. Will negates (harmless)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Hex Vulnerability",
|
||||||
|
"level": 1,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "The target becomes susceptible to a repeat use of your harmful hexes for 1 round/level, bypassing the once-per-day targeting limit. Will negates. No combat effect: the hex-reuse permission is outside the engine's model, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Hidden Diplomacy",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "As part of casting, you attempt a single Intimidate check to make the target act friendly; its memory of the threats is clouded, so its attitude does not worsen afterward. Will negates. Social effect only: no combat mechanics are modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Hide from Undead",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Undead cannot perceive warded creatures (nonintelligent undead ignore them automatically; intelligent undead get a single Will save) until the subject attacks, channels energy, or touches undead. Duration 10 min/level. Saving throw entries here cover the harmless-target save; the undead-perception effect is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "Ice Slick",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "ref",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 5,
|
||||||
|
"save_for_half": true,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d6",
|
||||||
|
"types": ["cold"],
|
||||||
|
"half_on_save": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "prone",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A blast of intense cold coats a 5-ft-radius burst in ice: creatures in the area take 1d6 points of cold damage (Reflex half) and fall prone (no prone on a successful save). The lingering slippery surface (half speed, Acrobatics checks) is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Ill Omen",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "The target is afflicted with bad luck: on its next d20 roll (one per 5 caster levels, up to five) it must roll twice and take the less favorable result; duration 1 round/level. No saving throw; spell resistance applies. The forced worst-of-two reroll mechanic is not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Inflict Light Wounds",
|
||||||
|
"level": 1,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d8+1",
|
||||||
|
"types": ["negative"],
|
||||||
|
"half_on_save": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Touching a creature channels negative energy, dealing 1d8 points of damage + 1 per caster level (maximum +5); at caster level 1 this is modeled as 1d8+1. Will half. Undead are instead cured of a like amount of damage - the engine only models the damaging side against living targets."
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "Ironskin",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "ac", "value": 4, "bonus_type": "natural" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Your skin hardens like iron: you gain a +4 enhancement bonus to your natural armor bonus (rising to +7 at caster level 15; the scaling is not modeled). Duration 1 min/level approximated as 60 rounds. The ability to dismiss the spell to negate one confirmed critical or sneak attack is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Light",
|
||||||
|
"level": 0,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: a touched object glows like a torch, shedding normal light in a 20-foot radius (plus dim light for 20 more feet) for 10 min/level. No combat effect; illumination is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Mage Hand",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: a spectral hand lifts and moves one unattended nonmagical object weighing up to 5 lb. from up to 25 ft. away, as far as 15 feet per move action while you concentrate. No combat effect; object manipulation is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Make Whole",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Repairs 1d6 points of damage per caster level (maximum 5d6) to one object or construct creature (10-minute casting). Will negates (harmless, object). Object/construct repair is outside the engine's combat model, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Masterwork Transformation",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "After 1 hour of casting (plus masterwork-priced reagents), a non-masterwork weapon, armor, shield, tool, or skill kit becomes its masterwork equivalent. Item crafting is outside the engine's combat model, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Mending",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: after 10 minutes, the spell repairs 1d4 hit points of damage to one object (up to 1 lb./level), removing the broken condition if restored to at least half HP. Will negates (harmless, object). Object repair is outside the engine's combat model, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Message",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you whisper messages and receive replies with targeted creatures within range for 10 min/level; bystanders hear nothing without a DC 25 Perception check. Communication is not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Mirror Image",
|
||||||
|
"level": 2,
|
||||||
|
"school": "illusion",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "blurred",
|
||||||
|
"duration_rounds": 10,
|
||||||
|
"save_negates": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Illusory doubles (1d4 + 1 per 3 caster levels, max 8) occupy your space, making attacks risk striking a figment instead. Duration 1 min/level approximated as 10 rounds. Simplification: the image-destruction mechanic is approximated as the blurred condition (20% miss chance); the real spell can deflect attacks entirely until the images are used up."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Oath of Anonymity",
|
||||||
|
"level": 0,
|
||||||
|
"school": "illusion",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you swear an oath of secrecy - your voice, body language and gear are magically distorted, granting a +10 bonus on Disguise checks to conceal your identity (not to impersonate a specific person) for 10 min/level. Social skill effect only: the engine does not model skill-check modifiers, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "Obscuring Mist",
|
||||||
|
"level": 1,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 20,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "blurred",
|
||||||
|
"duration_rounds": 10,
|
||||||
|
"save_negates": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A mist cloud spreads in a 20-ft radius from you for 1 min/level (approximated as 10 rounds): a creature 5 feet away has concealment (20% miss chance), farther away total concealment. Simplification: everyone in the area (allies included) gains the blurred 20% miss chance; the distance-scaled total concealment beyond 5 ft is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Open/Close",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you open or close one unsecured object or portal weighing up to 30 lb. at up to 25 ft. away (fails if a bar or lock resists). Will negates (object). Object manipulation is not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Owl's Wisdom",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "The subject gains a +4 enhancement bonus to Wisdom for 1 min/level, adding the usual benefit to Wisdom-based skills, Will saves and spell DCs. Will negates (harmless). Ability-score increases are not modeled by the engine, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Prestidigitation",
|
||||||
|
"level": 0,
|
||||||
|
"school": "universal",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: minor magical tricks for 1 hour - lift 1 lb. of material, color/clean/soil items in a 1-ft cube, chill/warm/flavor 1 lb. of nonliving material, or create crude trinkets. It can deal no damage and duplicates no other spell. No combat effect; the trivial manipulations are not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Protection from Evil",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A barrier wards the subject from evil for 1 min/level: +2 deflection bonus to AC and +2 resistance bonus on saves against attacks and effects created by evil creatures, renewed saves and suppression of mental control, and lawful summoned evil creatures cannot touch it. Will negates (harmless). The engine has no alignment system, so alignment-restricted bonuses cannot be modeled and the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Protection from Evil, Communal",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Functions like protection from evil (+2 deflection to AC and +2 resistance on saves vs evil creatures, protection from mental control), except the 1 min/level duration is divided in 1-minute intervals among the touched creatures. Will negates (harmless). Alignment-restricted bonuses and duration-sharing are not modeled, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Protection from Law",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A barrier wards the subject from lawful creatures for 1 min/level: +2 deflection bonus to AC and +2 resistance bonus on saves against attacks and effects created by lawful creatures, plus renewed saves against mental control by lawful creatures. Will negates (harmless). The engine has no alignment system, so alignment-restricted bonuses cannot be modeled and the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Protection from Law, Communal",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Functions like protection from law (+2 deflection to AC and +2 resistance on saves vs lawful creatures, protection from mental control), except the 1 min/level duration is divided in 1-minute intervals among the touched creatures. Will negates (harmless). Alignment-restricted bonuses and duration-sharing are not modeled, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Purify Food and Drink",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: cleanses 1 cu. ft./level of spoiled, rotten, diseased or poisoned food and water, making it pure and drinkable (no effect on creatures or magic potions). Will negates (object). Non-combat utility: the engine does not model objects, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Putrefy Food and Drink",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: instantly rots 1 cu. ft./level of edible food and makes water and liquids brackish and undrinkable (can also spoil a single potion; no effect on creatures or unholy water). Will negates (object). Non-combat utility: the engine does not model objects, so the spell has no mechanical effects here."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Ray of Enfeeblement",
|
||||||
|
"level": 1,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "close",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "fatigued",
|
||||||
|
"duration_rounds": 4,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A coruscating ray strikes the target (ranged touch attack), dealing 1d6 points of Strength damage +1 per two caster levels (maximum 1d6+5); a successful Fortitude save halves the damage. Simplification: the engine has no ability damage, so the Strength penalty is modeled as the fatigued condition (attack/damage penalties, no charge) for 4 rounds (1 round/level at caster level 4); Fortitude halves is approximated as Fortitude negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Ray of Frost",
|
||||||
|
"level": 0,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d3",
|
||||||
|
"types": ["cold"],
|
||||||
|
"half_on_save": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cantrip: a ray of freezing air and ice projects from your pointing finger. You must succeed on a ranged touch attack to deal 1d3 points of cold damage to the target. No save."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Read Magic",
|
||||||
|
"level": 0,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you can decipher magical inscriptions on objects that would otherwise be unintelligible, at one page per minute, and you can thereafter read that particular writing without the spell. Duration 10 min./level. No combat effect; reading magical writing is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Resistance",
|
||||||
|
"level": 0,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: the subject gains a +1 resistance bonus on saving throws for 1 minute. Will negates (harmless). Simplified: the engine has no resistance bonus type and no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Restoration, Lesser",
|
||||||
|
"level": 2,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Casting time 3 rounds. Dispels any magical effects reducing one of the subject's ability scores or cures 1d4 points of temporary ability damage to one ability score, and eliminates any fatigue (improving exhausted to fatigued). Will negates (harmless). No combat effect encoded: the engine has no ability damage, fatigue-from-spell, or magical-effect-reduction state to restore."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Sanctuary",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You ward a creature against attacks for 1 round/level: any opponent attempting to directly attack the warded creature must succeed on a Will save or be unable to follow through with that attack and cannot directly attack the subject for the duration. The subject cannot attack without ending the spell. Will negates. No combat effect encoded: the engine has no attack-refusal-by-save mechanic, so the protection cannot be represented."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Saving Finale",
|
||||||
|
"level": 1,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Immediate action, requires an active bardic performance: when a creature affected by your performance fails a saving throw, end the performance to let it immediately reroll the failed save and take the new result. Will negates (harmless). No combat effect encoded: conditional save rerolls tied to bardic performance are not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Scorching Ray",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "4d6",
|
||||||
|
"types": ["fire"],
|
||||||
|
"half_on_save": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "You blast your enemy with a searing beam of fire: each ray requires a ranged touch attack and deals 4d6 points of fire damage. You fire one ray, plus one additional ray per four levels beyond 3rd (max three at 11th) — the engine models a single ray. No save."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Shard of Chaos",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A dart-shaped projectile of chaotic energy (ranged touch attack): lawful creatures take 1d8 per two caster levels (max 5d8); lawful outsiders take 1d6 per caster level (max 10d6) and are slowed 1 round. A successful Will save halves the damage and negates the slow. Half damage to neutral creatures, no effect on chaotic ones. No combat effect encoded: the engine has no alignment, so the alignment-gated damage cannot be represented."
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "Shield",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "buff",
|
||||||
|
"modifiers": [
|
||||||
|
{ "target": "ac", "value": 4, "bonus_type": "deflection" }
|
||||||
|
],
|
||||||
|
"duration_rounds": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An invisible shield of force hovers in front of you, granting a +4 shield bonus to AC for 1 min./level (modeled as 10 rounds; the shield bonus type is approximated as deflection since the engine has no shield bonus type). Negating magic missile and the ranged-attack deflection are not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Shield of Faith",
|
||||||
|
"level": 1,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A shimmering magical field grants the target a +2 deflection bonus to AC (+1 per six caster levels, max +5) for 1 min./level. Will negates (harmless). Simplified: the engine has no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Shocking Grasp",
|
||||||
|
"level": 1,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d6",
|
||||||
|
"types": ["electricity"],
|
||||||
|
"half_on_save": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Your successful melee touch attack deals 1d6 points of electricity damage per caster level (maximum 5d6) — modeled at caster level 1 (1d6). No save; the +3 attack bonus against metal-armored foes is not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Silence",
|
||||||
|
"level": 2,
|
||||||
|
"school": "illusion",
|
||||||
|
"range": "long",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "Casting time 1 round. A 20-ft.-radius emanation centered on a creature, object, or point in space: all sound is stopped in the area, spells with verbal components cannot be cast, and creatures inside are immune to sonic and language-dependent effects. Duration 1 round/level. Will negates (object). No combat effect encoded: the engine has no verbal component or sound propagation model."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "Sleep",
|
||||||
|
"level": 1,
|
||||||
|
"school": "enchantment",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 10,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "asleep",
|
||||||
|
"duration_rounds": 10,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A magical slumber comes upon 4 HD of living creatures in a 10-ft.-radius burst (fewest HD first; the HD budget is not modeled). Sleeping creatures are helpless (modeled as the asleep condition, 1 min./level approximated as 10 rounds). Will negates. Constructs and undead are immune (not modeled)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "Sound Burst",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 10,
|
||||||
|
"save_for_half": true,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "damage",
|
||||||
|
"formula": "1d8",
|
||||||
|
"types": ["sonic"],
|
||||||
|
"half_on_save": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "stunned",
|
||||||
|
"duration_rounds": 1,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A tremendous cacophony blasts a 10-ft.-radius spread: every creature in the area takes 1d8 points of sonic damage and must succeed on a Fortitude save or be stunned for 1 round (Fortitude partial — modeled as save for half damage and negates the stun). Creatures that cannot hear take the damage but are not stunned (not modeled)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Spark",
|
||||||
|
"level": 0,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you create a tiny spark that ignites one unattended Fine flammable object within close range, in any weather (works as flint and steel but much faster). Fortitude negates (object). No combat effect: the spell targets objects, not creatures."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Spear of Purity",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A spear of good energy (ranged touch attack): evil creatures take 1d8 per two caster levels (max 5d8); evil outsiders take 1d6 per caster level (max 10d6) and are blinded 1 round. A successful Will save halves the damage and negates the blind. Half damage to neutral creatures, no effect on good ones. No combat effect encoded: the engine has no alignment, so the alignment-gated damage cannot be represented."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Spiritual Weapon",
|
||||||
|
"level": 2,
|
||||||
|
"school": "evocation",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A force weapon appears and attacks foes at a distance as you direct it (1d8 force damage +1 per three caster levels), using your base attack bonus plus Wisdom modifier, once per round on your turn for 1 round/level. No combat effect encoded: the engine has no autonomous floating-attack creature to summon, and the weapon's per-round attacks are not modeled."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Stabilize",
|
||||||
|
"level": 0,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: you touch a living creature with -1 or fewer hit points (up to close range) and stabilize it automatically, so it stops losing hit points until it takes more damage. Will negates (harmless). No combat effect encoded: the engine's dying/stabilization track is not exposed to the spell-effect system."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Status",
|
||||||
|
"level": 2,
|
||||||
|
"school": "divination",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You mentally monitor the relative position and general condition (unharmed, wounded, staggered, unconscious, dying, poisoned, and so on) of up to one creature per three caster levels for 1 hour/level. Will negates (harmless). No combat effect: out-of-combat scrying is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Stave Off Corruption",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You ward the target to slow the advancement of its corruption, granting a +2 circumstance bonus on saving throws against the advancement of that corruption for 1 day per 2 caster levels. Will negates (harmless). Simplified: the engine has no corruption track and no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Summon Instrument",
|
||||||
|
"level": 0,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip (casting time 1 round): you summon one handheld musical instrument of your choice into your hands or at your feet; it plays only for you and disappears when the spell ends (1 min./level). No combat effect: summoned objects are not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "Summon Monster I",
|
||||||
|
"level": 1,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "summon",
|
||||||
|
"creature": "data/monsters/celestial_wolf.json",
|
||||||
|
"duration_rounds": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Casting time 1 round: summons one extraplanar creature from the 1st-level list (e.g. dire rat, dog, eagle) to fight for you for 1 round/level. Simplified: the engine bestiary holds no 1st-level summon, so the celestial wolf model is reused and the duration is set to 4 rounds (1 round/level at caster level 4)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Suppress Charms and Compulsions",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You bolster the target's willpower: either a +4 morale bonus on saving throws against charm and compulsion effects for 10 minutes, or (as concentration, max 1 round/level) suppression of all charm and compulsion effects on the targets. Will negates (harmless). Simplified: the engine has no conditional save bonus and no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Surmount Affliction",
|
||||||
|
"level": 2,
|
||||||
|
"school": "abjuration",
|
||||||
|
"range": "personal",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You temporarily overcome one harmful condition on yourself (blinded, confused, dazed, dazzled, deafened, fatigued, frightened, paralyzed, shaken, or sickened) for 1 round/level — the condition's effect is suspended, not ended. No combat effect encoded: the engine has no condition-suspension mechanic."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Tears to Wine",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "close",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "You transmute up to 1 cubic foot of nonmagical liquid per two caster levels (including spoiled, poisoned, or contaminated drink, tears, seawater) into mead or wine of average quality for 10 min./level (RAW range 10 ft., approximated as close). Will negates (object). No combat effect: liquid transmutation is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Touch of Fatigue",
|
||||||
|
"level": 0,
|
||||||
|
"school": "necromancy",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "fort",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "fatigued",
|
||||||
|
"duration_rounds": 4,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A cantrip: a melee touch attack channels negative energy, making the target fatigued for 1 round/level (modeled as 4 rounds at caster level 4; the effect ends with the duration rather than by long rest). No effect on an already fatigued creature or on creatures immune to fatigue. Fortitude negates."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Unseen Servant",
|
||||||
|
"level": 1,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "close",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "An invisible, mindless, shapeless force performs simple tasks at your command for 1 hour/level: fetching, opening unstuck doors, holding chairs, cleaning or mending (effective Strength 2, speed 15 ft., no attacks, DC 10 skill limit). No combat effect: object manipulation by invisible servants is not modeled by the engine."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Vanish",
|
||||||
|
"level": 1,
|
||||||
|
"school": "illusion",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "invisible",
|
||||||
|
"duration_rounds": 5,
|
||||||
|
"save_negates": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "As invisibility, but only for 1 round/level (maximum 5 rounds) — the spell ends if the subject attacks. Will negates (harmless) — modeled as always accepted by the target. Modeled as the invisible condition (total concealment for the target; the attack-ends-spell rule is not modeled)."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Virtue",
|
||||||
|
"level": 0,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "none",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "A cantrip: with a touch you infuse a creature with a tiny surge of life, granting it 1 temporary hit point for 1 minute. Spell resistance yes (harmless). Simplified: the engine has no temporary hit points and no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Weapon of Awe",
|
||||||
|
"level": 2,
|
||||||
|
"school": "transmutation",
|
||||||
|
"range": "touch",
|
||||||
|
"save": "will",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [],
|
||||||
|
"description": "The touched weapon becomes an awe-inspiring instrument for 1 min./level: it gains a +2 sacred bonus on damage rolls, and a creature struck by a critical hit from it becomes shaken for 1 round (a mind-affecting fear effect). Will negates (harmless, object). Simplified: the engine has no weapon-targeted buff track and no self-buff encoding that preserves the pinned default-policy casting order, so no mechanical effect is applied."
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "Web",
|
||||||
|
"level": 2,
|
||||||
|
"school": "conjuration",
|
||||||
|
"range": "medium",
|
||||||
|
"save": "ref",
|
||||||
|
"base_dc": 10,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"radius_ft": 20,
|
||||||
|
"save_for_half": false,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"type": "condition",
|
||||||
|
"condition_name": "grappled",
|
||||||
|
"duration_rounds": 2,
|
||||||
|
"save_negates": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "You conjure a many-layered mass of sticky strands filling a 20-ft.-radius spread (modeled as a 20-ft. burst). Creatures caught in the area are grappled by the fibers (Reflex negates) until they break free; the web also makes the area difficult terrain and provides cover (not modeled). Duration 10 min./level approximated as 2 rounds of the grappled condition."
|
||||||
|
}
|
||||||
+2154
-162
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,7 @@ class Condition:
|
|||||||
cant_aoo: bool = False
|
cant_aoo: bool = False
|
||||||
must_flee: bool = False
|
must_flee: bool = False
|
||||||
speed_mult: float = 1.0
|
speed_mult: float = 1.0
|
||||||
|
miss_chance: int = 0
|
||||||
|
|
||||||
|
|
||||||
# ── Fear conditions ──────────────────────────────────────────────────────────
|
# ── Fear conditions ──────────────────────────────────────────────────────────
|
||||||
@@ -142,12 +143,15 @@ DAZZLED = Condition(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Blinded: -2 AC, loses Dex, -4 STR/DEX skill checks (CRB)
|
# Blinded: -2 AC, loses Dex, -4 Dexterity skill checks; NO flat attack
|
||||||
|
# penalty (the -2 was a non-RAW double penalty on top of the engine's
|
||||||
|
# modeled 50% total-concealment miss). The Str-skill half of the -4 is not
|
||||||
|
# modeled (no str_skills target). (CRB)
|
||||||
BLINDED = Condition(
|
BLINDED = Condition(
|
||||||
name="blinded",
|
name="blinded",
|
||||||
modifiers=(
|
modifiers=(
|
||||||
StatModifier(target="ac", value=-2),
|
StatModifier(target="ac", value=-2),
|
||||||
StatModifier(target="attack", value=-2),
|
StatModifier(target="dex_skills", value=-4),
|
||||||
),
|
),
|
||||||
denies_dex_to_ac=True,
|
denies_dex_to_ac=True,
|
||||||
)
|
)
|
||||||
@@ -204,18 +208,34 @@ DAZED = Condition(
|
|||||||
cant_act=True,
|
cant_act=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Asleep/Unconscious: helpless, can't act, -4 AC vs melee, no Dex to AC (CRB)
|
# Asleep/Unconscious: helpless (CRB) — can't act, no Dex to AC. The old flat
|
||||||
|
# -4 AC approximation is superseded by the engine's Dex-0 (-5) adjustment for
|
||||||
|
# helpless targets, applied in resolve_attack (CombatEngine._is_helpless).
|
||||||
ASLEEP = Condition(
|
ASLEEP = Condition(
|
||||||
name="asleep",
|
name="asleep",
|
||||||
modifiers=(
|
|
||||||
StatModifier(target="ac", value=-4),
|
|
||||||
),
|
|
||||||
denies_dex_to_ac=True,
|
denies_dex_to_ac=True,
|
||||||
cant_act=True,
|
cant_act=True,
|
||||||
cant_move=True,
|
cant_move=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Helpless: helpless for all intents, treated as Dex 0 (loses Dex to AC),
|
||||||
|
# can't act; melee attackers gain +4 (engine logic in resolve_attack). The
|
||||||
|
# engine also treats paralyzed/asleep/unconscious as helpless (CRB: "helpless"
|
||||||
|
# = paralyzed, held, bound, sleeping, unconscious; stunned is NOT helpless) —
|
||||||
|
# see CombatEngine._is_helpless (CRB)
|
||||||
|
HELPLESS = Condition(
|
||||||
|
name="helpless",
|
||||||
|
denies_dex_to_ac=True,
|
||||||
|
cant_act=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fascinated: distracted, takes no actions other than paying attention (CRB)
|
||||||
|
FASCINATED = Condition(
|
||||||
|
name="fascinated",
|
||||||
|
cant_act=True,
|
||||||
|
)
|
||||||
|
|
||||||
# Grappled: -4 Dex, -2 attack, no movement, no AoO, can't cast without concentration (CRB)
|
# Grappled: -4 Dex, -2 attack, no movement, no AoO, can't cast without concentration (CRB)
|
||||||
GRAPPLED = Condition(
|
GRAPPLED = Condition(
|
||||||
name="grappled",
|
name="grappled",
|
||||||
@@ -253,6 +273,42 @@ STAGGERED = Condition(
|
|||||||
name="staggered",
|
name="staggered",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ── Concealment conditions ───────────────────────────────────────────────────
|
||||||
|
# Blurred (blur spell): concealment — 20% miss chance on attacks (CRB)
|
||||||
|
BLURRED = Condition(
|
||||||
|
name="blurred",
|
||||||
|
miss_chance=20,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Displaced (displacement spell): total concealment — 50% miss chance (CRB)
|
||||||
|
DISPLACED = Condition(
|
||||||
|
name="displaced",
|
||||||
|
miss_chance=50,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Invisible: total concealment against attacks targeting it; the attacker-side
|
||||||
|
# +2 on attack rolls and the target's lost Dex bonus are engine logic (CRB)
|
||||||
|
INVISIBLE = Condition(
|
||||||
|
name="invisible",
|
||||||
|
miss_chance=50,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── Damage-over-time and mental conditions ───────────────────────────────────
|
||||||
|
# Bleeding: takes the listed bleed damage at the beginning of its turn (CRB).
|
||||||
|
# The damage-over-time is engine-driven (CombatantState.bleed_damage); the
|
||||||
|
# condition itself carries no stat modifiers or behavioral flags.
|
||||||
|
BLEEDING = Condition(
|
||||||
|
name="bleeding",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Confused: at the beginning of each turn the subject rolls d% to act randomly
|
||||||
|
# (CRB). The d% behavior is engine logic in ``_take_turn``; simplification:
|
||||||
|
# the "if attacked, attack the attacker" clause is reduced to "nearest
|
||||||
|
# creature". No stat modifiers or behavioral flags.
|
||||||
|
CONFUSED = Condition(
|
||||||
|
name="confused",
|
||||||
|
)
|
||||||
|
|
||||||
# ── Registry ─────────────────────────────────────────────────────────────────
|
# ── Registry ─────────────────────────────────────────────────────────────────
|
||||||
CONDITIONS_BY_NAME: dict[str, Condition] = {
|
CONDITIONS_BY_NAME: dict[str, Condition] = {
|
||||||
c.name: c
|
c.name: c
|
||||||
@@ -260,6 +316,7 @@ CONDITIONS_BY_NAME: dict[str, Condition] = {
|
|||||||
SHAKEN, SICKENED, FATIGUED, EXHAUSTED, ENTANGLED, DAZZLED,
|
SHAKEN, SICKENED, FATIGUED, EXHAUSTED, ENTANGLED, DAZZLED,
|
||||||
BLINDED, DEAFENED, FLAT_FOOTED, PRONE, STUNNED, PARALYZED,
|
BLINDED, DEAFENED, FLAT_FOOTED, PRONE, STUNNED, PARALYZED,
|
||||||
NAUSEATED, DAZED, STAGGERED, FRIGHTENED, PANICKED, COWERING,
|
NAUSEATED, DAZED, STAGGERED, FRIGHTENED, PANICKED, COWERING,
|
||||||
ASLEEP, GRAPPLED, PINNED,
|
ASLEEP, GRAPPLED, PINNED, BLURRED, DISPLACED,
|
||||||
|
HELPLESS, FASCINATED, INVISIBLE, BLEEDING, CONFUSED,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+100
-1
@@ -21,6 +21,8 @@ if TYPE_CHECKING:
|
|||||||
Pt = tuple[int, int] # lattice point (x, y) = (col, row)
|
Pt = tuple[int, int] # lattice point (x, y) = (col, row)
|
||||||
_Rat = tuple[int, int] # exact rational as (numerator, denominator), den > 0
|
_Rat = tuple[int, int] # exact rational as (numerator, denominator), den > 0
|
||||||
|
|
||||||
|
_STANDARD_COVER_BONUS = 4 # PF1e: standard cover, and soft cover from a creature
|
||||||
|
|
||||||
|
|
||||||
def _corners(pos: Pos) -> tuple[Pt, Pt, Pt, Pt]:
|
def _corners(pos: Pos) -> tuple[Pt, Pt, Pt, Pt]:
|
||||||
row, col = pos
|
row, col = pos
|
||||||
@@ -75,11 +77,13 @@ class _LineGrid:
|
|||||||
exclude: frozenset[Pos],
|
exclude: frozenset[Pos],
|
||||||
blocking: Callable[[TerrainType], bool],
|
blocking: Callable[[TerrainType], bool],
|
||||||
occupied: frozenset[Pos] = frozenset(),
|
occupied: frozenset[Pos] = frozenset(),
|
||||||
|
bonus_of: Callable[[TerrainType], int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self._grid = grid
|
self._grid = grid
|
||||||
self._exclude = exclude
|
self._exclude = exclude
|
||||||
self._blocking = blocking
|
self._blocking = blocking
|
||||||
self._occupied = occupied
|
self._occupied = occupied
|
||||||
|
self._bonus_of = bonus_of
|
||||||
|
|
||||||
def blocked(self, p1: Pt, p2: Pt) -> bool:
|
def blocked(self, p1: Pt, p2: Pt) -> bool:
|
||||||
min_x = min(p1[0], p2[0])
|
min_x = min(p1[0], p2[0])
|
||||||
@@ -97,9 +101,49 @@ class _LineGrid:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def bonus(self, p1: Pt, p2: Pt) -> int:
|
||||||
|
"""Highest cover bonus among the blocking cells the segment p1->p2 hits.
|
||||||
|
|
||||||
|
0 when the segment crosses no blocking cell (or when this view was
|
||||||
|
built without a bonus function, i.e. for plain line-of-effect).
|
||||||
|
Occupied cells always grant soft cover (+4, CRB).
|
||||||
|
"""
|
||||||
|
if self._bonus_of is None:
|
||||||
|
return 0
|
||||||
|
min_x = min(p1[0], p2[0])
|
||||||
|
max_x = max(p1[0], p2[0])
|
||||||
|
min_y = min(p1[1], p2[1])
|
||||||
|
max_y = max(p1[1], p2[1])
|
||||||
|
best = 0
|
||||||
|
for col in range(min_x - 1, max_x + 1):
|
||||||
|
for row in range(min_y - 1, max_y + 1):
|
||||||
|
pos = (row, col)
|
||||||
|
if pos in self._exclude or not self._grid.in_bounds(pos):
|
||||||
|
continue
|
||||||
|
terrain = self._grid.terrain_at(pos)
|
||||||
|
is_occupied = pos in self._occupied
|
||||||
|
if not (is_occupied or self._blocking(terrain)):
|
||||||
|
continue
|
||||||
|
if not _segment_hits_cell(p1, p2, row, col):
|
||||||
|
continue
|
||||||
|
value = self._bonus_of(terrain)
|
||||||
|
if is_occupied:
|
||||||
|
value = max(value, _STANDARD_COVER_BONUS)
|
||||||
|
best = max(best, value)
|
||||||
|
return best
|
||||||
|
|
||||||
|
|
||||||
|
def terrain_cover_bonus(terrain: TerrainType) -> int:
|
||||||
|
"""Cover bonus a terrain square grants: its level, else legacy +4 for cover."""
|
||||||
|
if terrain.cover_bonus > 0:
|
||||||
|
return terrain.cover_bonus
|
||||||
|
if terrain.cover or terrain.blocks_los:
|
||||||
|
return _STANDARD_COVER_BONUS
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _grants_cover(terrain: TerrainType) -> bool:
|
def _grants_cover(terrain: TerrainType) -> bool:
|
||||||
return terrain.cover or terrain.blocks_los
|
return terrain_cover_bonus(terrain) > 0
|
||||||
|
|
||||||
|
|
||||||
def has_line_of_effect(grid: Grid, a: Pos, b: Pos) -> bool:
|
def has_line_of_effect(grid: Grid, a: Pos, b: Pos) -> bool:
|
||||||
@@ -179,3 +223,58 @@ def has_cover_cells(
|
|||||||
for cell_a in attacker_cells
|
for cell_a in attacker_cells
|
||||||
for corner_a in _corners(cell_a)
|
for corner_a in _corners(cell_a)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def cover_bonus(
|
||||||
|
grid: Grid,
|
||||||
|
attacker: Pos,
|
||||||
|
target: Pos,
|
||||||
|
*,
|
||||||
|
ranged: bool,
|
||||||
|
occupied: frozenset[Pos] = frozenset(),
|
||||||
|
) -> int:
|
||||||
|
"""Effective cover bonus (0/2/4/8) for an attack between two single cells."""
|
||||||
|
return cover_bonus_cells(
|
||||||
|
grid,
|
||||||
|
frozenset({attacker}),
|
||||||
|
frozenset({target}),
|
||||||
|
ranged=ranged,
|
||||||
|
occupied=occupied,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def cover_bonus_cells(
|
||||||
|
grid: Grid,
|
||||||
|
attacker_cells: frozenset[Pos],
|
||||||
|
target_cells: frozenset[Pos],
|
||||||
|
*,
|
||||||
|
ranged: bool,
|
||||||
|
occupied: frozenset[Pos] = frozenset(),
|
||||||
|
) -> int:
|
||||||
|
"""Effective cover bonus (0/2/4/8) for an attack between two sets of cells.
|
||||||
|
|
||||||
|
0 when there is no cover (see has_cover_cells for the corner rule);
|
||||||
|
otherwise the highest cover level among the cells blocking the
|
||||||
|
attacker-corner to target-corner lines. Interposed creatures grant soft
|
||||||
|
cover (+4) on ranged attacks only, exactly as in has_cover_cells.
|
||||||
|
"""
|
||||||
|
if not attacker_cells or not target_cells:
|
||||||
|
return 0
|
||||||
|
if not has_cover_cells(
|
||||||
|
grid, attacker_cells, target_cells, ranged=ranged, occupied=occupied
|
||||||
|
):
|
||||||
|
return 0
|
||||||
|
lines = _LineGrid(
|
||||||
|
grid,
|
||||||
|
attacker_cells | target_cells,
|
||||||
|
_grants_cover,
|
||||||
|
occupied if ranged else frozenset(),
|
||||||
|
bonus_of=terrain_cover_bonus,
|
||||||
|
)
|
||||||
|
return max(
|
||||||
|
lines.bonus(corner_a, corner_t)
|
||||||
|
for cell_a in attacker_cells
|
||||||
|
for corner_a in _corners(cell_a)
|
||||||
|
for cell_t in target_cells
|
||||||
|
for corner_t in _corners(cell_t)
|
||||||
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user