56 lines
1.6 KiB
Python
56 lines
1.6 KiB
Python
from __future__ import annotations
|
|
from dataclasses import dataclass, field
|
|
from typing import Dict
|
|
|
|
@dataclass
|
|
class AbilityScores:
|
|
STR: int = 0
|
|
DEX: int = 0
|
|
INT: int = 0
|
|
WIS: int = 0
|
|
CON: int = 0
|
|
LUK: int = 0
|
|
CHA: int = 0
|
|
|
|
@dataclass(frozen=True)
|
|
class Race:
|
|
id: str
|
|
name: str
|
|
description: str
|
|
alignment: int = 0
|
|
ability_scores: AbilityScores = field(default_factory=AbilityScores)
|
|
tags: list[str] = field(default_factory=list) # e.g., {"playable"}, {"hostile","goblinoid"}
|
|
|
|
@property
|
|
def is_playable(self) -> bool:
|
|
return "playable" in self.tags
|
|
|
|
@staticmethod
|
|
def from_yaml(data: Dict[str, object]) -> "Race":
|
|
# basic validation with helpful errors
|
|
required = ["id", "name", "description", "alignment", "ability_mods"]
|
|
missing = [k for k in required if k not in data]
|
|
if missing:
|
|
raise ValueError(f"Spell missing required fields: {missing}")
|
|
|
|
mods = data.get("ability_mods", {}) or {}
|
|
|
|
abs = AbilityScores(
|
|
STR=int(mods.get("STR", 0)),
|
|
DEX=int(mods.get("DEX", 0)),
|
|
INT=int(mods.get("INT", 0)),
|
|
WIS=int(mods.get("WIS", 0)),
|
|
CON=int(mods.get("CON", 0)),
|
|
LUK=int(mods.get("LUK", 0)),
|
|
CHA=int(mods.get("CHA", 0)),
|
|
)
|
|
|
|
tags = list(data.get("tags", []))
|
|
|
|
return Race(
|
|
id=str(data["id"]),
|
|
name=str(data["name"]),
|
|
description=str(data["description"]),
|
|
ability_scores=abs,
|
|
tags=tags
|
|
) |