fix(rules): exclude the caster from a line spell's area

CRB Magic - Aiming a Spell: a line 'starts from any corner of your square', so the caster's own square is outside the template (SRD Lightning Bolt: 'The bolt begins at your fingertips' - it leaves the square, it does not fill it). line_cells now drops the origin and takes the length_cells squares beyond it; a degenerate aim affects nothing. Updated the Lightning Bolt and Line Sparks tests (caster no longer caught) and the README.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-13 11:30:30 +02:00
parent ee8c8f80ff
commit 642f449b9e
4 changed files with 38 additions and 24 deletions
+8 -6
View File
@@ -462,22 +462,24 @@ class TestLightningBoltSave:
1d6 per caster level max 10d6, ref save for half) cast by the level-5
fixture at a target straight ahead
When: the primary target succeeds its save
Then: damage is halved — and the caster, whose own square the line
starts in ("the bolt begins at your fingertips"), is caught as well."""
Then: damage is halved — and the caster is NOT caught by their own line
(CRB, Magic — Aiming a Spell: the line "starts from any corner of your
square", so the caster's own square is outside the template)."""
def test_successful_save_still_halves(self) -> None:
caster = _make_caster()
target = _make_target(hp_max=200)
# primary save (target) + secondary save (caster, same line) +
# 5 damage dice each (1d6/level, level 5)
# primary save (target, SAVED on a natural 20) + 5 damage dice
# (1d6/level, level 5); the caster is no longer in the line so no
# secondary save and no caster damage dice are rolled.
engine, c, t = _make_engine(
caster, target, [20, 20] + [3] * 10
caster, target, [20] + [3] * 5
)
hp_before = t.hp
engine._cast_spell(c, t, "Lightning Bolt")
full = 3 + 3 + 3 + 3 + 3
assert t.hp == hp_before - (full // 2)
assert c.hp == 20 - (full // 2)
assert c.hp == 20 # the caster's own square is outside the line
class TestDamageEffectHalfOnSaveDefault: