D&D: scaffold the five missing caster classes

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.
This commit is contained in:
prosolis
2026-05-14 14:43:05 -07:00
parent 0cd8fd3337
commit e6e0009253
4 changed files with 117 additions and 24 deletions

View File

@@ -519,6 +519,11 @@ func parseClass(s string) (DnDClass, bool) {
s = strings.ToLower(strings.TrimSpace(s))
for _, ci := range dndClasses {
if string(ci.Key) == s || strings.EqualFold(ci.Display, s) {
if !ci.Playable {
// Recognized class, but not yet selectable (Open5e
// caster scaffold — no spell list). Treat as no match.
return "", false
}
return ci.Key, true
}
}
@@ -565,6 +570,9 @@ func renderRaceMenu() string {
func renderClassMenu() string {
var b strings.Builder
for _, ci := range dndClasses {
if !ci.Playable {
continue // Open5e caster scaffold — hidden until spell lists land.
}
b.WriteString(fmt.Sprintf(" • **%s** (d%d, %s/%s)\n", ci.Display, ci.HPDie, ci.PrimaryA, ci.PrimaryB))
}
return b.String()