fix(rules): Lonely and Bitter drawbacks replace bogus +1 Will bonuses (SRD: Lonely -2 Sense Motive and -2 saves vs charm with mind_affecting standing in; Bitter reduces ally-sourced healing by 1 via engine hook)
This commit is contained in:
@@ -385,11 +385,16 @@ EXALTED_SOCIETY = AbilitySpec(
|
||||
resource_grants=(("channel_energy", 1),),
|
||||
)
|
||||
|
||||
# Bitter: +1 trait bonus on saves vs fear
|
||||
# Bitter (Drawback): "When you receive healing from an ally's class feature,
|
||||
# spell, or spell-like ability, reduce the amount of that healing by 1 hit
|
||||
# point." It is a healing-application behavior, not a stat modifier: the
|
||||
# engine checks for this feature by name in _channel_heal/_apply_heal_effect
|
||||
# (like Power Attack is a behavior marker). The previous "+1 Will vs fear"
|
||||
# was the wrong effect (and a positive bonus for a drawback).
|
||||
BITTER = AbilitySpec(
|
||||
name="Bitter",
|
||||
category="trait",
|
||||
effects=(StatModifier(target="will", value=1, condition="fear"),),
|
||||
source_detail="drawback: ally healing received reduced by 1 (engine behavior)",
|
||||
)
|
||||
|
||||
# Ambitious: +1 trait bonus on one Craft or Profession skill
|
||||
@@ -427,11 +432,21 @@ FORTIFIED_DRINKER = AbilitySpec(
|
||||
# Fate's Favored: +1 luck bonus on all luck bonuses
|
||||
FATES_FAVORED = AbilitySpec(name="Fate's Favored", category="trait")
|
||||
|
||||
# Lonely: +1 trait bonus on Will saves vs fear
|
||||
# Lonely (Drawback): "-2 penalty on Sense Motive checks and on Perception
|
||||
# checks to see through disguises, and on saving throws against charm spells
|
||||
# and spell-like abilities." The engine has no "charm" save descriptor, so
|
||||
# mind_affecting stands in for it (same documented convention as Inspire
|
||||
# Courage). The Perception-to-see-through-disguises check is a context the
|
||||
# engine never resolves, so only its Sense Motive half is modeled. The
|
||||
# previous "+1 Will vs fear" was a positive bonus for a drawback - wrong.
|
||||
LONELY = AbilitySpec(
|
||||
name="Lonely",
|
||||
category="trait",
|
||||
effects=(StatModifier(target="will", value=1, condition="fear"),),
|
||||
source_detail="drawback: -2 Sense Motive, -2 saves vs charm (mind_affecting stands in)",
|
||||
effects=(
|
||||
StatModifier(target="sense_motive", value=-2),
|
||||
StatModifier(target="will", value=-2, condition="mind_affecting"),
|
||||
),
|
||||
)
|
||||
|
||||
# Larger Than Life: +1 trait bonus on Intimidate
|
||||
|
||||
@@ -5459,6 +5459,7 @@ class CombatEngine:
|
||||
def _channel_heal(
|
||||
self, state: CombatantState, affected_state: CombatantState, dmg: int
|
||||
) -> None:
|
||||
dmg = self._bitter_reduced(state, affected_state, dmg)
|
||||
old_hp = affected_state.hp
|
||||
affected_state.hp = min(affected_state.hp + dmg, affected_state.combatant.hp_max)
|
||||
# PF1e (CRB, Stable Characters and Recovery): "If any sort of healing
|
||||
@@ -6526,6 +6527,7 @@ class CombatEngine:
|
||||
return self._apply_heal_effect(
|
||||
effect, target, caster_level=caster.combatant.level,
|
||||
empower=empower, maximize=maximize, saved=saved,
|
||||
healer=caster,
|
||||
)
|
||||
if isinstance(effect, PenaltyEffect):
|
||||
return self._apply_penalty_effect(
|
||||
@@ -6719,6 +6721,23 @@ class CombatEngine:
|
||||
target.bleed_damage = max(target.bleed_damage, 1)
|
||||
return f"{condition_name} ({duration_rounds}r)"
|
||||
|
||||
def _bitter_reduced(
|
||||
self, healer: CombatantState, target: CombatantState, amount: int
|
||||
) -> int:
|
||||
"""PF1e (Drawback "Bitter"): "When you receive healing from an ally's
|
||||
class feature, spell, or spell-like ability, reduce the amount of that
|
||||
healing by 1 hit point." Applies only to ally-sourced healing (an
|
||||
ally is another creature on the same side); self-healing is untouched.
|
||||
"""
|
||||
if (
|
||||
amount > 0
|
||||
and healer is not target
|
||||
and healer.side == target.side
|
||||
and self._has_feat(target, "Bitter")
|
||||
):
|
||||
return amount - 1
|
||||
return amount
|
||||
|
||||
def _apply_heal_effect(
|
||||
self,
|
||||
effect: HealEffect,
|
||||
@@ -6728,6 +6747,7 @@ class CombatEngine:
|
||||
empower: bool,
|
||||
maximize: bool,
|
||||
saved: bool,
|
||||
healer: CombatantState | None = None,
|
||||
) -> str:
|
||||
formula = effect.effective_formula(caster_level)
|
||||
heal = formula.roll(self._rng)
|
||||
@@ -6742,10 +6762,13 @@ class CombatEngine:
|
||||
# resistance, and can attempt a Will save to take half damage."
|
||||
# SR is resolved upstream (_spell_delivery_blocked); the rolled
|
||||
# save halves here. Cure damage is spell energy: never reduced by
|
||||
# DR, and it does not stop bleeding or stabilize.
|
||||
# DR, and it does not stop bleeding or stabilize. Bitter reduces
|
||||
# healing, not this damage.
|
||||
dmg = heal // 2 if saved else heal
|
||||
target.hp -= dmg
|
||||
return f"{dmg} damage (undead)"
|
||||
if healer is not None:
|
||||
heal = self._bitter_reduced(healer, target, heal)
|
||||
old_hp = target.hp
|
||||
target.hp = min(target.hp + heal, target.combatant.hp_max)
|
||||
# PF1e (CRB, Stable Characters and Recovery): "If any sort of healing
|
||||
|
||||
Reference in New Issue
Block a user