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
|
||||
|
||||
Reference in New Issue
Block a user