feat(abilities): add passive feats system (Weapon Focus, Iron Will, Dodge, Point-Blank Shot)
This commit is contained in:
@@ -357,11 +357,25 @@ class CombatEngine:
|
||||
return _FLANK_BONUS
|
||||
return 0
|
||||
|
||||
def _stat_modifiers(self, state: CombatantState, target: str) -> list[StatModifier]:
|
||||
"""Collect all StatModifiers for ``target`` from effects + conditions."""
|
||||
def _stat_modifiers(
|
||||
self, state: CombatantState, target: str, *, weapon_name: str | None = None
|
||||
) -> list[StatModifier]:
|
||||
"""Collect all StatModifiers for ``target`` from effects, conditions, and features.
|
||||
|
||||
``weapon_name`` filters out modifiers with a ``weapon_filter`` that
|
||||
doesn't match (e.g. Weapon Focus (Pistol) only applies to "Pistol").
|
||||
Modifiers without a ``weapon_filter`` are always included.
|
||||
"""
|
||||
mods = [e for e in state.effects if e.target == target]
|
||||
for cond in state.conditions:
|
||||
mods.extend(m for m in cond.modifiers if m.target == target)
|
||||
for feat in state.combatant.features:
|
||||
for m in feat.effects:
|
||||
if m.target != target:
|
||||
continue
|
||||
if m.weapon_filter is not None and m.weapon_filter != weapon_name:
|
||||
continue
|
||||
mods.append(m)
|
||||
return mods
|
||||
|
||||
def resolve_attack(
|
||||
@@ -378,7 +392,7 @@ class CombatEngine:
|
||||
penalty = self.range_penalty(weapon, dist_ft)
|
||||
flank = self._flanking_bonus(attacker, target) if weapon.kind == "melee" else 0
|
||||
base_bonus = bonus_override if bonus_override is not None else weapon.attack_bonus
|
||||
atk_mods = self._stat_modifiers(attacker, "attack")
|
||||
atk_mods = self._stat_modifiers(attacker, "attack", weapon_name=weapon.name)
|
||||
attack_mod = resolve_modifiers(atk_mods)
|
||||
total = roll + base_bonus + penalty + flank + attack_mod
|
||||
ac = target.combatant.ac.total + resolve_modifiers(self._stat_modifiers(target, "ac"))
|
||||
@@ -401,7 +415,7 @@ class CombatEngine:
|
||||
confirm = self._rng.d20()
|
||||
confirm_total = confirm + base_bonus + penalty + flank + attack_mod
|
||||
crit = confirm != _NATURAL_ONE and confirm_total >= ac
|
||||
dmg_mods = self._stat_modifiers(attacker, "damage")
|
||||
dmg_mods = self._stat_modifiers(attacker, "damage", weapon_name=weapon.name)
|
||||
damage = sum(c.formula.roll(self._rng) for c in weapon.damage) + weapon.damage_bonus
|
||||
damage += resolve_modifiers(dmg_mods)
|
||||
if crit:
|
||||
|
||||
Reference in New Issue
Block a user