From 32e252e3816f8418774f37607c6b7159348f6fa2 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Tue, 13 Oct 2026 12:38:29 +0200 Subject: [PATCH] fix(games): put Infinity Nikki's America and Europe servers on their own clocks Infinity Nikki resets at 04:00 on America UTC-7 and Europe UTC+2, not the regional default, so the app rolled the day 2h early for American readers and 1h late for European ones. Source: Game-Time-Master. Re-labels the game-day of some already-logged ticks for those readers. Co-Authored-By: Claude Opus 5.5 --- src/shared/games.ts | 7 ++++++- test/adapters/game8.test.ts | 12 +++++++----- test/daily.test.ts | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/shared/games.ts b/src/shared/games.ts index a81c840..bb1add3 100644 --- a/src/shared/games.ts +++ b/src/shared/games.ts @@ -81,7 +81,12 @@ export const GAMES: Record = { // and `america` already resolves to -5, so Europe is the only real override. endfield: { id: "endfield", name: "Arknights: Endfield", short: "Endfield", hue: "#E8635A" , studio: "Hypergryph", dailyTasks: "Daily missions", resetOffsets: { europe: -5 } }, nte: { id: "nte", name: "Neverness to Everness", short: "NTE", hue: "#C77DFF" , studio: "Hotta Studio", dailyTasks: "Daily tasks" }, - nikki: { id: "nikki", name: "Infinity Nikki", short: "Nikki", hue: "#F27BB0" , studio: "Infold Games", dailyTasks: "Daily tasks, Vital Energy" }, + // Infinity Nikki resets at 04:00 server time on three servers, and two of them + // are not on the regional default: America runs UTC-7 and Europe UTC+2, per + // Game-Time-Master (github.com/cicerakes/Game-Time-Master). The Fandom wiki's + // Daily Wishes page agrees, and America's is fixed rather than Pacific — the + // December 2024 maintenance was still announced in UTC-7. + nikki: { id: "nikki", name: "Infinity Nikki", short: "Nikki", hue: "#F27BB0" , studio: "Infold Games", dailyTasks: "Daily tasks, Vital Energy", resetOffsets: { america: -7, europe: 2 } }, // No `resetOffsets`: nothing in the source states a server map that differs // from the regional default, and an offset invented here would move real // readers' day keys. Add one only against evidence — see games.ts § resetOffsets. diff --git a/test/adapters/game8.test.ts b/test/adapters/game8.test.ts index b6f3d48..cd0f022 100644 --- a/test/adapters/game8.test.ts +++ b/test/adapters/game8.test.ts @@ -1734,8 +1734,9 @@ describe("Infinity Nikki wiki (the fourth Fandom template)", () => { // The row is dated "August 15, 2026 04:00 - August 22, 2026 03:59" and the // clock is discarded, so `endsAt` is the 00:00Z placeholder. Retiring the // row on that placeholder drops it nine hours before `clockFor` calls it - // over for an American reader — the reader watches the deadline they were - // counting down to vanish on its last day, which is a silent drop. + // over for an American reader — eleven, now that America is known to run + // UTC-7 — and the reader watches the deadline they were counting down to + // vanish on its last day, which is a silent drop. const html = await Bun.file(`${fixture}.html`).text(); const at = (now: string) => nikki @@ -1748,9 +1749,10 @@ describe("Infinity Nikki wiki (the fourth Fandom template)", () => { .some((e) => e.title === "Inspiration Burst"); expect(at("2026-08-22T01:00:00.000Z")).toBe(true); - // 04:00 on the last server to roll, UTC-5. Past that it is over everywhere. - expect(at("2026-08-22T08:59:00.000Z")).toBe(true); - expect(at("2026-08-22T09:01:00.000Z")).toBe(false); + // 04:00 on the last server to roll, America's UTC-7. Past that it is over + // everywhere. + expect(at("2026-08-22T10:59:00.000Z")).toBe(true); + expect(at("2026-08-22T11:01:00.000Z")).toBe(false); }); test("takes the printed date at day precision and drops the clock", async () => { diff --git a/test/daily.test.ts b/test/daily.test.ts index 330283c..b22ebc1 100644 --- a/test/daily.test.ts +++ b/test/daily.test.ts @@ -494,3 +494,25 @@ describe("catchUpDays", () => { expect(catchUpDays(NOW, "europe", "genshin", null)).toHaveLength(CATCH_UP_DAYS); }); }); + +describe("reset clocks, per server, as Game-Time-Master states them", () => { + // Each row is one game's server for one of our regions: the UTC instant its + // day rolls on, and the server's own UTC offset — the day key has to read as + // the server's calendar date, because a day-precision boundary resolves + // through it (time.ts § boundaryMs). Source for every row: + // github.com/cicerakes/Game-Time-Master, game-data.js. + const ROWS: [game: string, region: "asia" | "america" | "europe", utc: string, offset: number][] = [ + ["nikki", "asia", "20:00", 8], + ["nikki", "america", "11:00", -7], + ["nikki", "europe", "02:00", 2], + ]; + + for (const [game, region, utc, offset] of ROWS) { + test(`${game} ${region} rolls at ${utc} UTC`, () => { + const reset = nextResetMs(at("2026-10-13T00:30:00Z"), region, game); + expect(new Date(reset).toISOString().slice(11, 16)).toBe(utc); + const serverDate = new Date(reset + offset * HOUR).toISOString().slice(0, 10); + expect(dayKey(reset, region, game)).toBe(serverDate); + }); + } +});