first commit

This commit is contained in:
DuOtto
2026-10-19 22:27:05 +02:00
commit afbdc4b139
28 changed files with 4242 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
"""Computes modifiers, derived stats, skill totals and carried weight (mirror of frontend/src/calc.js)."""
def kit_items(ch: dict, rules: dict) -> list:
"""Returns [(label, item, qty)] for the starting kit and extra items."""
items = {e["id"]: e for e in rules.get("equipment", [])}
kit = ch.get("kit") or {}
out = []
for label, key in (("Weapon", "weapon"), ("Armor", "armor"), ("Tool", "tool")):
if kit.get(key) in items:
out.append((label, items[kit[key]], 1))
for rid in kit.get("resources", []):
if rid in items:
out.append(("Resource", items[rid], 1))
for iid, qty in (kit.get("extras") or {}).items():
if iid in items and int(qty) > 0:
out.append(("Extra", items[iid], int(qty)))
return out
def compute(ch: dict, rules: dict) -> dict:
cr = {**rules["creation"], **(ch.get("creation") or {})} # per-character rules preset overrides
prof_id = ch.get("profession")
bonus_attr = ch.get("profession_bonus_attr") if prof_id else None
attrs = {}
for a in rules["attributes"]:
base = int((ch.get("attributes") or {}).get(a["id"], cr["attr_start"]))
attrs[a["id"]] = base + (cr["profession_attr_bonus"] if a["id"] == bonus_attr else 0)
mods = {k: v // 10 for k, v in attrs.items()}
derived = {d["id"]: sum(mods[x] for x in d["formula"]) for d in rules["derived"]}
skills = []
for s in rules["skills"]:
pts = int((ch.get("skill_points") or {}).get(s["id"], 0))
# Proficiency "pips": 1 from the profession plus free picks, at most 2 (2 = Expertise)
prof_pip = 1 if (ch.get("proficiencies") or {}).get(s["id"]) else 0
free_pips = min(int((ch.get("proficiency_picks") or {}).get(s["id"], 0)), cr.get("max_proficiency_pips", 2) - prof_pip)
pips = prof_pip + max(0, free_pips)
prof = [0, cr["proficiency_bonus"], cr["expertise_bonus"]][pips]
unlocked = s["id"] in (ch.get("unlocked") or [])
usable = s["type"] == "basic" or unlocked or prof > 0 # advanced skills must be unlocked
best = max(attrs[a] for a in s["attrs"]) # with several attributes the higher one counts
skills.append({**s, "points": pts, "prof": prof, "pips": pips, "usable": usable, "unlocked": unlocked,
"total": best + pts + prof})
aug_by_id = {a["id"]: a for a in rules["augments"]}
chosen = [aug_by_id[i] for i in ch.get("augments", []) if i in aug_by_id]
used = sum(a["cost"] for a in chosen)
weight = round(sum(item["kg"] * qty for _, item, qty in kit_items(ch, rules)), 1)
return {"attrs": attrs, "mods": mods, "derived": derived, "skills": skills,
"capacity_used": used, "capacity_max": derived.get("augmentation", 0),
"augments": chosen, "weight": weight,
"carry_max": max(0, mods["strength"]) * cr.get("carry_per_strength_mod", 10)}