73 lines
2.8 KiB
Python
73 lines
2.8 KiB
Python
# race_catalog.py
|
|
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any
|
|
import yaml
|
|
|
|
|
|
from app.models.enums import Race
|
|
from app.models.primitives import Attributes, Resources
|
|
from app.models.races import RaceSheet, RacialTrait
|
|
from app.utils.hero_catalog import SkillDef, SpellDef
|
|
|
|
class RaceDataRegistry:
|
|
"""
|
|
In-memory catalog of YAML-defined race sheets.
|
|
"""
|
|
def __init__(self) -> None:
|
|
self._by_race: Dict[Race, RaceSheet] = {}
|
|
# promoted global catalogs for cross-use at runtime (optional)
|
|
self._skills: Dict[str, SkillDef] = {}
|
|
self._spells: Dict[str, SpellDef] = {}
|
|
|
|
def load_dir(self, directory: str | Path) -> None:
|
|
directory = Path(directory)
|
|
for path in sorted(directory.glob("*.y*ml")):
|
|
with path.open("r", encoding="utf-8") as f:
|
|
raw = yaml.safe_load(f) or {}
|
|
|
|
key_raw = raw.get("key")
|
|
if not key_raw:
|
|
raise ValueError(f"{path.name}: missing required 'key'")
|
|
race = Race(key_raw) # validates enum
|
|
|
|
base_attributes = Attributes(**(raw.get("base_attributes") or {}))
|
|
starting_resources = Resources(**(raw.get("starting_resources") or {}))
|
|
|
|
sheet = RaceSheet(
|
|
key=race,
|
|
display_name=raw.get("display_name", race.value.title()),
|
|
base_attributes=base_attributes,
|
|
starting_resources=starting_resources,
|
|
starting_skills=list(raw.get("starting_skills") or []),
|
|
starting_spells=list(raw.get("starting_spells") or []),
|
|
)
|
|
|
|
# Local skill/spell catalogs (optional)
|
|
for sid, sdef in (raw.get("skills") or {}).items():
|
|
s = SkillDef.from_yaml(sid, sdef)
|
|
sheet.skills[sid] = s
|
|
self._skills[sid] = s
|
|
|
|
for spid, spdef in (raw.get("spells") or {}).items():
|
|
sp = SpellDef.from_yaml(spid, spdef)
|
|
sheet.spells[spid] = sp
|
|
self._spells[spid] = sp
|
|
|
|
# Traits
|
|
traits_raw = raw.get("traits") or []
|
|
for t in traits_raw:
|
|
sheet.traits.append(RacialTrait(id=t.get("id"), data=dict(t.get("data") or {})))
|
|
|
|
self._by_race[race] = sheet
|
|
|
|
def for_race(self, race: Race) -> RaceSheet:
|
|
if race not in self._by_race:
|
|
raise KeyError(f"No race sheet loaded for {race.value}")
|
|
return self._by_race[race]
|
|
|
|
# Optional global lookups (if you want to fetch a skill from race-only files)
|
|
def get_skill(self, skill_id: str) -> SkillDef: return self._skills[skill_id]
|
|
def get_spell(self, spell_id: str) -> SpellDef: return self._spells[spell_id]
|