From 13458a0173f1dcacd47a74a84a21bd90bee3d0d5 Mon Sep 17 00:00:00 2001 From: David Kruger Date: Tue, 20 May 2025 23:26:23 -0700 Subject: [PATCH] Working on a filter to find spells requiring a template of some sort --- dnd5etools/scripts/spell_templates.py | 52 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/dnd5etools/scripts/spell_templates.py b/dnd5etools/scripts/spell_templates.py index 9e08fa3..9ca8cfe 100644 --- a/dnd5etools/scripts/spell_templates.py +++ b/dnd5etools/scripts/spell_templates.py @@ -1,8 +1,16 @@ import pprint +import re import dnd5etools.db.spells import dnd5etools.scripts.argparse +area_size_re = re.compile(r"\d+-foot") +sphere_size_re = re.compile(r"(?P\d+)-foot-radius sphere") +cylinder_size_re = re.compile(r"(?P\d+)-foot-radius, \d+-foot-high cylinder") +cube_size_re = re.compile(r"(?P\d+)-foot cube") +cone_size_re = re.compile(r"(?P\d+)-foot cone") + + def main(): args = dnd5etools.scripts.argparse.build_argument_parser( "Summarizes spell templates", @@ -12,7 +20,45 @@ def main(): codes = list(db.db_index.source_index.keys()) else: codes = args.source_code + all_template_spells = [] for code in codes: - spell_list = db.get_spell_list(code) - # pprint.pprint(spell_list.spells) - print(f"Found {len(spell_list.spells)} spells") + all_template_spells += filter(is_template_spell, db.get_spell_list(code).spells) + # pprint.pprint(all_template_spells) + spheres = set() + cylinders = set() + cubes = set() + cones = set() + for spell in all_template_spells: + found = False + for search_re, dest in [ + (sphere_size_re, spheres), + (cylinder_size_re, cylinders), + (cube_size_re, cubes), + (cone_size_re, cones), + ]: + m = search_re.search(spell.description) + if m is not None: + dest.add(m.group("size")) + found = True + break + if not found: + print(spell) + print("spheres", spheres) + print("cylinders", cylinders) + print("cubes", cubes) + print("cones", cones) + + +def is_template_spell(spell: dnd5etools.db.spells.Spell) -> bool: + return ( + len(spell.area_type) > 0 + and has_timed_duration(spell) + and area_size_re.search(spell.description) is not None + ) + + +def has_timed_duration(spell: dnd5etools.db.spells.Spell) -> bool: + for sd in spell.duration: + if sd.type != dnd5etools.db.spells.DurationType.Instant: + return True + return False