fix(rules): Combat Casting's +4 no longer applies to the entangled concentration check (SRD combat-casting: the feat covers only casting defensively or while grappled)

This commit is contained in:
2026-09-19 11:50:53 +02:00
parent cec3c5f459
commit 65a5e24609
2 changed files with 23 additions and 9 deletions
+18 -6
View File
@@ -3809,14 +3809,19 @@ class CombatEngine:
damage_taken: int,
*,
dc_override: int | None = None,
combat_casting_applies: bool = True,
) -> bool:
"""Concentration check: DC depends on situation.
PF1e (CRB): the check is d20 + caster level + the ability modifier
used to determine bonus spells (Int/Wis/Cha) — NOT Constitution.
Combat Casting's +4 applies only when casting defensively, while
grappled/pinned, or while entangled, never for damage taken while
casting. ``dc_override`` pins the DC (used by the entangled gate).
Combat Casting's +4 applies only when casting defensively or while
grappled (SRD feats/combat-casting.md: "a +4 bonus on concentration
checks made to cast a spell or use a spell-like ability when
casting on the defensive or while grappled") - never for damage
taken while casting, never while entangled. ``combat_casting_applies``
is passed False by the situations outside the feat (entangled);
``dc_override`` pins the DC (used by the entangled gate).
"""
dc = (
self._concentration_dc(caster, spell_level, damage_taken)
@@ -3824,7 +3829,9 @@ class CombatEngine:
else dc_override
)
injured_while_casting = damage_taken > 0 and caster.grappled_with is None
has_combat_casting = self._has_feat(caster, _COMBAT_CASTING_FEAT)
has_combat_casting = (
combat_casting_applies and self._has_feat(caster, _COMBAT_CASTING_FEAT)
)
bonus = 0 if injured_while_casting else (4 if has_combat_casting else 0)
roll = self._rng.d20()
total = (
@@ -6168,9 +6175,14 @@ class CombatEngine:
if self._has_condition_named(caster, "entangled"):
# PF1e (SRD Table 9-1 Concentration Check DCs): "Entangled while
# casting" requires a DC 15 + spell level check or the spell is
# lost. Combat Casting's +4 applies (not an injury check).
# lost. Combat Casting's +4 does NOT apply: the feat covers only
# "casting on the defensive or while grappled" (SRD
# feats/combat-casting.md).
dc = self._entangled_concentration_dc(spell_level)
if not self._check_concentration(caster, spell_level, 0, dc_override=dc):
if not self._check_concentration(
caster, spell_level, 0,
dc_override=dc, combat_casting_applies=False,
):
self._log(
f"round {self._current_round} {caster.combatant.id}: "
f"casting while entangled: concentration failed (DC {dc}), "
+5 -3
View File
@@ -211,10 +211,12 @@ class TestEntangledCasting:
engine, c = self._entangled_engine(11)
assert engine._spell_cast_interrupted(c, 1, cast_defensively=False) is False
def test_combat_casting_helps_while_entangled(self) -> None:
# d20 7 + level 5 + wis 0 + 4 = 16 >= 16 -> PASS with the feat.
def test_combat_casting_does_not_help_while_entangled(self) -> None:
# SRD feats/combat-casting.md: the +4 covers only "casting on the
# defensive or while grappled" - NOT the entangled check. d20 7 +
# level 5 + wis 0 = 12 < DC 16 -> spell lost even with the feat.
engine, c = self._entangled_engine(7, combat_casting=True)
assert engine._spell_cast_interrupted(c, 1, cast_defensively=False) is False
assert engine._spell_cast_interrupted(c, 1, cast_defensively=False) is True
def test_entangled_carries_minus4_dex_skills(self) -> None:
mods = {m.target: m.value for m in ENTANGLED.modifiers}