fix(rules): correct P2/P3 PF1e conformance bugs (flanking, touch, blinded, disabled, death, maneuvers, DR, sneak)
This commit is contained in:
+15
-11
@@ -66,6 +66,9 @@ def make_grid() -> Grid:
|
||||
def make_engine(
|
||||
queue: list[int], states: list[CombatantState]
|
||||
) -> CombatEngine:
|
||||
# A maneuver provokes an AoO from the (threatening) target BEFORE the CMB
|
||||
# check (B13 conformance): scripted queues carry a leading natural 1 so
|
||||
# the provoking attack always misses.
|
||||
return CombatEngine(ScriptedRng(queue), make_grid(), states)
|
||||
|
||||
|
||||
@@ -75,7 +78,7 @@ def test_sunder_damages_weapon_not_hp() -> None:
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
hp_before = b.hp
|
||||
engine = make_engine([12], [a, b])
|
||||
engine = make_engine([1, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "sunder")
|
||||
assert b.hp == hp_before
|
||||
assert b.weapon_damage["b-w"] == 2
|
||||
@@ -87,7 +90,8 @@ def test_sunder_destroys_weapon_and_disarms() -> None:
|
||||
b_spec = make_combatant("b")
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
engine = make_engine([12, 12, 12, 12, 12], [a, b])
|
||||
# Only the first sunder provokes: b's per-round AoO allowance is spent.
|
||||
engine = make_engine([1, 12, 12, 12, 12, 12], [a, b])
|
||||
for _ in range(5):
|
||||
engine._execute_maneuver(a, b, "sunder")
|
||||
assert b.hp == 6
|
||||
@@ -123,7 +127,7 @@ def test_overrun_knocks_prone_and_moves_through() -> None:
|
||||
b_spec = make_combatant("b")
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
engine = make_engine([12], [a, b])
|
||||
engine = make_engine([1, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "overrun")
|
||||
prone = next(c for c in b.active_conditions if c.condition.name == "prone")
|
||||
assert prone.rounds_left == 1
|
||||
@@ -138,7 +142,7 @@ def test_overrun_prone_but_no_space() -> None:
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
c = make_state(c_spec, "monsters", (1, 3))
|
||||
engine = make_engine([12], [a, b, c])
|
||||
engine = make_engine([1, 12], [a, b, c])
|
||||
engine._execute_maneuver(a, b, "overrun")
|
||||
assert any(cond.condition.name == "prone" for cond in b.active_conditions)
|
||||
assert a.pos == (1, 1)
|
||||
@@ -151,7 +155,7 @@ def test_dirty_trick_dazzles() -> None:
|
||||
b_spec = make_combatant("b")
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
engine = make_engine([12], [a, b])
|
||||
engine = make_engine([1, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "dirty_trick")
|
||||
dazzled = next(c for c in b.active_conditions if c.condition.name == "dazzled")
|
||||
assert dazzled.rounds_left == 1
|
||||
@@ -163,7 +167,7 @@ def test_dirty_trick_fails_on_natural_1() -> None:
|
||||
b_spec = make_combatant("b")
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
engine = make_engine([1], [a, b])
|
||||
engine = make_engine([1, 1], [a, b])
|
||||
engine._execute_maneuver(a, b, "dirty_trick")
|
||||
assert not any(c.condition.name == "dazzled" for c in b.active_conditions)
|
||||
assert not any(c.condition.name == "prone" for c in b.active_conditions)
|
||||
@@ -176,7 +180,7 @@ def test_steal_takes_melee_weapon() -> None:
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
hp_before = b.hp
|
||||
engine = make_engine([12], [a, b])
|
||||
engine = make_engine([1, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "steal")
|
||||
assert "b-w" in b.weapon_stolen
|
||||
assert engine.weapon_for(b, a) is None
|
||||
@@ -201,7 +205,7 @@ def test_reposition_moves_to_first_free_neighbor() -> None:
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
c = make_state(c_spec, "monsters", (1, 3))
|
||||
engine = make_engine([12], [a, b, c])
|
||||
engine = make_engine([1, 12], [a, b, c])
|
||||
engine._execute_maneuver(a, b, "reposition")
|
||||
assert b.pos == (0, 1)
|
||||
assert c.pos == (1, 3)
|
||||
@@ -217,7 +221,7 @@ def test_reposition_no_space() -> None:
|
||||
]
|
||||
a = make_state(a_spec, "players", (2, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 1))
|
||||
engine = make_engine([12], [a, b, *blockers])
|
||||
engine = make_engine([1, 12], [a, b, *blockers])
|
||||
engine._execute_maneuver(a, b, "reposition")
|
||||
assert b.pos == (1, 1)
|
||||
assert "no space" in engine._transcript[-1]
|
||||
@@ -228,7 +232,7 @@ def test_drag_moves_pair_together() -> None:
|
||||
b_spec = make_combatant("b")
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
engine = make_engine([12], [a, b])
|
||||
engine = make_engine([1, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "drag")
|
||||
assert b.pos == (1, 3)
|
||||
assert a.pos == (1, 2)
|
||||
@@ -241,7 +245,7 @@ def test_drag_no_space() -> None:
|
||||
a = make_state(a_spec, "players", (1, 1))
|
||||
b = make_state(b_spec, "monsters", (1, 2))
|
||||
c = make_state(c_spec, "monsters", (1, 3))
|
||||
engine = make_engine([12], [a, b, c])
|
||||
engine = make_engine([1, 12], [a, b, c])
|
||||
engine._execute_maneuver(a, b, "drag")
|
||||
assert b.pos == (1, 2)
|
||||
assert a.pos == (1, 1)
|
||||
|
||||
Reference in New Issue
Block a user