Class identity audit close-out: Fighter/Ranger/Paladin/Druid + Bard-Valor

Phase 2 Monte Carlo tuning had papered over four classes whose 5e-defining
mechanics never actually existed in the engine — only flat DamageBonus or
FlatDmgStart compensation riders that hit the right aggregate win rate.
This pass replaces the proxies with the real primitives.

New CombatModifiers fields: ExtraAttacks (additional swings/round, looped
in a new resolvePlayerSwings helper); HuntersMarkDie (per-hit Nd6 bonus,
same path as Sneak Attack); ThornLashDmg (flat counter on landed enemy
hits, fires in resolveEnemyAttack after ward/block).

Fighter L5/11/20 Extra Attack, Ranger L5 Extra Attack + Hunter's Mark
(1→4 d6 by level), Paladin L5 Extra Attack + per-hit Divine Smite
(replaces one-shot opener), Druid thorn lash. Bard College of Valor L7
"Extra Attack" subclass tier converted from +1 attack/+10% damage proxy
to the real primitive.

Post-fix T5 class-balance: martials cluster at top (Fighter/Rogue 0.90,
Ranger 0.89, Paladin 0.88), casters keep their relative ordering, spread
14pp top-to-bottom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-16 12:53:00 -07:00
parent 41adfce9f1
commit 98ba416359
5 changed files with 144 additions and 14 deletions

View File

@@ -103,6 +103,14 @@ func applyPlayerHitDamageMods(st *combatState, player *Combatant, dmg int, isCri
dmg += 1 + st.roll(6)
}
}
// Class-identity audit (2026-05-16) — Ranger Hunter's Mark. +Nd6 on
// every player hit. The implicit "you marked this enemy on round 0"
// model: in 1v1, the only foe is always the marked one.
if player.Mods.HuntersMarkDie > 0 {
for i := 0; i < player.Mods.HuntersMarkDie; i++ {
dmg += 1 + st.roll(6)
}
}
// Phase 10 SUB2a-ii — Assassin Death Strike proxy: bonus damage on the
// first hit only. Stacks on top of the Rogue's Sneak Attack auto-crit
// (which already doubled the base damage above) — the bonus itself is