fix(rules): a blinded creature cannot charge, run, or withdraw (SRD charge.md: 'If you don't have line of sight to the opponent at the start of your turn, you can't charge that opponent'; full-round-actions.md: 'You can't run ... if you can't see where you're going' and 'you can't withdraw from combat if you're blinded') - can_charge gates blinded with no_line_of_effect, _execute_run joins the cant_charge no-op, _withdraw rejects blinded

This commit is contained in:
2026-09-19 16:24:31 +02:00
parent 792cec140b
commit 778d6a8620
2 changed files with 143 additions and 2 deletions
+22 -2
View File
@@ -3904,6 +3904,11 @@ class CombatEngine:
straight-line distance in feet to the chosen anchor on success, 0 on
failure. Never mutates state nor consumes RNG.
"""
if self._has_condition_named(state, "blinded"):
# SRD "Charge" (charge.md): "If you don't have line of sight to
# the opponent at the start of your turn, you can't charge that
# opponent." A blinded creature has line of sight to nothing.
return ChargeResult(weapon=None, distance_ft=0, reason="no_line_of_effect")
if not has_line_of_effect_cells(
self._grid, state.occupied_cells(), target.occupied_cells()
):
@@ -4444,8 +4449,13 @@ class CombatEngine:
self._log(f"round {self._current_round} {state.combatant.id}: wait (cannot move)")
return ActionResult(kind=kind, ok=True, reason=_REASON_OK)
# SRD "Conditions — Fatigued": "A fatigued character can neither run
# nor charge" (same for exhausted/entangled via cant_charge).
if self.has_condition_flag(state, "cant_charge"):
# nor charge" (same for exhausted/entangled via cant_charge). SRD
# "Full-Round Actions — Run" (full-round-actions.md): "You can't run
# across difficult terrain or if you can't see where you're going" —
# a blinded creature sees nowhere.
if self.has_condition_flag(state, "cant_charge") or self._has_condition_named(
state, "blinded"
):
self._log(f"round {self._current_round} {state.combatant.id}: wait (cannot run)")
return ActionResult(kind=kind, ok=True, reason=_REASON_OK)
if action.destination is not None:
@@ -8146,11 +8156,21 @@ class CombatEngine:
Subsequent squares provoke AoOs normally (step-by-step, as for move).
Like every other movement it is mutually exclusive with movement
already spent this turn (``moved_this_turn``).
SRD "Full-Round Actions — Withdraw" (full-round-actions.md): "you
can't withdraw from combat if you're blinded" — a blinded creature
cannot even take the restricted (standard-action) withdraw.
"""
if state.moved_this_turn:
return
if threat is None:
return
if self._has_condition_named(state, "blinded"):
self._log(
f"round {self._current_round} {state.combatant.id}: "
f"withdraw rejected (blinded)"
)
return
path = self._flee_path(state, threat)
if not path:
return