diff --git a/src/features/characters/builder/CreationWizard.tsx b/src/features/characters/builder/CreationWizard.tsx index 1804de9..ea729db 100644 --- a/src/features/characters/builder/CreationWizard.tsx +++ b/src/features/characters/builder/CreationWizard.tsx @@ -18,6 +18,7 @@ import { getClassTip, raceSynergyNote } from '@/lib/assistant/builder'; import { briefOverview, dedupeByName } from './overview'; import { parseAsiBonuses, makeSkillResolver, parseBackgroundSkills, parseTraitSkills } from './origin'; import { PF2E_SUBCLASSES } from '@/lib/rules/pf2e/progression'; +import { DND5E_SUBCLASSES } from '@/lib/rules/dnd5e/progression'; import { Modal } from '@/components/ui/Modal'; import { Button } from '@/components/ui/Button'; import { Badge } from '@/components/ui/Codex'; @@ -94,7 +95,14 @@ export function CreationWizard({ campaign, onClose }: { campaign: Campaign; onCl const caster = def && def.caster !== 'none' && def.spellAbility ? def.spellAbility : rc.caster; return { ...rc, caster, subclasses }; }) - : c; + : c.map((rc) => { + // Merge curated official subclasses (classes.json is missing most PHB/XGE + // archetypes) ahead of the on-disk list, deduped by name. + const extra = DND5E_SUBCLASSES[rc.name] ?? []; + if (!extra.length) return rc; + const have = new Set(rc.subclasses.map((s) => s.name.toLowerCase())); + return { ...rc, subclasses: [...extra.filter((s) => !have.has(s.name.toLowerCase())), ...rc.subclasses] }; + }); setClasses([...enriched].sort((a, b) => a.name.localeCompare(b.name))); }); return () => { on = false; }; diff --git a/src/lib/rules/dnd5e/progression.ts b/src/lib/rules/dnd5e/progression.ts index 5c28cdc..f52bf78 100644 --- a/src/lib/rules/dnd5e/progression.ts +++ b/src/lib/rules/dnd5e/progression.ts @@ -99,3 +99,16 @@ export function dnd5eAsiLevels(className: string): number[] { if (c === 'rogue') return [...base, 10].sort((a, b) => a - b); return base; } + +/** + * Curated official 5e subclasses, merged into the builder's class list on top of + * whatever the on-disk classes.json carries (which is SRD + third-party homebrew and + * is missing most PHB/XGE archetypes). Keyed by class name; deduped by name at merge + * time. Descriptions are short "what it plays like" blurbs — subclass *features* are + * not yet auto-applied (a separate task), so these add the missing options to pick. + */ +export const DND5E_SUBCLASSES: Record = { + Rogue: [ + { name: 'Mastermind', desc: 'A master of intrigue and tactics: extra tool/language proficiencies, Help as a bonus action at range, and uncanny insight into a creature’s drives.' }, + ], +};