diff --git a/src/controllers/api/completeCalendarEventController.ts b/src/controllers/api/completeCalendarEventController.ts index 993b55c7..11aba85c 100644 --- a/src/controllers/api/completeCalendarEventController.ts +++ b/src/controllers/api/completeCalendarEventController.ts @@ -1,4 +1,4 @@ -import { checkCalendarChallengeCompletion, getCalendarProgress, getInventory } from "@/src/services/inventoryService"; +import { checkCalendarAutoAdvance, getCalendarProgress, getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { getWorldState } from "@/src/services/worldStateService"; @@ -28,7 +28,7 @@ export const completeCalendarEventController: RequestHandler = async (req, res) } } calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex; - checkCalendarChallengeCompletion(calendarProgress, currentSeason); + checkCalendarAutoAdvance(inventory, currentSeason); await inventory.save(); res.json({ InventoryChanges: inventoryChanges, diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 05d6aec2..0d2e8ac7 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -12,6 +12,7 @@ import { addEmailItem, addMiscItems, allDailyAffiliationKeys, + checkCalendarAutoAdvance, cleanupInventory, createLibraryDailyTask, getCalendarProgress @@ -29,6 +30,7 @@ import { unixTimesInMs } from "@/src/constants/timeConstants"; import { DailyDeal } from "@/src/models/worldStateModel"; import { EquipmentFeatures } from "@/src/types/equipmentTypes"; import { generateRewardSeed } from "@/src/services/rngService"; +import { getWorldState } from "@/src/services/worldStateService"; export const inventoryController: RequestHandler = async (request, response) => { const account = await getAccountForRequest(request); @@ -111,58 +113,61 @@ export const inventoryController: RequestHandler = async (request, response) => } } - if (inventory.CalendarProgress) { - const previousYearIteration = inventory.CalendarProgress.Iteration; - getCalendarProgress(inventory); // handle year rollover; the client expects to receive an inventory with an up-to-date CalendarProgress + // TODO: Setup CalendarProgress as part of 1999 mission completion? - // also handle sending of kiss cinematic at year rollover - if ( - inventory.CalendarProgress.Iteration != previousYearIteration && - inventory.DialogueHistory && - inventory.DialogueHistory.Dialogues - ) { - let kalymos = false; - for (const { dialogueName, kissEmail } of [ - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/ArthurKissEmailItem" - }, - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/EleanorKissEmailItem" - }, - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/LettieKissEmailItem" - }, - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/AmirKissEmailItem" - }, - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/AoiKissEmailItem" - }, - { - dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue", - kissEmail: "/Lotus/Types/Items/EmailItems/QuincyKissEmailItem" + const previousYearIteration = inventory.CalendarProgress?.Iteration; + + // We need to do the following to ensure the in-game calendar does not break: + getCalendarProgress(inventory); // Keep the CalendarProgress up-to-date (at least for the current year iteration) (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2364) + checkCalendarAutoAdvance(inventory, getWorldState().KnownCalendarSeasons[0]); // Skip birthday events for characters if we do not have them unlocked yet (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2424) + + // also handle sending of kiss cinematic at year rollover + if ( + inventory.CalendarProgress!.Iteration != previousYearIteration && + inventory.DialogueHistory && + inventory.DialogueHistory.Dialogues + ) { + let kalymos = false; + for (const { dialogueName, kissEmail } of [ + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/ArthurKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/EleanorKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/LettieKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/AmirKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/AoiKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/QuincyKissEmailItem" + } + ]) { + const dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == dialogueName); + if (dialogue) { + if (dialogue.Rank == 7) { + await addEmailItem(inventory, kissEmail); + kalymos = false; + break; } - ]) { - const dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == dialogueName); - if (dialogue) { - if (dialogue.Rank == 7) { - await addEmailItem(inventory, kissEmail); - kalymos = false; - break; - } - if (dialogue.Rank == 6) { - kalymos = true; - } + if (dialogue.Rank == 6) { + kalymos = true; } } - if (kalymos) { - await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem"); - } + } + if (kalymos) { + await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem"); } } diff --git a/src/controllers/custom/configController.ts b/src/controllers/custom/configController.ts index 5b318a47..0cc28698 100644 --- a/src/controllers/custom/configController.ts +++ b/src/controllers/custom/configController.ts @@ -37,6 +37,8 @@ const configIdToIndexable = (id: string): [Record; const arr = id.split("."); while (arr.length > 1) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + obj[arr[0]] ??= {} as never; obj = obj[arr[0]]; arr.splice(0, 1); } diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index 6ced29e9..2bcbe90a 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -51,6 +51,11 @@ export const fromMongoDate = (date: IMongoDate): Date => { return new Date(parseInt(date.$date.$numberLong)); }; +export type TTraitsPool = Record< + "Colors" | "EyeColors" | "FurPatterns" | "BodyTypes" | "Heads" | "Tails", + { type: string; rarity: TRarity }[] +>; + export const kubrowWeights: Record = { COMMON: 6, UNCOMMON: 4, @@ -65,126 +70,126 @@ export const kubrowFurPatternsWeights: Record = { LEGENDARY: 1 }; -export const catbrowDetails = { +export const catbrowDetails: TTraitsPool = { Colors: [ - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" } ], EyeColors: [ - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" } ], - FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" as TRarity }], + FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" }], BodyTypes: [ - { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" } ], Heads: [ - { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" } ], Tails: [ - { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" } ] }; -export const kubrowDetails = { +export const kubrowDetails: TTraitsPool = { Colors: [ - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" } ], EyeColors: [ - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" } ], FurPatterns: [ - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" }, - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" }, - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" } ], BodyTypes: [ - { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" as TRarity }, - { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" as TRarity } + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" }, + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" }, + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" } ], Heads: [], diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index fe9a683a..32595cdd 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -1216,8 +1216,8 @@ const calenderProgressSchema = new Schema( }, SeasonProgress: { SeasonType: { type: String, required: true }, - LastCompletedDayIdx: { type: Number, default: 0 }, - LastCompletedChallengeDayIdx: { type: Number, default: 0 }, + LastCompletedDayIdx: { type: Number, default: -1 }, + LastCompletedChallengeDayIdx: { type: Number, default: -1 }, ActivatedChallenges: { type: [String], default: [] } } }, diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 6042e34f..7f587a4b 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -67,7 +67,8 @@ import { kubrowDetails, kubrowFurPatternsWeights, kubrowWeights, - toOid + toOid, + TTraitsPool } from "@/src/helpers/inventoryHelpers"; import { addQuestKey, completeQuest } from "@/src/services/questService"; import { handleBundleAcqusition } from "@/src/services/purchaseService"; @@ -1048,6 +1049,21 @@ export const addSpaceSuit = ( return inventoryChanges; }; +const createRandomTraits = (kubrowPetName: string, traitsPool: TTraitsPool): ITraits => { + return { + BaseColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + SecondaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + TertiaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + AccentColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + EyeColor: getRandomWeightedReward(traitsPool.EyeColors, kubrowWeights)!.type, + FurPattern: getRandomWeightedReward(traitsPool.FurPatterns, kubrowFurPatternsWeights)!.type, + Personality: kubrowPetName, + BodyType: getRandomWeightedReward(traitsPool.BodyTypes, kubrowWeights)!.type, + Head: traitsPool.Heads.length ? getRandomWeightedReward(traitsPool.Heads, kubrowWeights)!.type : undefined, + Tail: traitsPool.Tails.length ? getRandomWeightedReward(traitsPool.Tails, kubrowWeights)!.type : undefined + }; +}; + export const addKubrowPet = ( inventory: TInventoryDatabaseDocument, kubrowPetName: string, @@ -1064,7 +1080,6 @@ export const addKubrowPet = ( addSpecialItem(inventory, specialItem, inventoryChanges); } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades); if (!details) { @@ -1074,9 +1089,10 @@ export const addKubrowPet = ( "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit" ].includes(kubrowPetName); - let traits: ITraits; + const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails; + let dominantTraits: ITraits; if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") { - traits = { + dominantTraits = { BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire", SecondaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryVampire", TertiaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryVampire", @@ -1089,19 +1105,31 @@ export const addKubrowPet = ( Tail: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailVampire" }; } else { - const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails; - traits = { - BaseColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, - SecondaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, - TertiaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, - AccentColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, - EyeColor: getRandomWeightedReward(traitsPool.EyeColors, kubrowWeights)!.type, - FurPattern: getRandomWeightedReward(traitsPool.FurPatterns, kubrowFurPatternsWeights)!.type, - Personality: kubrowPetName, - BodyType: getRandomWeightedReward(traitsPool.BodyTypes, kubrowWeights)!.type, - Head: isCatbrow ? getRandomWeightedReward(traitsPool.Heads, kubrowWeights)!.type : undefined, - Tail: isCatbrow ? getRandomWeightedReward(traitsPool.Tails, kubrowWeights)!.type : undefined - }; + dominantTraits = createRandomTraits(kubrowPetName, traitsPool); + } + + const recessiveTraits: ITraits = createRandomTraits( + getRandomElement( + isCatbrow + ? [ + "/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit", + "/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit" + ] + : [ + "/Lotus/Types/Game/KubrowPet/AdventurerKubrowPetPowerSuit", + "/Lotus/Types/Game/KubrowPet/FurtiveKubrowPetPowerSuit", + "/Lotus/Types/Game/KubrowPet/GuardKubrowPetPowerSuit", + "/Lotus/Types/Game/KubrowPet/HunterKubrowPetPowerSuit", + "/Lotus/Types/Game/KubrowPet/RetrieverKubrowPetPowerSuit" + ] + )!, + traitsPool + ); + for (const key of Object.keys(recessiveTraits) as (keyof ITraits)[]) { + // My heurstic approximation is a 20% chance for a dominant trait to be copied into the recessive traits. TODO: A more scientific statistical analysis maybe? + if (Math.random() < 0.2) { + recessiveTraits[key] = dominantTraits[key]!; + } } details = { @@ -1113,8 +1141,8 @@ export const addKubrowPet = ( HatchDate: premiumPurchase ? new Date() : new Date(Date.now() + 10 * unixTimesInMs.hour), // On live, this seems to be somewhat randomised so that the pet hatches 9~11 hours after start. IsMale: !!getRandomInt(0, 1), Size: getRandomInt(70, 100) / 100, - DominantTraits: traits, - RecessiveTraits: traits + DominantTraits: dominantTraits, + RecessiveTraits: recessiveTraits }; } @@ -1897,7 +1925,7 @@ export const addCalendarProgress = (inventory: TInventoryDatabaseDocument, value calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = currentSeason.Days.findIndex( day => day.events.length != 0 && day.events[0].challenge == value[value.length - 1].challenge ); - checkCalendarChallengeCompletion(calendarProgress, currentSeason); + checkCalendarAutoAdvance(inventory, currentSeason); }; export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes, Tier }: IMission): void => { @@ -2082,8 +2110,8 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal }, SeasonProgress: { SeasonType: currentSeason.Season, - LastCompletedDayIdx: 0, - LastCompletedChallengeDayIdx: 0, + LastCompletedDayIdx: -1, + LastCompletedChallengeDayIdx: -1, ActivatedChallenges: [] } }; @@ -2104,16 +2132,44 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal return inventory.CalendarProgress; }; -export const checkCalendarChallengeCompletion = ( - calendarProgress: ICalendarProgress, +export const checkCalendarAutoAdvance = ( + inventory: TInventoryDatabaseDocument, currentSeason: ICalendarSeason ): void => { - const dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1; - if (calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx >= dayIndex) { + const calendarProgress = inventory.CalendarProgress!; + for ( + let dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1; + dayIndex != currentSeason.Days.length; + ++dayIndex + ) { const day = currentSeason.Days[dayIndex]; - if (day.events.length != 0 && day.events[0].type == "CET_CHALLENGE") { + if (day.events.length == 0) { + // birthday + if (day.day == 1) { + // kaya + if ((inventory.Affiliations.find(x => x.Tag == "HexSyndicate")?.Title || 0) >= 4) { + break; + } + logger.debug(`cannot talk to kaya, skipping birthday`); + calendarProgress.SeasonProgress.LastCompletedDayIdx++; + } else if (day.day == 74 || day.day == 355) { + // minerva, velimir + if ((inventory.Affiliations.find(x => x.Tag == "HexSyndicate")?.Title || 0) >= 5) { + break; + } + logger.debug(`cannot talk to minerva/velimir, skipping birthday`); + calendarProgress.SeasonProgress.LastCompletedDayIdx++; + } else { + break; + } + } else if (day.events[0].type == "CET_CHALLENGE") { + if (calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx < dayIndex) { + break; + } //logger.debug(`already completed the challenge, skipping ahead`); calendarProgress.SeasonProgress.LastCompletedDayIdx++; + } else { + break; } } }; diff --git a/src/services/rngService.ts b/src/services/rngService.ts index d277c50e..876d7584 100644 --- a/src/services/rngService.ts +++ b/src/services/rngService.ts @@ -151,4 +151,57 @@ export class SRng { arr[lastIdx] = tmp; } } + + shuffledArray(inarr: readonly T[]): T[] { + const arr = [...inarr]; + this.shuffleArray(arr); + return arr; + } } + +export const sequentiallyUniqueRandomElement = ( + deck: readonly T[], + idx: number, + lookbehind: number, + seed: number = 0 +): T | undefined => { + // This algorithm may modify a shuffle up to index `lookbehind + 1`. It assumes that the last `lookbehind` cards are not adjusted. + if (lookbehind + 1 >= deck.length - lookbehind) { + throw new Error( + `this algorithm cannot guarantee ${lookbehind} unique cards in a row with a deck of size ${deck.length}` + ); + } + + const iteration = Math.trunc(idx / deck.length); + const card = idx % deck.length; + const currentShuffle = new SRng(mixSeeds(new SRng(iteration).randomInt(0, 100_000), seed)).shuffledArray(deck); + if (card < currentShuffle.length - lookbehind) { + // We are indexing before the end of the deck, so adjustments may be needed to achieve uniqueness. + const window: T[] = []; + { + const previousShuffle = new SRng( + mixSeeds(new SRng(iteration - 1).randomInt(0, 100_000), seed) + ).shuffledArray(deck); + for (let i = previousShuffle.length - lookbehind; i != previousShuffle.length; ++i) { + window.push(previousShuffle[i]); + } + } + // From this point on, `window.length == lookbehind` should hold. + for (let i = 0; i != lookbehind; ++i) { + if (window.indexOf(currentShuffle[i]) != -1) { + for (let j = i; ; ++j) { + // `j < currentShuffle.length - lookbehind` should hold. + if (window.indexOf(currentShuffle[j]) == -1) { + const tmp = currentShuffle[j]; + currentShuffle[j] = currentShuffle[i]; + currentShuffle[i] = tmp; + break; + } + } + } + window.splice(0, 1); + window.push(currentShuffle[i]); + } + } + return currentShuffle[card]; +}; diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index dcf8b786..3433883f 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -9,7 +9,7 @@ import darvoDeals from "@/static/fixed_responses/worldState/darvoDeals.json"; import { buildConfig } from "@/src/services/buildConfigService"; import { unixTimesInMs } from "@/src/constants/timeConstants"; import { config } from "@/src/services/configService"; -import { getRandomElement, getRandomInt, SRng } from "@/src/services/rngService"; +import { getRandomElement, getRandomInt, sequentiallyUniqueRandomElement, SRng } from "@/src/services/rngService"; import { eMissionType, ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus"; import { ICalendarDay, @@ -385,44 +385,35 @@ const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallenge const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: number): ISeasonChallenge => { const dayStart = EPOCH + day * 86400000; const dayEnd = EPOCH + (day + 3) * 86400000; - const rng = new SRng(new SRng(day).randomInt(0, 100_000)); return { _id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") }, Daily: true, Activation: { $date: { $numberLong: dayStart.toString() } }, Expiry: { $date: { $numberLong: dayEnd.toString() } }, - Challenge: rng.randomElement(pools.daily)! + Challenge: sequentiallyUniqueRandomElement(pools.daily, day, 2, 605732938)! }; }; -const getSeasonWeeklyChallenge = (pools: IRotatingSeasonChallengePools, week: number, id: number): ISeasonChallenge => { - const weekStart = EPOCH + week * 604800000; - const weekEnd = weekStart + 604800000; - const challengeId = week * 7 + id; - const rng = new SRng(new SRng(challengeId).randomInt(0, 100_000)); - return { - _id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") }, - Activation: { $date: { $numberLong: weekStart.toString() } }, - Expiry: { $date: { $numberLong: weekEnd.toString() } }, - Challenge: rng.randomElement(pools.weekly)! - }; -}; - -const getSeasonWeeklyHardChallenge = ( - pools: IRotatingSeasonChallengePools, +const pushSeasonWeeklyChallenge = ( + activeChallenges: ISeasonChallenge[], + pool: string[], week: number, id: number -): ISeasonChallenge => { +): void => { const weekStart = EPOCH + week * 604800000; const weekEnd = weekStart + 604800000; const challengeId = week * 7 + id; const rng = new SRng(new SRng(challengeId).randomInt(0, 100_000)); - return { + let challenge: string; + do { + challenge = rng.randomElement(pool)!; + } while (activeChallenges.some(x => x.Challenge == challenge)); + activeChallenges.push({ _id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") }, Activation: { $date: { $numberLong: weekStart.toString() } }, Expiry: { $date: { $numberLong: weekEnd.toString() } }, - Challenge: rng.randomElement(pools.hardWeekly)! - }; + Challenge: challenge + }); }; const pushWeeklyActs = ( @@ -433,8 +424,8 @@ const pushWeeklyActs = ( const weekStart = EPOCH + week * 604800000; const weekEnd = weekStart + 604800000; - activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 0)); - activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 1)); + pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 0); + pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 1); if (pools.hasWeeklyPermanent) { activeChallenges.push({ _id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") }, @@ -454,14 +445,14 @@ const pushWeeklyActs = ( Expiry: { $date: { $numberLong: weekEnd.toString() } }, Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" }); - activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 2)); - activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 3)); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 2); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 3); } else { - activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 2)); - activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 3)); - activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 4)); - activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 5)); - activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 6)); + pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 2); + pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 3); + pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 4); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 5); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 6); } }; @@ -1476,9 +1467,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => { const pt: IPrimeVaultTrader = { _id: { $oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "c36af423770eaa97" }, Activation: { $date: { $numberLong: weekStart.toString() } }, - Expiry: { $date: { $numberLong: weekEnd.toString() } }, + InitialStartDate: { $date: { $numberLong: "1662738144266" } }, Node: "TradeHUB1", Manifest: [], + Expiry: { $date: { $numberLong: weekEnd.toString() } }, EvergreenManifest: varzia.evergreen, ScheduleInfo: [] }; diff --git a/static/fixed_responses/worldState/worldState.json b/static/fixed_responses/worldState/worldState.json index 9afa5cc5..1b849391 100644 --- a/static/fixed_responses/worldState/worldState.json +++ b/static/fixed_responses/worldState/worldState.json @@ -349,7 +349,7 @@ ], "PrimeAccessAvailability": { "State": "PRIME1" }, "PrimeVaultAvailabilities": [false, false, false, false, false], - "PrimeTokenAvailability": false, + "PrimeTokenAvailability": true, "LibraryInfo": { "LastCompletedTargetType": "/Lotus/Types/Game/Library/Targets/Research7Target" }, "PVPChallengeInstances": [ { diff --git a/static/webui/index.html b/static/webui/index.html index a258ad35..63d4d936 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -485,7 +485,7 @@ - + @@ -870,7 +870,7 @@
- diff --git a/static/webui/script.js b/static/webui/script.js index 05ccc157..9649019e 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -2010,7 +2010,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () { if (elm.type == "checkbox") { elm.checked = value; } else if (elm.classList.contains("tags-input")) { - elm.value = value.join(", "); + elm.value = (value ?? []).join(", "); elm.oninput(); } else { elm.value = value ?? elm.getAttribute("data-default"); diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 2e140583..05eceed6 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -3,7 +3,6 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Hinzufügen`, general_setButton: `[UNTRANSLATED] Set`, - general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `Massenaktionen`, code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index b214631c..fa6d3d18 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -2,7 +2,6 @@ dict = { general_inventoryUpdateNote: `Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Add`, general_setButton: `Set`, - general_removeButton: `Remove`, general_bulkActions: `Bulk Actions`, code_loginFail: `Login failed. Double-check the email and password.`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 9193b3de..c66adccf 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -3,7 +3,6 @@ dict = { general_inventoryUpdateNote: `Para ver los cambios en el juego, necesitas volver a sincronizar tu inventario, por ejemplo, usando el comando /sync del bootstrapper, visitando un dojo o repetidor, o volviendo a iniciar sesión.`, general_addButton: `Agregar`, general_setButton: `Establecer`, - general_removeButton: `Quitar`, general_bulkActions: `Acciones masivas`, code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 15a27c86..48b991e9 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -3,7 +3,6 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Ajouter`, general_setButton: `[UNTRANSLATED] Set`, - general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `Action groupée`, code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 6ae326c3..791df3c3 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -3,7 +3,6 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Добавить`, general_setButton: `Установить`, - general_removeButton: `Удалить`, general_bulkActions: `Массовые действия`, code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index fc02c0f2..8afa941d 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -3,7 +3,6 @@ dict = { general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场/中继站或重新登录客户端.`, general_addButton: `添加`, general_setButton: `设置`, - general_removeButton: `移除`, general_bulkActions: `批量操作`, code_loginFail: `登录失败.请检查邮箱和密码.`,