fix(rules): cap reposition and drag by size category

PF1e (APG Reposition / Drag): "You can only reposition/drag an opponent
that is no more than one size category larger than you" — the same cap the
SRD puts on trip/bull rush/overrun. reposition and drag join
_SIZE_RESTRICTED_MANEUVERS, so a two-categories-larger target is rejected
outright (no roll, no AoO). 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 10:58:13 +02:00
parent 5a848fd07c
commit 57a597babd
3 changed files with 25 additions and 16 deletions
+7 -4
View File
@@ -249,16 +249,19 @@ def test_overrun_fail_adjacent_attacker_does_not_move() -> None:
def test_maneuver_rejects_target_two_sizes_larger() -> None:
# SRD Trip/Bull Rush/Overrun: "You can only [affect] an opponent who is
# no more than one size category larger than you." Medium vs Huge: the
# attempt is illegal — no d20 consumed, no effect, logged rejection.
for maneuver in ("trip", "bull_rush", "overrun"):
# SRD Trip/Bull Rush/Overrun + APG Reposition/Drag: "You can only
# [affect/reposition/drag] an opponent who is no more than one size
# category larger than you." Medium vs Huge: the attempt is illegal — no
# d20 consumed, no effect, logged rejection.
for maneuver in ("trip", "bull_rush", "overrun", "reposition", "drag"):
a = make_state(make_combatant("a", attack_bonus=2), "players", (1, 1))
huge = make_state(_resized(make_combatant("h"), "Huge", 10, 10), "monsters", (1, 2))
engine = make_engine([1, 12], [a, huge])
engine._execute_maneuver(a, huge, maneuver)
assert len(engine._rng._queue) == 2
assert not any(c.condition.name == "prone" for c in huge.active_conditions)
assert huge.pos == (1, 2) # reposition/drag must not move the target
assert a.pos == (1, 1) # drag must not displace the attacker either
assert f"{maneuver} vs h rejected (target too large)" in engine._transcript[-1]