import csv import re from enum import Enum from dataclasses import dataclass class Difficulty(Enum): Terrible = -2 Low = -1 Moderate = 0 High = 1 Extreme = 2 @classmethod def from_str(cls, name): name = name.strip().lower() for member in cls: if member.name.lower() == name: return member raise ValueError(f"{name!r} is not a valid {cls.__name__}") @dataclass class RollInfo: die_size: int dice_count: int = 1 bonus: int = 0 @classmethod def parse(cls, str_data): # match strings like 2d6+8 (15) match = re.fullmatch(r"^(\d+)d(\d+)\s*(\+\s*\d+)?\s*(\s*\(\s*\d+\s*\))?", str_data) if not match: raise ValueError(f"{str_data!r} is not a valid RollInfo") res = RollInfo(int(match.group(2).strip())) res.dice_count = int(match.group(1).strip()) bonus = match.group(3) if bonus: res.bonus = int(bonus.strip(" +")) return res def safe_item_level(creature_level: int): if creature_level <= 3: return 0 if creature_level == 4: return 1 return creature_level - 4 def load_csv(name, value_parser=None): def parse_col_name(name): try: return Difficulty.from_str(name) except ValueError: return name.lower() if value_parser is None: value_parser = lambda x:x res = dict() # Table by level and Difficulty with open(f"creature_stats/{name}.csv", newline='', encoding='utf8') as file: reader = csv.DictReader(file) for row in reader: level = int(row.pop("Level")) res[level] = {parse_col_name(name): value_parser(val) for name,val in row.items()} return res def parse_stat(str_data): try: return int(str_data) except ValueError: pass separator = "-" if separator in str_data: # parse range values = [int(i) for i in str_data.split(separator)[:2]] return tuple((min(*values), max(*values))) else: return RollInfo.parse(str_data) class StatsDB: stat_names = ["ac","abilities","attack_bonus", "hp", "perception", "saves", "resistances", "skills", "strike_damage"] def __init__(self) -> None: self.stats = dict() for stat_name in StatsDB.stat_names: self.stats[stat_name] = load_csv(stat_name, parse_stat) self.stats["resistances"] = {k:(v["minimum"], v["maximum"]) for k,v in self.stats["resistances"].items()} stats = StatsDB() # if __name__ == '__main__': # main()