diff --git a/dnd5etools/db/spells.py b/dnd5etools/db/spells.py index cb7d666..f40a916 100644 --- a/dnd5etools/db/spells.py +++ b/dnd5etools/db/spells.py @@ -33,7 +33,7 @@ class Duration(typing.NamedTuple): time_type: typing.Optional[DurationTimeType] time_value: typing.Optional[int] concentration: bool - end_condition: typing.Set[str] + end_condition: typing.Set[str] # TODO: replace with a full enum @classmethod def from_json(cls, json_data) -> typing.Self: @@ -75,6 +75,42 @@ class SpellAreaType(enum.StrEnum): Wall = "W" +class SpellRangeType(enum.StrEnum): + Special = "special" + Point = "point" + Line = "line" + Cube = "cube" + Cone = "cone" + EmanatioN = "emanation" + Radius = "radius" + Sphere = "sphere" + Hemisphere = "hemisphere" + Cylinder = "cylinder" + Self = "self" + Sight = "sight" + Unlimited = "unlimited" + UnlimitedSamePlane = "plane" + Touch = "touch" + + +class SpellRange(typing.NamedTuple): + type: SpellRangeType + distance_type: str # TODO Replace with a full enum + distance_value: typing.Optional[int] + + @classmethod + def from_json(cls, json_data) -> typing.Self: + return cls( + type=SpellRangeType(json_data["type"]), + distance_type=json_data["distance"]["type"], + distance_value=( + int(json_data["distance"]["amount"]) + if "amount" in json_data["distance"] + else None + ), + ) + + class Spell(typing.NamedTuple): name: str source: str @@ -83,7 +119,8 @@ class Spell(typing.NamedTuple): duration: typing.List[Duration] attack_type: typing.Set[SpellAttackType] area_type: typing.Set[SpellAreaType] - # remaining: 'affectsCreatureType', 'alias', 'basicRules2024', 'components', 'conditionImmune', 'conditionInflict', 'damageImmune', 'damageInflict', 'damageResist', 'damageVulnerable', 'entriesHigherLevel', 'hasFluffImages', 'level', 'meta', 'miscTags', 'page', 'range', 'savingThrow', 'scalingLevelDice', 'school', 'srd52', 'time' + range: SpellRange + # remaining: 'affectsCreatureType', 'alias', 'basicRules2024', 'components', 'conditionImmune', 'conditionInflict', 'damageImmune', 'damageInflict', 'damageResist', 'damageVulnerable', 'entriesHigherLevel', 'hasFluffImages', 'level', 'meta', 'miscTags', 'page', 'savingThrow', 'scalingLevelDice', 'school', 'srd52', 'time' @classmethod def from_json(cls, json_data) -> typing.Self: @@ -109,6 +146,10 @@ class Spell(typing.NamedTuple): area_type = cls.area_type_from_json(json_data) except Exception as e: raise Exception(f"Unable to parse areaTags for {name}: {e}") + try: + range = cls.range_from_json(json_data) + except Exception as e: + raise Exception(f"Unable to parse range for {name}: {e}") return cls( name=name, source=source, @@ -117,6 +158,7 @@ class Spell(typing.NamedTuple): duration=duration, attack_type=attack_type, area_type=area_type, + range=range, ) @classmethod @@ -147,6 +189,10 @@ class Spell(typing.NamedTuple): def duration_from_json(cls, json_data) -> typing.List[Duration]: return [Duration.from_json(d) for d in json_data["duration"]] + @classmethod + def range_from_json(cls, json_data) -> typing.List[SpellRange]: + return SpellRange.from_json(json_data["range"]) + class SpellList: def __init__(self, code: str, filepath: pathlib.Path) -> None: