fix(rules): cover the feat/trait no-op batch in test_feats (assert the eight documented inert specs, the two traced-noop names, and misty's resistances/bite data encoding)
This commit is contained in:
@@ -12,17 +12,23 @@ import json
|
||||
from pathlib import Path
|
||||
|
||||
from pf1e_simulator.abilities import (
|
||||
AMBITIOUS,
|
||||
AXE_TO_GRIND,
|
||||
BITTER,
|
||||
BORN_DAMNED,
|
||||
BREEZE_KISSED,
|
||||
COMBAT_REFLEXES,
|
||||
EXALTED_SOCIETY,
|
||||
EXTREMELY_FASHIONABLE,
|
||||
FOCUSED_STUDY,
|
||||
FORTIFIED_DRINKER,
|
||||
FRIENDLY_FACE,
|
||||
LARGER_THAN_LIFE,
|
||||
LIKE_THE_WIND,
|
||||
LONELY,
|
||||
MOUNTED_COMBAT,
|
||||
POINT_BLANK_SHOT,
|
||||
WHISPERING_WIND,
|
||||
AbilitySpec,
|
||||
)
|
||||
from pf1e_simulator.combat import CombatantState, CombatEngine
|
||||
@@ -305,6 +311,69 @@ def test_extremely_fashionable_is_inert_documented_noop() -> None:
|
||||
assert "not modeled" in EXTREMELY_FASHIONABLE.source_detail
|
||||
|
||||
|
||||
# ── SRD conformance: feat/trait divergence batch (size/speed/skill gates) ─────
|
||||
|
||||
|
||||
def test_larger_than_life_is_inert_documented_noop() -> None:
|
||||
"""SRD (Basic Combat trait): considered one size larger for Intimidate
|
||||
while wielding a firearm. Intimidate and size-for-skill are not modeled
|
||||
-> inert no-op (the old flat +1 Intimidate was the wrong effect)."""
|
||||
assert LARGER_THAN_LIFE.effects == ()
|
||||
assert "not modeled" in LARGER_THAN_LIFE.source_detail
|
||||
|
||||
|
||||
def test_ambitious_is_inert_documented_noop() -> None:
|
||||
"""SRD (Basic Social trait): +4 trait bonus on Diplomacy vs creatures
|
||||
with 5+ more HD. The HD-differential gate is not expressible -> inert."""
|
||||
assert AMBITIOUS.effects == ()
|
||||
assert "not modeled" in AMBITIOUS.source_detail
|
||||
|
||||
|
||||
def test_focused_study_is_inert_documented_noop() -> None:
|
||||
"""SRD (human alternate racial trait): +2 on one chosen skill (re-chosen
|
||||
at 8th/16th). The chosen skill is never resolved in combat -> inert."""
|
||||
assert FOCUSED_STUDY.effects == ()
|
||||
assert "not modeled" in FOCUSED_STUDY.source_detail
|
||||
|
||||
|
||||
def test_esha_sylph_traits_are_inert_documented_noops() -> None:
|
||||
"""SRD (ARG sylph alternate racial traits; Esha's sheet declares race
|
||||
Sylph so the picks are legal): Whispering Wind = +4 racial Stealth,
|
||||
Like the Wind = +5 ft base speed, Breeze-Kissed = +2 racial AC vs
|
||||
nonmagical ranged + 1/day gust. None is expressible (no stealth checks,
|
||||
speed_ft modifiers unresolved, AC is a final sheet value) -> all inert;
|
||||
the previously coded Fly/save/speed bonuses were fabricated."""
|
||||
for spec in (WHISPERING_WIND, LIKE_THE_WIND, BREEZE_KISSED):
|
||||
assert spec.effects == (), spec.name
|
||||
assert "not modeled" in spec.source_detail, spec.name
|
||||
|
||||
|
||||
def test_fey_touched_and_pingre_are_traced_noop_names() -> None:
|
||||
"""Not PF1e features (no SRD entry under those names): Harvie's
|
||||
"Fey-touched" and Nairda's joke trait "Pingre" join the decorative
|
||||
traced-noop list; their old coded bonuses were fabricated."""
|
||||
assert "fey-touched" in _NOOP_FEATS
|
||||
assert "pingre" in _NOOP_FEATS
|
||||
for name in ("Fey-touched", "Pingre"):
|
||||
spec = _resolve_feat(name, 1)
|
||||
assert spec.name == name
|
||||
assert spec.effects == ()
|
||||
|
||||
|
||||
def test_misty_scaled_skin_and_maw_or_claw_encoded_in_data() -> None:
|
||||
"""SRD (ARG tiefling daemon-spawn): Scaled Skin (electricity) = resist
|
||||
electricity 5 (replaces fiendish resistance - no cold/fire); Maw or Claw
|
||||
= bite natural attack, 1d6 for a Medium tiefling (the Foundry sheet's
|
||||
"1d4 estimé" is an author guess, discrepancy recorded in the JSON notes).
|
||||
Both benefits are Combatant data, not stat modifiers."""
|
||||
misty = load_combatant(Path("data/pcs/misty.json"))
|
||||
assert misty.resistances == {"electricity": 5}
|
||||
bites = [a for a in misty.attacks if a.name.startswith("Bite")]
|
||||
assert len(bites) == 1
|
||||
formula = bites[0].damage[0].formula
|
||||
assert (formula.count, formula.sides, formula.bonus) == (1, 6, 0)
|
||||
|
||||
|
||||
def _make_battle_combatant(
|
||||
cid: str, *, features: tuple[AbilitySpec, ...] = (), hp_max: int = 30
|
||||
) -> Combatant:
|
||||
|
||||
Reference in New Issue
Block a user