D&D: class passives + subclasses for the five caster classes

Adds signature class passives for Druid/Bard/Sorcerer/Warlock/Paladin in
dnd_passives.go, each riding an existing CombatModifiers channel so a
playable caster is no longer mechanically empty: Druid Wild Resilience
(damage reduction), Bard Bardic Inspiration (initiative), Sorcerer Innate
Sorcery (CHA-scaled pre-combat burst), Warlock Agonizing Blast (+10%
damage), Paladin Divine Smite (level-scaled burst).

Adds 15 subclasses (3 per caster, registry now 30) using canonical 5e
archetype names, with passive-only L5/7/10/15 effects in
applySubclassPassives — consistent with the majority of the original
fifteen, no new resource pools or active abilities. subclassesForClass is
now non-empty for casters, so the L5 !subclass prompt and sheet display
light up through the existing generic plumbing.

Tests: TestApplyClassPassives extended to all ten classes and the new
channels; TestSubclassRegistry_* updated to expect 30 entries across all
ten classes.
This commit is contained in:
prosolis
2026-05-14 15:18:29 -07:00
parent 6ef8b9fd0a
commit d6ea08bba6
5 changed files with 480 additions and 14 deletions

View File

@@ -12,9 +12,9 @@ import (
// ── Registry sanity ──────────────────────────────────────────────────────
func TestSubclassRegistry_FifteenEntriesThreePerClass(t *testing.T) {
if got := len(dndSubclassRegistry); got != 15 {
t.Fatalf("registry size: got %d, want 15", got)
func TestSubclassRegistry_ThirtyEntriesThreePerClass(t *testing.T) {
if got := len(dndSubclassRegistry); got != 30 {
t.Fatalf("registry size: got %d, want 30", got)
}
perClass := map[DnDClass]int{}
for _, s := range dndSubclassRegistry {
@@ -23,7 +23,10 @@ func TestSubclassRegistry_FifteenEntriesThreePerClass(t *testing.T) {
t.Errorf("incomplete entry: %+v", s)
}
}
for _, cls := range []DnDClass{ClassFighter, ClassRogue, ClassMage, ClassCleric, ClassRanger} {
for _, cls := range []DnDClass{
ClassFighter, ClassRogue, ClassMage, ClassCleric, ClassRanger,
ClassDruid, ClassBard, ClassSorcerer, ClassWarlock, ClassPaladin,
} {
if perClass[cls] != 3 {
t.Errorf("%s: %d subclasses, want 3", cls, perClass[cls])
}