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:
@@ -635,6 +635,50 @@ class TestBullsStrength:
|
||||
assert any("buff" in line for line in engine._transcript)
|
||||
|
||||
|
||||
class TestBlessAlliesOnly:
|
||||
"""Given: a caster casting Bless (SRD: 50-ft burst, "the caster and all
|
||||
allies")
|
||||
When: _cast_spell is called
|
||||
Then: the caster and allies inside the burst are buffed, enemies inside
|
||||
the burst are not."""
|
||||
|
||||
def _bless_engine(
|
||||
self,
|
||||
) -> tuple[CombatEngine, CombatantState, CombatantState, CombatantState]:
|
||||
caster = _make_caster()
|
||||
ally = _make_target("ally", hp_max=20)
|
||||
enemy = _make_target("enemy", hp_max=20)
|
||||
c = CombatantState(combatant=caster, side="players", pos=(0, 0), hp=caster.hp_max)
|
||||
a = CombatantState(combatant=ally, side="players", pos=(1, 0), hp=ally.hp_max)
|
||||
e = CombatantState(combatant=enemy, side="monsters", pos=(2, 0), hp=enemy.hp_max)
|
||||
legend = {".": TerrainType(type="floor", move_cost=1)}
|
||||
spec = MapSpec(name="test", terrain=tuple(["." * 12] * 12), legend=legend)
|
||||
grid = Grid.from_spec(spec)
|
||||
engine = CombatEngine(
|
||||
ScriptedRng([]), grid, [c, a, e],
|
||||
spell_registry=load_spell_registry(_SPELLS_DIR),
|
||||
)
|
||||
return engine, c, a, e
|
||||
|
||||
def test_allies_buffed_enemy_not(self) -> None:
|
||||
engine, c, a, e = self._bless_engine()
|
||||
engine._cast_spell(c, c, "Bless")
|
||||
caster_buffs = [m for b in c.active_buffs for m in b.modifiers]
|
||||
ally_buffs = [m for b in a.active_buffs for m in b.modifiers]
|
||||
assert any(m.target == "attack" and m.value == 1 for m in caster_buffs)
|
||||
assert any(m.target == "attack" and m.value == 1 for m in ally_buffs)
|
||||
assert not e.active_buffs
|
||||
|
||||
def test_enemy_outside_burst_unaffected(self) -> None:
|
||||
engine, c, a, e = self._bless_engine()
|
||||
# Move the enemy beyond the 50-ft burst (10 cells) before casting.
|
||||
e.pos = (11, 0)
|
||||
engine._cast_spell(c, c, "Bless")
|
||||
assert not e.active_buffs
|
||||
assert any(m.target == "attack" and m.value == 1
|
||||
for b in c.active_buffs for m in b.modifiers)
|
||||
|
||||
|
||||
class TestOutOfRange:
|
||||
"""Given: a target beyond the spell's maximum range
|
||||
When: _cast_spell is called
|
||||
|
||||
Reference in New Issue
Block a user