mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
J3 D8-d-fix: caster AC floor + HP ×1.25
computeAC: lift caster floors (cleric/druid 3→5, bard/warlock 1→3, mage/sorcerer 0→2). Ranger 3 / rogue 1 / fighter+paladin 6 unchanged. computeMaxHP: new casterHPMult(class) = 1.25 for the same caster set, applied multiplicatively on top of phase5BHPMult. Martials unchanged. New caster L10 HPMax: mage/sorc ~98 (was 78), bard/cleric/druid/warlock ~118 (was 95); martial L10 ~141 unchanged. bootstrap_caster_hp.go: new bootstrapCasterHPRefresh (job key caster_hp_refresh_v1) refreshes existing rows once at startup; mirrors bootstrapPhase5BHPRefresh — only raises HPMax, preserves absolute wound. Wired in adventure.go. Measured on n=2500 d8dfix2 corpus (gitignored sim_results) vs d8c: - T3 manor caster lift confirmed — bard +13 (43→56), druid +8 (88→96), warlock +8, sorcerer +5, mage +5, cleric +2. Martials flat. - Macro deltas: bard +2.6, warlock +2.0, druid +1.4, mage/sorcerer +1.0, cleric -0.2. n=500 1σ ≈ 2.2pp — bard/warlock cleanly past noise. - T4 underdark wall still holds (every caster ~0%). Lift directionally correct but undersized for T4 atk-bonus + multiattack — separate follow-up. - T5 dragons_lair universal wall unchanged (martials TPK too). Diagnostic context: project_d8d_diagnostic. Cleric flat manor likely the concentration AOE re-tick engine gap (filed for D8-e+).
This commit is contained in:
@@ -161,6 +161,20 @@ func abilityModifier(score int) int {
|
||||
// startup to refresh stale rows.
|
||||
const phase5BHPMult = 1.5
|
||||
|
||||
// casterHPMult is the J3 D8-d-fix caster durability lift. T4 sim showed
|
||||
// caster HPMax sat ~30% below martial (~95 vs 141 at L10) and the AC-floor
|
||||
// lift alone wasn't enough to crack the wall. Applied multiplicatively in
|
||||
// computeMaxHP on top of phase5BHPMult so the existing Phase 5-B floor
|
||||
// stays intact for martials. Refreshed for existing rows by
|
||||
// bootstrapCasterHPRefresh (job key caster_hp_refresh_v1).
|
||||
func casterHPMult(class DnDClass) float64 {
|
||||
switch class {
|
||||
case ClassCleric, ClassDruid, ClassBard, ClassWarlock, ClassMage, ClassSorcerer:
|
||||
return 1.25
|
||||
}
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// computeMaxHP — D&D5e style. L1: full HP die + CON mod (min 1).
|
||||
// Per level after: average HP die (roundup of die/2 + 1) + CON mod.
|
||||
// The result is scaled by phase5BHPMult — see that constant for the
|
||||
@@ -181,8 +195,8 @@ func computeMaxHP(class DnDClass, conMod, level int) int {
|
||||
}
|
||||
hp += gain
|
||||
}
|
||||
// Phase 5-B player power floor — round to nearest int.
|
||||
scaled := int(float64(hp)*phase5BHPMult + 0.5)
|
||||
// Phase 5-B player power floor + J3 D8-d-fix caster lift — round to nearest int.
|
||||
scaled := int(float64(hp)*phase5BHPMult*casterHPMult(class) + 0.5)
|
||||
if scaled < 1 {
|
||||
scaled = 1
|
||||
}
|
||||
@@ -197,10 +211,16 @@ func computeAC(class DnDClass, dexMod int) int {
|
||||
switch class {
|
||||
case ClassFighter, ClassPaladin:
|
||||
floor = 6 // heavy/medium-armor baseline
|
||||
case ClassCleric, ClassRanger, ClassDruid:
|
||||
case ClassCleric, ClassDruid:
|
||||
floor = 5
|
||||
case ClassRanger:
|
||||
floor = 3
|
||||
case ClassRogue, ClassBard, ClassWarlock:
|
||||
case ClassBard, ClassWarlock:
|
||||
floor = 3
|
||||
case ClassRogue:
|
||||
floor = 1
|
||||
case ClassMage, ClassSorcerer:
|
||||
floor = 2
|
||||
}
|
||||
return 10 + dexMod + floor
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user