fix(rules): only total concealment blocks sneak attack
PF1e (CRB rogue Sneak Attack): "A rogue cannot sneak attack while striking a creature with total concealment." _sneak_attack_dice now gates on miss_chance >= 50 instead of any concealment > 0, so a blurred (20%) target can still be sneak attacked while a displaced (50%) one cannot. The test that pinned the old any-concealment denial was retargeted to total concealment and a partial-concealment case added; 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:
@@ -138,7 +138,8 @@ def test_total_concealment_triggers_at_50() -> None:
|
||||
assert t.hp == 100
|
||||
|
||||
|
||||
def test_concealment_denies_sneak_attack() -> None:
|
||||
def test_total_concealment_denies_sneak_attack() -> None:
|
||||
"""(A7) total concealment (displaced 50%) denies the sneak attack."""
|
||||
sneak = _combatant("atk", level=3, features=("Sneak Attack",))
|
||||
eng = _engine(
|
||||
[sneak, _combatant("tgt")],
|
||||
@@ -148,13 +149,37 @@ def test_concealment_denies_sneak_attack() -> None:
|
||||
)
|
||||
a, t = eng._states
|
||||
_add_condition(t, "flat_footed")
|
||||
_add_condition(t, "blurred")
|
||||
_add_condition(t, "displaced")
|
||||
result = eng.resolve_attack(a, t, a.combatant.attacks[0])
|
||||
# d20=15 hits, d100=90 > 50% lands; sneak denied by total concealment,
|
||||
# so only the 1d6 weapon die (3) lands.
|
||||
assert result.damage == 3
|
||||
assert t.hp == 97
|
||||
assert not any("sneak" in line for line in eng._transcript)
|
||||
|
||||
|
||||
def test_partial_concealment_still_allows_sneak_attack() -> None:
|
||||
"""(A7) a blurred (20%) target CAN be sneak attacked — CRB rogue text is
|
||||
"cannot sneak attack while striking a creature with total concealment",
|
||||
so partial concealment no longer denies the precision damage."""
|
||||
sneak = _combatant("atk", level=3, features=("Sneak Attack",))
|
||||
eng = _engine(
|
||||
[sneak, _combatant("tgt")],
|
||||
[(0, 0), (0, 1)],
|
||||
["players", "monsters"],
|
||||
[15, 90, 6, 6, 4],
|
||||
)
|
||||
a, t = eng._states
|
||||
_add_condition(t, "flat_footed")
|
||||
_add_condition(t, "blurred")
|
||||
result = eng.resolve_attack(a, t, a.combatant.attacks[0])
|
||||
# d20=15 hits, d100=90 > 20% lands; 2d6 sneak (6+6=12) + 1d6 weapon (4)
|
||||
# = 16 precision-inclusive damage.
|
||||
assert result.damage == 16
|
||||
assert t.hp == 84
|
||||
assert any("sneak attack" in line and "2d6" in line for line in eng._transcript)
|
||||
|
||||
|
||||
def test_concealment_miss_does_not_consume_deed() -> None:
|
||||
eng = _engine(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user