fix(rules): disarm drops the wielded weapon (weapon_dropped) instead of a synthetic -4 penalty
This commit is contained in:
@@ -284,6 +284,62 @@ def test_unrestricted_maneuver_ignores_size_limit() -> None:
|
||||
assert not engine._rng._queue
|
||||
|
||||
|
||||
# --- SRD Disarm: the target DROPS the weapon (no synthetic -4 penalty) --------
|
||||
|
||||
|
||||
def test_disarm_success_drops_target_weapon() -> None:
|
||||
# SRD Disarm: "If your attack is successful, your target drops one item
|
||||
# it is carrying." The dropped weapon is unusable until retrieved; the
|
||||
# old synthetic "disarmed" -4 attack condition is gone.
|
||||
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, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "disarm")
|
||||
assert "b-w" in b.weapon_dropped
|
||||
assert [w.id for w in b.usable_attacks()] == []
|
||||
assert engine.weapon_for(b, a) is None
|
||||
assert not any(c.condition.name == "disarmed" for c in b.active_conditions)
|
||||
assert "SUCCESS (sword dropped)" in engine._transcript[-1]
|
||||
|
||||
|
||||
def test_retrieve_weapon_picks_dropped_weapon_back_up() -> None:
|
||||
# Picking the dropped weapon back up is a move action (retrieve_weapon);
|
||||
# once restored, the weapon is usable again.
|
||||
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, 12], [a, b])
|
||||
engine._execute_maneuver(a, b, "disarm")
|
||||
assert "b-w" in b.weapon_dropped
|
||||
engine._retrieve_weapon(b, "b-w")
|
||||
assert "b-w" not in b.weapon_dropped
|
||||
assert [w.id for w in b.usable_attacks()] == ["b-w"]
|
||||
assert "retrieve b-w (restored)" in engine._transcript[-1]
|
||||
|
||||
|
||||
def test_retrieve_weapon_still_restores_stolen() -> None:
|
||||
# The steal path keeps working: retrieve removes the weapon from
|
||||
# weapon_stolen.
|
||||
b = make_state(make_combatant("b"), "monsters", (1, 2))
|
||||
b.weapon_stolen.add("b-w")
|
||||
engine = make_engine([], [b])
|
||||
engine._retrieve_weapon(b, "b-w")
|
||||
assert not b.weapon_stolen
|
||||
assert [w.id for w in b.usable_attacks()] == ["b-w"]
|
||||
|
||||
|
||||
def test_disarm_fail_by_10_drops_attacker_weapon() -> None:
|
||||
# SRD Disarm: "If your attack fails by 10 or more, you drop the weapon
|
||||
# that you were using to attempt the disarm." a total 2+2=4 vs CMD 14
|
||||
# fails by 10 -> a drops its sword; b's weapon is untouched.
|
||||
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, 2], [a, b])
|
||||
engine._execute_maneuver(a, b, "disarm")
|
||||
assert "a-w" in a.weapon_dropped
|
||||
assert not b.weapon_dropped
|
||||
assert any("disarm backfire -> drops sword" in line for line in engine._transcript)
|
||||
|
||||
|
||||
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