fix(rules): Toughness is +3 hp below 4 Hit Dice (max(3, level))

This commit is contained in:
2026-09-16 19:58:30 +02:00
parent 350844fc68
commit fdc9127483
2 changed files with 19 additions and 4 deletions
+4 -4
View File
@@ -49,16 +49,16 @@ def weapon_focus(weapon_name: str) -> AbilitySpec:
) )
# Toughness: +1 HP per Hit Die (approximated as +level HP, untyped, CRB) # Toughness (CRB): "+3 hit points. If the character has 4 or more Hit Dice,
# For simplicity at this stage, we model it as a flat HP bonus. # she gains +1 hit point per Hit Die." => max(3, HD). The engine doesn't yet
# The engine doesn't yet compute per-HD bonuses, so the caller sets the value. # compute per-HD bonuses, so the caller passes the level.
def toughness(level: int) -> AbilitySpec: def toughness(level: int) -> AbilitySpec:
return AbilitySpec( return AbilitySpec(
name="Toughness", name="Toughness",
category="feat", category="feat",
source_detail="feat lv1", source_detail="feat lv1",
effects=( effects=(
StatModifier(target="hp", value=level), StatModifier(target="hp", value=max(3, level)),
), ),
) )
+15
View File
@@ -135,6 +135,21 @@ def test_spot_check_toughness_level_tied() -> None:
assert any(e.value == 5 for e in spec.effects) assert any(e.value == 5 for e in spec.effects)
def test_toughness_is_plus3_below_four_hd_and_plus_hd_above() -> None:
# CRB Toughness: "+3 hit points. If the character has 4 or more Hit
# Dice, she gains +1 hit point per Hit Die."
def hp_value(level: int) -> int:
spec = _resolve_feat("Toughness", level)
values = [e.value for e in spec.effects if e.target == "hp"]
assert len(values) == 1
return values[0]
assert hp_value(1) == 3
assert hp_value(2) == 3
assert hp_value(3) == 3
assert hp_value(4) == 4
# ── Expected mapping table (name -> resolved display name or traced-no-op) ───── # ── Expected mapping table (name -> resolved display name or traced-no-op) ─────
_EXPECTED_RESOLUTION: dict[str, str] = { _EXPECTED_RESOLUTION: dict[str, str] = {