Adv 2.0 D&D Phase 10 SUB3a-ii: Battle Master L10/L15

L10 Improved Combat Superiority — superiority dice grow d8 → d10. The
two scalar maneuvers (Precision Attack +4→+5; Rally heal +4→+5) bump in
their Apply hooks; Trip Attack has no scalar to scale.

L15 Relentless — 5e regenerates one die when initiative is rolled with
an empty pool. Proxied as +1 max pool size (4→5), which gives the same
"always at least one die per encounter" guarantee across the long-rest
cycle without introducing per-fight regen state.

subclassResourceMax now takes level; initSubclassResources upserts the
max (and bumps current by the delta) so existing characters grow on
level-up. Hooked into the dnd_xp level-up loop so Battle Masters
crossing L15 see the new die without waiting for a long rest. 4 new
tests; no regression in subclass/resource/level-up paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-08 11:17:55 -07:00
parent 97c2c37396
commit 64c70dda27
6 changed files with 162 additions and 22 deletions

View File

@@ -173,7 +173,7 @@ func TestChannelDivinity_ResourceMaxForAllClericSubs(t *testing.T) {
for _, sub := range []DnDSubclass{
SubclassLifeDomain, SubclassWarDomain, SubclassTrickeryDomain,
} {
res, max := subclassResourceMax(sub)
res, max := subclassResourceMax(sub, 5)
if res != "channel_divinity" {
t.Errorf("%s resource = %q, want channel_divinity", sub, res)
}
@@ -189,7 +189,7 @@ func TestChannelDivinity_InitAndSpend(t *testing.T) {
if err := createAdvCharacter(uid, "cd_pool"); err != nil {
t.Fatal(err)
}
if err := initSubclassResources(uid, SubclassLifeDomain); err != nil {
if err := initSubclassResources(uid, SubclassLifeDomain, 5); err != nil {
t.Fatal(err)
}
cur, max, err := getResource(uid, "channel_divinity")