diff --git a/server/prisma/data/spell-slot-overlays.ts b/server/prisma/data/spell-slot-overlays.ts new file mode 100644 index 0000000..687b455 --- /dev/null +++ b/server/prisma/data/spell-slot-overlays.ts @@ -0,0 +1,83 @@ +/** + * Hand-curated spell-slot / cantrip / repertoire progression overlay. + * + * WHY HAND-CURATED: Foundry pf2e encodes slot tables in description prose, not machine- + * readable rules (Pitfall #6 / verified 2026-04-27 against `wizard-spellcasting.json`). + * NLP-parsing prose is fragile; the canonical PF2e tables fit in ~300 lines and are stable + * across reprints. + * + * SOURCE: Archives of Nethys — Pathfinder 2e Player Core + Advanced Player's Guide + * (https://2e.aonprd.com). Per-class spell-slot tables, cantrip counts, and repertoire + * sizes (spontaneous casters only). + * + * SCOPE: 16 D-16 classes (Core + APG). This file (Plan 03) ships the type definitions + * and Wizard fully populated as the worked example. Plan 03b appends entries for the + * remaining 6 caster classes (Cleric, Druid, Witch, Bard, Sorcerer, Oracle) and the + * empty-array entries for non-casters. + * + * SPONTANEOUS vs PREPARED: Spontaneous casters (Bard, Sorcerer, Oracle) get + * repertoireIncrement entries on level-up. Prepared casters (Cleric, Druid, Witch, Wizard) + * get spellSlotIncrement only. Both get cantripIncrement at L1. + */ + +export type SpellTradition = 'ARCANE' | 'DIVINE' | 'OCCULT' | 'PRIMAL'; + +export interface SpellSlotOverlayEntry { + level: number; + spellSlotIncrement?: { tradition: SpellTradition; spellLevel: number; count: number }; + cantripIncrement?: number; + repertoireIncrement?: number; +} + +/** + * Each class maps to an array of overlay entries. Multiple entries per level are allowed + * (e.g. L1 Wizard gets 5 cantrips AND 2 grade-1 slots — two separate entries). + * Order within a level does not matter — the seed script merges them per (class, level). + */ +export const SPELL_SLOT_OVERLAY: Record = { + // === PREPARED CASTER — WIZARD (worked example, fully populated in Plan 03) === + Wizard: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 1, count: 2 } }, + { level: 2, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 1, count: 1 } }, + { level: 3, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 2, count: 2 } }, + { level: 4, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 2, count: 1 } }, + { level: 5, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 3, count: 2 } }, + { level: 6, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 3, count: 1 } }, + { level: 7, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 4, count: 2 } }, + { level: 8, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 4, count: 1 } }, + { level: 9, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 5, count: 2 } }, + { level: 10, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 5, count: 1 } }, + { level: 11, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 6, count: 2 } }, + { level: 12, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 6, count: 1 } }, + { level: 13, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 7, count: 2 } }, + { level: 14, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 7, count: 1 } }, + { level: 15, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 8, count: 2 } }, + { level: 16, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 8, count: 1 } }, + { level: 17, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 9, count: 2 } }, + { level: 18, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 9, count: 1 } }, + // L19 Magnum Opus = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 10, count: 1 } }, + // L20: no slot increment (capstone is qualitative) + ], + + // === STUBS — populated by Plan 03b === + // Caster stubs (Plan 03b will replace [] with full L1..L20 entries): + Cleric: [], + Druid: [], + Witch: [], + Bard: [], + Sorcerer: [], + Oracle: [], + Champion: [], // focus-only; minimal entries + + // Non-caster stubs (Plan 03b confirms these stay empty): + Alchemist: [], + Barbarian: [], + Fighter: [], + Investigator: [], + Monk: [], + Ranger: [], + Rogue: [], + Swashbuckler: [], +};