Rebuilds the cmd/open5e-import CLI (fetch/gen × spells) to vendor
data/open5e/spells.json (319 SRD spells) and generate
dnd_spells_srd_data.go (237 after the level>5 filter). mapClasses unions
the API's incomplete structured spell_lists field with the complete
free-text dnd_class field so all eight casters get spells.
dndSpellRegistry loads buildSRDSpellList() first; the hand-authored
buildSpellList() overlays it (hand wins on ID collision). Playable=true
flipped for Druid/Bard/Sorcerer/Warlock/Paladin, each with a
defaultKnownSpells case. TestDefaultKnownSpellsExistInRegistry now covers
all eight classes.
.gitignore: vendor data/open5e/ while keeping the rest of data/ ignored,
and anchor the open5e-import binary pattern so it stops swallowing the
cmd/open5e-import source dir. NOTICE adds CC-BY-4.0 / SRD attribution.
Add Druid, Bard, Sorcerer, Warlock and Paladin as structural
scaffolding ahead of the Open5e spell-data import. They are wired
through the mechanical layer but gated out of !setup via the new
DnDClassInfo.Playable flag — they have no spell list yet.
- dnd.go: class constants, dndClasses rows, Playable gate, AC floors
- dnd_combat.go: classAttackStatMod, dndClassWeaponBonus,
classStatPriority arrays for the five
- dnd_spells.go: mageSlots generalized to fullCasterSlots (shared by
the full casters); Paladin shares rangerSlots; new warlockSlots
simplified long-rest pool; spellcastingMod + classIsCaster extended
- dnd_setup.go: renderClassMenu and parseClass filter on Playable
Subclasses and spell lists are deferred to later sessions.
Slots into the Phase 9 spell pipeline so an L5+ Rogue who picks Arcane
Trickster becomes a third-caster on the Mage list, INT-based.
- isSpellcaster(c) gate: full casters by class plus AT Rogue at L5+.
!cast / !spells now consult this; the cast class-gate also accepts
Mage-tagged spells when the player is an AT Rogue.
- subclassSpellSlots() / slotsForCharacter() / setSpellSlotsForCharacter()
layer subclass slots on top of the class baseline. AT pool: 3 L1 at
L5–6, 4 L1 + 2 L2 at L7+, +2 L3 at L13+ (third-caster table).
- spellcastingMod returns INT for AT Rogue.
- L7 Magical Ambush proxy: spellSaveDC bumps +2 once Rogue+AT hits L7,
standing in for "targets have disadvantage when casting from hidden"
since the one-shot combat layer doesn't model hidden state.
- ensureSpellsForCharacter bootstraps a Mage-list starter spellbook
(minor_illusion, shocking_grasp, magic_missile, shield, sleep at L5;
mirror_image + misty_step at L7+; hypnotic_pattern at L13+) and
refreshes the slot pool on level/subclass change.
- applySubclassChoice runs ensureSpellsForCharacter for AT so the
spellbook is provisioned at selection time (idempotent).
- !cast clamps upcasts to highestAvailableSlotForChar when AT, since
third-caster's slot ceiling lags behind the spell list.
Tests added: AT spellcaster gate (L5 cutoff, non-AT Rogue rejected), INT
mod, subclass slot pool by tier, L7 ambush DC bump, ensureSpells default
list (all on Mage list, slots correct), end-to-end !cast queues
magic_missile for AT Rogue, !cast rejects plain Thief Rogue.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Enforce per-level Mage known-spell cap in handleSpellsLearn; surface
spellbook budget in renderSpellsList.
- Mage level-up DM now nudges with "Spells available to learn: N" via
extracted buildLevelUpMessage.
- Extract halveSavedDamage and enemySpellSaveMod for clarity; document
single-target AoE limitation in applySpellDamageSave.
- Add tests: mage learn cap, prepare flow, AoE behavior, spell save
rounding, spells migration.