mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
J3 D8-prereq: split compact flag so sim drives the picker
Adds inlineBossCombat alongside compact in runAutopilotWalk and advanceOnceWithOpts. Production background autorun keeps both true (inline auto-resolve), foreground stays both false (manual !fight), the sim now uses compact=true + inlineBossCombat=false so the boss/elite doorway returns stopBoss/stopElite after the safety gate — autoResolveCombat + simPickCombatAction / simPickSpell drive the fight via the turn-based engine. The picker (and D8-b upcasting) has been dead since D3's compact-inline boss rooms; this re-wires it. n=50/cell L10 smoke vs d7d (zones T1-T3): bard forest_shadows 61 → 100 (+39) bard manor_blackspire 10 → 34 (+24) cleric forest_shadows 15 → 96 (+81) cleric manor_blackspire 0 → 54 (+54) fighter T1-T3 100 (unchanged) Also parallelizes matrix mode via subprocess workers (each child has its own SQLite — db package globals preclude in-process parallelism). New -jobs flag, defaults to runtime.NumCPU(). 8 workers gave ~7x speedup on the smoke matrix.
This commit is contained in:
@@ -642,7 +642,7 @@ type autopilotWalkResult struct {
|
||||
// combat already auto-resolves inside resolveCombatRoom; elite/boss
|
||||
// doorways stop here so the player can choose !fight on their own terms.
|
||||
func (p *AdventurePlugin) expeditionCmdRun(ctx MessageContext) error {
|
||||
r := p.runAutopilotWalk(ctx, autopilotRoomCap, false)
|
||||
r := p.runAutopilotWalk(ctx, autopilotRoomCap, false, false)
|
||||
if r.initErr != "" {
|
||||
return p.SendDM(ctx.Sender, r.initErr)
|
||||
}
|
||||
@@ -667,7 +667,7 @@ func (p *AdventurePlugin) expeditionCmdRun(ctx MessageContext) error {
|
||||
// run graph / harvest tally / supplies / threat — same as before, just
|
||||
// no streamFlow here. compact==true switches the underlying combat
|
||||
// narration into terse mode and auto-resolves elite (not boss) rooms.
|
||||
func (p *AdventurePlugin) runAutopilotWalk(ctx MessageContext, maxRooms int, compact bool) autopilotWalkResult {
|
||||
func (p *AdventurePlugin) runAutopilotWalk(ctx MessageContext, maxRooms int, compact, inlineBossCombat bool) autopilotWalkResult {
|
||||
exp, err := getActiveExpedition(ctx.Sender)
|
||||
if err != nil {
|
||||
return autopilotWalkResult{initErr: "Couldn't read expedition state: " + err.Error()}
|
||||
@@ -717,7 +717,7 @@ func (p *AdventurePlugin) runAutopilotWalk(ctx MessageContext, maxRooms int, com
|
||||
}
|
||||
}
|
||||
|
||||
res, aerr := p.advanceOnceWithOpts(ctx, compact)
|
||||
res, aerr := p.advanceOnceWithOpts(ctx, compact, inlineBossCombat)
|
||||
if aerr != nil {
|
||||
return autopilotWalkResult{initErr: aerr.Error()}
|
||||
}
|
||||
|
||||
@@ -472,10 +472,17 @@ func (p *AdventurePlugin) zoneCmdAdvance(ctx MessageContext) error {
|
||||
// doorways (boss still stops; boss is the climax beat). Foreground
|
||||
// `!expedition run` / `!zone advance` always pass false.
|
||||
func (p *AdventurePlugin) advanceOnce(ctx MessageContext) (advanceResult, error) {
|
||||
return p.advanceOnceWithOpts(ctx, false)
|
||||
return p.advanceOnceWithOpts(ctx, false, false)
|
||||
}
|
||||
|
||||
func (p *AdventurePlugin) advanceOnceWithOpts(ctx MessageContext, compact bool) (advanceResult, error) {
|
||||
// inlineBossCombat (only consulted when compact==true) selects between the
|
||||
// two background combat paths at a boss/elite doorway. true keeps the
|
||||
// long-expedition D3 inline auto-resolve (production autorun). false
|
||||
// returns stopBoss/stopElite after the safety gate so a turn-based driver
|
||||
// — currently only the headless sim's autoResolveCombat / simPickCombatAction
|
||||
// — handles the fight via the regular !fight / !attack engine. The sim
|
||||
// uses false so simPickSpell actually fires; D8-prereq re-wired this seam.
|
||||
func (p *AdventurePlugin) advanceOnceWithOpts(ctx MessageContext, compact, inlineBossCombat bool) (advanceResult, error) {
|
||||
run, err := getActiveZoneRun(ctx.Sender)
|
||||
if err != nil {
|
||||
return advanceResult{}, fmt.Errorf("Couldn't read run state: %s", err.Error())
|
||||
@@ -560,6 +567,17 @@ func (p *AdventurePlugin) advanceOnceWithOpts(ctx MessageContext, compact bool)
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
if !inlineBossCombat {
|
||||
// Background caller wants to drive the fight itself (sim's
|
||||
// autoResolveCombat / simPickCombatAction). Surface the
|
||||
// doorway like the foreground path does, after the safety
|
||||
// gate has had a chance to defer the engagement.
|
||||
r := stopElite
|
||||
if prev == RoomBoss {
|
||||
r = stopBoss
|
||||
}
|
||||
return advanceResult{reason: r}, nil
|
||||
}
|
||||
// Compact-mode elite/boss auto-resolve. resolveCombatRoom
|
||||
// selects monster + label by run.CurrentRoomType().
|
||||
ai, ap, ao, aended, aerr := p.resolveCombatRoom(ctx.Sender, run, zone, prev == RoomElite, true)
|
||||
|
||||
@@ -170,7 +170,7 @@ func (p *AdventurePlugin) tryAutoRun(e *Expedition, now time.Time) error {
|
||||
}
|
||||
|
||||
uid := id.UserID(e.UserID)
|
||||
r := p.runAutopilotWalk(MessageContext{Sender: uid}, autoRunRoomCap, true)
|
||||
r := p.runAutopilotWalk(MessageContext{Sender: uid}, autoRunRoomCap, true, true)
|
||||
if r.initErr != "" {
|
||||
// "no expedition" / "no run" — race with abandon/extract. Silent.
|
||||
return nil
|
||||
|
||||
@@ -429,7 +429,7 @@ func (s *SimRunner) RunExpedition(uid id.UserID, zoneID ZoneID, walkCap, maxDays
|
||||
|
||||
for i := 0; i < walkCap; i++ {
|
||||
simNow = simNow.Add(simWalkInterval)
|
||||
walk := s.P.runAutopilotWalk(ctx, autopilotRoomCap, true)
|
||||
walk := s.P.runAutopilotWalk(ctx, autopilotRoomCap, true, false)
|
||||
if walk.initErr != "" {
|
||||
res.Outcome = "halted"
|
||||
res.StopCode = "init:" + walk.initErr
|
||||
|
||||
Reference in New Issue
Block a user