fix(rules): use the attacker's best corner for cover bonus

SRD 'Cover': 'To determine whether your target has cover from your ranged attack, choose a corner of your square.' The ranged scorer in cover_bonus_cells took the MAX over all attacker corners (worst corner); the cover gate has_cover_cells and RAW use the attacker's best corner. Ranged cells are now scored min over attacker corners of (max over target-corner lines), then min over attacker cells - the bonus can no longer exceed what the gate admits. Melee keeps the worst-corner rule ('any line from ANY corner of your square'). Updated the two pins that locked the old worst-corner scores.

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 14:57:56 +02:00
parent a989266747
commit 5bf2850e2f
3 changed files with 45 additions and 25 deletions
+9 -6
View File
@@ -43,11 +43,13 @@ def test_two_cell_attacker_uses_best_cell_cover() -> None:
top = frozenset({(0, 0)})
bottom = frozenset({(1, 0)})
target = frozenset({(1, 4)})
# Per-cell scores pin the geometry: the top cell only sees +2 ruins,
# the bottom cell's low lines also graze the +4 wall.
# L9 rule: each cell is scored by the attacker's BEST corner (min over
# its corners of the max over target-corner lines). The top cell only
# sees +2 ruins; the bottom cell's LOW lines graze the +4 wall, but its
# best (top) corner avoids it -> 2.
assert cover_bonus_cells(grid, top, target, ranged=True) == 2
assert cover_bonus_cells(grid, bottom, target, ranged=True) == 4
# B20 fix: the attacker picks its best square -> min(2, 4) = 2.
assert cover_bonus_cells(grid, bottom, target, ranged=True) == 2
# B20 fix: the attacker picks its best square -> min(2, 2) = 2.
assert (
cover_bonus_cells(grid, top | bottom, target, ranged=True) == 2
)
@@ -56,9 +58,10 @@ def test_two_cell_attacker_uses_best_cell_cover() -> None:
def test_two_cell_attacker_best_cell_alone_is_unchanged() -> None:
grid = _grid(_CORNER_GRID)
target = frozenset({(1, 4)})
# A single-square attacker is the golden path: exactly its own score.
# A single-square attacker is the golden path: exactly its own
# best-corner score (L9: the +4 wall graze is avoidable from (1,0)).
assert cover_bonus_cells(grid, frozenset({(0, 0)}), target, ranged=True) == 2
assert cover_bonus_cells(grid, frozenset({(1, 0)}), target, ranged=True) == 4
assert cover_bonus_cells(grid, frozenset({(1, 0)}), target, ranged=True) == 2
# ---------------------------------------------------------------------------