first commit
This commit is contained in:
@@ -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)}
|
||||
Reference in New Issue
Block a user