mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Pet arrival: fire after run narration, not before
The run-complete emergence seam rolled the pet-arrival DM synchronously, then handed the run narration to streamFlow's paced (fire-and-forget) streamer. The 'animal in your house' prompt landed ahead of the queued 'Run complete' + loot beats. Add streamFlowThen to run the roll after the final message is delivered; fix the same inverted order in tryAutoRun.
This commit is contained in:
@@ -560,11 +560,15 @@ func (p *AdventurePlugin) expeditionCmdRun(ctx MessageContext) error {
|
|||||||
// surfaces the player alive just like an extract or abandon — roll pet
|
// surfaces the player alive just like an extract or abandon — roll pet
|
||||||
// arrival here too. The roll lives in the real callers, not in
|
// arrival here too. The roll lives in the real callers, not in
|
||||||
// runAutopilotWalk, so the sim path (which calls the walk directly)
|
// runAutopilotWalk, so the sim path (which calls the walk directly)
|
||||||
// never fires arrival DMs. See maybeRollPetArrivalOnEmerge.
|
// never fires arrival DMs. See maybeRollPetArrivalOnEmerge. Defer it
|
||||||
|
// behind the paced stream so the "animal in your house" DM lands after
|
||||||
|
// the "Run complete" beat, not before it.
|
||||||
|
var after func()
|
||||||
if r.reason == stopComplete {
|
if r.reason == stopComplete {
|
||||||
p.maybeRollPetArrivalOnEmerge(ctx.Sender)
|
uid := ctx.Sender
|
||||||
|
after = func() { p.maybeRollPetArrivalOnEmerge(uid) }
|
||||||
}
|
}
|
||||||
return p.streamFlow(ctx.Sender, r.stream, r.finalMsg)
|
return p.streamFlowThen(ctx.Sender, r.stream, r.finalMsg, after)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runAutopilotWalk runs the autopilot loop up to maxRooms times and
|
// runAutopilotWalk runs the autopilot loop up to maxRooms times and
|
||||||
|
|||||||
@@ -817,6 +817,30 @@ func (p *AdventurePlugin) streamFlow(userID id.UserID, phaseMessages []string, f
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// streamFlowThen behaves like streamFlow but runs after() once the final
|
||||||
|
// message has actually been delivered. Emergence follow-ups (e.g. the pet
|
||||||
|
// arrival DM) must land strictly *after* the paced run narration — rolling
|
||||||
|
// them before streamFlow returns races the streamer's goroutine and surfaces
|
||||||
|
// "there's an animal in your house" ahead of the "Run complete" beat the
|
||||||
|
// player is still waiting on. after may be nil.
|
||||||
|
func (p *AdventurePlugin) streamFlowThen(userID id.UserID, phaseMessages []string, finalMessage string, after func()) error {
|
||||||
|
if len(phaseMessages) == 0 {
|
||||||
|
err := p.SendDM(userID, finalMessage)
|
||||||
|
if after != nil {
|
||||||
|
after()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := p.sendZoneCombatMessages(userID, phaseMessages, finalMessage)
|
||||||
|
if after != nil {
|
||||||
|
go func() {
|
||||||
|
<-done
|
||||||
|
after()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// resolveRoom dispatches to the per-room-type resolver. Returns staged
|
// resolveRoom dispatches to the per-room-type resolver. Returns staged
|
||||||
// messages (intro, phases, outcome) so combat rooms can be paced with
|
// messages (intro, phases, outcome) so combat rooms can be paced with
|
||||||
// inter-phase delays — see resolveCombatRoom for the contract. For
|
// inter-phase delays — see resolveCombatRoom for the contract. For
|
||||||
|
|||||||
@@ -165,17 +165,17 @@ func (p *AdventurePlugin) tryAutoRun(e *Expedition, now time.Time) error {
|
|||||||
}
|
}
|
||||||
// Emergence seam: a run-complete reached by the background ticker is
|
// Emergence seam: a run-complete reached by the background ticker is
|
||||||
// still a live emergence — roll pet arrival. See maybeRollPetArrivalOnEmerge.
|
// still a live emergence — roll pet arrival. See maybeRollPetArrivalOnEmerge.
|
||||||
|
// Deferred until after the run-summary DM below so the "animal in your
|
||||||
|
// house" prompt lands after the summary, not ahead of it.
|
||||||
|
if shouldDMAutoRun(r) {
|
||||||
|
body := renderAutoRunDM(r)
|
||||||
|
if err := p.SendDM(uid, body); err != nil {
|
||||||
|
slog.Warn("expedition: autorun DM", "user", uid, "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if r.reason == stopComplete {
|
if r.reason == stopComplete {
|
||||||
p.maybeRollPetArrivalOnEmerge(uid)
|
p.maybeRollPetArrivalOnEmerge(uid)
|
||||||
}
|
}
|
||||||
if !shouldDMAutoRun(r) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
body := renderAutoRunDM(r)
|
|
||||||
if err := p.SendDM(uid, body); err != nil {
|
|
||||||
slog.Warn("expedition: autorun DM", "user", uid, "err", err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user