feat(combat): skills system

This commit is contained in:
2026-09-04 22:55:41 +02:00
parent d792b6e28f
commit ab2874d79b
4 changed files with 233 additions and 1 deletions
+28 -1
View File
@@ -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