feat: sortie rotation #1453
@ -11,7 +11,8 @@ import { config } from "@/src/services/configService";
 | 
				
			|||||||
import { CRng } from "@/src/services/rngService";
 | 
					import { CRng } from "@/src/services/rngService";
 | 
				
			||||||
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
 | 
					import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    getTorontoTimeAtHour,
 | 
					    EPOCH,
 | 
				
			||||||
 | 
					    getSortieTime,
 | 
				
			||||||
    missionTags,
 | 
					    missionTags,
 | 
				
			||||||
    sortieBosses,
 | 
					    sortieBosses,
 | 
				
			||||||
    sortieBossNode,
 | 
					    sortieBossNode,
 | 
				
			||||||
@ -20,8 +21,6 @@ import {
 | 
				
			|||||||
    sortieFactionToSystemIndexes
 | 
					    sortieFactionToSystemIndexes
 | 
				
			||||||
} from "@/src/helpers/worlstateHelper";
 | 
					} from "@/src/helpers/worlstateHelper";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const worldStateController: RequestHandler = (req, res) => {
 | 
					export const worldStateController: RequestHandler = (req, res) => {
 | 
				
			||||||
    const day = Math.trunc((Date.now() - EPOCH) / 86400000);
 | 
					    const day = Math.trunc((Date.now() - EPOCH) / 86400000);
 | 
				
			||||||
    const week = Math.trunc(day / 7);
 | 
					    const week = Math.trunc(day / 7);
 | 
				
			||||||
@ -166,10 +165,23 @@ export const worldStateController: RequestHandler = (req, res) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Sortie cycling every day
 | 
					    // Sortie cycling every day
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        const dayStart = getTorontoTimeAtHour(EPOCH + day * 86400000, 12);
 | 
					        let genDay;
 | 
				
			||||||
        const dayEnd = getTorontoTimeAtHour(EPOCH + (day + 1) * 86400000, 12);
 | 
					        let dayStart;
 | 
				
			||||||
 | 
					        let dayEnd;
 | 
				
			||||||
 | 
					        const sortieRolloverToday = getSortieTime(day);
 | 
				
			||||||
 | 
					        if (Date.now() < sortieRolloverToday) {
 | 
				
			||||||
 | 
					            // Early in the day, generate sortie for `day - 1`, expiring at `sortieRolloverToday`.
 | 
				
			||||||
 | 
					            genDay = day - 1;
 | 
				
			||||||
 | 
					            dayStart = getSortieTime(genDay);
 | 
				
			||||||
 | 
					            dayEnd = sortieRolloverToday;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // Late in the day, generate sortie for `day`, expiring at `getSortieTime(day + 1)`.
 | 
				
			||||||
 | 
					            genDay = day;
 | 
				
			||||||
 | 
					            dayStart = getSortieTime(genDay);
 | 
				
			||||||
 | 
					            dayEnd = getSortieTime(day + 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const rng = new CRng(day);
 | 
					        const rng = new CRng(genDay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const boss = rng.randomElement(sortieBosses);
 | 
					        const boss = rng.randomElement(sortieBosses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -281,7 +293,7 @@ export const worldStateController: RequestHandler = (req, res) => {
 | 
				
			|||||||
            Activation: { $date: { $numberLong: dayStart.toString() } },
 | 
					            Activation: { $date: { $numberLong: dayStart.toString() } },
 | 
				
			||||||
            Expiry: { $date: { $numberLong: dayEnd.toString() } },
 | 
					            Expiry: { $date: { $numberLong: dayEnd.toString() } },
 | 
				
			||||||
            Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
 | 
					            Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
 | 
				
			||||||
            Seed: day,
 | 
					            Seed: genDay,
 | 
				
			||||||
            Boss: boss,
 | 
					            Boss: boss,
 | 
				
			||||||
            Variants: selectedNodes
 | 
					            Variants: selectedNodes
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
				
			|||||||
@ -113,28 +113,18 @@ export const sortieBossNode: Record<string, string> = {
 | 
				
			|||||||
    SORTIE_BOSS_INFALAD: "SolNode705"
 | 
					    SORTIE_BOSS_INFALAD: "SolNode705"
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ChatGPT generated that. And seems it works fine
 | 
					export const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
 | 
				
			||||||
export const getTorontoTimeAtHour = (date: number, hour: number): number => {
 | 
					
 | 
				
			||||||
    const formatter = new Intl.DateTimeFormat("en-US", {
 | 
					export const getSortieTime = (day: number): number => {
 | 
				
			||||||
 | 
					    const dayStart = EPOCH + day * 86400000;
 | 
				
			||||||
 | 
					    const date = new Date(dayStart);
 | 
				
			||||||
 | 
					    date.setUTCHours(12);
 | 
				
			||||||
 | 
					    const isDst = new Intl.DateTimeFormat("en-US", {
 | 
				
			||||||
        timeZone: "America/Toronto",
 | 
					        timeZone: "America/Toronto",
 | 
				
			||||||
        year: "numeric",
 | 
					        timeZoneName: "short"
 | 
				
			||||||
        month: "2-digit",
 | 
					    })
 | 
				
			||||||
        day: "2-digit"
 | 
					        .formatToParts(date)
 | 
				
			||||||
    });
 | 
					        .find(part => part.type === "timeZoneName")!
 | 
				
			||||||
 | 
					        .value.includes("DT");
 | 
				
			||||||
    const parts = formatter.formatToParts(date).reduce<Record<string, string>>((acc, { type, value }) => {
 | 
					    return dayStart + (isDst ? 16 : 17) * 3600000;
 | 
				
			||||||
        if (["year", "month", "day"].includes(type)) {
 | 
					 | 
				
			||||||
            acc[type] = value;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return acc;
 | 
					 | 
				
			||||||
    }, {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const assumedLocalDate = new Date(
 | 
					 | 
				
			||||||
        `${parts.year}-${parts.month}-${parts.day}T${hour.toString().padStart(2, "0")}:00:00`
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const localDate = new Date(assumedLocalDate.toLocaleString("en-US", { timeZone: "America/Toronto" }));
 | 
					 | 
				
			||||||
    const offsetMs = assumedLocalDate.getTime() - localDate.getTime();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return assumedLocalDate.getTime() + offsetMs;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user