diff --git a/server/prisma/data/spell-slot-overlays.ts b/server/prisma/data/spell-slot-overlays.ts index 687b455..b114817 100644 --- a/server/prisma/data/spell-slot-overlays.ts +++ b/server/prisma/data/spell-slot-overlays.ts @@ -10,14 +10,28 @@ * (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. + * SCOPE: 16 D-16 classes (Core + APG). Plan 03 shipped 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 (confirmed empty per design). * * 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. + * + * SLOT-PROGRESSION CADENCE (all D-16 full casters share this base shape): + * L1 : +2 grade-1 slots (3 for spontaneous Sorcerer/Oracle), +5 cantrips + * L2 : +1 grade-1 slot + * L3 : +2 grade-2 slots + * L4 : +1 grade-2 slot + * ... continues +2 / +1 per spell-grade through L18 (+1 grade-9) + * L19: +1 grade-10 slot (Magnum Opus / capstone equivalent) + * L20: no further slot increment (capstone is qualitative) + * + * REPERTOIRE CADENCE (spontaneous casters, Plan 03b model): + * L2..L19 each grant +1 spell known (`repertoireIncrement: 1`). The recompute pipeline + * in Plan 04 distributes that capacity across known spell grades; this overlay simply + * tracks "new spell known this level" so the wizard can prompt the player. */ export type SpellTradition = 'ARCANE' | 'DIVINE' | 'OCCULT' | 'PRIMAL'; @@ -36,6 +50,7 @@ export interface SpellSlotOverlayEntry { */ export const SPELL_SLOT_OVERLAY: Record = { // === PREPARED CASTER — WIZARD (worked example, fully populated in Plan 03) === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=12 (Wizard) — Player Core p.205 spell-slot table. Wizard: [ { level: 1, cantripIncrement: 5 }, { level: 1, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 1, count: 2 } }, @@ -61,17 +76,251 @@ export const SPELL_SLOT_OVERLAY: Record = { // 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 + // === PREPARED CASTER — CLERIC === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=4 (Cleric) — Player Core p.119 spell-slot table. + // Tradition: DIVINE. Cadence: identical to Wizard, replacing tradition. + Cleric: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 1, count: 2 } }, + { level: 2, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 1, count: 1 } }, + { level: 3, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 2, count: 2 } }, + { level: 4, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 2, count: 1 } }, + { level: 5, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 3, count: 2 } }, + { level: 6, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 3, count: 1 } }, + { level: 7, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 4, count: 2 } }, + { level: 8, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 4, count: 1 } }, + { level: 9, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 5, count: 2 } }, + { level: 10, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 5, count: 1 } }, + { level: 11, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 6, count: 2 } }, + { level: 12, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 6, count: 1 } }, + { level: 13, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 7, count: 2 } }, + { level: 14, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 7, count: 1 } }, + { level: 15, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 8, count: 2 } }, + { level: 16, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 8, count: 1 } }, + { level: 17, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 9, count: 2 } }, + { level: 18, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 9, count: 1 } }, + // L19 Miraculous Spell = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 10, count: 1 } }, + ], - // Non-caster stubs (Plan 03b confirms these stay empty): + // === PREPARED CASTER — DRUID === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=6 (Druid) — Player Core p.131 spell-slot table. + // Tradition: PRIMAL. Cadence: identical to Wizard. + Druid: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 1, count: 2 } }, + { level: 2, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 1, count: 1 } }, + { level: 3, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 2, count: 2 } }, + { level: 4, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 2, count: 1 } }, + { level: 5, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 3, count: 2 } }, + { level: 6, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 3, count: 1 } }, + { level: 7, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 4, count: 2 } }, + { level: 8, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 4, count: 1 } }, + { level: 9, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 5, count: 2 } }, + { level: 10, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 5, count: 1 } }, + { level: 11, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 6, count: 2 } }, + { level: 12, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 6, count: 1 } }, + { level: 13, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 7, count: 2 } }, + { level: 14, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 7, count: 1 } }, + { level: 15, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 8, count: 2 } }, + { level: 16, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 8, count: 1 } }, + { level: 17, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 9, count: 2 } }, + { level: 18, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 9, count: 1 } }, + // L19 Hierophant's Power = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'PRIMAL', spellLevel: 10, count: 1 } }, + ], + + // === PREPARED CASTER — WITCH === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=27 (Witch) — Player Core (Witch) spell-slot table. + // CAVEAT: Witch tradition depends on patron (the player picks the patron at L1 — see the + // CLASS_FEATURE_OPTIONS witch-patron entries). The overlay defaults to ARCANE for slot + // bookkeeping; the recompute pipeline (Plan 04) may need to remap this to the actual + // patron's tradition at commit time. For Phase 1 we accept the default — the slot count + // is the same regardless of tradition; only spell list / known-spell pool differs. + Witch: [ + { 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 Patron's Truth = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 10, count: 1 } }, + ], + + // === SPONTANEOUS CASTER — BARD === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=2 (Bard) — Player Core p.99 spell-slot + repertoire table. + // Tradition: OCCULT (fixed by class, not by muse). + // L1: 5 cantrips + 2 grade-1 slots (initial repertoire = 4 cantrips known + 2 grade-1 known). + // L2..L19: each level adds 1 known spell (repertoireIncrement: 1) per the spontaneous-caster + // progression. L20 is the qualitative capstone (no new slots/spells). + Bard: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 1, count: 2 } }, + { level: 2, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 1, count: 1 } }, + { level: 2, repertoireIncrement: 1 }, + { level: 3, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 2, count: 2 } }, + { level: 3, repertoireIncrement: 1 }, + { level: 4, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 2, count: 1 } }, + { level: 4, repertoireIncrement: 1 }, + { level: 5, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 3, count: 2 } }, + { level: 5, repertoireIncrement: 1 }, + { level: 6, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 3, count: 1 } }, + { level: 6, repertoireIncrement: 1 }, + { level: 7, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 4, count: 2 } }, + { level: 7, repertoireIncrement: 1 }, + { level: 8, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 4, count: 1 } }, + { level: 8, repertoireIncrement: 1 }, + { level: 9, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 5, count: 2 } }, + { level: 9, repertoireIncrement: 1 }, + { level: 10, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 5, count: 1 } }, + { level: 10, repertoireIncrement: 1 }, + { level: 11, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 6, count: 2 } }, + { level: 11, repertoireIncrement: 1 }, + { level: 12, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 6, count: 1 } }, + { level: 12, repertoireIncrement: 1 }, + { level: 13, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 7, count: 2 } }, + { level: 13, repertoireIncrement: 1 }, + { level: 14, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 7, count: 1 } }, + { level: 14, repertoireIncrement: 1 }, + { level: 15, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 8, count: 2 } }, + { level: 15, repertoireIncrement: 1 }, + { level: 16, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 8, count: 1 } }, + { level: 16, repertoireIncrement: 1 }, + { level: 17, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 9, count: 2 } }, + { level: 17, repertoireIncrement: 1 }, + { level: 18, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 9, count: 1 } }, + { level: 18, repertoireIncrement: 1 }, + // L19 Magnum Opus equivalent — 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'OCCULT', spellLevel: 10, count: 1 } }, + { level: 19, repertoireIncrement: 1 }, + ], + + // === SPONTANEOUS CASTER — SORCERER === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=15 (Sorcerer) — Player Core p.193 spell-slot table. + // CAVEAT: Tradition depends on bloodline (the player picks the bloodline at L1 — see the + // CLASS_FEATURE_OPTIONS sorcerer-bloodline entries). The overlay defaults to ARCANE for + // slot bookkeeping; recompute pipeline (Plan 04) may remap to the actual bloodline's + // tradition at commit time. + // L1: 5 cantrips + 3 grade-1 slots (one more than Bard/prepared casters per Sorcerer/Oracle table). + // L2..L19: standard +1 / +2 cadence; repertoireIncrement: 1 each level for known-spell growth. + Sorcerer: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 1, count: 3 } }, + { level: 2, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 1, count: 1 } }, + { level: 2, repertoireIncrement: 1 }, + { level: 3, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 2, count: 3 } }, + { level: 3, repertoireIncrement: 1 }, + { level: 4, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 2, count: 1 } }, + { level: 4, repertoireIncrement: 1 }, + { level: 5, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 3, count: 3 } }, + { level: 5, repertoireIncrement: 1 }, + { level: 6, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 3, count: 1 } }, + { level: 6, repertoireIncrement: 1 }, + { level: 7, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 4, count: 3 } }, + { level: 7, repertoireIncrement: 1 }, + { level: 8, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 4, count: 1 } }, + { level: 8, repertoireIncrement: 1 }, + { level: 9, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 5, count: 3 } }, + { level: 9, repertoireIncrement: 1 }, + { level: 10, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 5, count: 1 } }, + { level: 10, repertoireIncrement: 1 }, + { level: 11, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 6, count: 3 } }, + { level: 11, repertoireIncrement: 1 }, + { level: 12, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 6, count: 1 } }, + { level: 12, repertoireIncrement: 1 }, + { level: 13, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 7, count: 3 } }, + { level: 13, repertoireIncrement: 1 }, + { level: 14, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 7, count: 1 } }, + { level: 14, repertoireIncrement: 1 }, + { level: 15, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 8, count: 3 } }, + { level: 15, repertoireIncrement: 1 }, + { level: 16, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 8, count: 1 } }, + { level: 16, repertoireIncrement: 1 }, + { level: 17, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 9, count: 3 } }, + { level: 17, repertoireIncrement: 1 }, + { level: 18, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 9, count: 1 } }, + { level: 18, repertoireIncrement: 1 }, + // L19 Bloodline Paragon = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'ARCANE', spellLevel: 10, count: 1 } }, + { level: 19, repertoireIncrement: 1 }, + ], + + // === SPONTANEOUS CASTER — ORACLE === + // SOURCE: https://2e.aonprd.com/Classes.aspx?ID=12 (Oracle) — APG / Player Core 2 spell-slot table. + // Tradition: DIVINE (fixed — Mystery does not change tradition). + // L1: 5 cantrips + 3 grade-1 slots (matches Sorcerer pattern, not Bard). + // L2..L19: standard +1 / +2 cadence; repertoireIncrement: 1 each level. + Oracle: [ + { level: 1, cantripIncrement: 5 }, + { level: 1, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 1, count: 3 } }, + { level: 2, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 1, count: 1 } }, + { level: 2, repertoireIncrement: 1 }, + { level: 3, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 2, count: 3 } }, + { level: 3, repertoireIncrement: 1 }, + { level: 4, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 2, count: 1 } }, + { level: 4, repertoireIncrement: 1 }, + { level: 5, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 3, count: 3 } }, + { level: 5, repertoireIncrement: 1 }, + { level: 6, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 3, count: 1 } }, + { level: 6, repertoireIncrement: 1 }, + { level: 7, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 4, count: 3 } }, + { level: 7, repertoireIncrement: 1 }, + { level: 8, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 4, count: 1 } }, + { level: 8, repertoireIncrement: 1 }, + { level: 9, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 5, count: 3 } }, + { level: 9, repertoireIncrement: 1 }, + { level: 10, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 5, count: 1 } }, + { level: 10, repertoireIncrement: 1 }, + { level: 11, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 6, count: 3 } }, + { level: 11, repertoireIncrement: 1 }, + { level: 12, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 6, count: 1 } }, + { level: 12, repertoireIncrement: 1 }, + { level: 13, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 7, count: 3 } }, + { level: 13, repertoireIncrement: 1 }, + { level: 14, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 7, count: 1 } }, + { level: 14, repertoireIncrement: 1 }, + { level: 15, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 8, count: 3 } }, + { level: 15, repertoireIncrement: 1 }, + { level: 16, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 8, count: 1 } }, + { level: 16, repertoireIncrement: 1 }, + { level: 17, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 9, count: 3 } }, + { level: 17, repertoireIncrement: 1 }, + { level: 18, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 9, count: 1 } }, + { level: 18, repertoireIncrement: 1 }, + // L19 Mystery Conduit = 1 grade-10 slot per day + { level: 19, spellSlotIncrement: { tradition: 'DIVINE', spellLevel: 10, count: 1 } }, + { level: 19, repertoireIncrement: 1 }, + ], + + // === FOCUS-ONLY CASTER — CHAMPION === + // Champion casts Devotion Spells via a focus pool (1-3 focus points), NOT via spell slots. + // Phase 1 records minimal entries — focus-spell mechanics are handled outside the slot + // table and may grow into a Plan 04 Phase 2 focus-pool tracker. Champion remains + // effectively non-caster from the slot-overlay perspective; choiceOptionsRef + // 'champion-cause' (set by the seed script's L1_CHOICE_MAP) routes the L1 cause pick + // through ClassFeatureOption. + Champion: [], + + // === NON-CASTERS — confirmed empty per design === + // These classes have no spell-slot, cantrip, or repertoire progression. Some (Alchemist, + // Investigator, Ranger) have other resource pools (alchemical-bombs / clue-pool / hunt-prey) + // tracked outside this overlay. Empty arrays are required because the seed script's + // `(SPELL_SLOT_OVERLAY[className] || []).filter(...)` relies on key presence to avoid + // missing-key bugs. Alchemist: [], Barbarian: [], Fighter: [],