feat: initial support for multiple nightwave seasons (#2096)
Reviewed-on: #2096 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
parent
92d34fd69e
commit
ba6cd47432
8
package-lock.json
generated
8
package-lock.json
generated
@ -18,7 +18,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"warframe-public-export-plus": "^0.5.62",
|
||||
"warframe-public-export-plus": "^0.5.64",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
@ -3703,9 +3703,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/warframe-public-export-plus": {
|
||||
"version": "0.5.62",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.62.tgz",
|
||||
"integrity": "sha512-D8ZzjkU9rrK/59VqCfpMoV31HVmwHZV1dNZxPO85AOlcjg/G81Fu3kgITQTaw9sdNagLPLQnFaiXY58pxxRwgA=="
|
||||
"version": "0.5.64",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.64.tgz",
|
||||
"integrity": "sha512-JyHRtYumfwQ1Iog2unzlBWfQHJlZER+iUISquyFFv0Qqtv2QsNzFv2AbV7sCaqgDcE8tw6e5/YqGgfI0m403/g=="
|
||||
},
|
||||
"node_modules/warframe-riven-info": {
|
||||
"version": "0.1.2",
|
||||
|
@ -25,7 +25,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"warframe-public-export-plus": "^0.5.62",
|
||||
"warframe-public-export-plus": "^0.5.64",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
|
@ -57,7 +57,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
||||
const firstCompletion = missionReport.SortieId
|
||||
? inventory.CompletedSorties.indexOf(missionReport.SortieId) == -1
|
||||
: false;
|
||||
const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
|
||||
const inventoryUpdates = await addMissionInventoryUpdates(account, inventory, missionReport);
|
||||
|
||||
if (
|
||||
missionReport.MissionStatus !== "GS_SUCCESS" &&
|
||||
|
@ -1,15 +1,13 @@
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { ExportNightwave, ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
||||
import { ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||
import { isStoreItem, toStoreItem } from "@/src/services/itemDataService";
|
||||
import { toStoreItem } from "@/src/services/itemDataService";
|
||||
import { logger } from "@/src/utils/logger";
|
||||
|
||||
const nightwaveCredsItemType = ExportNightwave.rewards[ExportNightwave.rewards.length - 1].uniqueName;
|
||||
|
||||
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
||||
const accountId = await getAccountIdForRequest(request);
|
||||
const inventory = await getInventory(accountId);
|
||||
@ -54,13 +52,6 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
||||
syndicate.Title ??= 0;
|
||||
syndicate.Title += 1;
|
||||
|
||||
if (syndicate.Title > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == syndicate.Title)) {
|
||||
syndicate.FreeFavorsEarned ??= [];
|
||||
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
||||
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
||||
}
|
||||
}
|
||||
|
||||
if (reward) {
|
||||
combineInventoryChanges(
|
||||
res.InventoryChanges,
|
||||
@ -68,24 +59,37 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
||||
);
|
||||
}
|
||||
|
||||
if (data.AffiliationTag == ExportNightwave.affiliationTag) {
|
||||
const index = syndicate.Title - 1;
|
||||
if (index < ExportNightwave.rewards.length) {
|
||||
// Quacks like a nightwave syndicate?
|
||||
if (manifest.dailyChallenges) {
|
||||
const title = manifest.titles!.find(x => x.level == syndicate.Title);
|
||||
if (title) {
|
||||
res.NewEpisodeReward = true;
|
||||
const reward = ExportNightwave.rewards[index];
|
||||
let rewardType = reward.uniqueName;
|
||||
if (!isStoreItem(rewardType)) {
|
||||
rewardType = toStoreItem(rewardType);
|
||||
let rewardType: string;
|
||||
let rewardCount: number;
|
||||
if (title.storeItemReward) {
|
||||
rewardType = title.storeItemReward;
|
||||
rewardCount = 1;
|
||||
} else {
|
||||
rewardType = toStoreItem(title.reward!.ItemType);
|
||||
rewardCount = title.reward!.ItemCount;
|
||||
}
|
||||
const rewardInventoryChanges = (await handleStoreItemAcquisition(rewardType, inventory, reward.itemCount))
|
||||
const rewardInventoryChanges = (await handleStoreItemAcquisition(rewardType, inventory, rewardCount))
|
||||
.InventoryChanges;
|
||||
if (Object.keys(rewardInventoryChanges).length == 0) {
|
||||
logger.debug(`nightwave rank up reward did not seem to get added, giving 50 creds instead`);
|
||||
const nightwaveCredsItemType = manifest.titles![0].reward!.ItemType;
|
||||
rewardInventoryChanges.MiscItems = [{ ItemType: nightwaveCredsItemType, ItemCount: 50 }];
|
||||
addMiscItems(inventory, rewardInventoryChanges.MiscItems);
|
||||
}
|
||||
combineInventoryChanges(res.InventoryChanges, rewardInventoryChanges);
|
||||
}
|
||||
} else {
|
||||
if (syndicate.Title > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == syndicate.Title)) {
|
||||
syndicate.FreeFavorsEarned ??= [];
|
||||
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
||||
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
|
@ -1,18 +1,26 @@
|
||||
import { RequestHandler } from "express";
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { getAccountForRequest } from "@/src/services/loginService";
|
||||
import { addChallenges, getInventory } from "@/src/services/inventoryService";
|
||||
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||
import { IAffiliationMods } from "@/src/types/purchaseTypes";
|
||||
|
||||
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
||||
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
|
||||
const inventory = await getInventory(accountId, "ChallengeProgress SeasonChallengeHistory Affiliations");
|
||||
const inventory = await getInventory(
|
||||
account._id.toString(),
|
||||
"ChallengeProgress SeasonChallengeHistory Affiliations"
|
||||
);
|
||||
let affiliationMods: IAffiliationMods[] = [];
|
||||
if (challenges.ChallengeProgress) {
|
||||
affiliationMods = addChallenges(inventory, challenges.ChallengeProgress, challenges.SeasonChallengeCompletions);
|
||||
affiliationMods = addChallenges(
|
||||
account,
|
||||
inventory,
|
||||
challenges.ChallengeProgress,
|
||||
challenges.SeasonChallengeCompletions
|
||||
);
|
||||
}
|
||||
if (challenges.SeasonChallengeHistory) {
|
||||
challenges.SeasonChallengeHistory.forEach(({ challenge, id }) => {
|
||||
|
@ -44,6 +44,7 @@ import {
|
||||
import {
|
||||
ExportArcanes,
|
||||
ExportBundles,
|
||||
ExportChallenges,
|
||||
ExportCustoms,
|
||||
ExportDrones,
|
||||
ExportEmailItems,
|
||||
@ -53,7 +54,6 @@ import {
|
||||
ExportGear,
|
||||
ExportKeys,
|
||||
ExportMisc,
|
||||
ExportNightwave,
|
||||
ExportRailjackWeapons,
|
||||
ExportRecipes,
|
||||
ExportResources,
|
||||
@ -83,8 +83,9 @@ import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
|
||||
import { createMessage } from "./inboxService";
|
||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||
import { getWorldState } from "./worldStateService";
|
||||
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
|
||||
import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers";
|
||||
import { TAccountDocument } from "./loginService";
|
||||
|
||||
export const createInventory = async (
|
||||
accountOwnerId: Types.ObjectId,
|
||||
@ -1716,6 +1717,7 @@ export const addLoreFragmentScans = (inventory: TInventoryDatabaseDocument, arr:
|
||||
};
|
||||
|
||||
export const addChallenges = (
|
||||
account: TAccountDocument,
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
ChallengeProgress: IChallengeProgress[],
|
||||
SeasonChallengeCompletions: ISeasonChallenge[] | undefined
|
||||
@ -1738,26 +1740,32 @@ export const addChallenges = (
|
||||
continue;
|
||||
}
|
||||
|
||||
const meta = ExportNightwave.challenges[challenge.challenge];
|
||||
logger.debug("Completed challenge", meta);
|
||||
const meta = ExportChallenges[challenge.challenge];
|
||||
const nightwaveSyndicateTag = getNightwaveSyndicateTag(account.BuildLabel);
|
||||
logger.debug("Completed season challenge", {
|
||||
uniqueName: challenge.challenge,
|
||||
syndicateTag: nightwaveSyndicateTag,
|
||||
...meta
|
||||
});
|
||||
if (nightwaveSyndicateTag) {
|
||||
let affiliation = inventory.Affiliations.find(x => x.Tag == nightwaveSyndicateTag);
|
||||
if (!affiliation) {
|
||||
affiliation =
|
||||
inventory.Affiliations[
|
||||
inventory.Affiliations.push({
|
||||
Tag: nightwaveSyndicateTag,
|
||||
Standing: 0
|
||||
}) - 1
|
||||
];
|
||||
}
|
||||
affiliation.Standing += meta.standing!;
|
||||
|
||||
let affiliation = inventory.Affiliations.find(x => x.Tag == ExportNightwave.affiliationTag);
|
||||
if (!affiliation) {
|
||||
affiliation =
|
||||
inventory.Affiliations[
|
||||
inventory.Affiliations.push({
|
||||
Tag: ExportNightwave.affiliationTag,
|
||||
Standing: 0
|
||||
}) - 1
|
||||
];
|
||||
if (affiliationMods.length == 0) {
|
||||
affiliationMods.push({ Tag: nightwaveSyndicateTag });
|
||||
}
|
||||
affiliationMods[0].Standing ??= 0;
|
||||
affiliationMods[0].Standing += meta.standing!;
|
||||
}
|
||||
affiliation.Standing += meta.standing;
|
||||
|
||||
if (affiliationMods.length == 0) {
|
||||
affiliationMods.push({ Tag: ExportNightwave.affiliationTag });
|
||||
}
|
||||
affiliationMods[0].Standing ??= 0;
|
||||
affiliationMods[0].Standing += meta.standing;
|
||||
}
|
||||
}
|
||||
return affiliationMods;
|
||||
|
@ -79,6 +79,7 @@ import { config } from "./configService";
|
||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
||||
import { fromOid } from "../helpers/inventoryHelpers";
|
||||
import { TAccountDocument } from "./loginService";
|
||||
|
||||
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
||||
// For Spy missions, e.g. 3 vaults cracked = A, B, C
|
||||
@ -135,6 +136,7 @@ const getRandomRewardByChance = (pool: IReward[], rng?: SRng): IRngResult | unde
|
||||
//const knownUnhandledKeys: readonly string[] = ["test"] as const; // for unimplemented but important keys
|
||||
|
||||
export const addMissionInventoryUpdates = async (
|
||||
account: TAccountDocument,
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
inventoryUpdates: IMissionInventoryUpdateRequest
|
||||
): Promise<IInventoryChanges> => {
|
||||
@ -287,7 +289,7 @@ export const addMissionInventoryUpdates = async (
|
||||
addRecipes(inventory, value);
|
||||
break;
|
||||
case "ChallengeProgress":
|
||||
addChallenges(inventory, value, inventoryUpdates.SeasonChallengeCompletions);
|
||||
addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions);
|
||||
break;
|
||||
case "FusionTreasures":
|
||||
addFusionTreasures(inventory, value);
|
||||
|
@ -27,7 +27,6 @@ import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSal
|
||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
||||
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
|
||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
||||
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
|
||||
@ -54,7 +53,6 @@ const rawVendorManifests: IVendorManifest[] = [
|
||||
Nova1999ConquestShopManifest,
|
||||
OstronPetVendorManifest,
|
||||
OstronProspectorVendorManifest,
|
||||
RadioLegionIntermission12VendorManifest,
|
||||
SolarisDebtTokenVendorRepossessionsManifest,
|
||||
SolarisProspectorVendorManifest,
|
||||
Temple1999VendorManifest,
|
||||
|
@ -6,7 +6,7 @@ import { buildConfig } from "@/src/services/buildConfigService";
|
||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||
import { config } from "@/src/services/configService";
|
||||
import { SRng } from "@/src/services/rngService";
|
||||
import { ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
|
||||
import { ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
|
||||
import {
|
||||
ICalendarDay,
|
||||
ICalendarEvent,
|
||||
@ -344,11 +344,26 @@ export const getSortie = (day: number): ISortie => {
|
||||
};
|
||||
};
|
||||
|
||||
const dailyChallenges = Object.keys(ExportNightwave.challenges).filter(x =>
|
||||
x.startsWith("/Lotus/Types/Challenges/Seasons/Daily/")
|
||||
);
|
||||
interface IRotatingSeasonChallengePools {
|
||||
daily: string[];
|
||||
weekly: string[];
|
||||
hardWeekly: string[];
|
||||
}
|
||||
|
||||
const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
|
||||
const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallengePools => {
|
||||
const syndicate = ExportSyndicates[syndicateTag];
|
||||
return {
|
||||
daily: syndicate.dailyChallenges!,
|
||||
weekly: syndicate.weeklyChallenges!.filter(
|
||||
x =>
|
||||
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/") &&
|
||||
!x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
|
||||
),
|
||||
hardWeekly: syndicate.weeklyChallenges!.filter(x => x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/"))
|
||||
};
|
||||
};
|
||||
|
||||
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));
|
||||
@ -357,17 +372,11 @@ const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
|
||||
Daily: true,
|
||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||
Challenge: rng.randomElement(dailyChallenges)!
|
||||
Challenge: rng.randomElement(pools.daily)!
|
||||
};
|
||||
};
|
||||
|
||||
const weeklyChallenges = Object.keys(ExportNightwave.challenges).filter(
|
||||
x =>
|
||||
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/") &&
|
||||
!x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
|
||||
);
|
||||
|
||||
const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge => {
|
||||
const getSeasonWeeklyChallenge = (pools: IRotatingSeasonChallengePools, week: number, id: number): ISeasonChallenge => {
|
||||
const weekStart = EPOCH + week * 604800000;
|
||||
const weekEnd = weekStart + 604800000;
|
||||
const challengeId = week * 7 + id;
|
||||
@ -376,15 +385,15 @@ const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge =>
|
||||
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Challenge: rng.randomElement(weeklyChallenges)!
|
||||
Challenge: rng.randomElement(pools.weekly)!
|
||||
};
|
||||
};
|
||||
|
||||
const weeklyHardChallenges = Object.keys(ExportNightwave.challenges).filter(x =>
|
||||
x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/")
|
||||
);
|
||||
|
||||
const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChallenge => {
|
||||
const getSeasonWeeklyHardChallenge = (
|
||||
pools: IRotatingSeasonChallengePools,
|
||||
week: number,
|
||||
id: number
|
||||
): ISeasonChallenge => {
|
||||
const weekStart = EPOCH + week * 604800000;
|
||||
const weekEnd = weekStart + 604800000;
|
||||
const challengeId = week * 7 + id;
|
||||
@ -393,35 +402,39 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng
|
||||
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Challenge: rng.randomElement(weeklyHardChallenges)!
|
||||
Challenge: rng.randomElement(pools.hardWeekly)!
|
||||
};
|
||||
};
|
||||
|
||||
const pushWeeklyActs = (worldState: IWorldState, week: number): void => {
|
||||
const pushWeeklyActs = (
|
||||
activeChallenges: ISeasonChallenge[],
|
||||
pools: IRotatingSeasonChallengePools,
|
||||
week: number
|
||||
): void => {
|
||||
const weekStart = EPOCH + week * 604800000;
|
||||
const weekEnd = weekStart + 604800000;
|
||||
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 0));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 1));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 2));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 3));
|
||||
worldState.SeasonInfo.ActiveChallenges.push({
|
||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 0));
|
||||
activeChallenges.push(getSeasonWeeklyChallenge(pools, week, 1));
|
||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 2));
|
||||
activeChallenges.push(getSeasonWeeklyHardChallenge(pools, week, 3));
|
||||
activeChallenges.push({
|
||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions"
|
||||
});
|
||||
worldState.SeasonInfo.ActiveChallenges.push({
|
||||
activeChallenges.push({
|
||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus"
|
||||
});
|
||||
worldState.SeasonInfo.ActiveChallenges.push({
|
||||
activeChallenges.push({
|
||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies"
|
||||
});
|
||||
};
|
||||
|
||||
@ -926,15 +939,6 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
LiteSorties: [],
|
||||
GlobalUpgrades: [],
|
||||
EndlessXpChoices: [],
|
||||
SeasonInfo: {
|
||||
Activation: { $date: { $numberLong: "1715796000000" } },
|
||||
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||
AffiliationTag: "RadioLegionIntermission12Syndicate",
|
||||
Season: 14,
|
||||
Phase: 0,
|
||||
Params: "",
|
||||
ActiveChallenges: []
|
||||
},
|
||||
KnownCalendarSeasons: [],
|
||||
...staticWorldState,
|
||||
SyndicateMissions: [...staticWorldState.SyndicateMissions]
|
||||
@ -967,17 +971,27 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
}
|
||||
|
||||
// Nightwave Challenges
|
||||
// Current nightwave season was introduced in 38.0.8 so omitting challenges before that to avoid UI bugs and even crashes on really old versions.
|
||||
if (!buildLabel || version_compare(buildLabel, "2025.02.05.11.19") >= 0) {
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 2));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 1));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 0));
|
||||
const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
|
||||
if (nightwaveSyndicateTag) {
|
||||
worldState.SeasonInfo = {
|
||||
Activation: { $date: { $numberLong: "1715796000000" } },
|
||||
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||
AffiliationTag: nightwaveSyndicateTag,
|
||||
Season: nightwaveTagToSeason[nightwaveSyndicateTag],
|
||||
Phase: 0,
|
||||
Params: "",
|
||||
ActiveChallenges: []
|
||||
};
|
||||
const pools = getSeasonChallengePools(nightwaveSyndicateTag);
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day - 2));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day - 1));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day - 0));
|
||||
if (isBeforeNextExpectedWorldStateRefresh(EPOCH + (day + 1) * 86400000)) {
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day + 1));
|
||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day + 1));
|
||||
}
|
||||
pushWeeklyActs(worldState, week);
|
||||
pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week);
|
||||
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||
pushWeeklyActs(worldState, week + 1);
|
||||
pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1242,3 +1256,18 @@ export const isArchwingMission = (node: IRegion): boolean => {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string | undefined => {
|
||||
if (!buildLabel || version_compare(buildLabel, "2025.05.20.10.18") >= 0) {
|
||||
return "RadioLegionIntermission13Syndicate";
|
||||
}
|
||||
if (version_compare(buildLabel, "2025.02.05.11.19") >= 0) {
|
||||
return "RadioLegionIntermission12Syndicate";
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const nightwaveTagToSeason: Record<string, number> = {
|
||||
RadioLegionIntermission13Syndicate: 15,
|
||||
RadioLegionIntermission12Syndicate: 14
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ export interface IWorldState {
|
||||
NodeOverrides: INodeOverride[];
|
||||
PVPChallengeInstances: IPVPChallengeInstance[];
|
||||
EndlessXpChoices: IEndlessXpChoice[];
|
||||
SeasonInfo: {
|
||||
SeasonInfo?: {
|
||||
Activation: IMongoDate;
|
||||
Expiry: IMongoDate;
|
||||
AffiliationTag: string;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user