Files
AWCharacterCreator/frontend/src/sheetModel.js
T
Claude 5f3b2b2874 Add accounts, presets, live sheet panel and equipment tiles
- Login with registration code, sessions, rate limiting, per-user characters
- Share characters with other users (read-only), admin CLI
- Rules presets with a Presets tab, applied/pending changes with diff in a side sheet
- Equipment as tiles with amounts, starting kit removed
- Rename nav tab to "Character", add "New character" button
- Stop tracking _to_delete/

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJhXuLD2Z6hv3Wqeq9UL9K
2026-10-20 20:37:09 +00:00

47 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { compute, effectiveRules, kitItems } from './calc.js'
// Flat, comparable view of a character, used by the side panel to show what changed.
export function sheetModel(ch, baseRules) {
const rules = effectiveRules(baseRules, ch)
const c = compute(ch, rules)
const prof = rules.professions.find((p) => p.id === ch.profession)
const cls = rules.classes.find((k) => k.id === ch.class_id)
const sub = cls?.subclasses.find((x) => x.id === ch.subclass_id)
const preset = ch.preset === 'custom' ? 'Custom' : baseRules.presets?.find((p) => p.id === ch.preset)?.name || 'Custom'
const training = (s) => (s.pips === 2 ? 'Expertise' : s.pips === 1 ? 'Proficient' : !s.usable ? 'Locked' : s.type === 'advanced' ? 'Unlocked' : '')
return {
c,
head: [
{ k: 'name', label: 'Name', val: ch.name || 'Nameless' },
{ k: 'profession', label: 'Profession', val: prof?.name || '–' },
{ k: 'class', label: 'Class', val: cls ? [cls.name, sub?.name].filter(Boolean).join(' / ') : '–' },
{ k: 'preset', label: 'Rules', val: preset },
],
attrs: rules.attributes.map((a) => ({ k: a.id, label: a.name, val: c.attrs[a.id], extra: `Mod ${c.mods[a.id]}` })),
derived: rules.derived.map((d) => ({ k: d.id, label: d.name, val: c.derived[d.id] })),
skills: c.skills.map((s) => ({ k: s.id, label: s.name, val: s.total, extra: training(s), dim: !s.usable })),
talents: rules.talents.filter((t) => ch.talents.includes(t.id)).map((t) => ({ k: t.id, label: t.name, desc: t.desc })),
augments: rules.augments.filter((a) => ch.augments.includes(a.id)).map((a) => ({ k: a.id, label: a.name, desc: `${a.kind === 'implant' ? 'Implant' : 'Mutation'} · cost ${a.cost}${a.desc ? ` · ${a.desc}` : ''}` })),
gear: kitItems(ch, rules).map((g) => ({ k: g.item.id, label: g.item.name, val: g.qty, desc: [g.item.stat, `${g.item.kg} kg`, g.item.note].filter(Boolean).join(' · ') })),
}
}
// Merges two row lists into one with a status per row: same | changed | added | removed.
export function diffRows(now, before) {
const old = new Map(before.map((r) => [r.k, r]))
const seen = new Set()
const out = now.map((r) => {
seen.add(r.k)
const o = old.get(r.k)
if (!o) return { ...r, status: 'added' }
return { ...r, old: o, status: o.val === r.val && (o.extra || '') === (r.extra || '') ? 'same' : 'changed' }
})
before.forEach((o) => { if (!seen.has(o.k)) out.push({ ...o, status: 'removed' }) })
return out
}
export const countChanges = (a, b) => {
const n = (rows, bef) => diffRows(rows, bef).filter((r) => r.status !== 'same').length
return n(a.head, b.head) + n(a.attrs, b.attrs) + n(a.skills, b.skills) + n(a.talents, b.talents) + n(a.augments, b.augments) + n(a.gear, b.gear)
}