feat(rules): restrict bless to allies in a 50-ft burst

SRD spells/bless.md: 'The caster and all allies within a 50-ft. burst,
centered on the caster'. Add an AreaEffect.targets filter (all/allies/
enemies) applied where area creatures are collected; bless.json now
declares radius_ft 50 and targets allies (the caster included).
This commit is contained in:
2026-09-16 11:14:46 +02:00
parent 312f9fd6b8
commit e43066e0ef
4 changed files with 87 additions and 12 deletions
+21 -10
View File
@@ -6499,20 +6499,31 @@ class CombatEngine:
caster's anchor cell and opens toward ``aim`` (PF1e CRB "Aiming a
Spell" — see ``areas.py``); a creature is affected when ANY of its
occupied cells lies inside the template.
``effect.targets`` restricts the selection (SRD bless/bane bursts):
"allies" keeps only creatures on the caster's side (the caster
included — SRD bless "The caster and all allies"), "enemies" keeps
only the opposite side, "all" keeps everyone.
"""
span_cells = effect.radius_ft // _SQUARE_FT
if effect.shape == "burst":
return self._creatures_in_range(aim, span_cells)
origin = caster.pos
if effect.shape == "cone":
cells = cone_cells(self._grid, origin, aim, span_cells)
affected = self._creatures_in_range(aim, span_cells)
else:
cells = line_cells(self._grid, origin, aim, span_cells)
return [
state
for state in self._states
if state.active and state.occupied_cells() & cells
]
origin = caster.pos
if effect.shape == "cone":
cells = cone_cells(self._grid, origin, aim, span_cells)
else:
cells = line_cells(self._grid, origin, aim, span_cells)
affected = [
state
for state in self._states
if state.active and state.occupied_cells() & cells
]
if effect.targets == "allies":
return [s for s in affected if s.side == caster.side]
if effect.targets == "enemies":
return [s for s in affected if s.side != caster.side]
return affected
def _creatures_in_range(
self, center: tuple[int, int], radius_cells: int