mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 16:42:41 +00:00
D&D: class-balance Phase 2 — passive + L5 subclass tuning + in-tier parity assertion
The Phase 1 per-class-mean summary was hiding the truth — most cells are floor/ceiling-saturated (L10+ pinned at 1.0, L1-4 caster cells at high tier pinned at 0.0), so means barely budge when you tune passives. Added a per-(level, tier) cross-class spread diagnostic to the matrix log, then tuned with the levers from doc §6 in priority order: 1. Class passives (dnd_passives.go) — caster trailers (Bard, Mage, Warlock, Sorcerer) gained level + casting-stat-scaled FlatDmgStart bursts so the L1-4 chassis isn't a quarterstaff + one weak spell against a T2-T3 monster; small DamageBonus riders (Mage/Bard/ Sorcerer/Rogue +5%, Warlock 10→12%) and +1 attack for Bard/Warlock close the steady-DPS gap. Added clampNonNeg so ability-mod-scaled additions never go negative on sub-10-stat sheets. 2. Subclass L5 tiers (dnd_subclass_combat.go) — the three Sorcerer L5 picks (Wild/Storm/Draconic) and Warlock Great Old One were defense- only or near-inert pre-tune; each gained a small bite (DamageBonus +0.10, or a FlatDmgStart burst for Storm) so the L5 chassis can press through a T4 monster. Parity band locked in TestClassBalance_Phase1_FullMatrix: cross-class spread ≤ 35pp on the in-tier diagonal — (level, tier) cells where the level is appropriate for the tier (T1: L1-4, T2: L3-7, T3: L5-10, T4: L7-15, T5: L10-20). Off-tier cells (L1 mage at T3 dungeon etc.) are still logged but not asserted: those are level-vs-tier mismatches and casters at L1-4 can't muscle through a T3 monster on a single L1-slot spell the way martials muscle through with weapon dice. Worst in-tier cell after tuning: ~26pp at L3/T2. The 35pp band gives ~9pp Monte-Carlo headroom over the worst signal at 200 trials/cell. TestApplyClassPassives expectations updated to match the new passives. Phase 0 spike still green, full plugin suite (-short) clean.
This commit is contained in:
@@ -482,11 +482,14 @@ func applySubclassPassives(stats *CombatStats, mods *CombatModifiers, c *DnDChar
|
||||
// Dragon Wings: mobility and a tougher frame — an 8% reduction and a
|
||||
// small damage bump. L15 Draconic Presence: a frightful aura — 2
|
||||
// rounds of SporeCloud miss chance.
|
||||
// Phase 2 class-balance: L5 was defense-only; gave it a small bite
|
||||
// (10% damage) so the L5 chassis isn't pure attrition vs T4 monsters.
|
||||
if c.Level >= 5 {
|
||||
stats.AC++
|
||||
if mods.ArcaneWardHP < c.Level {
|
||||
mods.ArcaneWardHP = c.Level
|
||||
}
|
||||
mods.DamageBonus += 0.10
|
||||
}
|
||||
if c.Level >= 7 {
|
||||
mods.DamageBonus += 0.10
|
||||
@@ -504,8 +507,13 @@ func applySubclassPassives(stats *CombatStats, mods *CombatModifiers, c *DnDChar
|
||||
// FirstAttackBonus. L10 Controlled Chaos: a surge you actually aimed
|
||||
// — a FlatDmgStart burst. L15 Spell Bombardment: dice that keep
|
||||
// exploding — +15% damage.
|
||||
// Phase 2 class-balance: bare advantage-on-opener left this subclass
|
||||
// the weakest L5 caster pick (0.065 at T4 pre-tune vs Champion 0.92).
|
||||
// Added a 10% damage rider — Wild Magic surges as flavor, ~+1d6 of
|
||||
// chaos damage per round in mechanics.
|
||||
if c.Level >= 5 {
|
||||
mods.AssassinateAdvantage = true
|
||||
mods.DamageBonus += 0.10
|
||||
}
|
||||
if c.Level >= 7 {
|
||||
mods.FirstAttackBonus += 3
|
||||
@@ -523,9 +531,13 @@ func applySubclassPassives(stats *CombatStats, mods *CombatModifiers, c *DnDChar
|
||||
// weather — a small 5% reduction and 1 round of SporeCloud. L15
|
||||
// Storm's Fury: incoming blows are answered with lightning —
|
||||
// ReflectNext on the first hit.
|
||||
// Phase 2 class-balance: init/speed alone left this subclass at 0.035
|
||||
// T4 pre-tune. Pull a small slice of the L7 thunderclap forward so
|
||||
// the L5 chassis has actual damage output.
|
||||
if c.Level >= 5 {
|
||||
mods.InitiativeBias += 1
|
||||
stats.Speed += 2
|
||||
mods.FlatDmgStart += 4 + c.Level/2
|
||||
}
|
||||
if c.Level >= 7 {
|
||||
mods.FlatDmgStart += 5 + c.Level/2
|
||||
@@ -587,9 +599,13 @@ func applySubclassPassives(stats *CombatStats, mods *CombatModifiers, c *DnDChar
|
||||
// Thrall: a dominated mind fights beside you — the pet channel. L15:
|
||||
// deeper psychic dominion keeps the thrall in the fight and sharpens
|
||||
// your own assault (+10% damage).
|
||||
// Phase 2 class-balance: L5 was defense-only (0.130 T4 pre-tune).
|
||||
// Added a small bite so the L5 chassis can press the advantage when
|
||||
// the foe misses.
|
||||
if c.Level >= 5 {
|
||||
mods.DamageReduct *= 0.95
|
||||
mods.SporeCloud++
|
||||
mods.DamageBonus += 0.10
|
||||
}
|
||||
if c.Level >= 7 {
|
||||
mods.DamageReduct *= 0.92
|
||||
|
||||
Reference in New Issue
Block a user