mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Sim: short-rest between rooms; H5 alone doesn't close caster gap
autoResolveCombat now calls maybeShortRest after a won fight (HP < 60% or any slots used, charges > 0), mirroring what a competent prod player does between rooms. Re-baseline at n=100 across the full 10×3×5 matrix written to baseline_h5sim_all10.jsonl. Headline (vs baseline_j2a_v2_all10.jsonl, full delta in h5sim_findings.md): mage L12 manor +8pp, cleric L12 manor +7pp, but bard L12 manor stays at 1pp and bard/cleric L12 underdark still 0. J2c (defaultKnownSpells damage option at L3+ for bard, L4+ for cleric) is still the lever for the trailers. Four borderline -9pp regressions on n=100 cells; flagged for an n=300 re-run before declaring a sim defect.
This commit is contained in:
@@ -384,6 +384,12 @@ func (s *SimRunner) RunExpedition(uid id.UserID, zoneID ZoneID, walkCap int) (*S
|
||||
res.Outcome = "fled"
|
||||
}
|
||||
i = walkCap
|
||||
} else {
|
||||
// Combat won — a competent prod player would short-rest
|
||||
// between fights when wounded or down on slots (H5 added
|
||||
// the partial slot refresh). Without this the sim
|
||||
// under-counts caster mid-expedition staying power.
|
||||
s.maybeShortRest(ctx, uid)
|
||||
}
|
||||
// Boss kill closes the run via combat resolution → continue
|
||||
// the loop so the next walk picks up the cleared-run state.
|
||||
@@ -602,6 +608,39 @@ func (s *SimRunner) autoResolveCombat(ctx MessageContext) (bool, error) {
|
||||
return false, fmt.Errorf("combat exceeded %d rounds", autoCombatRoundCap)
|
||||
}
|
||||
|
||||
// simShortRestHPPct is the HP-percentage threshold below which the sim
|
||||
// pulls the short-rest lever after a combat. 60% mirrors the
|
||||
// "competent prod player" model: rest when you've taken real damage and
|
||||
// have charges to spend, but don't burn charges on scratches.
|
||||
const simShortRestHPPct = 60
|
||||
|
||||
// maybeShortRest fires a short rest after a won combat when the
|
||||
// character has charges and either (a) HP is below simShortRestHPPct or
|
||||
// (b) any spell slots have been used. Mirrors what a prod player would
|
||||
// type between rooms; H5 (commit 1cd53eb) made this slot-recovering for
|
||||
// casters. Errors are swallowed — short rest is best-effort QoL and a
|
||||
// failure should not abort the sim run.
|
||||
func (s *SimRunner) maybeShortRest(ctx MessageContext, uid id.UserID) {
|
||||
c, _ := LoadDnDCharacter(uid)
|
||||
if c == nil || c.ShortRestCharges <= 0 {
|
||||
return
|
||||
}
|
||||
needsHP := c.HPMax > 0 && c.HPCurrent*100 < c.HPMax*simShortRestHPPct
|
||||
hasUsedSlots, _ := casterHasUsedSlots(uid)
|
||||
if !needsHP && !hasUsedSlots {
|
||||
return
|
||||
}
|
||||
_ = s.P.handleDnDShortRest(ctx)
|
||||
// handleDnDShortRest sets RestingUntil = now+1h. The autopilot walk
|
||||
// doesn't gate on that, but TickDay's overnight camp / future zone
|
||||
// transitions might — clear it so the sim isn't accidentally
|
||||
// locked out of state it would otherwise reach.
|
||||
if c2, _ := LoadDnDCharacter(uid); c2 != nil && c2.RestingUntil != nil {
|
||||
c2.RestingUntil = nil
|
||||
_ = SaveDnDCharacter(c2)
|
||||
}
|
||||
}
|
||||
|
||||
// simHealHPThresholdPct is the player-HP percentage below which the sim
|
||||
// reaches for a heal consumable before its !attack/!cast. 40% mirrors
|
||||
// the "competent player" prod assumption — heal early enough to absorb
|
||||
|
||||
24096
sim_results/baseline_h5sim_all10.err
Normal file
24096
sim_results/baseline_h5sim_all10.err
Normal file
File diff suppressed because it is too large
Load Diff
15000
sim_results/baseline_h5sim_all10.jsonl
Normal file
15000
sim_results/baseline_h5sim_all10.jsonl
Normal file
File diff suppressed because it is too large
Load Diff
151
sim_results/h5sim_all10_summary.txt
Normal file
151
sim_results/h5sim_all10_summary.txt
Normal file
@@ -0,0 +1,151 @@
|
||||
class level zone n p50_yld p50_yld_clr mean_yld mean_rms %clr %boss %tpk %fled %ext
|
||||
bard 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
bard 7 dragons_lair 100 3 0 3.8 6.1 0 31 98 0 2
|
||||
bard 12 dragons_lair 100 3 0 4.1 7.5 0 75 98 0 2
|
||||
cleric 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
cleric 7 dragons_lair 100 3 0 3.6 5.5 0 16 99 0 1
|
||||
cleric 12 dragons_lair 100 3 0 3.2 6.9 0 47 100 0 0
|
||||
druid 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
druid 7 dragons_lair 100 3 0 3.3 6.3 0 36 98 0 2
|
||||
druid 12 dragons_lair 100 4 0 4.3 7.5 0 78 99 0 1
|
||||
fighter 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
fighter 7 dragons_lair 100 3 0 4.3 7.2 0 67 98 0 2
|
||||
fighter 12 dragons_lair 100 4 0 4.7 8 0 100 100 0 0
|
||||
mage 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
mage 7 dragons_lair 100 5 0 5.1 5.6 0 22 100 0 0
|
||||
mage 12 dragons_lair 100 5 0 5 7.4 0 72 99 0 1
|
||||
paladin 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
paladin 7 dragons_lair 100 4 0 4 6.9 0 62 95 0 5
|
||||
paladin 12 dragons_lair 100 4 0 4.2 7.9 0 97 100 0 0
|
||||
ranger 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
ranger 7 dragons_lair 100 9 0 8.5 7.7 0 86 95 0 5
|
||||
ranger 12 dragons_lair 100 7 0 7.5 8 0 100 100 0 0
|
||||
rogue 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
rogue 7 dragons_lair 100 4 0 5.5 6.8 0 54 92 0 8
|
||||
rogue 12 dragons_lair 100 6 0 6.5 7.9 0 94 100 0 0
|
||||
sorcerer 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
sorcerer 7 dragons_lair 100 3 0 3.9 5.7 0 16 99 0 1
|
||||
sorcerer 12 dragons_lair 100 5 0 5.2 7.2 0 66 100 0 0
|
||||
warlock 3 dragons_lair 100 0 0 0 0 0 0 0 0 0
|
||||
warlock 7 dragons_lair 100 3 0 3.7 5.6 0 14 99 0 1
|
||||
warlock 12 dragons_lair 100 4 0 4.6 7.5 0 74 100 0 0
|
||||
bard 3 forest_shadows 100 4 0 4.9 4.1 0 1 100 0 0
|
||||
bard 7 forest_shadows 100 6 0 6.1 6 0 99 100 0 0
|
||||
bard 12 forest_shadows 100 6 6 6.6 7 100 100 0 0 0
|
||||
cleric 3 forest_shadows 100 4 0 5.1 4.6 0 1 100 0 0
|
||||
cleric 7 forest_shadows 100 7 12 7.4 5.6 2 71 98 0 0
|
||||
cleric 12 forest_shadows 100 8 9 8.5 6.8 88 88 12 0 0
|
||||
druid 3 forest_shadows 100 5 0 6.3 5.2 0 17 100 0 0
|
||||
druid 7 forest_shadows 100 8 8 8.7 6.9 92 99 8 0 0
|
||||
druid 12 forest_shadows 100 7 7 8.1 7 100 100 0 0 0
|
||||
fighter 3 forest_shadows 100 4 0 5 5.3 0 37 100 0 0
|
||||
fighter 7 forest_shadows 100 6 6 6.9 7 100 100 0 0 0
|
||||
fighter 12 forest_shadows 100 6 6 6.9 7 100 100 0 0 0
|
||||
mage 3 forest_shadows 100 4 0 5 3.8 0 0 100 0 0
|
||||
mage 7 forest_shadows 100 6 6 6.9 6.8 88 95 12 0 0
|
||||
mage 12 forest_shadows 100 5 5 6.6 7 100 100 0 0 0
|
||||
paladin 3 forest_shadows 100 6 0 7 5.8 0 78 100 0 0
|
||||
paladin 7 forest_shadows 100 6 6 6.7 7 100 100 0 0 0
|
||||
paladin 12 forest_shadows 100 7 7 7.5 7 100 100 0 0 0
|
||||
ranger 3 forest_shadows 100 10 0 12.9 5.2 0 26 100 0 0
|
||||
ranger 7 forest_shadows 100 13 13 15.1 7 100 100 0 0 0
|
||||
ranger 12 forest_shadows 100 14 14 15.6 7 100 100 0 0 0
|
||||
rogue 3 forest_shadows 100 7 0 7.1 5.8 0 73 100 0 0
|
||||
rogue 7 forest_shadows 100 7 7 7.1 6.9 87 100 13 0 0
|
||||
rogue 12 forest_shadows 100 8 8 8.4 7 99 99 1 0 0
|
||||
sorcerer 3 forest_shadows 100 4 0 4.9 3.3 0 0 100 0 0
|
||||
sorcerer 7 forest_shadows 100 5 5 5.5 6.6 67 93 33 0 0
|
||||
sorcerer 12 forest_shadows 100 6 6 6.6 7 98 98 2 0 0
|
||||
warlock 3 forest_shadows 100 4 0 4.5 4.1 0 1 100 0 0
|
||||
warlock 7 forest_shadows 100 5 7 6.6 6.3 36 96 64 0 0
|
||||
warlock 12 forest_shadows 100 6 6 7 7 100 100 0 0 0
|
||||
bard 3 goblin_warrens 100 4 8 4.7 4.8 1 81 99 0 0
|
||||
bard 7 goblin_warrens 100 4 4 5.1 6 100 100 0 0 0
|
||||
bard 12 goblin_warrens 100 4 4 5.2 6 100 100 0 0 0
|
||||
cleric 3 goblin_warrens 100 4 4 4.3 4.9 6 79 94 0 0
|
||||
cleric 7 goblin_warrens 100 4 4 4.9 5.9 95 95 5 0 0
|
||||
cleric 12 goblin_warrens 100 4 4 4.7 6 99 99 1 0 0
|
||||
druid 3 goblin_warrens 100 4 4 4.4 5.6 69 92 31 0 0
|
||||
druid 7 goblin_warrens 100 4 4 4.9 6 100 100 0 0 0
|
||||
druid 12 goblin_warrens 100 4 4 5 6 100 100 0 0 0
|
||||
fighter 3 goblin_warrens 100 5 4 5.5 5.6 64 98 36 0 0
|
||||
fighter 7 goblin_warrens 100 4 4 5.5 6 100 100 0 0 0
|
||||
fighter 12 goblin_warrens 100 4 4 5.6 6 100 100 0 0 0
|
||||
mage 3 goblin_warrens 100 6 7 7.6 5.3 61 73 39 0 0
|
||||
mage 7 goblin_warrens 100 6 6 7.4 6 100 100 0 0 0
|
||||
mage 12 goblin_warrens 100 7 7 7.9 6 100 100 0 0 0
|
||||
paladin 3 goblin_warrens 100 5 6 5.6 5.9 92 100 8 0 0
|
||||
paladin 7 goblin_warrens 100 4 4 5.5 6 100 100 0 0 0
|
||||
paladin 12 goblin_warrens 100 4 4 5 6 100 100 0 0 0
|
||||
ranger 3 goblin_warrens 100 6 7 6.2 5.5 54 94 46 0 0
|
||||
ranger 7 goblin_warrens 100 5 5 6.4 6 100 100 0 0 0
|
||||
ranger 12 goblin_warrens 100 5 5 5.6 6 100 100 0 0 0
|
||||
rogue 3 goblin_warrens 100 6 6 6.9 5.8 86 97 14 0 0
|
||||
rogue 7 goblin_warrens 100 7 7 7.1 6 100 100 0 0 0
|
||||
rogue 12 goblin_warrens 100 7 7 7.1 6 100 100 0 0 0
|
||||
sorcerer 3 goblin_warrens 100 6 7 6.7 5.6 72 88 28 0 0
|
||||
sorcerer 7 goblin_warrens 100 6 6 7 6 99 99 1 0 0
|
||||
sorcerer 12 goblin_warrens 100 7 7 6.9 6 100 100 0 0 0
|
||||
warlock 3 goblin_warrens 100 3 4 4.4 5.5 64 86 36 0 0
|
||||
warlock 7 goblin_warrens 100 4 4 4.9 6 100 100 0 0 0
|
||||
warlock 12 goblin_warrens 100 4 4 5.1 6 100 100 0 0 0
|
||||
bard 3 manor_blackspire 100 4 0 4.7 4.3 0 2 100 0 0
|
||||
bard 7 manor_blackspire 100 5 0 5.2 5.9 0 53 100 0 0
|
||||
bard 12 manor_blackspire 100 4 5 5.4 6 1 75 99 0 0
|
||||
cleric 3 manor_blackspire 100 3 0 3.7 4.6 0 1 100 0 0
|
||||
cleric 7 manor_blackspire 100 4 0 4.7 5.8 0 28 100 0 0
|
||||
cleric 12 manor_blackspire 100 4 7 4.7 6.2 16 56 84 0 0
|
||||
druid 3 manor_blackspire 100 4 0 4.2 5.3 0 14 100 0 0
|
||||
druid 7 manor_blackspire 100 4 0 4.4 5.9 0 65 100 0 0
|
||||
druid 12 manor_blackspire 100 5 4 5.1 6.8 75 82 25 0 0
|
||||
fighter 3 manor_blackspire 100 4 0 4.5 5.4 0 17 100 0 0
|
||||
fighter 7 manor_blackspire 100 4 4 4 6.2 17 100 83 0 0
|
||||
fighter 12 manor_blackspire 100 4 4 4.6 7 100 100 0 0 0
|
||||
mage 3 manor_blackspire 100 5 0 6.2 4.2 0 0 100 0 0
|
||||
mage 7 manor_blackspire 100 6 6 6.6 6 4 32 96 0 0
|
||||
mage 12 manor_blackspire 100 6 5 6.2 6.6 57 73 43 0 0
|
||||
paladin 3 manor_blackspire 100 4 0 4.4 5.8 0 43 100 0 0
|
||||
paladin 7 manor_blackspire 100 3 2 4.2 6.1 12 97 88 0 0
|
||||
paladin 12 manor_blackspire 100 4 4 4.3 7 98 100 2 0 0
|
||||
ranger 3 manor_blackspire 100 4 0 4.8 5.3 0 14 100 0 0
|
||||
ranger 7 manor_blackspire 100 5 4 5.1 6.3 30 100 70 0 0
|
||||
ranger 12 manor_blackspire 100 6 6 5.7 7 100 100 0 0 0
|
||||
rogue 3 manor_blackspire 100 5 0 6.1 5.7 0 35 100 0 0
|
||||
rogue 7 manor_blackspire 100 6 2 6.2 6 1 99 99 0 0
|
||||
rogue 12 manor_blackspire 100 6 6 7 6.9 89 100 11 0 0
|
||||
sorcerer 3 manor_blackspire 100 6 0 5.7 3.6 0 0 100 0 0
|
||||
sorcerer 7 manor_blackspire 100 6 4 6.9 6 3 36 97 0 0
|
||||
sorcerer 12 manor_blackspire 100 6 5 6 6.3 38 54 62 0 0
|
||||
warlock 3 manor_blackspire 100 4 0 5.2 4.4 0 0 100 0 0
|
||||
warlock 7 manor_blackspire 100 6 0 5.9 6 0 58 100 0 0
|
||||
warlock 12 manor_blackspire 100 5 8 5.2 6.2 25 61 75 0 0
|
||||
bard 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
bard 7 underdark 100 3 0 3.2 3.9 0 3 100 0 0
|
||||
bard 12 underdark 100 3 0 4 5.7 0 59 100 0 0
|
||||
cleric 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
cleric 7 underdark 100 2 0 3.1 3.2 0 0 100 0 0
|
||||
cleric 12 underdark 100 3 0 4.2 4.7 0 18 100 0 0
|
||||
druid 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
druid 7 underdark 100 3 0 3.6 4 0 3 100 0 0
|
||||
druid 12 underdark 100 6 7 6.3 6.3 34 86 66 0 0
|
||||
fighter 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
fighter 7 underdark 100 4 3 5 6 4 96 96 0 0
|
||||
fighter 12 underdark 100 4 4 4.6 7 100 100 0 0 0
|
||||
mage 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
mage 7 underdark 100 2 0 3.1 3.3 0 2 100 0 0
|
||||
mage 12 underdark 100 4 5 4.4 5.7 20 50 80 0 0
|
||||
paladin 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
paladin 7 underdark 100 4 3 4.6 5.9 1 82 99 0 0
|
||||
paladin 12 underdark 100 4 4 5.2 6.9 94 100 6 0 0
|
||||
ranger 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
ranger 7 underdark 100 8 8 9.6 6.2 22 99 78 0 0
|
||||
ranger 12 underdark 100 11 11 12.1 7 100 100 0 0 0
|
||||
rogue 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
rogue 7 underdark 100 5 4 5.1 5.7 2 73 98 0 0
|
||||
rogue 12 underdark 100 5 6 6 6.9 94 96 6 0 0
|
||||
sorcerer 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
sorcerer 7 underdark 100 2 0 2.8 3.1 0 0 100 0 0
|
||||
sorcerer 12 underdark 100 3 6 4 5.2 8 33 92 0 0
|
||||
warlock 3 underdark 100 0 0 0 0 0 0 0 0 0
|
||||
warlock 7 underdark 100 2 0 2.8 3.7 0 4 100 0 0
|
||||
warlock 12 underdark 100 4 6 4.1 5.7 3 54 97 0 0
|
||||
39
sim_results/h5sim_findings.md
Normal file
39
sim_results/h5sim_findings.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# H5-sim re-baseline — does prod short-rest close the caster gap?
|
||||
|
||||
**Corpus:** `baseline_h5sim_all10.jsonl` (15k rows, n=100). Summary table: `h5sim_all10_summary.txt`. **Baseline for comparison:** `baseline_j2a_v2_all10.jsonl` (J2b).
|
||||
|
||||
## TL;DR
|
||||
|
||||
**No.** Wiring short-rest into the sim between rooms gives mage L12 manor a real lift (+8pp clear rate) but does not move the bard/cleric trailers in the cells that matter:
|
||||
|
||||
| class | lvl | zone | J2b %clr | H5sim %clr | Δ |
|
||||
| ------ | --- | ---------------- | -------: | ---------: | -: |
|
||||
| bard | 12 | manor_blackspire | 2 | 1 | −1 |
|
||||
| cleric | 12 | manor_blackspire | 9 | 16 | +7 |
|
||||
| bard | 12 | underdark | 0 | 0 | 0 |
|
||||
| cleric | 12 | underdark | 0 | 0 | 0 |
|
||||
| mage | 12 | manor_blackspire | 49 | 57 | +8 |
|
||||
|
||||
J2c (defaultKnownSpells widening — bard damage option at L3+, cleric at L4+) is still the lever. The hypothesis that H5 alone would close it is falsified.
|
||||
|
||||
## Notable regressions (n=100, ~±10pp 95% CI — borderline)
|
||||
|
||||
| class | lvl | zone | J2b %clr | H5sim %clr | Δ |
|
||||
| -------- | --- | ---------------- | -------: | ---------: | -: |
|
||||
| warlock | 12 | manor_blackspire | 34 | 25 | −9 |
|
||||
| sorcerer | 12 | manor_blackspire | 47 | 38 | −9 |
|
||||
| cleric | 3 | goblin_warrens | 15 | 6 | −9 |
|
||||
| ranger | 3 | goblin_warrens | 64 | 54 | −10 |
|
||||
|
||||
n=100 standard error on a 50/50 cell is ~5pp, so these are ~2σ. Could be real (the picker prefers high-tier slots and short-rest refreshes low-tier first, so a mid-zone short rest may flush the high-tier-slot budget by encouraging more L2/L3 spends), or noise. Re-run at n=300 to disambiguate before declaring this a sim defect.
|
||||
|
||||
## Cells that lifted
|
||||
|
||||
Mage L12 manor +8, cleric L12 manor +7, fighter L3 goblin +10, druid L7 forest +8, sorcerer L7 forest +4, mage L7 goblin +3. Pattern: classes that already had viable damage rosters benefited; classes whose damage rosters are thin (bard/cleric) did not.
|
||||
|
||||
## Verdict
|
||||
|
||||
- Ship H5+sim short-rest as-is — the prod fix (full-HP gate loosened) is correct independently and the sim now reflects what a competent player does.
|
||||
- J2c (defaultKnownSpells widening) is still required to lift bard/cleric trailers.
|
||||
- T5 dragons_lair untouched (0% across all 10 classes) — J3 territory.
|
||||
- Re-baseline at n=300 on the four borderline regressions before tuning the picker.
|
||||
Reference in New Issue
Block a user