feat(rules): add the surprise round
SRD Surprise: when some but not all combatants are aware of their opponents, a surprise round precedes round 1. Aware combatants take a single standard OR move action plus free actions (swift and full-round are dropped, full_attack collapses to one standard attack, withdraw survives as the Restricted Withdraw standard); unaware combatants skip their turn. New Combatant.aware flag (default true, parsed at the JSON boundary) keeps every existing encounter bit-identical, exposed in the observation snapshot. Unaware combatants are not flagged flat-footed (documented simplification). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -364,6 +364,26 @@ Règles modélisées :
|
||||
appliqué.
|
||||
- `hp < 0` = inactive (mourante ou morte) ; `hp = 0` = active mais invalide.
|
||||
- Initiative : triée sur (total, modificateur, ordre de liste), sans re-jet.
|
||||
- Round de surprise (SRD « Surprise ») : le champ booléen `aware` du JSON de
|
||||
combattant (défaut `true`) encode la conscience des adversaires au début du
|
||||
combat. Si certains combattants actifs sont `aware` et d'autres non, un
|
||||
round de surprise (round 0) précède le round 1 : « In initiative order
|
||||
(highest to lowest), combatants who started the battle aware of their
|
||||
opponents each take a standard or move action during the surprise round.
|
||||
You can also take free actions during the surprise round. » Le filtre
|
||||
`_surprise_filter` applique cette allowance : une seule action standard
|
||||
**ou** de mouvement (la première de la séquence gagne), les actions libres
|
||||
conservées, les actions swift et à round complet retirées
|
||||
(`downgraded:surprise`) ; un `full_attack` se dégrade en attaque standard
|
||||
unique (même convention que le filtre accablé) et `withdraw` survit comme
|
||||
retraite restreinte standard (SRD « Full-Round Actions »). « Combatants who
|
||||
are unaware at the start of battle don't get to act in the surprise round »
|
||||
— les non-`aware` sautent leur tour (journalisé). « If no one or everyone is
|
||||
surprised, no surprise round occurs » — avec le défaut `aware: true`, le
|
||||
comportement est bit-identique à l'absence de la règle. Simplification
|
||||
documentée : les combattants non avertis ne sont pas marqués `flat_footed`
|
||||
pendant le round de surprise (le moteur n'injecte jamais cette condition
|
||||
lui-même — voir « Actions immédiates »).
|
||||
- Économie d'action : un tour normal donne une action standard + une action de
|
||||
mouvement (ou une action à round complet), plus swift/free/immediate. La
|
||||
politique renvoie une séquence ordonnée d'actions exécutées dans l'ordre ;
|
||||
@@ -1321,7 +1341,8 @@ Règles modélisées :
|
||||
- Par combattant : id, side, pos, occupied_cells, hp/hp_max, active/dead,
|
||||
dying/stabilized, conditions (noms + rounds_left), resources_left (+ `spell_slot_{level}`),
|
||||
weapon_broken/weapon_stolen, grappled_with, moved_this_turn, power_attack,
|
||||
name, level, size, dr {amount, bypass} ou None (C1), creature_type (C3),
|
||||
name, level, size, aware (SRD « Surprise » : agit au round de surprise),
|
||||
dr {amount, bypass} ou None (C1), creature_type (C3),
|
||||
bab (E1), initiative_mod (E2) et initiative_total (U2 : total du jet
|
||||
d'initiative courant = d20 + mod, 0 si pas encore de clé — invocation
|
||||
fraîche), casting_ability ou None pour non-jeteur
|
||||
@@ -1432,9 +1453,6 @@ la lecture mais non appliquée dans la résolution.
|
||||
Limites hors périmètre (arrêtées lors de la conformance L1-L10, documentées
|
||||
plutôt que bricolées) :
|
||||
|
||||
- **Pas de round de surprise** : le modèle de combattant n'a pas de champ de
|
||||
perception/attention (conscience du combat), donc le SRD « Surprise » ne
|
||||
peut pas être résolu — le combat démarre toujours au round 1 complet.
|
||||
- **Incantation `one_round` bornée à un round complet** : le moteur ne tient
|
||||
pas d'incantation en cours entre les tours ; un sort d'1 round se résout à
|
||||
la fin du tour courant au lieu du suivant (approximation documentée dans
|
||||
@@ -1561,7 +1579,7 @@ Limites de sorts (conformance D6-D9, documentées plutôt que bricolées) :
|
||||
La gate de validation complète (tests + lint + types) :
|
||||
|
||||
```bash
|
||||
uv run pytest -q # 1393 tests
|
||||
uv run pytest -q # 1402 tests
|
||||
uv run ruff check src tests
|
||||
uv run basedpyright src # mode strict
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user