fix(rules): scale the bull rush push distance with the margin
PF1e (SRD Bull Rush): "your target is pushed back 5 feet. For every 5 by which your attack exceeds your opponent's CMD you can push the target back an additional 5 feet." _bull_rush_push (and the explicit-direction branch) now walk 1 + margin//5 cells, stopping at the first obstacle; a natural-20 auto-success below CMD floors the margin at 0 (base push only). 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:
@@ -162,6 +162,38 @@ def test_escape_natural_1_still_fails_above_cmd() -> None:
|
||||
assert any(c.condition.name == "grappled" for c in a.active_conditions)
|
||||
|
||||
|
||||
def test_bull_rush_push_scales_with_margin() -> None:
|
||||
# SRD Bull Rush: "For every 5 by which your attack exceeds your
|
||||
# opponent's CMD you can push the target back an additional 5 feet."
|
||||
# d20=20+2=22 vs CMD 12: margin 10 -> push 1 + 10//5 = 3 cells.
|
||||
a = make_state(make_combatant("a", attack_bonus=2), "players", (1, 1))
|
||||
b = make_state(make_combatant("b"), "monsters", (1, 2))
|
||||
engine = make_engine([1, 20], [a, b])
|
||||
engine._execute_maneuver(a, b, "bull_rush")
|
||||
assert b.pos == (1, 5)
|
||||
|
||||
|
||||
def test_bull_rush_push_stops_at_obstacle() -> None:
|
||||
# Same margin 10 (3 cells) but a creature blocks (1, 4): the push moves
|
||||
# b two cells and stops.
|
||||
a = make_state(make_combatant("a", attack_bonus=2), "players", (1, 1))
|
||||
b = make_state(make_combatant("b"), "monsters", (1, 2))
|
||||
c = make_state(make_combatant("c"), "monsters", (1, 4))
|
||||
engine = make_engine([1, 20], [a, b, c])
|
||||
engine._execute_maneuver(a, b, "bull_rush")
|
||||
assert b.pos == (1, 3)
|
||||
|
||||
|
||||
def test_bull_rush_natural_20_below_cmd_pushes_one_cell() -> None:
|
||||
# Natural 20 auto-succeeds even below CMD (bab 20 foe: CMD 30, total 22):
|
||||
# the margin floors at 0, so only the base 5 ft push applies.
|
||||
a = make_state(make_combatant("a", attack_bonus=2), "players", (1, 1))
|
||||
b = make_state(make_combatant("b", attack_bonus=20), "monsters", (1, 2))
|
||||
engine = make_engine([1, 20], [a, b])
|
||||
engine._execute_maneuver(a, b, "bull_rush")
|
||||
assert b.pos == (1, 3)
|
||||
|
||||
|
||||
def test_overrun_knocks_prone_and_moves_through() -> None:
|
||||
# d20=15+2=17 vs CMD 12: margin 5 -> prone AND moved through (CRB
|
||||
# "Overrun": prone only when the attack exceeds CMD by 5 or more).
|
||||
|
||||
Reference in New Issue
Block a user