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
- New Action kind 'full_attack': manufactured weapons (count=1) gain BAB
iteratives at +6/+11/+16 (-5/-10/-15 from attack bonus, capped at 4);
natural weapons (count>1) delegate to _attack (no iteratives).
- Extracted _resolve_swing from _attack: one swing, log, stats, target-down
check. Both _attack and _full_attack use it. AttackResult gains base_bonus
field so the transcript shows the actual bonus used per iterative.
- default_policy now returns full_attack instead of attack when in range.
Non-breaking for BAB < 6 (single swing, identical transcript).
- Refactored round_no to self._current_round instance variable, removing it
from 6 method signatures and fixing PLR0913 on _resolve_swing.
- 4 new tests: BAB+6 two iteratives, BAB+11 three iteratives, target drops
mid-full-attack, BAB<6 single swing. README and docstring updated; test
count 202 -> 206.
- _flanking_bonus checks for an active same-side ally with a melee weapon
at the position diametrically opposite the attacker through the target.
- +2 applies to melee attack rolls and crit-confirm rolls; ranged attacks
ignore flanking; allies without melee weapons don't threaten.
- AttackResult gains flank_bonus field; transcript shows '+2(flank)' when
active.
- 6 new tests: opposite ally grants +2, no ally = no bonus, ranged ignores
flanking, diagonal flanking, downed ally doesn't flank, enemy on opposite
side doesn't flank.
- README and module docstring updated; test count 196 -> 202.
- default_policy returns (move, attack) when target out of reach: full-speed
move along the Dijkstra path (up to speed cells, 5-10-5 diagonals, stops
adjacent to nearest enemy), then attack if a weapon is usable; returns
(attack,) when already in range.
- _move logs the full path in one line (start)->(step1)->...->(end); silent
on empty path. _execute is silent on invalid attacks/moves (no spurious
wait log); run() adds a wait line only when a combatant's turn produced
no transcript line.
- Extract _take_turn helper from run() to keep cyclomatic complexity <= 10.
- Module docstring updated for activated economy.
- 4 pinned transcripts regenerated (move-then-attack shifts combat pacing):
test_default_policy_moves_toward_enemy, test_scripted_2v2_transcript
(monsters win in R2 instead of R3 — orc-2 moves + attacks same turn),
test_ranged_no_line_of_effect_moves_around_wall (archer rounds wall and
shoots in 1 turn), test_ranged_weapon_unusable_beyond_maximum_range
(archer moves 6 cells then attacks at -14 penalty).
- README: demo numbers refreshed (1v2: 49.6%->22.0%, 11.4->5.2 rounds;
3v2: 97.8%->91.4%, 6.9->6.0 rounds), rules and non-modeled sections
updated for the activated economy.
A weapon with count>1 ('2x Talons') now resolves one independent attack
roll per swing in the same attack action (label '#N'), aggregating stats
per swing. Remaining swings are lost if the target drops mid-routine.
BAB iterative attacks remain out of Phase 0 scope.
All 8 sheets from fiches_personnages/ converted to the strict Combatant
JSON schema (data/monsters convention) so the CLI can run PCs directly:
--side players data/pcs/esha.json
- id derived from the file stem; source field points at the original sheet
- oni: placeholder attacks without encoded damage ('une Pioche', 'Weapon')
left out, documented in notes (pick stats ambiguous light/heavy in the
rules KB; no identification possible for 'Weapon')
- README: PC section now documents data/pcs usage
- tests: parametrized load check + golden spots for the 8 PC files