fix(rules): self-centered bursts for bless and bane - AreaEffect gains a data-driven 'centered_on_caster' flag (bless.json/bane.json set it per SRD bless.md '50-ft. burst, centered on the caster' and bane.md 'centered on you'); the burst origin is the caster's square regardless of the resolved target or a U7b target_pos, and with no chosen origin there is no primary save - every creature in the area rolls its own (mirror of the point-cast path); snapshot area key exposes centered_on_caster; golden transcript unchanged; +6 tests

This commit is contained in:
2026-09-19 22:38:39 +02:00
parent 4665a1c245
commit 9f0d86273a
7 changed files with 189 additions and 10 deletions
+3 -3
View File
@@ -88,7 +88,7 @@ def test_area_snapshot_burst_exposes_shape_and_radius() -> None:
When: its snapshot dict is built
Then: area equals {"shape": "burst", "radius_ft": 20}."""
s = _spell_dict_for(_FIREBALL, "Fireball")
assert s["area"] == {"shape": "burst", "radius_ft": 20}
assert s["area"] == {"shape": "burst", "radius_ft": 20, "centered_on_caster": False}
def test_area_snapshot_single_target_is_none() -> None:
@@ -104,7 +104,7 @@ def test_area_snapshot_first_area_wins() -> None:
When: its snapshot dict is built
Then: only the FIRST AreaEffect is exposed."""
s = _spell_dict_for(_TWO_AREAS, "Twin Burst")
assert s["area"] == {"shape": "burst", "radius_ft": 20}
assert s["area"] == {"shape": "burst", "radius_ft": 20, "centered_on_caster": False}
def test_area_snapshot_unknown_spell_is_none() -> None:
@@ -175,5 +175,5 @@ def test_area_snapshot_is_json_serializable() -> None:
json.dumps(data)
restored = json.loads(json.dumps(data))
spells = restored["combatants"][0]["spells"]
assert spells[0]["area"] == {"shape": "burst", "radius_ft": 20}
assert spells[0]["area"] == {"shape": "burst", "radius_ft": 20, "centered_on_caster": False}
assert spells[1]["area"] is None