fix(rules): make the run reachability check avoid difficult terrain

PF1e (CRB Movement): "You can't run or charge across difficult
terrain". _execute_run checked the explicit destination against the full
cost field (which routes through difficult terrain at 2x) but descended
with avoid_difficult=True, so a destination beyond rubble was accepted
(ok=True) yet silently truncated at the obstacle. _destination_reachable
now takes the same avoid_difficult constraint (difficult cells removed
from the field; a destination whose footprint touches difficult terrain is
not a legal run endpoint either), so verdict and path agree. The test that
pinned the old silent-stop-short convention now expects
unreachable_destination; README updated.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-12 11:53:27 +02:00
parent 8043dd393c
commit e3818fa6c9
3 changed files with 57 additions and 13 deletions
+6 -2
View File
@@ -737,11 +737,15 @@ Règles modélisées :
(mécanisme `avoid_difficult` de `_descend_path`, symétrique du refus de la
charge dans `_charge_path_clear`) ; le combattant **avance jusqu'à
l'obstacle et s'y arrête** (comportement déterministe, retenu plutôt que
le rejet de l'action). À l'achèvement, le combattant est `running` jusqu'au
le rejet de l'action) **quand la course est auto-dirigée**. À 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
(`unreachable_destination`) ; une `destination` joignable uniquement en
traversant le terrain difficile est **aussi rejetée** — le test de
portée (`_destination_reachable`) applique la même contrainte
`avoid_difficult` que la descente, donc le verdict et le chemin parcouru
sont cohérents (pas d'arrêt silencieux avant la 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