feat(observation): expose structured spell areas

This commit is contained in:
2026-09-10 14:14:54 +02:00
parent 61c9b7fa47
commit 7fafbe43cf
4 changed files with 193 additions and 1 deletions
+15
View File
@@ -268,6 +268,19 @@ def _spell_half_on_save(spell: SpellSpec) -> bool:
return False
def _spell_area_dict(spell: SpellSpec) -> dict[str, object] | None:
"""Structured area template of a spell, or None if it has no top-level AreaEffect.
Returns ``{"shape": str, "radius_ft": int}`` for the FIRST AreaEffect found
in ``spell.effects`` (a spell may declare several effects; only the first
area is exposed, and effects nested inside an AreaEffect are not scanned).
"""
for effect in spell.effects:
if isinstance(effect, AreaEffect):
return {"shape": effect.shape, "radius_ft": effect.radius_ft}
return None
_STEP_DELTAS: tuple[Pos, ...] = (
(-1, -1),
(-1, 0),
@@ -3710,6 +3723,7 @@ class CombatEngine:
"summary": "",
"half_on_save": False,
"save_negates": False,
"area": None,
}
half_on_save = _spell_half_on_save(spell)
return {
@@ -3722,6 +3736,7 @@ class CombatEngine:
"summary": _spell_summary(spell),
"half_on_save": half_on_save,
"save_negates": spell.save != "none" and not half_on_save,
"area": _spell_area_dict(spell),
}
def _cast_spell(