5e builder: add curated official subclasses (start with Rogue Mastermind)
classes.json ships the SRD subclass + third-party homebrew but is missing most official PHB/XGE archetypes. New DND5E_SUBCLASSES supplement is merged (deduped by name) ahead of the on-disk list in the builder, surviving any classes.json regeneration. First entry: Rogue → Mastermind. (Subclass feature mechanics remain a separate task; this adds the selectable options.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import { getClassTip, raceSynergyNote } from '@/lib/assistant/builder';
|
|||||||
import { briefOverview, dedupeByName } from './overview';
|
import { briefOverview, dedupeByName } from './overview';
|
||||||
import { parseAsiBonuses, makeSkillResolver, parseBackgroundSkills, parseTraitSkills } from './origin';
|
import { parseAsiBonuses, makeSkillResolver, parseBackgroundSkills, parseTraitSkills } from './origin';
|
||||||
import { PF2E_SUBCLASSES } from '@/lib/rules/pf2e/progression';
|
import { PF2E_SUBCLASSES } from '@/lib/rules/pf2e/progression';
|
||||||
|
import { DND5E_SUBCLASSES } from '@/lib/rules/dnd5e/progression';
|
||||||
import { Modal } from '@/components/ui/Modal';
|
import { Modal } from '@/components/ui/Modal';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Badge } from '@/components/ui/Codex';
|
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;
|
const caster = def && def.caster !== 'none' && def.spellAbility ? def.spellAbility : rc.caster;
|
||||||
return { ...rc, caster, subclasses };
|
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)));
|
setClasses([...enriched].sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
});
|
});
|
||||||
return () => { on = false; };
|
return () => { on = false; };
|
||||||
|
|||||||
@@ -99,3 +99,16 @@ export function dnd5eAsiLevels(className: string): number[] {
|
|||||||
if (c === 'rogue') return [...base, 10].sort((a, b) => a - b);
|
if (c === 'rogue') return [...base, 10].sort((a, b) => a - b);
|
||||||
return base;
|
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<string, { name: string; desc: string }[]> = {
|
||||||
|
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.' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user