mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Long expeditions D2-b: event-anchored day rollover
Splits the legacy briefing body into nightRolloverBurn + nightRolloverDrift, plus a processNightCamp convenience. For expeditions started after the new eventAnchoredCutoff, the 06:00 UTC briefing stops mutating: it posts a re-engagement DM, and only force-fires processNightCamp itself after a 28h safety-net window. Day++/burn/threat-drift now ride along the autopilot night-camp pitch (decideAutopilotCamp sets Night=true when ≥16h since the last rollover) and on the first player !camp since the last rollover. The legacy UTC-anchored flow still works via the same staged helpers, with processOvernightCamp interleaved to preserve the rest-before-drift ordering. Tests pin eventAnchoredCutoff to year 9999 in TestMain so the existing legacy assertions still run; new tests cover the night decision, the night-camp pitch advancing the day, the event-anchored skip, and the safety-net force-rollover.
This commit is contained in:
@@ -160,6 +160,30 @@ func (p *AdventurePlugin) campPitch(ctx MessageContext, exp *Expedition, kind st
|
||||
cost, exp.Supplies.Current))
|
||||
}
|
||||
|
||||
// D2-b: event-anchored manual !camp counts as the night camp if it's
|
||||
// the first camp since the last rollover. Burn supplies *before* the
|
||||
// camp cost so the burn lands against pre-pitch supplies (matches the
|
||||
// legacy morning-burn ordering), then pitch, then drift.
|
||||
nightCamp := false
|
||||
var nightBurn float32
|
||||
var nightRoll nightRolloverResult
|
||||
if isEventAnchored(exp) {
|
||||
var since time.Duration
|
||||
if exp.LastBriefingAt != nil {
|
||||
since = time.Now().UTC().Sub(*exp.LastBriefingAt)
|
||||
} else {
|
||||
since = time.Now().UTC().Sub(exp.StartDate)
|
||||
}
|
||||
if since >= nightCampWindow {
|
||||
nightCamp = true
|
||||
burn, err := p.nightRolloverBurn(exp)
|
||||
if err != nil {
|
||||
return p.SendDM(ctx.Sender, "Couldn't burn night supplies: "+err.Error())
|
||||
}
|
||||
nightBurn = burn
|
||||
}
|
||||
}
|
||||
|
||||
exp.Supplies.Current -= cost
|
||||
if err := updateSupplies(exp.ID, exp.Supplies); err != nil {
|
||||
return p.SendDM(ctx.Sender, "Couldn't deduct supplies: "+err.Error())
|
||||
@@ -180,6 +204,10 @@ func (p *AdventurePlugin) campPitch(ctx MessageContext, exp *Expedition, kind st
|
||||
// until the next 06:00 UTC briefing for HP and spell slots to come
|
||||
// back. The flag tells processOvernightCamp not to re-apply at briefing.
|
||||
restSummary := applyCampRest(exp, kind)
|
||||
if nightCamp {
|
||||
nightRoll = p.nightRolloverDrift(exp, time.Now().UTC())
|
||||
nightRoll.Burn = nightBurn
|
||||
}
|
||||
camp.RestApplied = true
|
||||
if err := updateCamp(exp.ID, camp); err != nil {
|
||||
slog.Warn("camp: mark rest applied", "expedition", exp.ID, "err", err)
|
||||
@@ -221,6 +249,15 @@ func (p *AdventurePlugin) campPitch(ctx MessageContext, exp *Expedition, kind st
|
||||
case CampTypeBase:
|
||||
b.WriteString("\n_Base camp — **waypoint persisted**. Camp here again at no eligibility cost on later returns._")
|
||||
}
|
||||
if nightCamp {
|
||||
b.WriteString(fmt.Sprintf("\n\n🌙 **Day %d.** _Overnight burn: %.1f SU._\n", exp.CurrentDay, nightRoll.Burn))
|
||||
for _, tl := range nightRoll.TemporalLines {
|
||||
b.WriteString("\n🌀 " + tl + "\n")
|
||||
}
|
||||
for _, ml := range nightRoll.MilestoneLines {
|
||||
b.WriteString("\n" + ml)
|
||||
}
|
||||
}
|
||||
return p.SendDM(ctx.Sender, b.String())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user