merge upstream
This commit is contained in:
commit
48f671978d
@ -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 { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { getWorldState } from "@/src/services/worldStateService";
|
import { getWorldState } from "@/src/services/worldStateService";
|
||||||
@ -28,7 +28,7 @@ export const completeCalendarEventController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
||||||
checkCalendarChallengeCompletion(calendarProgress, currentSeason);
|
checkCalendarAutoAdvance(inventory, currentSeason);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
addEmailItem,
|
addEmailItem,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
allDailyAffiliationKeys,
|
allDailyAffiliationKeys,
|
||||||
|
checkCalendarAutoAdvance,
|
||||||
cleanupInventory,
|
cleanupInventory,
|
||||||
createLibraryDailyTask,
|
createLibraryDailyTask,
|
||||||
getCalendarProgress
|
getCalendarProgress
|
||||||
@ -29,6 +30,7 @@ import { unixTimesInMs } from "@/src/constants/timeConstants";
|
|||||||
import { DailyDeal } from "@/src/models/worldStateModel";
|
import { DailyDeal } from "@/src/models/worldStateModel";
|
||||||
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
|
||||||
import { generateRewardSeed } from "@/src/services/rngService";
|
import { generateRewardSeed } from "@/src/services/rngService";
|
||||||
|
import { getWorldState } from "@/src/services/worldStateService";
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
export const inventoryController: RequestHandler = async (request, response) => {
|
||||||
const account = await getAccountForRequest(request);
|
const account = await getAccountForRequest(request);
|
||||||
@ -111,13 +113,17 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inventory.CalendarProgress) {
|
// TODO: Setup CalendarProgress as part of 1999 mission completion?
|
||||||
const previousYearIteration = inventory.CalendarProgress.Iteration;
|
|
||||||
getCalendarProgress(inventory); // handle year rollover; the client expects to receive an inventory with an up-to-date CalendarProgress
|
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
|
// also handle sending of kiss cinematic at year rollover
|
||||||
if (
|
if (
|
||||||
inventory.CalendarProgress.Iteration != previousYearIteration &&
|
inventory.CalendarProgress!.Iteration != previousYearIteration &&
|
||||||
inventory.DialogueHistory &&
|
inventory.DialogueHistory &&
|
||||||
inventory.DialogueHistory.Dialogues
|
inventory.DialogueHistory.Dialogues
|
||||||
) {
|
) {
|
||||||
@ -164,7 +170,6 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem");
|
await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cleanupInventory(inventory);
|
cleanupInventory(inventory);
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ const configIdToIndexable = (id: string): [Record<string, boolean | string | num
|
|||||||
let obj = config as unknown as Record<string, never>;
|
let obj = config as unknown as Record<string, never>;
|
||||||
const arr = id.split(".");
|
const arr = id.split(".");
|
||||||
while (arr.length > 1) {
|
while (arr.length > 1) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
obj[arr[0]] ??= {} as never;
|
||||||
obj = obj[arr[0]];
|
obj = obj[arr[0]];
|
||||||
arr.splice(0, 1);
|
arr.splice(0, 1);
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,11 @@ export const fromMongoDate = (date: IMongoDate): Date => {
|
|||||||
return new Date(parseInt(date.$date.$numberLong));
|
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<TRarity, number> = {
|
export const kubrowWeights: Record<TRarity, number> = {
|
||||||
COMMON: 6,
|
COMMON: 6,
|
||||||
UNCOMMON: 4,
|
UNCOMMON: 4,
|
||||||
@ -65,126 +70,126 @@ export const kubrowFurPatternsWeights: Record<TRarity, number> = {
|
|||||||
LEGENDARY: 1
|
LEGENDARY: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export const catbrowDetails = {
|
export const catbrowDetails: TTraitsPool = {
|
||||||
Colors: [
|
Colors: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" as TRarity },
|
{ 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/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" as TRarity },
|
{ 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/CatbrowPetColorTertiaryA", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" as TRarity },
|
{ 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/CatbrowPetColorAccentsA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
EyeColors: [
|
EyeColors: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" as TRarity }
|
{ 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: [
|
BodyTypes: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Heads: [
|
Heads: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Tails: [
|
Tails: [
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const kubrowDetails = {
|
export const kubrowDetails: TTraitsPool = {
|
||||||
Colors: [
|
Colors: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" as TRarity },
|
{ 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/KubrowPetColorMidA", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" as TRarity },
|
{ 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/KubrowPetColorVibrantA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
EyeColors: [
|
EyeColors: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
FurPatterns: [
|
FurPatterns: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" as TRarity },
|
{ 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/KubrowPetPatternC", rarity: "RARE" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" as TRarity },
|
{ 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/KubrowPetPatternE", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
BodyTypes: [
|
BodyTypes: [
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" as TRarity },
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" },
|
||||||
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" as TRarity }
|
{ type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" }
|
||||||
],
|
],
|
||||||
|
|
||||||
Heads: [],
|
Heads: [],
|
||||||
|
@ -1216,8 +1216,8 @@ const calenderProgressSchema = new Schema<ICalendarProgress>(
|
|||||||
},
|
},
|
||||||
SeasonProgress: {
|
SeasonProgress: {
|
||||||
SeasonType: { type: String, required: true },
|
SeasonType: { type: String, required: true },
|
||||||
LastCompletedDayIdx: { type: Number, default: 0 },
|
LastCompletedDayIdx: { type: Number, default: -1 },
|
||||||
LastCompletedChallengeDayIdx: { type: Number, default: 0 },
|
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
|
||||||
ActivatedChallenges: { type: [String], default: [] }
|
ActivatedChallenges: { type: [String], default: [] }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -67,7 +67,8 @@ import {
|
|||||||
kubrowDetails,
|
kubrowDetails,
|
||||||
kubrowFurPatternsWeights,
|
kubrowFurPatternsWeights,
|
||||||
kubrowWeights,
|
kubrowWeights,
|
||||||
toOid
|
toOid,
|
||||||
|
TTraitsPool
|
||||||
} from "@/src/helpers/inventoryHelpers";
|
} from "@/src/helpers/inventoryHelpers";
|
||||||
import { addQuestKey, completeQuest } from "@/src/services/questService";
|
import { addQuestKey, completeQuest } from "@/src/services/questService";
|
||||||
import { handleBundleAcqusition } from "@/src/services/purchaseService";
|
import { handleBundleAcqusition } from "@/src/services/purchaseService";
|
||||||
@ -1048,6 +1049,21 @@ export const addSpaceSuit = (
|
|||||||
return inventoryChanges;
|
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 = (
|
export const addKubrowPet = (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
kubrowPetName: string,
|
kubrowPetName: string,
|
||||||
@ -1064,7 +1080,6 @@ export const addKubrowPet = (
|
|||||||
addSpecialItem(inventory, specialItem, inventoryChanges);
|
addSpecialItem(inventory, specialItem, inventoryChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades);
|
const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades);
|
||||||
|
|
||||||
if (!details) {
|
if (!details) {
|
||||||
@ -1074,9 +1089,10 @@ export const addKubrowPet = (
|
|||||||
"/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit"
|
"/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit"
|
||||||
].includes(kubrowPetName);
|
].includes(kubrowPetName);
|
||||||
|
|
||||||
let traits: ITraits;
|
const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails;
|
||||||
|
let dominantTraits: ITraits;
|
||||||
if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") {
|
if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") {
|
||||||
traits = {
|
dominantTraits = {
|
||||||
BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire",
|
BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire",
|
||||||
SecondaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryVampire",
|
SecondaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryVampire",
|
||||||
TertiaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryVampire",
|
TertiaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryVampire",
|
||||||
@ -1089,19 +1105,31 @@ export const addKubrowPet = (
|
|||||||
Tail: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailVampire"
|
Tail: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailVampire"
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails;
|
dominantTraits = createRandomTraits(kubrowPetName, traitsPool);
|
||||||
traits = {
|
}
|
||||||
BaseColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
|
|
||||||
SecondaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
|
const recessiveTraits: ITraits = createRandomTraits(
|
||||||
TertiaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
|
getRandomElement(
|
||||||
AccentColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
|
isCatbrow
|
||||||
EyeColor: getRandomWeightedReward(traitsPool.EyeColors, kubrowWeights)!.type,
|
? [
|
||||||
FurPattern: getRandomWeightedReward(traitsPool.FurPatterns, kubrowFurPatternsWeights)!.type,
|
"/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit",
|
||||||
Personality: kubrowPetName,
|
"/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit"
|
||||||
BodyType: getRandomWeightedReward(traitsPool.BodyTypes, kubrowWeights)!.type,
|
]
|
||||||
Head: isCatbrow ? getRandomWeightedReward(traitsPool.Heads, kubrowWeights)!.type : undefined,
|
: [
|
||||||
Tail: isCatbrow ? getRandomWeightedReward(traitsPool.Tails, kubrowWeights)!.type : undefined
|
"/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 = {
|
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.
|
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),
|
IsMale: !!getRandomInt(0, 1),
|
||||||
Size: getRandomInt(70, 100) / 100,
|
Size: getRandomInt(70, 100) / 100,
|
||||||
DominantTraits: traits,
|
DominantTraits: dominantTraits,
|
||||||
RecessiveTraits: traits
|
RecessiveTraits: recessiveTraits
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1897,7 +1925,7 @@ export const addCalendarProgress = (inventory: TInventoryDatabaseDocument, value
|
|||||||
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = currentSeason.Days.findIndex(
|
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = currentSeason.Days.findIndex(
|
||||||
day => day.events.length != 0 && day.events[0].challenge == value[value.length - 1].challenge
|
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 => {
|
export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes, Tier }: IMission): void => {
|
||||||
@ -2082,8 +2110,8 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
|
|||||||
},
|
},
|
||||||
SeasonProgress: {
|
SeasonProgress: {
|
||||||
SeasonType: currentSeason.Season,
|
SeasonType: currentSeason.Season,
|
||||||
LastCompletedDayIdx: 0,
|
LastCompletedDayIdx: -1,
|
||||||
LastCompletedChallengeDayIdx: 0,
|
LastCompletedChallengeDayIdx: -1,
|
||||||
ActivatedChallenges: []
|
ActivatedChallenges: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2104,16 +2132,44 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
|
|||||||
return inventory.CalendarProgress;
|
return inventory.CalendarProgress;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkCalendarChallengeCompletion = (
|
export const checkCalendarAutoAdvance = (
|
||||||
calendarProgress: ICalendarProgress,
|
inventory: TInventoryDatabaseDocument,
|
||||||
currentSeason: ICalendarSeason
|
currentSeason: ICalendarSeason
|
||||||
): void => {
|
): void => {
|
||||||
const dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1;
|
const calendarProgress = inventory.CalendarProgress!;
|
||||||
if (calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx >= dayIndex) {
|
for (
|
||||||
|
let dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1;
|
||||||
|
dayIndex != currentSeason.Days.length;
|
||||||
|
++dayIndex
|
||||||
|
) {
|
||||||
const day = currentSeason.Days[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`);
|
//logger.debug(`already completed the challenge, skipping ahead`);
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -151,4 +151,57 @@ export class SRng {
|
|||||||
arr[lastIdx] = tmp;
|
arr[lastIdx] = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shuffledArray<T>(inarr: readonly T[]): T[] {
|
||||||
|
const arr = [...inarr];
|
||||||
|
this.shuffleArray(arr);
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sequentiallyUniqueRandomElement = <T>(
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
@ -9,7 +9,7 @@ import darvoDeals from "@/static/fixed_responses/worldState/darvoDeals.json";
|
|||||||
import { buildConfig } from "@/src/services/buildConfigService";
|
import { buildConfig } from "@/src/services/buildConfigService";
|
||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
import { config } from "@/src/services/configService";
|
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 { eMissionType, ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
|
||||||
import {
|
import {
|
||||||
ICalendarDay,
|
ICalendarDay,
|
||||||
@ -385,44 +385,35 @@ const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallenge
|
|||||||
const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: number): ISeasonChallenge => {
|
const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: number): ISeasonChallenge => {
|
||||||
const dayStart = EPOCH + day * 86400000;
|
const dayStart = EPOCH + day * 86400000;
|
||||||
const dayEnd = EPOCH + (day + 3) * 86400000;
|
const dayEnd = EPOCH + (day + 3) * 86400000;
|
||||||
const rng = new SRng(new SRng(day).randomInt(0, 100_000));
|
|
||||||
return {
|
return {
|
||||||
_id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
|
_id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
|
||||||
Daily: true,
|
Daily: true,
|
||||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: dayEnd.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 pushSeasonWeeklyChallenge = (
|
||||||
const weekStart = EPOCH + week * 604800000;
|
activeChallenges: ISeasonChallenge[],
|
||||||
const weekEnd = weekStart + 604800000;
|
pool: string[],
|
||||||
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,
|
|
||||||
week: number,
|
week: number,
|
||||||
id: number
|
id: number
|
||||||
): ISeasonChallenge => {
|
): void => {
|
||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
const challengeId = week * 7 + id;
|
const challengeId = week * 7 + id;
|
||||||
const rng = new SRng(new SRng(challengeId).randomInt(0, 100_000));
|
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") },
|
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: rng.randomElement(pools.hardWeekly)!
|
Challenge: challenge
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const pushWeeklyActs = (
|
const pushWeeklyActs = (
|
||||||
@ -433,8 +424,8 @@ const pushWeeklyActs = (
|
|||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
|
|
||||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 0));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 0);
|
||||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 1));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 1);
|
||||||
if (pools.hasWeeklyPermanent) {
|
if (pools.hasWeeklyPermanent) {
|
||||||
activeChallenges.push({
|
activeChallenges.push({
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
||||||
@ -454,14 +445,14 @@ const pushWeeklyActs = (
|
|||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies"
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies"
|
||||||
});
|
});
|
||||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 2));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 2);
|
||||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 3));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 3);
|
||||||
} else {
|
} else {
|
||||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 2));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 2);
|
||||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 3));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 3);
|
||||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 4));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 4);
|
||||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 5));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 5);
|
||||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 6));
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 6);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1476,9 +1467,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
const pt: IPrimeVaultTrader = {
|
const pt: IPrimeVaultTrader = {
|
||||||
_id: { $oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "c36af423770eaa97" },
|
_id: { $oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "c36af423770eaa97" },
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
InitialStartDate: { $date: { $numberLong: "1662738144266" } },
|
||||||
Node: "TradeHUB1",
|
Node: "TradeHUB1",
|
||||||
Manifest: [],
|
Manifest: [],
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
EvergreenManifest: varzia.evergreen,
|
EvergreenManifest: varzia.evergreen,
|
||||||
ScheduleInfo: []
|
ScheduleInfo: []
|
||||||
};
|
};
|
||||||
|
@ -349,7 +349,7 @@
|
|||||||
],
|
],
|
||||||
"PrimeAccessAvailability": { "State": "PRIME1" },
|
"PrimeAccessAvailability": { "State": "PRIME1" },
|
||||||
"PrimeVaultAvailabilities": [false, false, false, false, false],
|
"PrimeVaultAvailabilities": [false, false, false, false, false],
|
||||||
"PrimeTokenAvailability": false,
|
"PrimeTokenAvailability": true,
|
||||||
"LibraryInfo": { "LastCompletedTargetType": "/Lotus/Types/Game/Library/Targets/Research7Target" },
|
"LibraryInfo": { "LastCompletedTargetType": "/Lotus/Types/Game/Library/Targets/Research7Target" },
|
||||||
"PVPChallengeInstances": [
|
"PVPChallengeInstances": [
|
||||||
{
|
{
|
||||||
|
@ -485,7 +485,7 @@
|
|||||||
<select class="form-control" id="valenceBonus-innateDamage"></select>
|
<select class="form-control" id="valenceBonus-innateDamage"></select>
|
||||||
<input type="number" id="valenceBonus-procent" min="25" max="60" step="0.1" class="form-control" style="max-width:100px" />
|
<input type="number" id="valenceBonus-procent" min="25" max="60" step="0.1" class="form-control" style="max-width:100px" />
|
||||||
<button class="btn btn-primary" type="submit" value="set" data-loc="general_setButton"></button>
|
<button class="btn btn-primary" type="submit" value="set" data-loc="general_setButton"></button>
|
||||||
<button class="btn btn-danger" type="submit" value="remove" data-loc="general_removeButton"></button>
|
<button class="btn btn-danger" type="submit" value="remove" data-loc="code_remove"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -870,7 +870,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-2">
|
<div class="form-group mt-2">
|
||||||
<label class="form-label" for="worldState.galleonOfGhouls" data-loc="worldState_galleonOfGhouls"></label>
|
<label class="form-label" for="worldState.galleonOfGhouls" data-loc="worldState_galleonOfGhouls"></label>
|
||||||
<select class="form-control" id="worldState.galleonOfGhouls" data-default="">
|
<select class="form-control" id="worldState.galleonOfGhouls" data-default="0">
|
||||||
<option value="0" data-loc="disabled"></option>
|
<option value="0" data-loc="disabled"></option>
|
||||||
<option value="1" data-loc="worldState_we1"></option>
|
<option value="1" data-loc="worldState_we1"></option>
|
||||||
<option value="2" data-loc="worldState_we2"></option>
|
<option value="2" data-loc="worldState_we2"></option>
|
||||||
|
@ -2010,7 +2010,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
|
|||||||
if (elm.type == "checkbox") {
|
if (elm.type == "checkbox") {
|
||||||
elm.checked = value;
|
elm.checked = value;
|
||||||
} else if (elm.classList.contains("tags-input")) {
|
} else if (elm.classList.contains("tags-input")) {
|
||||||
elm.value = value.join(", ");
|
elm.value = (value ?? []).join(", ");
|
||||||
elm.oninput();
|
elm.oninput();
|
||||||
} else {
|
} else {
|
||||||
elm.value = value ?? elm.getAttribute("data-default");
|
elm.value = value ?? elm.getAttribute("data-default");
|
||||||
|
@ -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_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_addButton: `Hinzufügen`,
|
||||||
general_setButton: `[UNTRANSLATED] Set`,
|
general_setButton: `[UNTRANSLATED] Set`,
|
||||||
general_removeButton: `[UNTRANSLATED] Remove`,
|
|
||||||
general_bulkActions: `Massenaktionen`,
|
general_bulkActions: `Massenaktionen`,
|
||||||
|
|
||||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||||
|
@ -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_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_addButton: `Add`,
|
||||||
general_setButton: `Set`,
|
general_setButton: `Set`,
|
||||||
general_removeButton: `Remove`,
|
|
||||||
general_bulkActions: `Bulk Actions`,
|
general_bulkActions: `Bulk Actions`,
|
||||||
|
|
||||||
code_loginFail: `Login failed. Double-check the email and password.`,
|
code_loginFail: `Login failed. Double-check the email and password.`,
|
||||||
|
@ -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_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_addButton: `Agregar`,
|
||||||
general_setButton: `Establecer`,
|
general_setButton: `Establecer`,
|
||||||
general_removeButton: `Quitar`,
|
|
||||||
general_bulkActions: `Acciones masivas`,
|
general_bulkActions: `Acciones masivas`,
|
||||||
|
|
||||||
code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
|
code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
|
||||||
|
@ -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_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_addButton: `Ajouter`,
|
||||||
general_setButton: `[UNTRANSLATED] Set`,
|
general_setButton: `[UNTRANSLATED] Set`,
|
||||||
general_removeButton: `[UNTRANSLATED] Remove`,
|
|
||||||
general_bulkActions: `Action groupée`,
|
general_bulkActions: `Action groupée`,
|
||||||
|
|
||||||
code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
|
code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
|
||||||
|
@ -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_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_addButton: `Добавить`,
|
||||||
general_setButton: `Установить`,
|
general_setButton: `Установить`,
|
||||||
general_removeButton: `Удалить`,
|
|
||||||
general_bulkActions: `Массовые действия`,
|
general_bulkActions: `Массовые действия`,
|
||||||
|
|
||||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||||
|
@ -3,7 +3,6 @@ dict = {
|
|||||||
general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场/中继站或重新登录客户端.`,
|
general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场/中继站或重新登录客户端.`,
|
||||||
general_addButton: `添加`,
|
general_addButton: `添加`,
|
||||||
general_setButton: `设置`,
|
general_setButton: `设置`,
|
||||||
general_removeButton: `移除`,
|
|
||||||
general_bulkActions: `批量操作`,
|
general_bulkActions: `批量操作`,
|
||||||
|
|
||||||
code_loginFail: `登录失败.请检查邮箱和密码.`,
|
code_loginFail: `登录失败.请检查邮箱和密码.`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user