feat(combat): skills system
This commit is contained in:
@@ -36,6 +36,7 @@ from pf1e_simulator.models import (
|
||||
Combatant,
|
||||
DamageComponent,
|
||||
Saves,
|
||||
SkillRank,
|
||||
)
|
||||
|
||||
type Json = dict[str, Json] | list[Json] | str | int | float | bool | None
|
||||
@@ -108,6 +109,30 @@ def _extract_spells(spellcasting: Json) -> list[str]:
|
||||
return names
|
||||
|
||||
|
||||
def _extract_skills(skills_section: Json) -> dict[str, SkillRank]:
|
||||
"""Extract skills from Foundry sheet skills section."""
|
||||
if not isinstance(skills_section, dict):
|
||||
return {}
|
||||
skills: dict[str, SkillRank] = {}
|
||||
for name, data in skills_section.items():
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
key = name.lower().replace(" ", "_").replace("(", "").replace(")", "")
|
||||
# Handle special cases
|
||||
key = key.replace("knowledge_", "knowledge_")
|
||||
rank = data.get("rank", 0)
|
||||
class_skill = data.get("classSkill", False)
|
||||
armor_penalty = data.get("armorPenalty", 0)
|
||||
if isinstance(armor_penalty, bool):
|
||||
armor_penalty = 0
|
||||
if isinstance(rank, bool):
|
||||
rank = 0
|
||||
skills[key] = SkillRank(
|
||||
rank=int(rank) if isinstance(rank, (int, float)) else 0,
|
||||
class_skill=bool(class_skill),
|
||||
armor_penalty=int(armor_penalty) if isinstance(armor_penalty, (int, float)) else 0,
|
||||
)
|
||||
return skills
|
||||
class SheetLoadError(Exception):
|
||||
"""Raised when a sheet cannot be loaded; carries path and reason."""
|
||||
|
||||
@@ -300,7 +325,8 @@ def load_sheet_detailed(path: Path) -> tuple[Combatant, LoadReport]:
|
||||
speed_raw = reader.as_dict(combat.get("speed"), "combat.speed")
|
||||
ac_raw = reader.as_dict(combat.get("ac"), "combat.ac")
|
||||
hp_raw = reader.as_dict(combat.get("hp"), "combat.hp")
|
||||
|
||||
skills_raw = root.get("skills")
|
||||
skills = _extract_skills(skills_raw)
|
||||
sheet_id = reader.req_str(meta, "id", "meta.id")
|
||||
land_speed = reader.speed(speed_raw.get("land"), "combat.speed.land")
|
||||
if land_speed is None:
|
||||
@@ -350,6 +376,7 @@ def load_sheet_detailed(path: Path) -> tuple[Combatant, LoadReport]:
|
||||
attacks=kept,
|
||||
features=_extract_features(root.get("feats")),
|
||||
spells=_extract_spells(root.get("spellcasting")),
|
||||
skills=skills,
|
||||
)
|
||||
report = LoadReport(path=str(path), kept=len(kept), skipped=tuple(skipped))
|
||||
return combatant, report
|
||||
|
||||
Reference in New Issue
Block a user