diff --git a/src/pf1e_simulator/effects.py b/src/pf1e_simulator/effects.py index ba05f05..59fe378 100644 --- a/src/pf1e_simulator/effects.py +++ b/src/pf1e_simulator/effects.py @@ -44,6 +44,13 @@ BonusType = Literal[ "shield", # no stack "armor", # no stack (SRD mage armor: "+4 armor bonus to AC") "circumstance", # no stack (simulator can't distinguish circumstances) + # SRD "Ultimate Magic" Table 2-7: Bonus Types and Effects — remaining + # named types, all non-stacking like every typed bonus (CRB "Combining + # Magic Effects": "two bonuses of the same type don't stack"). + "alchemical", # no stack (UM T2-7: ability scores, saves; antitoxin) + "inherent", # no stack (UM T2-7: ability scores; Manual of bodily health) + "resistance", # no stack (UM T2-7: saves; cloak of resistance) + "size", # no stack (UM T2-7: ability scores, attacks, AC; enlarge person) ] StatTarget = Literal[ diff --git a/tests/test_effects.py b/tests/test_effects.py index d5b8e71..a199566 100644 --- a/tests/test_effects.py +++ b/tests/test_effects.py @@ -2,7 +2,7 @@ from __future__ import annotations -from pf1e_simulator.effects import StatModifier, resolve_modifiers +from pf1e_simulator.effects import BonusType, StatModifier, resolve_modifiers # ── Stacking types: sum together ────────────────────────────────────────────── @@ -228,3 +228,19 @@ class TestEdgeCases: StatModifier("ac", 3, "morale"), ] assert resolve_modifiers(mods) == 3 # same non-stacking type → max(2, 3) + + def test_um_table_2_7_bonus_types_parse_and_do_not_stack(self) -> None: + # SRD "Ultimate Magic" Table 2-7 types: alchemical, inherent, + # resistance, size — accepted by StatModifier, non-stacking. + new_types: tuple[BonusType, ...] = ( + "alchemical", + "inherent", + "resistance", + "size", + ) + for bonus_type in new_types: + mods = [ + StatModifier("ac", 2, bonus_type), + StatModifier("ac", 4, bonus_type), + ] + assert resolve_modifiers(mods) == 4, bonus_type