Power Attack is the first active feat: a free-action toggle declared at
turn start. When state.power_attack is True and the combatant has the
POWER_ATTACK feature, melee attacks apply -X to the attack roll and
+2X to damage, where X = BAB//4 + 1 (min 1). Ranged attacks are
unaffected. The flag is cleared at the start of each turn via
_take_turn, like other per-turn state.
- abilities.py: POWER_ATTACK constant (AbilitySpec, no passive effects)
- combat.py: _has_feat helper, _power_attack_amt, resolve_attack
applies penalty to attack total + crit confirm, bonus to damage
- tests/test_power_attack.py: 14 tests (amount at BAB 1/4/8/12, flag
false, feat missing, attack penalty, damage bonus, ranged unaffected,
flag cleared on turn)
- pyproject.toml: add SLF001 + RUF059 to test per-file-ignores (white-box
testing accesses private helpers, partial tuple unpacking)
- README.md: document Power Attack in abilities.py section, 307 tests
Adds the S6 layer on top of the deterministic combat engine:
- metrics.py: closed-form binomial statistics (win rate, standard error,
3-sigma confidence band) with clamped degenerate proportions.
- runner.py: EncounterSpec/Side definitions, per-run SeededRng streams,
global duplicate-id disambiguation, attrition averages per combatant.
- cli.py: pf1e-sim entry point producing a French balance report with
win rates, 3-sigma bands, draws, rounds, and attrition.
- Movement fix: greedy straight-line heuristic could oscillate at walls;
_step_toward now follows the true shortest path via an unbounded
Dijkstra cost field from the target (Grid.reachable budget=None).
- Regression tests: melee unit routes around a wall and engages; grid
unbounded-budget coverage.