mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +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:
@@ -14,6 +14,20 @@ import (
|
||||
// synthetic "now" and verify state transitions. Ticker scheduling is a
|
||||
// thin wrapper over those.
|
||||
|
||||
// rewindToLegacyAnchor backdates an expedition's start_date to before
|
||||
// eventAnchoredCutoff so deliverBriefing exercises the legacy UTC-anchored
|
||||
// mutator path. Tests of the D2-b event-anchored path should NOT call this.
|
||||
func rewindToLegacyAnchor(t *testing.T, exp *Expedition) {
|
||||
t.Helper()
|
||||
before := eventAnchoredCutoff.Add(-24 * time.Hour)
|
||||
if _, err := db.Get().Exec(
|
||||
`UPDATE dnd_expedition SET start_date = ? WHERE expedition_id = ?`,
|
||||
before, exp.ID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp.StartDate = before
|
||||
}
|
||||
|
||||
func TestPickMorningBriefing_DayBands(t *testing.T) {
|
||||
cases := []struct {
|
||||
day int
|
||||
@@ -57,6 +71,7 @@ func TestDeliverBriefing_AdvancesDayAndBurnsSupplies(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rewindToLegacyAnchor(t, exp)
|
||||
p := &AdventurePlugin{}
|
||||
now := time.Now().UTC()
|
||||
if err := p.deliverBriefing(exp, now); err != nil {
|
||||
@@ -87,6 +102,76 @@ func TestDeliverBriefing_AdvancesDayAndBurnsSupplies(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// useEventAnchored fences the eventAnchoredCutoff to before the given
|
||||
// expedition's start_date so the D2-b path is taken. Test-scoped via t.Cleanup.
|
||||
func useEventAnchored(t *testing.T, exp *Expedition) {
|
||||
t.Helper()
|
||||
saved := eventAnchoredCutoff
|
||||
eventAnchoredCutoff = exp.StartDate.Add(-time.Minute)
|
||||
t.Cleanup(func() { eventAnchoredCutoff = saved })
|
||||
}
|
||||
|
||||
func TestDeliverBriefing_EventAnchoredSkipsMutators(t *testing.T) {
|
||||
setupZoneRunTestDB(t)
|
||||
uid := id.UserID("@exp-evt-skip:example")
|
||||
defer cleanupExpeditions(uid)
|
||||
|
||||
exp, err := startExpedition(uid, ZoneGoblinWarrens, "",
|
||||
ExpeditionSupplies{Current: 10, Max: 10, DailyBurn: 1, HarshMod: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
useEventAnchored(t, exp)
|
||||
|
||||
// last_briefing_at is NULL and start_date is "now-ish", so the safety
|
||||
// net should NOT fire — sub-28h since start.
|
||||
p := &AdventurePlugin{}
|
||||
if err := p.deliverBriefing(exp, time.Now().UTC()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, _ := getExpedition(exp.ID)
|
||||
if got.CurrentDay != 1 {
|
||||
t.Errorf("day = %d, want 1 (event-anchored briefing should not advance day)", got.CurrentDay)
|
||||
}
|
||||
if got.Supplies.Current != 10 {
|
||||
t.Errorf("supplies = %v, want 10 (event-anchored briefing should not burn)", got.Supplies.Current)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliverBriefing_EventAnchoredSafetyNetForces(t *testing.T) {
|
||||
setupZoneRunTestDB(t)
|
||||
uid := id.UserID("@exp-evt-safety:example")
|
||||
defer cleanupExpeditions(uid)
|
||||
|
||||
exp, err := startExpedition(uid, ZoneGoblinWarrens, "",
|
||||
ExpeditionSupplies{Current: 10, Max: 10, DailyBurn: 1, HarshMod: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
useEventAnchored(t, exp)
|
||||
|
||||
// Backdate start_date so > nightSafetyNet has elapsed with no rollover.
|
||||
before := time.Now().UTC().Add(-(nightSafetyNet + time.Hour))
|
||||
if _, err := db.Get().Exec(
|
||||
`UPDATE dnd_expedition SET start_date = ? WHERE expedition_id = ?`,
|
||||
before, exp.ID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp.StartDate = before
|
||||
|
||||
p := &AdventurePlugin{}
|
||||
if err := p.deliverBriefing(exp, time.Now().UTC()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, _ := getExpedition(exp.ID)
|
||||
if got.CurrentDay != 2 {
|
||||
t.Errorf("day = %d, want 2 (safety net should force rollover)", got.CurrentDay)
|
||||
}
|
||||
if got.Supplies.Current >= 10 {
|
||||
t.Errorf("supplies = %v, want < 10 (safety net should burn)", got.Supplies.Current)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliverBriefing_HarshConditionsBurnFaster(t *testing.T) {
|
||||
setupZoneRunTestDB(t)
|
||||
uid := id.UserID("@exp-cycle-harsh:example")
|
||||
@@ -97,6 +182,7 @@ func TestDeliverBriefing_HarshConditionsBurnFaster(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rewindToLegacyAnchor(t, exp)
|
||||
// Force harsh conditions via threat clock above 60.
|
||||
if err := applyThreatDelta(exp.ID, 70, "test"); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
Reference in New Issue
Block a user