From a22f3ae6e53a0f1dc46d84ab13b5828115e86335 Mon Sep 17 00:00:00 2001 From: BanLanGen Date: Fri, 25 Jul 2025 08:19:00 -0700 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add worldState Event --- configService.ts | 144 ++ index.html | 1119 +++++++++++ worldStateService.ts | 4370 ++++++++++++++++++++++++++++++++++++++++++ zh.js | 358 ++++ 4 files changed, 5991 insertions(+) create mode 100644 configService.ts create mode 100644 index.html create mode 100644 worldStateService.ts create mode 100644 zh.js diff --git a/configService.ts b/configService.ts new file mode 100644 index 00000000..0e39203a --- /dev/null +++ b/configService.ts @@ -0,0 +1,144 @@ +import fs from "fs"; +import path from "path"; +import { repoDir } from "@/src/helpers/pathHelper"; +import { args } from "@/src/helpers/commandLineArguments"; +import { Inbox } from "@/src/models/inboxModel"; + +export interface IConfig { + mongodbUrl: string; + logger: { + files: boolean; + level: string; // "fatal" | "error" | "warn" | "info" | "http" | "debug" | "trace"; + }; + myAddress: string; + httpPort?: number; + httpsPort?: number; + myIrcAddresses?: string[]; + NRS?: string[]; + administratorNames?: string[]; + autoCreateAccount?: boolean; + skipTutorial?: boolean; + skipAllDialogue?: boolean; + unlockAllScans?: boolean; + infiniteCredits?: boolean; + infinitePlatinum?: boolean; + infiniteEndo?: boolean; + infiniteRegalAya?: boolean; + infiniteHelminthMaterials?: boolean; + claimingBlueprintRefundsIngredients?: boolean; + dontSubtractPurchaseCreditCost?: boolean; + dontSubtractPurchasePlatinumCost?: boolean; + dontSubtractPurchaseItemCost?: boolean; + dontSubtractPurchaseStandingCost?: boolean; + dontSubtractVoidTraces?: boolean; + dontSubtractConsumables?: boolean; + unlockAllShipFeatures?: boolean; + unlockAllShipDecorations?: boolean; + unlockAllFlavourItems?: boolean; + unlockAllSkins?: boolean; + unlockAllCapturaScenes?: boolean; + unlockAllDecoRecipes?: boolean; + universalPolarityEverywhere?: boolean; + unlockDoubleCapacityPotatoesEverywhere?: boolean; + unlockExilusEverywhere?: boolean; + unlockArcanesEverywhere?: boolean; + noDailyStandingLimits?: boolean; + noDailyFocusLimit?: boolean; + noArgonCrystalDecay?: boolean; + noMasteryRankUpCooldown?: boolean; + noVendorPurchaseLimits?: boolean; + noDeathMarks?: boolean; + noKimCooldowns?: boolean; + fullyStockedVendors?: boolean; + baroAlwaysAvailable?: boolean; + baroFullyStocked?: boolean; + syndicateMissionsRepeatable?: boolean; + unlockAllProfitTakerStages?: boolean; + instantFinishRivenChallenge?: boolean; + instantResourceExtractorDrones?: boolean; + noResourceExtractorDronesDamage?: boolean; + skipClanKeyCrafting?: boolean; + noDojoRoomBuildStage?: boolean; + noDojoDecoBuildStage?: boolean; + fastDojoRoomDestruction?: boolean; + noDojoResearchCosts?: boolean; + noDojoResearchTime?: boolean; + fastClanAscension?: boolean; + missionsCanGiveAllRelics?: boolean; + exceptionalRelicsAlwaysGiveBronzeReward?: boolean; + flawlessRelicsAlwaysGiveSilverReward?: boolean; + radiantRelicsAlwaysGiveGoldReward?: boolean; + unlockAllSimarisResearchEntries?: boolean; + disableDailyTribute?: boolean; + spoofMasteryRank?: number; + relicRewardItemCountMultiplier?: number; + nightwaveStandingMultiplier?: number; + unfaithfulBugFixes?: { + ignore1999LastRegionPlayed?: boolean; + fixXtraCheeseTimer?: boolean; + }; + worldState?: { + creditBoost?: boolean; + affinityBoost?: boolean; + resourceBoost?: boolean; + starDays?: boolean; + galleonOfGhouls?: number; + eidolonOverride?: string; + vallisOverride?: string; + duviriOverride?: string; + nightwaveOverride?: string; + allTheFissures?: string; + circuitGameModes?: string[]; + darvoStockMultiplier?: number; + varziaOverride?: string; + varziaFullyStocked?: boolean; + TennoCon?: boolean; + Fomorian?: boolean; + BellyoftheBeast?: boolean; + RecurringGhoul?: boolean; + HeatFissures?:boolean; + }; + dev?: { + keepVendorsExpired?: boolean; + }; +} + +export const configPath = path.join(repoDir, args.configPath ?? "config.json"); + +export const config: IConfig = { + mongodbUrl: "mongodb://127.0.0.1:27017/openWF", + logger: { + files: true, + level: "trace" + }, + myAddress: "localhost" +}; + +export const loadConfig = (): void => { + const newConfig = JSON.parse(fs.readFileSync(configPath, "utf-8")) as IConfig; + + // Set all values to undefined now so if the new config.json omits some fields that were previously present, it's correct in-memory. + for (const key of Object.keys(config)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (config as any)[key] = undefined; + } + + Object.assign(config, newConfig); +}; + +export const syncConfigWithDatabase = (): void => { + // Event messages are deleted after endDate. Since we don't use beginDate/endDate and instead have config toggles, we need to delete the messages once those bools are false. + // Also, for some reason, I can't just do `Inbox.deleteMany(...)`; - it needs this whole circus. + if (!config.worldState?.creditBoost) { + void Inbox.deleteMany({ globaUpgradeId: "5b23106f283a555109666672" }).then(() => {}); + } + if (!config.worldState?.affinityBoost) { + void Inbox.deleteMany({ globaUpgradeId: "5b23106f283a555109666673" }).then(() => {}); + } + if (!config.worldState?.resourceBoost) { + void Inbox.deleteMany({ globaUpgradeId: "5b23106f283a555109666674" }).then(() => {}); + } + if (!config.worldState?.galleonOfGhouls) { + void Inbox.deleteMany({ goalTag: "GalleonRobbery" }).then(() => {}); + } +}; diff --git a/index.html b/index.html new file mode 100644 index 00000000..597649a7 --- /dev/null +++ b/index.html @@ -0,0 +1,1119 @@ + + + + OpenWF WebUI + + + + + + +
+ +
+
+

+
+ + +
+ + +
+ + +
+
+
+

+
+
+
+ + + +
+
+
+
+
+
+
+

+
+ + +
+
+
+
+
+
+
+
+

+
+ + +
+
+
+
+
+
+
+
+

+
+ + +
+
+
+
+
+
+
+
+

+
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + +
+ + + + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + + + +
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+
+
+
+
+
+
+
+ + + + + +
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + + + + + + +
+
+ + + + + + + +
+
+
+
+
+

+

+

+
+
+
+

+ + +

+
+ + x + + +
+ + +
+
+
+
+
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+ + + + +
+
+
+
+
+

+
+
+
+
+
+ + + + +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+ + + + +
+ + +
+
+
+
+
+
+ + + +
+
+
+
+
+
+

+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + +
+
+ +
+ + +
+
+
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+
+

+ + +

+
    +
  • +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/worldStateService.ts b/worldStateService.ts new file mode 100644 index 00000000..72414248 --- /dev/null +++ b/worldStateService.ts @@ -0,0 +1,4370 @@ +import staticWorldState from "@/static/fixed_responses/worldState/worldState.json"; +import baro from "@/static/fixed_responses/worldState/baro.json"; +import varzia from "@/static/fixed_responses/worldState/varzia.json"; +import fissureMissions from "@/static/fixed_responses/worldState/fissureMissions.json"; +import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json"; +import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json"; +import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json"; +import darvoDeals from "@/static/fixed_responses/worldState/darvoDeals.json"; +import invasionNodes from "@/static/fixed_responses/worldState/invasionNodes.json"; +import invasionRewards from "@/static/fixed_responses/worldState/invasionRewards.json"; +import { buildConfig } from "@/src/services/buildConfigService"; +import { unixTimesInMs } from "@/src/constants/timeConstants"; +import { config } from "@/src/services/configService"; +import { getRandomElement, getRandomInt, sequentiallyUniqueRandomElement, SRng } from "@/src/services/rngService"; +import { eMissionType, ExportRegions, ExportSyndicates, IMissionReward, IRegion } from "warframe-public-export-plus"; +import { + ICalendarDay, + ICalendarEvent, + ICalendarSeason, + IInvasion, + ILiteSortie, + IPrimeVaultTrader, + IPrimeVaultTraderOffer, + ISeasonChallenge, + ISortie, + ISortieMission, + ISyndicateMissionInfo, + ITmp, + IVoidStorm, + IVoidTrader, + IVoidTraderOffer, + IWorldState, + TCircuitGameMode +} from "@/src/types/worldStateTypes"; +import { toMongoDate, toOid, version_compare } from "@/src/helpers/inventoryHelpers"; +import { logger } from "@/src/utils/logger"; +import { DailyDeal, Fissure } from "@/src/models/worldStateModel"; + +const sortieBosses = [ + "SORTIE_BOSS_HYENA", + "SORTIE_BOSS_KELA", + "SORTIE_BOSS_VOR", + "SORTIE_BOSS_RUK", + "SORTIE_BOSS_HEK", + "SORTIE_BOSS_KRIL", + "SORTIE_BOSS_TYL", + "SORTIE_BOSS_JACKAL", + "SORTIE_BOSS_ALAD", + "SORTIE_BOSS_AMBULAS", + "SORTIE_BOSS_NEF", + "SORTIE_BOSS_RAPTOR", + "SORTIE_BOSS_PHORID", + "SORTIE_BOSS_LEPHANTIS", + "SORTIE_BOSS_INFALAD", + "SORTIE_BOSS_CORRUPTED_VOR" +] as const; + +type TSortieBoss = (typeof sortieBosses)[number]; + +const sortieBossToFaction: Record = { + SORTIE_BOSS_HYENA: "FC_CORPUS", + SORTIE_BOSS_KELA: "FC_GRINEER", + SORTIE_BOSS_VOR: "FC_GRINEER", + SORTIE_BOSS_RUK: "FC_GRINEER", + SORTIE_BOSS_HEK: "FC_GRINEER", + SORTIE_BOSS_KRIL: "FC_GRINEER", + SORTIE_BOSS_TYL: "FC_GRINEER", + SORTIE_BOSS_JACKAL: "FC_CORPUS", + SORTIE_BOSS_ALAD: "FC_CORPUS", + SORTIE_BOSS_AMBULAS: "FC_CORPUS", + SORTIE_BOSS_NEF: "FC_CORPUS", + SORTIE_BOSS_RAPTOR: "FC_CORPUS", + SORTIE_BOSS_PHORID: "FC_INFESTATION", + SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION", + SORTIE_BOSS_INFALAD: "FC_INFESTATION", + SORTIE_BOSS_CORRUPTED_VOR: "FC_OROKIN" +}; + +const sortieFactionToSystemIndexes: Record = { + FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18], + FC_CORPUS: [1, 4, 7, 8, 12, 15], + FC_INFESTATION: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15], + FC_OROKIN: [14] +}; + +const sortieFactionToFactionIndexes: Record = { + FC_GRINEER: [0], + FC_CORPUS: [1], + FC_INFESTATION: [0, 1, 2], + FC_OROKIN: [3] +}; + +const sortieBossNode: Record, string> = { + SORTIE_BOSS_ALAD: "SolNode53", + SORTIE_BOSS_AMBULAS: "SolNode51", + SORTIE_BOSS_HEK: "SolNode24", + SORTIE_BOSS_HYENA: "SolNode127", + SORTIE_BOSS_INFALAD: "SolNode166", + SORTIE_BOSS_JACKAL: "SolNode104", + SORTIE_BOSS_KELA: "SolNode193", + SORTIE_BOSS_KRIL: "SolNode99", + SORTIE_BOSS_LEPHANTIS: "SolNode712", + SORTIE_BOSS_NEF: "SettlementNode20", + SORTIE_BOSS_PHORID: "SolNode171", + SORTIE_BOSS_RAPTOR: "SolNode210", + SORTIE_BOSS_RUK: "SolNode32", + SORTIE_BOSS_TYL: "SolNode105", + SORTIE_BOSS_VOR: "SolNode108" +}; + +const eidolonJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyAss", + "/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyCap", + "/Lotus/Types/Gameplay/Eidolon/Jobs/AttritionBountySab", + "/Lotus/Types/Gameplay/Eidolon/Jobs/AttritionBountyLib", + "/Lotus/Types/Gameplay/Eidolon/Jobs/AttritionBountyCap", + "/Lotus/Types/Gameplay/Eidolon/Jobs/AttritionBountyExt", + "/Lotus/Types/Gameplay/Eidolon/Jobs/ReclamationBountyCap", + "/Lotus/Types/Gameplay/Eidolon/Jobs/ReclamationBountyTheft", + "/Lotus/Types/Gameplay/Eidolon/Jobs/ReclamationBountyCache", + "/Lotus/Types/Gameplay/Eidolon/Jobs/CaptureBountyCapOne", + "/Lotus/Types/Gameplay/Eidolon/Jobs/CaptureBountyCapTwo", + "/Lotus/Types/Gameplay/Eidolon/Jobs/SabotageBountySab", + "/Lotus/Types/Gameplay/Eidolon/Jobs/RescueBountyResc" +]; + +const eidolonNarmerJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AssassinateBountyAss", + "/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AttritionBountyExt", + "/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/ReclamationBountyTheft", + "/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AttritionBountyLib" +]; + +const venusJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobAmbush", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobExcavation", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobRecovery", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusChaosJobAssassinate", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusChaosJobExcavation", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusCullJobAssassinate", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusCullJobExterminate", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusCullJobResource", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusIntelJobRecovery", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusIntelJobResource", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusIntelJobSpy", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusSpyJobSpy", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusTheftJobAmbush", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusTheftJobExcavation", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusTheftJobResource", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusHelpingJobCaches", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusHelpingJobResource", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusHelpingJobSpy", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusPreservationJobDefense", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusPreservationJobRecovery", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusPreservationJobResource", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusWetworkJobAssassinate", + "/Lotus/Types/Gameplay/Venus/Jobs/VenusWetworkJobSpy" +]; + +const venusNarmerJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/Venus/Jobs/Narmer/NarmerVenusCullJobAssassinate", + "/Lotus/Types/Gameplay/Venus/Jobs/Narmer/NarmerVenusCullJobExterminate", + "/Lotus/Types/Gameplay/Venus/Jobs/Narmer/NarmerVenusPreservationJobDefense", + "/Lotus/Types/Gameplay/Venus/Jobs/Narmer/NarmerVenusTheftJobExcavation" +]; + +const microplanetJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosAreaDefenseBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosAssassinateBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosCrpSurvivorBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosGrnSurvivorBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosKeyPiecesBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosExcavateBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosPurifyBounty" +]; + +const microplanetEndlessJobs: readonly string[] = [ + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessAreaDefenseBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessExcavateBounty", + "/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty" +]; + +const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0 + +const isBeforeNextExpectedWorldStateRefresh = (nowMs: number, thenMs: number): boolean => { + return nowMs + 300_000 > thenMs; +}; + +const getSortieTime = (day: number): number => { + const dayStart = EPOCH + day * 86400000; + const date = new Date(dayStart); + date.setUTCHours(12); + const isDst = new Intl.DateTimeFormat("en-US", { + timeZone: "America/Toronto", + timeZoneName: "short" + }) + .formatToParts(date) + .find(part => part.type === "timeZoneName")! + .value.includes("DT"); + return dayStart + (isDst ? 16 : 17) * 3600000; +}; + +const pushSyndicateMissions = ( + worldState: IWorldState, + day: number, + seed: number, + idSuffix: string, + syndicateTag: string +): void => { + const nodeOptions: string[] = [...syndicateMissions]; + + const rng = new SRng(seed); + const nodes: string[] = []; + for (let i = 0; i != 6; ++i) { + const index = rng.randomInt(0, nodeOptions.length - 1); + nodes.push(nodeOptions[index]); + nodeOptions.splice(index, 1); + } + + const dayStart = getSortieTime(day); + const dayEnd = getSortieTime(day + 1); + worldState.SyndicateMissions.push({ + _id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + idSuffix }, + Activation: { $date: { $numberLong: dayStart.toString() } }, + Expiry: { $date: { $numberLong: dayEnd.toString() } }, + Tag: syndicateTag, + Seed: seed, + Nodes: nodes + }); +}; + +type TSortieTileset = keyof typeof sortieTilesetMissions; + +const pushTilesetModifiers = (modifiers: string[], tileset: TSortieTileset): void => { + switch (tileset) { + case "GrineerForestTileset": + modifiers.push("SORTIE_MODIFIER_HAZARD_FOG"); + break; + case "CorpusShipTileset": + case "GrineerGalleonTileset": + case "InfestedCorpusShipTileset": + modifiers.push("SORTIE_MODIFIER_HAZARD_MAGNETIC"); + modifiers.push("SORTIE_MODIFIER_HAZARD_FIRE"); + modifiers.push("SORTIE_MODIFIER_HAZARD_ICE"); + break; + case "CorpusIcePlanetTileset": + case "CorpusIcePlanetTilesetCaves": + modifiers.push("SORTIE_MODIFIER_HAZARD_COLD"); + break; + } +}; + +export const getSortie = (day: number): ISortie => { + const seed = new SRng(day).randomInt(0, 100_000); + const rng = new SRng(seed); + + const boss = rng.randomElement(sortieBosses)!; + + const nodes: string[] = []; + for (const [key, value] of Object.entries(ExportRegions)) { + if ( + sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) && + sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) && + key in sortieTilesets && + (key != "SolNode228" || sortieBossToFaction[boss] == "FC_GRINEER") // PoE does not work for non-infested enemies + ) { + nodes.push(key); + } + } + + const selectedNodes: ISortieMission[] = []; + const missionTypes = new Set(); + + for (let i = 0; i < 3; i++) { + const randomIndex = rng.randomInt(0, nodes.length - 1); + const node = nodes[randomIndex]; + + const modifiers = [ + "SORTIE_MODIFIER_LOW_ENERGY", + "SORTIE_MODIFIER_IMPACT", + "SORTIE_MODIFIER_SLASH", + "SORTIE_MODIFIER_PUNCTURE", + "SORTIE_MODIFIER_EXIMUS", + "SORTIE_MODIFIER_MAGNETIC", + "SORTIE_MODIFIER_CORROSIVE", + "SORTIE_MODIFIER_VIRAL", + "SORTIE_MODIFIER_ELECTRICITY", + "SORTIE_MODIFIER_RADIATION", + "SORTIE_MODIFIER_FIRE", + "SORTIE_MODIFIER_EXPLOSION", + "SORTIE_MODIFIER_FREEZE", + "SORTIE_MODIFIER_POISON", + "SORTIE_MODIFIER_SECONDARY_ONLY", + "SORTIE_MODIFIER_SHOTGUN_ONLY", + "SORTIE_MODIFIER_SNIPER_ONLY", + "SORTIE_MODIFIER_RIFLE_ONLY", + "SORTIE_MODIFIER_BOW_ONLY" + ]; + + if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) { + const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] as TSortieTileset; + pushTilesetModifiers(modifiers, tileset); + + const modifierType = rng.randomElement(modifiers)!; + + selectedNodes.push({ + missionType: "MT_ASSASSINATION", + modifierType, + node: sortieBossNode[boss], + tileset + }); + continue; + } + + const tileset = sortieTilesets[node as keyof typeof sortieTilesets] as TSortieTileset; + pushTilesetModifiers(modifiers, tileset); + + const missionType = rng.randomElement(sortieTilesetMissions[tileset])!; + + if (missionTypes.has(missionType) || missionType == "MT_ASSASSINATION") { + i--; + continue; + } + + modifiers.push("SORTIE_MODIFIER_MELEE_ONLY"); // not an assassination mission, can now push this + + if (missionType != "MT_TERRITORY") { + modifiers.push("SORTIE_MODIFIER_HAZARD_RADIATION"); + } + + if (ExportRegions[node].factionIndex == 0) { + // Grineer + modifiers.push("SORTIE_MODIFIER_ARMOR"); + } else if (ExportRegions[node].factionIndex == 1) { + // Corpus + modifiers.push("SORTIE_MODIFIER_SHIELDS"); + } + + const modifierType = rng.randomElement(modifiers)!; + + selectedNodes.push({ + missionType, + modifierType, + node, + tileset + }); + nodes.splice(randomIndex, 1); + missionTypes.add(missionType); + } + + const dayStart = getSortieTime(day); + const dayEnd = getSortieTime(day + 1); + return { + _id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "d4d932c97c0a3acd" }, + Activation: { $date: { $numberLong: dayStart.toString() } }, + Expiry: { $date: { $numberLong: dayEnd.toString() } }, + Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards", + Seed: seed, + Boss: boss, + Variants: selectedNodes + }; +}; + +interface IRotatingSeasonChallengePools { + daily: string[]; + weekly: string[]; + hardWeekly: string[]; + hasWeeklyPermanent: boolean; +} + +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/") + ), + hasWeeklyPermanent: syndicate.weeklyChallenges!.some(x => + x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent") + ) + }; +}; + +const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: number): ISeasonChallenge => { + const dayStart = EPOCH + day * 86400000; + const dayEnd = EPOCH + (day + 3) * 86400000; + return { + _id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") }, + Daily: true, + Activation: { $date: { $numberLong: dayStart.toString() } }, + Expiry: { $date: { $numberLong: dayEnd.toString() } }, + Challenge: sequentiallyUniqueRandomElement(pools.daily, day, 2, 605732938)! + }; +}; + +const pushSeasonWeeklyChallenge = ( + activeChallenges: ISeasonChallenge[], + pool: string[], + week: number, + id: number +): 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)); + 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: challenge + }); +}; + +const pushWeeklyActs = ( + activeChallenges: ISeasonChallenge[], + pools: IRotatingSeasonChallengePools, + week: number +): void => { + const weekStart = EPOCH + week * 604800000; + const weekEnd = weekStart + 604800000; + + 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") }, + Activation: { $date: { $numberLong: weekStart.toString() } }, + Expiry: { $date: { $numberLong: weekEnd.toString() } }, + Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + }); + 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" + }); + 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" + }); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 2); + pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 3); + } else { + 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); + } +}; + +const generateXpAmounts = (rng: SRng, stageCount: number, minXp: number, maxXp: number): number[] => { + const step = minXp < 1000 ? 1 : 10; + const totalDeciXp = rng.randomInt(minXp / step, maxXp / step); + const xpAmounts: number[] = []; + if (stageCount < 4) { + const perStage = Math.ceil(totalDeciXp / stageCount) * step; + for (let i = 0; i != stageCount; ++i) { + xpAmounts.push(perStage); + } + } else { + const perStage = Math.ceil(Math.round(totalDeciXp * 0.667) / (stageCount - 1)) * step; + for (let i = 0; i != stageCount - 1; ++i) { + xpAmounts.push(perStage); + } + xpAmounts.push(Math.ceil(totalDeciXp * 0.332) * step); + } + return xpAmounts; +}; +// Test vectors: +//console.log(generateXpAmounts(new SRng(1337n), 5, 5000, 5000)); // [840, 840, 840, 840, 1660] +//console.log(generateXpAmounts(new SRng(1337n), 3, 40, 40)); // [14, 14, 14] +//console.log(generateXpAmounts(new SRng(1337n), 5, 150, 150)); // [25, 25, 25, 25, 50] +//console.log(generateXpAmounts(new SRng(1337n), 4, 10, 10)); // [2, 2, 2, 4] +//console.log(generateXpAmounts(new SRng(1337n), 4, 15, 15)); // [4, 4, 4, 5] +//console.log(generateXpAmounts(new SRng(1337n), 4, 20, 20)); // [5, 5, 5, 7] + +export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[], bountyCycle: number): void => { + const table = String.fromCharCode(65 + (bountyCycle % 3)); + const vaultTable = String.fromCharCode(65 + ((bountyCycle + 1) % 3)); + const deimosDTable = String.fromCharCode(65 + (bountyCycle % 2)); + + const seed = new SRng(bountyCycle).randomInt(0, 100_000); + const bountyCycleStart = bountyCycle * 9000000; + const bountyCycleEnd = bountyCycleStart + 9000000; + + { + const rng = new SRng(seed); + const pool = [...eidolonJobs]; + syndicateMissions.push({ + _id: { + $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008" + }, + Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } }, + Tag: "CetusSyndicate", + Seed: seed, + Nodes: [], + Jobs: [ + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierATable${table}Rewards`, + masteryReq: 0, + minEnemyLevel: 5, + maxEnemyLevel: 15, + xpAmounts: generateXpAmounts(rng, 3, 1000, 1500) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierBTable${table}Rewards`, + masteryReq: 1, + minEnemyLevel: 10, + maxEnemyLevel: 30, + xpAmounts: generateXpAmounts(rng, 3, 1750, 2250) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierCTable${table}Rewards`, + masteryReq: 2, + minEnemyLevel: 20, + maxEnemyLevel: 40, + xpAmounts: generateXpAmounts(rng, 4, 2500, 3000) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierDTable${table}Rewards`, + masteryReq: 3, + minEnemyLevel: 30, + maxEnemyLevel: 50, + xpAmounts: generateXpAmounts(rng, 5, 3250, 3750) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierETable${table}Rewards`, + masteryReq: 5, + minEnemyLevel: 40, + maxEnemyLevel: 60, + xpAmounts: generateXpAmounts(rng, 5, 4000, 4500) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierETable${table}Rewards`, + masteryReq: 10, + minEnemyLevel: 100, + maxEnemyLevel: 100, + xpAmounts: [840, 840, 840, 840, 1660] + }, + { + jobType: rng.randomElement(eidolonNarmerJobs), + rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/NarmerTable${table}Rewards`, + masteryReq: 0, + minEnemyLevel: 50, + maxEnemyLevel: 70, + xpAmounts: generateXpAmounts(rng, 5, 4500, 5000) + } + ] + }); + } + + { + const rng = new SRng(seed); + const pool = [...venusJobs]; + syndicateMissions.push({ + _id: { + $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000025" + }, + Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } }, + Tag: "SolarisSyndicate", + Seed: seed, + Nodes: [], + Jobs: [ + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierATable${table}Rewards`, + masteryReq: 0, + minEnemyLevel: 5, + maxEnemyLevel: 15, + xpAmounts: generateXpAmounts(rng, 3, 1000, 1500) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierBTable${table}Rewards`, + masteryReq: 1, + minEnemyLevel: 10, + maxEnemyLevel: 30, + xpAmounts: generateXpAmounts(rng, 3, 1750, 2250) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierCTable${table}Rewards`, + masteryReq: 2, + minEnemyLevel: 20, + maxEnemyLevel: 40, + xpAmounts: generateXpAmounts(rng, 4, 2500, 3000) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierDTable${table}Rewards`, + masteryReq: 3, + minEnemyLevel: 30, + maxEnemyLevel: 50, + xpAmounts: generateXpAmounts(rng, 5, 3250, 3750) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`, + masteryReq: 5, + minEnemyLevel: 40, + maxEnemyLevel: 60, + xpAmounts: generateXpAmounts(rng, 5, 4000, 4500) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`, + masteryReq: 10, + minEnemyLevel: 100, + maxEnemyLevel: 100, + xpAmounts: [840, 840, 840, 840, 1660] + }, + { + jobType: rng.randomElement(venusNarmerJobs), + rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/NarmerTableBRewards", + masteryReq: 0, + minEnemyLevel: 50, + maxEnemyLevel: 70, + xpAmounts: generateXpAmounts(rng, 5, 4500, 5000) + } + ] + }); + } + + { + const rng = new SRng(seed); + const pool = [...microplanetJobs]; + syndicateMissions.push({ + _id: { + $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000002" + }, + Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } }, + Tag: "EntratiSyndicate", + Seed: seed, + Nodes: [], + Jobs: [ + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierATable${table}Rewards`, + masteryReq: 0, + minEnemyLevel: 5, + maxEnemyLevel: 15, + xpAmounts: generateXpAmounts(rng, 3, 12, 18) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierCTable${table}Rewards`, + masteryReq: 1, + minEnemyLevel: 15, + maxEnemyLevel: 25, + xpAmounts: generateXpAmounts(rng, 3, 24, 36) + }, + { + jobType: rng.randomElement(microplanetEndlessJobs), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierBTable${table}Rewards`, + masteryReq: 5, + minEnemyLevel: 25, + maxEnemyLevel: 30, + endless: true, + xpAmounts: [14, 14, 14] + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierDTable${deimosDTable}Rewards`, + masteryReq: 2, + minEnemyLevel: 30, + maxEnemyLevel: 40, + xpAmounts: generateXpAmounts(rng, 4, 72, 88) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierETableARewards`, + masteryReq: 3, + minEnemyLevel: 40, + maxEnemyLevel: 60, + xpAmounts: generateXpAmounts(rng, 5, 115, 135) + }, + { + jobType: rng.randomElementPop(pool), + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierETableARewards`, + masteryReq: 10, + minEnemyLevel: 100, + maxEnemyLevel: 100, + xpAmounts: [25, 25, 25, 25, 50] + }, + { + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/VaultBountyTierATable${vaultTable}Rewards`, + masteryReq: 5, + minEnemyLevel: 30, + maxEnemyLevel: 40, + xpAmounts: [2, 2, 2, 4], + locationTag: "ChamberB", + isVault: true + }, + { + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/VaultBountyTierBTable${vaultTable}Rewards`, + masteryReq: 5, + minEnemyLevel: 40, + maxEnemyLevel: 50, + xpAmounts: [4, 4, 4, 5], + locationTag: "ChamberA", + isVault: true + }, + { + rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/VaultBountyTierCTable${vaultTable}Rewards`, + masteryReq: 5, + minEnemyLevel: 50, + maxEnemyLevel: 60, + xpAmounts: [5, 5, 5, 7], + locationTag: "ChamberC", + isVault: true + } + ] + }); + } +}; + +const birthdays: number[] = [ + 1, // Kaya + 45, // Lettie + 74, // Minerva (MinervaVelemirDialogue_rom.dialogue) + 143, // Amir + 166, // Flare + 191, // Aoi + 306, // Eleanor + 307, // Arthur + 338, // Quincy + 355 // Velimir (MinervaVelemirDialogue_rom.dialogue) +]; + +const getCalendarSeason = (week: number): ICalendarSeason => { + const seasonIndex = week % 4; + const seasonDay1 = [1, 91, 182, 274][seasonIndex]; + const seasonDay91 = seasonDay1 + 90; + const eventDays: ICalendarDay[] = []; + for (const day of birthdays) { + if (day < seasonDay1) { + continue; + } + if (day >= seasonDay91) { + break; + } + //logger.debug(`birthday on day ${day}`); + eventDays.push({ day, events: [] }); // This is how CET_PLOT looks in worldState as of around 38.5.0 + } + const rng = new SRng(new SRng(week).randomInt(0, 100_000)); + const challenges = [ + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTankHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeHard" + ]; + const rewardRanges: number[] = []; + const upgradeRanges: number[] = []; + for (let i = 0; i != 6; ++i) { + const chunkDay1 = seasonDay1 + i * 15; + const chunkDay13 = chunkDay1 - 1 + 13; + let challengeDay: number; + do { + challengeDay = rng.randomInt(chunkDay1, chunkDay13); + } while (birthdays.indexOf(challengeDay) != -1); + + let challengeIndex; + let challenge; + do { + challengeIndex = rng.randomInt(0, challenges.length - 1); + challenge = challenges[challengeIndex]; + } while (i < 2 && !challenge.endsWith("Easy")); // First 2 challenges should be easy + challenges.splice(challengeIndex, 1); + + //logger.debug(`challenge on day ${challengeDay}`); + eventDays.push({ + day: challengeDay, + events: [{ type: "CET_CHALLENGE", challenge }] + }); + + rewardRanges.push(challengeDay); + if (i == 0 || i == 3 || i == 5) { + upgradeRanges.push(challengeDay); + } + } + rewardRanges.push(seasonDay91); + upgradeRanges.push(seasonDay91); + + const rewards = [ + "/Lotus/StoreItems/Types/Items/MiscItems/UtilityUnlocker", + "/Lotus/StoreItems/Types/Recipes/Components/FormaAuraBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/FormaBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker", + "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CircuitSilverSteelPathFusionBundle", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarRivenPack", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleLarge", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack", + "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem", + "/Lotus/Types/StoreItems/Boosters/ModDropChanceBooster3DayStoreItem", + "/Lotus/Types/StoreItems/Boosters/ResourceDropChance3DayStoreItem", + "/Lotus/StoreItems/Types/Items/MiscItems/Forma", + "/Lotus/StoreItems/Types/Recipes/Components/OrokinCatalystBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/OrokinReactorBlueprint", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarVosforPack", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalOrange", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalGreen", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalViolet" + ]; + for (let i = 0; i != rewardRanges.length - 1; ++i) { + const events: ICalendarEvent[] = []; + for (let j = 0; j != 2; ++j) { + const rewardIndex = rng.randomInt(0, rewards.length - 1); + events.push({ type: "CET_REWARD", reward: rewards[rewardIndex] }); + rewards.splice(rewardIndex, 1); + } + + //logger.debug(`trying to fit rewards between day ${rewardRanges[i]} and ${rewardRanges[i + 1]}`); + let day: number; + do { + day = rng.randomInt(rewardRanges[i] + 1, rewardRanges[i + 1] - 1); + } while (eventDays.find(x => x.day == day)); + eventDays.push({ day, events }); + } + + const upgradesByHexMember = [ + [ + "/Lotus/Upgrades/Calendar/AttackAndMovementSpeedOnCritMelee", + "/Lotus/Upgrades/Calendar/ElectricalDamageOnBulletJump", + "/Lotus/Upgrades/Calendar/ElectricDamagePerDistance", + "/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance", + "/Lotus/Upgrades/Calendar/OvershieldCap", + "/Lotus/Upgrades/Calendar/SpeedBuffsWhenAirborne" + ], + [ + "/Lotus/Upgrades/Calendar/AbilityStrength", + "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange", + "/Lotus/Upgrades/Calendar/MagnetStatusPull", + "/Lotus/Upgrades/Calendar/MagnitizeWithinRangeEveryXCasts", + "/Lotus/Upgrades/Calendar/PowerStrengthAndEfficiencyPerEnergySpent", + "/Lotus/Upgrades/Calendar/SharedFreeAbilityEveryXCasts" + ], + [ + "/Lotus/Upgrades/Calendar/EnergyWavesOnCombo", + "/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier", + "/Lotus/Upgrades/Calendar/MeleeAttackSpeed", + "/Lotus/Upgrades/Calendar/MeleeCritChance", + "/Lotus/Upgrades/Calendar/MeleeSlideFowardMomentumOnEnemyHit", + "/Lotus/Upgrades/Calendar/RadialJavelinOnHeavy" + ], + [ + "/Lotus/Upgrades/Calendar/Armor", + "/Lotus/Upgrades/Calendar/CloneActiveCompanionForEnergySpent", + "/Lotus/Upgrades/Calendar/CompanionDamage", + "/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer", + "/Lotus/Upgrades/Calendar/CompanionsRadiationChance", + "/Lotus/Upgrades/Calendar/RadiationProcOnTakeDamage", + "/Lotus/Upgrades/Calendar/ReviveEnemyAsSpectreOnKill" + ], + [ + "/Lotus/Upgrades/Calendar/EnergyOrbsGrantShield", + "/Lotus/Upgrades/Calendar/EnergyRestoration", + "/Lotus/Upgrades/Calendar/ExplodingHealthOrbs", + "/Lotus/Upgrades/Calendar/GenerateOmniOrbsOnWeakKill", + "/Lotus/Upgrades/Calendar/HealingEffects", + "/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup" + ], + [ + "/Lotus/Upgrades/Calendar/BlastEveryXShots", + "/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary", + "/Lotus/Upgrades/Calendar/GuidingMissilesChance", + "/Lotus/Upgrades/Calendar/MagazineCapacity", + "/Lotus/Upgrades/Calendar/PunchToPrimary", + "/Lotus/Upgrades/Calendar/RefundBulletOnStatusProc", + "/Lotus/Upgrades/Calendar/StatusChancePerAmmoSpent" + ] + ]; + for (let i = 0; i != upgradeRanges.length - 1; ++i) { + // Pick 3 unique hex members + const hexMembersPickedForThisDay: number[] = []; + for (let j = 0; j != 3; ++j) { + let hexMemberIndex: number; + do { + hexMemberIndex = rng.randomInt(0, upgradesByHexMember.length - 1); + } while (hexMembersPickedForThisDay.indexOf(hexMemberIndex) != -1); + hexMembersPickedForThisDay.push(hexMemberIndex); + } + hexMembersPickedForThisDay.sort(); // Always present them in the same order + + // For each hex member, pick an upgrade that was not yet picked this season. + const events: ICalendarEvent[] = []; + for (const hexMemberIndex of hexMembersPickedForThisDay) { + const upgrades = upgradesByHexMember[hexMemberIndex]; + const upgradeIndex = rng.randomInt(0, upgrades.length - 1); + events.push({ type: "CET_UPGRADE", upgrade: upgrades[upgradeIndex] }); + upgrades.splice(upgradeIndex, 1); + } + + //logger.debug(`trying to fit upgrades between day ${upgradeRanges[i]} and ${upgradeRanges[i + 1]}`); + let day: number; + do { + day = rng.randomInt(upgradeRanges[i] + 1, upgradeRanges[i + 1] - 1); + } while (eventDays.find(x => x.day == day)); + eventDays.push({ day, events }); + } + + eventDays.sort((a, b) => a.day - b.day); + + const weekStart = EPOCH + week * 604800000; + const weekEnd = weekStart + 604800000; + return { + Activation: { $date: { $numberLong: weekStart.toString() } }, + Expiry: { $date: { $numberLong: weekEnd.toString() } }, + Days: eventDays, + Season: (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[seasonIndex], + YearIteration: Math.trunc(week / 4), + Version: 19, + UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"] + }; +}; + +// Not very faithful, but to avoid the same node coming up back-to-back (which is not valid), I've split these into 2 arrays which we're alternating between. + +const voidStormMissions = { + VoidT1: [ + "CrewBattleNode519", + "CrewBattleNode518", + "CrewBattleNode515", + "CrewBattleNode503", + "CrewBattleNode509", + "CrewBattleNode522", + "CrewBattleNode511", + "CrewBattleNode512" + ], + VoidT2: ["CrewBattleNode501", "CrewBattleNode534", "CrewBattleNode530", "CrewBattleNode535", "CrewBattleNode533"], + VoidT3: ["CrewBattleNode521", "CrewBattleNode516", "CrewBattleNode524", "CrewBattleNode525"], + VoidT4: [ + "CrewBattleNode555", + "CrewBattleNode553", + "CrewBattleNode554", + "CrewBattleNode539", + "CrewBattleNode531", + "CrewBattleNode527", + "CrewBattleNode542", + "CrewBattleNode538", + "CrewBattleNode543", + "CrewBattleNode536", + "CrewBattleNode550", + "CrewBattleNode529" + ] +} as const; + +const voidStormLookbehind = { + VoidT1: 3, + VoidT2: 1, + VoidT3: 1, + VoidT4: 3 +} as const; + +const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => { + const activation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute; + const expiry = activation + 90 * unixTimesInMs.minute; + let accum = 0; + const tierIdx = { VoidT1: hour * 2, VoidT2: hour, VoidT3: hour, VoidT4: hour * 2 }; + for (const tier of ["VoidT1", "VoidT1", "VoidT2", "VoidT3", "VoidT4", "VoidT4"] as const) { + arr.push({ + _id: { + $oid: + ((activation / 1000) & 0xffffffff).toString(16).padStart(8, "0") + + "0321e89b" + + (accum++).toString().padStart(8, "0") + }, + Node: sequentiallyUniqueRandomElement( + voidStormMissions[tier], + tierIdx[tier]++, + voidStormLookbehind[tier], + 2051969264 + )!, + Activation: { $date: { $numberLong: activation.toString() } }, + Expiry: { $date: { $numberLong: expiry.toString() } }, + ActiveMissionTier: tier + }); + } +}; + +interface ITimeConstraint { + //name: string; + isValidTime: (timeSecs: number) => boolean; + getIdealTimeBefore: (timeSecs: number) => number; +} + +const eidolonDayConstraint: ITimeConstraint = { + //name: "eidolon day", + isValidTime: (timeSecs: number): boolean => { + const eidolonEpoch = 1391992660; + const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); + const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000; + const eidolonCycleEnd = eidolonCycleStart + 9000; + const eidolonCycleNightStart = eidolonCycleEnd - 3000; + return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000); + }, + getIdealTimeBefore: (timeSecs: number): number => { + const eidolonEpoch = 1391992660; + const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); + const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000; + return eidolonCycleStart; + } +}; + +const eidolonNightConstraint: ITimeConstraint = { + //name: "eidolon night", + isValidTime: (timeSecs: number): boolean => { + const eidolonEpoch = 1391992660; + const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); + const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000; + const eidolonCycleEnd = eidolonCycleStart + 9000; + const eidolonCycleNightStart = eidolonCycleEnd - 3000; + return ( + timeSecs >= eidolonCycleNightStart && + !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000) + ); + }, + getIdealTimeBefore: (timeSecs: number): number => { + const eidolonEpoch = 1391992660; + const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); + const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000; + const eidolonCycleEnd = eidolonCycleStart + 9000; + const eidolonCycleNightStart = eidolonCycleEnd - 3000; + if (eidolonCycleNightStart > timeSecs) { + // Night hasn't started yet, but we need to return a time in the past. + return eidolonCycleNightStart - 9000; + } + return eidolonCycleNightStart; + } +}; + +const venusColdConstraint: ITimeConstraint = { + //name: "venus cold", + isValidTime: (timeSecs: number): boolean => { + const vallisEpoch = 1541837628; + const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); + const vallisCycleStart = vallisEpoch + vallisCycle * 1600; + const vallisCycleEnd = vallisCycleStart + 1600; + const vallisCycleColdStart = vallisCycleStart + 400; + return ( + timeSecs >= vallisCycleColdStart && + !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000) + ); + }, + getIdealTimeBefore: (timeSecs: number): number => { + const vallisEpoch = 1541837628; + const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); + const vallisCycleStart = vallisEpoch + vallisCycle * 1600; + const vallisCycleColdStart = vallisCycleStart + 400; + if (vallisCycleColdStart > timeSecs) { + // Cold hasn't started yet, but we need to return a time in the past. + return vallisCycleColdStart - 1600; + } + return vallisCycleColdStart; + } +}; + +const venusWarmConstraint: ITimeConstraint = { + //name: "venus warm", + isValidTime: (timeSecs: number): boolean => { + const vallisEpoch = 1541837628; + const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); + const vallisCycleStart = vallisEpoch + vallisCycle * 1600; + const vallisCycleColdStart = vallisCycleStart + 400; + return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000); + }, + getIdealTimeBefore: (timeSecs: number): number => { + const vallisEpoch = 1541837628; + const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); + const vallisCycleStart = vallisEpoch + vallisCycle * 1600; + return vallisCycleStart; + } +}; + +const getIdealTimeSatsifyingConstraints = (constraints: ITimeConstraint[]): number => { + let timeSecs = Math.trunc(Date.now() / 1000); + let allGood; + do { + allGood = true; + for (const constraint of constraints) { + if (!constraint.isValidTime(timeSecs)) { + //logger.debug(`${constraint.name} is not happy with ${timeSecs}`); + const prevTimeSecs = timeSecs; + const suggestion = constraint.getIdealTimeBefore(timeSecs); + timeSecs = suggestion; + do { + timeSecs += 60; + if (timeSecs >= prevTimeSecs || !constraint.isValidTime(timeSecs)) { + timeSecs = suggestion; // Can't find a compromise; just take the suggestion and try to compromise on another constraint. + break; + } + } while (!constraints.every(constraint => constraint.isValidTime(timeSecs))); + allGood = false; + break; + } + } + } while (!allGood); + return timeSecs; +}; + +const getVarziaRotation = (week: number): string => { + const seed = new SRng(week).randomInt(0, 100_000); + const rng = new SRng(seed); + return rng.randomElement(varzia.primeDualPacks)!.ItemType; +}; + +const getVarziaManifest = (dualPack: string): IPrimeVaultTraderOffer[] => { + const rotrationManifest = varzia.primeDualPacks.find(pack => pack.ItemType === dualPack); + if (!rotrationManifest) return []; + + const mainPack = [{ ItemType: rotrationManifest.ItemType, PrimePrice: 10 }]; + const singlePacks: IPrimeVaultTraderOffer[] = []; + const items: IPrimeVaultTraderOffer[] = []; + const bobbleHeads: IPrimeVaultTraderOffer[] = []; + + for (const singlePackType of rotrationManifest.SinglePacks) { + singlePacks.push({ ItemType: singlePackType, PrimePrice: 6 }); + + const sp = varzia.primeSinglePacks.find(pack => pack.ItemType === singlePackType); + if (sp) { + items.push(...sp.Items); + sp.BobbleHeads.forEach(bobbleHead => { + bobbleHeads.push({ ItemType: bobbleHead, PrimePrice: 1 }); + }); + } + } + + const relics = rotrationManifest.Relics.map(relic => ({ ItemType: relic, RegularPrice: 1 })); + + return [singlePacks[0], ...mainPack, singlePacks[1], ...items, ...bobbleHeads, ...relics]; +}; + +const getAllVarziaManifests = (): IPrimeVaultTraderOffer[] => { + const dualPacks: IPrimeVaultTraderOffer[] = []; + const singlePacks: IPrimeVaultTraderOffer[] = []; + const items: IPrimeVaultTraderOffer[] = []; + const bobbleHeads: IPrimeVaultTraderOffer[] = []; + const relics: IPrimeVaultTraderOffer[] = []; + + const singlePackSet = new Set(); + const itemsSet = new Set(); + const bobbleHeadsSet = new Set(); + + varzia.primeDualPacks.forEach(dualPack => { + dualPacks.push({ ItemType: dualPack.ItemType, PrimePrice: 10 }); + + dualPack.SinglePacks.forEach(singlePackType => { + if (!singlePackSet.has(singlePackType)) { + singlePackSet.add(singlePackType); + singlePacks.push({ ItemType: singlePackType, PrimePrice: 6 }); + } + + const sp = varzia.primeSinglePacks.find(pack => pack.ItemType === singlePackType)!; + sp.Items.forEach(item => { + if (!itemsSet.has(item.ItemType)) { + itemsSet.add(item.ItemType); + items.push(item); + } + }); + + sp.BobbleHeads.forEach(bobbleHead => { + if (!bobbleHeadsSet.has(bobbleHead)) { + bobbleHeadsSet.add(bobbleHead); + bobbleHeads.push({ ItemType: bobbleHead, PrimePrice: 1 }); + } + }); + }); + + relics.push(...dualPack.Relics.map(relic => ({ ItemType: relic, RegularPrice: 1 }))); + }); + + return [...dualPacks, ...singlePacks, ...items, ...bobbleHeads, ...relics]; +}; + +const createInvasion = (day: number, idx: number): IInvasion => { + const id = day * 3 + idx; + const defender = (["FC_GRINEER", "FC_CORPUS", day % 2 ? "FC_GRINEER" : "FC_CORPUS"] as const)[idx]; + const rng = new SRng(new SRng(id).randomInt(0, 1_000_000)); + const isInfestationOutbreak = rng.randomInt(0, 1) == 0; + const attacker = isInfestationOutbreak ? "FC_INFESTATION" : defender == "FC_GRINEER" ? "FC_CORPUS" : "FC_GRINEER"; + const startMs = EPOCH + day * 86400_000; + const oid = + ((startMs / 1000) & 0xffffffff).toString(16).padStart(8, "0") + + "fd148cb8" + + (idx & 0xffffffff).toString(16).padStart(8, "0"); + const node = sequentiallyUniqueRandomElement(invasionNodes[defender], id, 5, 690175)!; // Can't repeat the other 2 on this day nor the last 3 + const progress = (Date.now() - startMs) / 86400_000; + const countMultiplier = isInfestationOutbreak || rng.randomInt(0, 1) ? -1 : 1; // if defender is winning, count is negative + const fiftyPercent = rng.randomInt(1000, 29000); // introduce some 'yitter' for the percentages + const rewardFloat = rng.randomFloat(); + const rewardTier = rewardFloat < 0.201 ? "RARE" : rewardFloat < 0.7788 ? "COMMON" : "UNCOMMON"; + const attackerReward: IMissionReward = {}; + const defenderReward: IMissionReward = {}; + if (isInfestationOutbreak) { + defenderReward.countedItems = [ + rng.randomElement(invasionRewards[rng.randomInt(0, 1) ? "FC_INFESTATION" : defender][rewardTier])! + ]; + } else { + attackerReward.countedItems = [rng.randomElement(invasionRewards[attacker][rewardTier])!]; + defenderReward.countedItems = [rng.randomElement(invasionRewards[defender][rewardTier])!]; + } + return { + _id: { $oid: oid }, + Faction: attacker, + DefenderFaction: defender, + Node: node, + Count: Math.round( + (progress < 0.5 ? progress * 2 * fiftyPercent : fiftyPercent + (30_000 - fiftyPercent) * (progress - 0.5)) * + countMultiplier + ), + Goal: 30000, // Value seems to range from 30000 to 98000 in intervals of 1000. Higher values are increasingly rare. I don't think this is relevant for the frontend besides dividing count by it. + LocTag: isInfestationOutbreak + ? ExportRegions[node].missionIndex == 0 + ? "/Lotus/Language/Menu/InfestedInvasionBoss" + : "/Lotus/Language/Menu/InfestedInvasionGeneric" + : attacker == "FC_CORPUS" + ? "/Lotus/Language/Menu/CorpusInvasionGeneric" + : "/Lotus/Language/Menu/GrineerInvasionGeneric", + Completed: startMs + 86400_000 < Date.now(), // Sorta unfaithful. Invasions on live are (at least in part) in fluenced by people completing them. And otherwise also probably not hardcoded to last 24 hours. + ChainID: { $oid: oid }, + AttackerReward: attackerReward, + AttackerMissionInfo: { + seed: rng.randomInt(0, 1_000_000), + faction: defender + }, + DefenderReward: defenderReward, + DefenderMissionInfo: { + seed: rng.randomInt(0, 1_000_000), + faction: attacker + }, + Activation: { + $date: { + $numberLong: startMs.toString() + } + } + }; +}; + +export const getInvasionByOid = (oid: string): IInvasion | undefined => { + const arr = oid.split("fd148cb8"); + if (arr.length == 2 && arr[0].length == 8 && arr[1].length == 8) { + return createInvasion(idToDay(oid), parseInt(arr[1], 16)); + } + return undefined; +}; + +export const getWorldState = (buildLabel?: string): IWorldState => { + const constraints: ITimeConstraint[] = []; + if (config.worldState?.eidolonOverride) { + constraints.push(config.worldState.eidolonOverride == "day" ? eidolonDayConstraint : eidolonNightConstraint); + } + if (config.worldState?.vallisOverride) { + constraints.push(config.worldState.vallisOverride == "cold" ? venusColdConstraint : venusWarmConstraint); + } + if (config.worldState?.duviriOverride) { + const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"]; + const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride); + if (desiredMood == -1) { + logger.warn(`ignoring invalid config value for worldState.duviriOverride`, { + value: config.worldState.duviriOverride, + valid_values: duviriMoods + }); + } else { + constraints.push({ + //name: `duviri ${config.worldState.duviriOverride}`, + isValidTime: (timeSecs: number): boolean => { + const moodIndex = Math.trunc(timeSecs / 7200); + return moodIndex % 5 == desiredMood; + }, + getIdealTimeBefore: (timeSecs: number): number => { + let moodIndex = Math.trunc(timeSecs / 7200); + moodIndex -= ((moodIndex % 5) - desiredMood + 5) % 5; // while (moodIndex % 5 != desiredMood) --moodIndex; + const moodStart = moodIndex * 7200; + return moodStart; + } + }); + } + } + const timeSecs = getIdealTimeSatsifyingConstraints(constraints); + const timeMs = timeSecs * 1000; + const day = Math.trunc((timeMs - EPOCH) / 86400000); + const week = Math.trunc(day / 7); + const weekStart = EPOCH + week * 604800000; + const weekEnd = weekStart + 604800000; + + const worldState: IWorldState = { + BuildLabel: typeof buildLabel == "string" ? buildLabel.split(" ").join("+") : buildConfig.buildLabel, + Time: timeSecs, + Goals: [], + Alerts: [], + Sorties: [], + LiteSorties: [], + ActiveMissions: [], + GlobalUpgrades: [], + Invasions: [], + VoidTraders: [], + PrimeVaultTraders: [], + VoidStorms: [], + DailyDeals: [], + EndlessXpChoices: [], + KnownCalendarSeasons: [], + ...staticWorldState, + SyndicateMissions: [...staticWorldState.SyndicateMissions] + }; + + // Old versions seem to really get hung up on not being able to load these. + if (buildLabel && version_compare(buildLabel, "2017.10.12.17.04") < 0) { + worldState.PVPChallengeInstances = []; + } + + if (config.worldState?.starDays) { + worldState.Goals.push({ + _id: { $oid: "67a4dcce2a198564d62e1647" }, + Activation: { $date: { $numberLong: "1738868400000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 0, + Success: 0, + Personal: true, + Desc: "/Lotus/Language/Events/ValentinesFortunaName", + ToolTip: "/Lotus/Language/Events/ValentinesFortunaName", + Icon: "/Lotus/Interface/Icons/WorldStatePanel/ValentinesEventIcon.png", + Tag: "FortunaValentines", + Node: "SolarisUnitedHub1" + }); + } + if (config.worldState?.TennoCon) { + worldState.Goals.push({ + _id: { $oid: "687bf9400000000000000000" }, + Activation: { $date: { $numberLong: "1752955200000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 0, + Success: 0, + Personal: true, + Desc: "/Lotus/Language/Locations/RelayStationTennoConB", + ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDescB", + Icon: "/Lotus/Interface/Icons/Categories/IconTennoLive.png", + Tag: "TennoConRelayB", + Node: "TennoConBHUB6" + }); + } + if (config.worldState?.Fomorian) { + worldState.Goals.push({ + _id: { $oid: "67c8924faf8bb9628dc1c18d" }, + Fomorian: true, + Activation: { $date: { $numberLong: "1741284514166" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 1000000, + HealthPct: 0.980806, + VictimNode: "PlutoHUB", + Personal: true, + Best: true, + ScoreVar: "FomorianEventScore", + ScoreMaxTag: "FomorianEventScore", + ScoreTagBlocksGuildTierChanges: false, + Success: 0, + Node: "EventNode8", + Faction: "FC_GRINEER", + Desc: "/Lotus/Language/G1Quests/FomorianRevengeBattleName", + Icon: "/Lotus/Materials/Emblems/SlingStone2_e.png", + RegionDrops: ["/Lotus/Types/Items/MiscItems/OmegaIsotopePickup"], + ArchwingDrops: [], + ScoreLocTag: "/Lotus/Language/Menu/FomorianScoreHint", + Tag: "", + MissionInfo: { + missionType: "MT_SABOTAGE", + faction: "FC_GRINEER", + location: "EventNode8", + levelOverride: "/Lotus/Levels/Proc/Space/SpaceGrineerFomorianAssaultProcLevel", + enemySpec: "/Lotus/Types/Game/EnemySpecs/FomorianAttackSpec", + minEnemyLevel: 20, + maxEnemyLevel: 30, + difficulty: 1, + archwingRequired: true, + requiredItems: ["/Lotus/StoreItems/Types/Restoratives/Consumable/FomorianNegator"], + consumeRequiredItems: false, + missionReward: { randomizedItems: "fomorianRewardManifest" }, + vipAgent: "", + leadersAlwaysAllowed: true, + goalTag: "", + levelAuras: [], + icon: "/Lotus/Interface/Icons/Events/Fomorian.png" + }, + ContinuousHubEvent: { + Transmissions: ["/Lotus/Sounds/Dialog/HubAnnouncements/HekPropoganda"], + Activation: { $date: { $numberLong: "1741284514166" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + RepeatInterval: 1800 + }, + Reward: { + credits: 200000, + items: ["/Lotus/StoreItems/Types/Items/MiscItems/OrokinCatalyst"] + } + }); + } + if (config.worldState?.BellyoftheBeast) { + worldState.Goals.push({ + _id: { $oid: "67a5035c2a198564d62e165e" }, + Activation: { $date: { $numberLong: "1738868400000" } }, + Community: true, + ClanGoal: [72, 216, 648, 1944, 5832], + Count: 0, + Desc: "/Lotus/Language/JadeShadows/JadeShadowsEventName", + Expiry: { $date: { $numberLong: "2000000000000" } }, + Faction: "FC_MITW", + Goal: 100, + HealthPct: 1, + Icon: "/Lotus/Interface/Icons/WorldStatePanel/JadeShadowsEventBadge.png", + ScoreLocTag: "/Lotus/Language/JadeShadows/JadeShadowsEventScore", + Tag: "JadeShadowsEvent", + ToolTip: "/Lotus/Language/JadeShadows/JadeShadowsShortEventDesc", + MissionKeyName: "/Lotus/Types/Keys/JadeShadowsEventMission", + Node: "SolNode723", + Personal: true, + ItemType: "/Lotus/Types/Gameplay/JadeShadows/Resources/AscensionEventResourceItem" + }); + } + if (config.worldState?.RecurringGhoul) { + worldState.Goals.push({ + _id: { $oid: "687ebbe6d1d17841c9c59f38" }, + Activation: { $date: { $numberLong: "1753204900185" } }, + Expiry: { $date: { $numberLong: "1755019300185" } }, + HealthPct: 0.001108, + VictimNode: "SolNode228", + Regions: [2], + Success: 0, + Desc: "/Lotus/Language/GameModes/RecurringGhoulAlert", + ToolTip: "/Lotus/Language/GameModes/RecurringGhoulAlertDesc", + Icon: "/Lotus/Interface/Icons/Categories/IconGhouls256.png", + Tag: "GhoulEmergence", + JobAffiliationTag: "CetusSyndicate", + JobCurrentVersion: { $oid: "688341880000000000000009" }, + Jobs: [ + { + jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyAss", + rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards", + masteryReq: 1, + minEnemyLevel: 15, + maxEnemyLevel: 25, + xpAmounts: [260, 260, 260, 380] + }, + { + jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyHunt", + rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards", + masteryReq: 3, + minEnemyLevel: 40, + maxEnemyLevel: 50, + xpAmounts: [450, 450, 450, 670] + } + ], + JobPreviousVersion: { $oid: "68831e610000000000000009" }, + PreviousJobs: [ + { + jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyRes", + rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards", + masteryReq: 1, + minEnemyLevel: 15, + maxEnemyLevel: 25, + xpAmounts: [270, 270, 270, 400] + }, + { + jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyHunt", + rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards", + masteryReq: 3, + minEnemyLevel: 40, + maxEnemyLevel: 50, + xpAmounts: [480, 480, 480, 710] + } + ], + Count: 0, + Goal: 0, + Personal: true + }); + } + if (config.worldState?.HeatFissures) { + worldState.Goals.push({ + _id: { $oid: "5c7cb0d00000000000000000" }, + Activation: { $date: { $numberLong: "1737392400000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Node: "SolNode129", + ScoreVar: "FissuresClosed", + ScoreLocTag: "/Lotus/Language/G1Quests/HeatFissuresEventScore", + Count: 2, + HealthPct: 0.02, + Regions: [1], + Desc: "/Lotus/Language/G1Quests/HeatFissuresEventName", + ToolTip: "/Lotus/Language/G1Quests/HeatFissuresEventDesc", + OptionalInMission: true, + Tag: "HeatFissure", + UpgradeIds: [{ $oid: "678be06a422c69eb0ac1c18c" }, { $oid: "678be06a422c69eb0ac1c18d" }], + Personal: true, + Community: true, + Goal: 100, + Reward: { + credits: 0, + xp: 0, + items: ["/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpBFG/Vandal/VandalCrpBFG"], + countedItems: [] + }, + InterimGoals: [5, 25, 50, 75], + InterimRewards: [ + { + credits: 0, + xp: 0, + items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/OrbBadgeItem"], + countedItems: [] + }, + { + credits: 0, + xp: 0, + items: [ + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Shotgun/ShotgunMedicMod", + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Rifle/SerratedRushMod" + ], + countedItems: [] + }, + { + credits: 0, + xp: 0, + items: [ + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Pistol/MultishotDodgeMod", + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Melee/CritDamageChargeSpeedMod" + ], + countedItems: [] + }, + { + credits: 0, + xp: 0, + items: ["/Lotus/StoreItems/Upgrades/Skins/Sigils/OrbSigil"], + countedItems: [] + } + ], + Success: 0, + Icon: "" + }); + } + // The client gets kinda confused when multiple goals have the same tag, so considering these mutually exclusive. + if (config.worldState?.galleonOfGhouls == 1) { + worldState.Goals.push({ + _id: { $oid: "6814ddf00000000000000000" }, + Activation: { $date: { $numberLong: "1746198000000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 1, + Success: 0, + Personal: true, + Bounty: true, + ClampNodeScores: true, + Node: "EventNode19", + MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlert", + Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle", + Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png", + Tag: "GalleonRobbery", + Reward: { + items: [ + "/Lotus/StoreItems/Types/Recipes/Weapons/GrnChainSawTonfaBlueprint", + "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem" + ] + } + }); + } else if (config.worldState?.galleonOfGhouls == 2) { + worldState.Goals.push({ + _id: { $oid: "681e18700000000000000000" }, + Activation: { $date: { $numberLong: "1746802800000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 1, + Success: 0, + Personal: true, + Bounty: true, + ClampNodeScores: true, + Node: "EventNode28", + MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlertB", + Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle", + Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png", + Tag: "GalleonRobbery", + Reward: { + items: [ + "/Lotus/StoreItems/Types/Recipes/Weapons/MortiforShieldAndSwordBlueprint", + "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem" + ] + } + }); + } else if (config.worldState?.galleonOfGhouls == 3) { + worldState.Goals.push({ + _id: { $oid: "682752f00000000000000000" }, + Activation: { $date: { $numberLong: "1747407600000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Count: 0, + Goal: 1, + Success: 0, + Personal: true, + Bounty: true, + ClampNodeScores: true, + Node: "EventNode19", + MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlertC", + Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle", + Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png", + Tag: "GalleonRobbery", + Reward: { + items: [ + "/Lotus/Types/StoreItems/Packages/EventCatalystReactorBundle", + "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem" + ] + } + }); + } + + // Nightwave Challenges + 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(timeMs, EPOCH + (day + 1) * 86400000)) { + worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day + 1)); + } + pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week); + if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) { + pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week + 1); + } + } + + // Elite Sanctuary Onslaught cycling every week + worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = new SRng(week).randomInt(0, 0xff_ffff); + + // Holdfast, Cavia, & Hex bounties cycling every 2.5 hours; unfaithful implementation + let bountyCycle = Math.trunc(timeSecs / 9000); + let bountyCycleEnd: number | undefined; + do { + const bountyCycleStart = bountyCycle * 9000000; + bountyCycleEnd = bountyCycleStart + 9000000; + worldState.SyndicateMissions.push({ + _id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000029" }, + Activation: { $date: { $numberLong: bountyCycleStart.toString() } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } }, + Tag: "ZarimanSyndicate", + Seed: bountyCycle, + Nodes: [] + }); + worldState.SyndicateMissions.push({ + _id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000004" }, + Activation: { $date: { $numberLong: bountyCycleStart.toString() } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } }, + Tag: "EntratiLabSyndicate", + Seed: bountyCycle, + Nodes: [] + }); + worldState.SyndicateMissions.push({ + _id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000006" }, + Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } }, + Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } }, + Tag: "HexSyndicate", + Seed: bountyCycle, + Nodes: [] + }); + + pushClassicBounties(worldState.SyndicateMissions, bountyCycle); + } while (isBeforeNextExpectedWorldStateRefresh(timeMs, bountyCycleEnd) && ++bountyCycle); + + if (config.worldState?.creditBoost) { + worldState.GlobalUpgrades.push({ + _id: { $oid: "5b23106f283a555109666672" }, + Activation: { $date: { $numberLong: "1740164400000" } }, + ExpiryDate: { $date: { $numberLong: "2000000000000" } }, + UpgradeType: "GAMEPLAY_MONEY_REWARD_AMOUNT", + OperationType: "MULTIPLY", + Value: 2, + LocalizeTag: "", + LocalizeDescTag: "" + }); + } + if (config.worldState?.affinityBoost) { + worldState.GlobalUpgrades.push({ + _id: { $oid: "5b23106f283a555109666673" }, + Activation: { $date: { $numberLong: "1740164400000" } }, + ExpiryDate: { $date: { $numberLong: "2000000000000" } }, + UpgradeType: "GAMEPLAY_KILL_XP_AMOUNT", + OperationType: "MULTIPLY", + Value: 2, + LocalizeTag: "", + LocalizeDescTag: "" + }); + } + if (config.worldState?.resourceBoost) { + worldState.GlobalUpgrades.push({ + _id: { $oid: "5b23106f283a555109666674" }, + Activation: { $date: { $numberLong: "1740164400000" } }, + ExpiryDate: { $date: { $numberLong: "2000000000000" } }, + UpgradeType: "GAMEPLAY_PICKUP_AMOUNT", + OperationType: "MULTIPLY", + Value: 2, + LocalizeTag: "", + LocalizeDescTag: "" + }); + } + + // Rough outline of dynamic invasions. + // TODO: Invasions chains, e.g. an infestation mission would soon lead to other nodes on that planet also having an infestation invasion. + // TODO: Grineer/Corpus to fund their death stars with each invasion win. + { + worldState.Invasions.push(createInvasion(day, 0)); + worldState.Invasions.push(createInvasion(day, 1)); + worldState.Invasions.push(createInvasion(day, 2)); + + // Completed invasions stay for up to 24 hours as the winner 'occupies' that node + worldState.Invasions.push(createInvasion(day - 1, 0)); + worldState.Invasions.push(createInvasion(day - 1, 1)); + worldState.Invasions.push(createInvasion(day - 1, 2)); + } + + // Baro + { + const baroIndex = Math.trunc((Date.now() - 910800000) / (unixTimesInMs.day * 14)); + const baroStart = baroIndex * (unixTimesInMs.day * 14) + 910800000; + const baroActualStart = baroStart + unixTimesInMs.day * (config.baroAlwaysAvailable ? 0 : 12); + const baroEnd = baroStart + unixTimesInMs.day * 14; + const baroNode = ["EarthHUB", "MercuryHUB", "SaturnHUB", "PlutoHUB"][baroIndex % 4]; + const vt: IVoidTrader = { + _id: { $oid: ((baroStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "493c96d6067610bc" }, + Activation: { $date: { $numberLong: baroActualStart.toString() } }, + Expiry: { $date: { $numberLong: baroEnd.toString() } }, + Character: "Baro'Ki Teel", + Node: baroNode, + Manifest: [] + }; + worldState.VoidTraders.push(vt); + // add Baro TennoCon Relay + if (config.baroAlwaysAvailable) { + worldState.Goals.push({ + _id: { + $oid: "687bb2f00000000000000000" + }, + Activation: { + $date: { + $numberLong: baroActualStart.toString() + } + }, + Expiry: { + $date: { + $numberLong: baroEnd.toString() + } + }, + Count: 0, + Goal: 0, + Success: 0, + Personal: true, + Desc: "/Lotus/Language/Locations/RelayStationTennoCon", + ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDesc", + Icon: "/Lotus/Interface/Icons/Categories/IconTennoConSigil.png", + Tag: "TennoConRelay", + Node: "TennoConHUB2" + }); + worldState.VoidTraders.push({ + _id: { + $oid: "687809030379266d790495c6" + }, + Activation: { + $date: { + $numberLong: baroActualStart.toString() + } + }, + Expiry: { + $date: { + $numberLong: baroEnd.toString() + } + }, + Character: "Baro'Ki Teel", + Node: "TennoConHUB2", + Manifest: [ + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageAvaClemCommunityGlyph", + PrimePrice: 20, + RegularPrice: 33333 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TennoconConcert2025Display", + PrimePrice: 90, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/EventSniperReloadDamageMod", + PrimePrice: 2995, + RegularPrice: 1000000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/TennoCon2024GlyphAlt", + PrimePrice: 15, + RegularPrice: 1000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/Emotes/Tennocon2024EmoteAlt", + PrimePrice: 15, + RegularPrice: 1000 + }, + { + ItemType: "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem", + PrimePrice: 450, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/Types/StoreItems/Boosters/CreditBooster3DayStoreItem", + PrimePrice: 350, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/Types/StoreItems/Boosters/ModDropChanceBooster3DayStoreItem", + PrimePrice: 500, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/Types/StoreItems/Boosters/ResourceAmount3DayStoreItem", + PrimePrice: 400, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/GlaiveCmbTwoMeleeTree", + PrimePrice: 385, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponEventSlashDamageMod", + PrimePrice: 375, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponEventMeleeImpactDamageMod", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponGlaiveOnKillBuffSecondary", + PrimePrice: 300, + RegularPrice: 115000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponGlaiveSecondaryHeadshotKillMod", + PrimePrice: 300, + RegularPrice: 115000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponEventRifleImpactDamageMod", + PrimePrice: 330, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponEventSlashDamageMod", + PrimePrice: 375, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/WeaponEventShotgunImpactDamageMod", + PrimePrice: 365, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/DualStat/ElectEventRifleMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/ElectEventPistolMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/WeaponEventSlashDamageMod", + PrimePrice: 375, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponGlaiveOnSixKillsBuffSecondary", + PrimePrice: 300, + RegularPrice: 115000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Sentinel/SentinelLootRadarEnemyRadarExpertMod", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/PrimedWeaponFactionDamageCorpus", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/PrimedWeaponFactionDamageCorrupted", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/PrimedWeaponFactionDamageGrineer", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/PrimedWeaponFactionDamageInfested", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponElectricityDamageModExpert", + PrimePrice: 350, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponFreezeDamageModExpert", + PrimePrice: 350, + RegularPrice: 125000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponShotgunFactionDamageCorpusExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponShotgunFactionDamageCorruptedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponShotgunFactionDamageGrineerExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponShotgunFactionDamageInfestedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Warframe/Expert/AvatarAbilityDurationModExpert", + PrimePrice: 350, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponFreezeDamageModExpert", + PrimePrice: 350, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageCorpusExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageCorruptedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageGrineerExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageInfestedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponReloadSpeedModExpert", + PrimePrice: 375, + RegularPrice: 120000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponToxinDamageModExpert", + PrimePrice: 350, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Warframe/Expert/AvatarPowerMaxModExpert", + PrimePrice: 350, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponFireDamageModExpert", + PrimePrice: 350, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponImpactDamageModExpert", + PrimePrice: 350, + RegularPrice: 100000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Archwing/Expert/ArchwingSuitAbilityStrengthModExpert", + PrimePrice: 350, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Sentinel/Kubrow/Expert/KubrowPackLeaderExpertMod", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolConvertAmmoModExpert", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponCritChanceModBeginnerExpert", + PrimePrice: 400, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponSnipersConvertAmmoModExpert", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponDamageAmountModExpert", + PrimePrice: 300, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeDamageModExpert", + PrimePrice: 385, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponReloadSpeedModExpert", + PrimePrice: 375, + RegularPrice: 120000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponCritDamageModExpert", + PrimePrice: 280, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Sentinels/SentinelPrecepts/PrimedRegen", + PrimePrice: 300, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeRangeIncModExpert", + PrimePrice: 300, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponRifleConvertAmmoModExpert", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Archwing/Rifle/Expert/ArchwingRifleDamageAmountModExpert", + PrimePrice: 350, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponShotgunConvertAmmoModExpert", + PrimePrice: 400, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponClipMaxModExpert", + PrimePrice: 280, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeFactionDamageCorpusExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeFactionDamageCorruptedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeFactionDamageGrineerExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeFactionDamageInfestedExpert", + PrimePrice: 350, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponReloadSpeedModExpert", + PrimePrice: 300, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/PrimedWeaponCritDamageMod", + PrimePrice: 400, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/WeaponEventPistolImpactDamageMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/DualStat/FireEventShotgunMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/FireEventPistolMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/DualStat/ElectEventShotgunMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/BowMultiShotOnHitMod", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/WeaponEventSlashDamageMod", + PrimePrice: 375, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/AxeCmbThreeMeleeTree", + PrimePrice: 385, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/DualStat/FireEventRifleMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/ClawCmbTwoMeleeTree", + PrimePrice: 385, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/DualStat/FireEventMeleeMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/DualStat/ElectEventMeleeMod", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: + "/Lotus/StoreItems/Upgrades/Mods/Pistol/Event/AmbulasEvent/Expert/SecondaryExplosionRadiusModExpert", + PrimePrice: 350, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponRecoilReductionModExpert", + PrimePrice: 300, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponRecoilReductionModExpert", + PrimePrice: 300, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponRecoilReductionModExpert", + PrimePrice: 300, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Melee/Expert/WeaponMeleeFactionDamageMurmursExpert", + PrimePrice: 375, + RegularPrice: 130000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponClipMaxModExpert", + PrimePrice: 280, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Warframe/Expert/AvatarShieldMaxModExpert", + PrimePrice: 350, + RegularPrice: 225000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Rifle/Expert/WeaponIncreaseRadialExplosionModExpert", + PrimePrice: 350, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/PrimedWeaponElectricityDamageMod", + PrimePrice: 350, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Shotgun/Expert/WeaponClipMaxModExpert", + PrimePrice: 280, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Archwing/Rifle/PrimedArchwingRifleFireIterationsMod", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Mods/Archwing/Rifle/PrimedArchwingDamageOnReloadMod", + PrimePrice: 375, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/DomsFinalDrink", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationB", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Masks/GaussSentinelMask", + PrimePrice: 450, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Skins/GaussSentinelSkin", + PrimePrice: 500, + RegularPrice: 425000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Tails/GaussSentinelTail", + PrimePrice: 400, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Wings/GaussSentinelWings", + PrimePrice: 400, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/BaroInarosPolearmSkin", + PrimePrice: 325, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MeleeDangles/BaroInarosMeleeDangle", + PrimePrice: 250, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Vignettes/Warframes/ArchwingAFItem", + PrimePrice: 100, + RegularPrice: 330000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationE", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/Projections/T4VoidProjectionPBronze", + PrimePrice: 50, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/Projections/T4VoidProjectionMagNovaVaultBBronze", + PrimePrice: 125, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/Projections/T4VoidProjectionBaroAkmagnusPrimeBronze", + PrimePrice: 125, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/Projections/T4VoidProjectionVoltOdonataPrimeBronze", + PrimePrice: 125, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/Projections/T3VoidProjectionVoltOdonataPrimeBronze", + PrimePrice: 125, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCleaningDroneBaro", + PrimePrice: 700, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyBaro", + PrimePrice: 100, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/ImageBaroKiteer", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerBobbleHead", + PrimePrice: 70, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageBaruukDoanStyle", + PrimePrice: 75, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Pacifist/BaruukImmortalSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCorpusBasilisk", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCleaningDroneBeachcomber", + PrimePrice: 800, + RegularPrice: 625000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BekranZaftBucketBroom", + PrimePrice: 100, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Hoverboard/HoverboardStickerBaroA", + PrimePrice: 75, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/KavatBust", + PrimePrice: 220, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/KubrowBust", + PrimePrice: 220, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Dragon/ChromaAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BoredTennoPoster", + PrimePrice: 90, + RegularPrice: 120000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroPlanter", + PrimePrice: 125, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MeleeDangles/InfestedMeleeDangle", + PrimePrice: 250, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/EventSigilScarletSpear", + PrimePrice: 45, + RegularPrice: 45000 + }, + { + ItemType: + "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Seasonal/AvatarImageGlyphCookieKavat", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: + "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Seasonal/AvatarImageGlyphCookieKubrow", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Factions/GlyphFactionCorpus", + PrimePrice: 70, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Recipes/Components/CorruptedBombardBallBlueprint", + PrimePrice: 100, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Restoratives/Consumable/CorruptedHeavyGunnerBall", + PrimePrice: 100, + RegularPrice: 40000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropGrineerCutter", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/VTHalloweenDarkSword", + PrimePrice: 320, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/AshLeverianLiosPistol", + PrimePrice: 400, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConH", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConA", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConD", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConF", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConJ", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConE", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConG", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConB", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConC", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDesertSkate", + PrimePrice: 125, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/BaroStalkerBadgeItem", + PrimePrice: 55, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Camo/DesertDirigaSkin", + PrimePrice: 225, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/OrbiterPictureFrameBaro", + PrimePrice: 100, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/SummerGameFestPoster", + PrimePrice: 90, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCleaningDroneDuviri", + PrimePrice: 800, + RegularPrice: 650000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/LisetScarf", + PrimePrice: 600, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/EraHypnosisPoster", + PrimePrice: 100, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Halloween/HalloweenDread", + PrimePrice: 300, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/1999DrippySigil", + PrimePrice: 50, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Weapons/DualSword/DualRibbonKamasSkin", + PrimePrice: 350, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationD", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisLatronPistol", + PrimePrice: 400, + RegularPrice: 215000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/SuitCustomizations/ColourPickerTwitchBItemA", + PrimePrice: 220, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/ActionFigureDioramas/EmpyreanRegionADiorama", + PrimePrice: 155, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Factions/GlyphFactionEntrati", + PrimePrice: 99, + RegularPrice: 1900 + }, + { + ItemType: "/Lotus/Types/StoreItems/Packages/VTEosArmourBundle", + PrimePrice: 285, + RegularPrice: 260000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/VTEos/VTEosChestArmor", + PrimePrice: 125, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/ErraBobbleHead", + PrimePrice: 75, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageExcaliburActionProto", + PrimePrice: 75, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/ExcaliburArchwingBobbleHead", + PrimePrice: 90, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Archwing/GrendelArchwingSkin", + PrimePrice: 400, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/Deimos/PlushySunMonsterCommon", + PrimePrice: 150, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropGrineerFlak", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Glass/GaraAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/GarvLatroxPoster", + PrimePrice: 80, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/BaroKavatBadgeItem", + PrimePrice: 50, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/BaroKavatSigil", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpFreezeRay/Vandal/CrpFreezeRayVandalRifle", + PrimePrice: 475, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/SummerSolstice/SummerSolsticeGorgon", + PrimePrice: 300, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/LongGuns/GrnOrokinRifle/GrnOrokinRifleWeapon", + PrimePrice: 675, + RegularPrice: 625000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/GaussTowerOfAltraDeco", + PrimePrice: 110, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Hoverboard/HoverboardStickerBaroB", + PrimePrice: 75, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Restoratives/Consumable/AssassinBaitC", + PrimePrice: 200, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/GrineerTurbines/WraithTurbinesChestArmor", + PrimePrice: 300, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/WraithTurbinesScarf", + PrimePrice: 400, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/GrineerTurbines/WraithTurbinesLegArmor", + PrimePrice: 350, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/GrineerTurbines/WraithTurbinesArmArmor", + PrimePrice: 350, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCorpusHarpi", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Pirate/HydroidAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/SummerSolstice/SummerIgnisSkin", + PrimePrice: 300, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/ClanTech/Chemical/FlameThrowerWraith", + PrimePrice: 550, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/Melee/GrnBoomerang/HalikarWraithWeapon", + PrimePrice: 450, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Seasonal/Halloween2019GrendelTreat", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyInaros", + PrimePrice: 120, + RegularPrice: 90000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileInarosTomb", + PrimePrice: 325, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageIvaraAction", + PrimePrice: 75, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/JavisExperimentsPosterA", + PrimePrice: 90, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/JavisExperimentsPosterD", + PrimePrice: 90, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/JavisExperimentsPosterC", + PrimePrice: 90, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/JavisExperimentsPosterB", + PrimePrice: 90, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/QuartersWallpapers/LavosAlchemistWallpaper", + PrimePrice: 275, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/GrendelOrokinDishSet", + PrimePrice: 110, + RegularPrice: 130000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Masks/KavatPetMask", + PrimePrice: 500, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Tails/KavatPetTail", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Wings/KavatPetWings", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/SuitCustomizations/ColourPickerKiteerItemA", + PrimePrice: 150, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/BaroArrow", + PrimePrice: 375, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/BaroTiara", + PrimePrice: 525, + RegularPrice: 375000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/EarpieceBaroC", + PrimePrice: 500, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/BaroMouthPieceA", + PrimePrice: 500, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/BaroVisor", + PrimePrice: 525, + RegularPrice: 375000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmour/BaroArmourC", + PrimePrice: 150, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/BaroHorn", + PrimePrice: 525, + RegularPrice: 375000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/KazBaroCape", + PrimePrice: 325, + RegularPrice: 450000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/EarpieceBaroA", + PrimePrice: 500, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Effects/BaroEphemeraA", + PrimePrice: 100, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Restoratives/Consumable/BaroFireWorksCrate", + PrimePrice: 50, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourTwo/BaroArmourTwoC", + PrimePrice: 175, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourTwo/BaroArmourTwoL", + PrimePrice: 225, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourTwo/BaroArmourTwoA", + PrimePrice: 310, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourThree/BaroArmourThreeC", + PrimePrice: 350, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourThree/BaroArmourThreeL", + PrimePrice: 400, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmourThree/BaroArmourThreeA", + PrimePrice: 400, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Catbrows/Armor/CatbrowArmorVoidTraderA", + PrimePrice: 500, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Kubrows/Armor/KubrowArmorBaro", + PrimePrice: 500, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmour/BaroArmourL", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroPedestal", + PrimePrice: 150, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MoaPet/BaroMoaPetSkin", + PrimePrice: 500, + RegularPrice: 325000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/Emotes/BaroEmote", + PrimePrice: 0, + RegularPrice: 1000000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/BaroCape2Scarf", + PrimePrice: 400, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Effects/BaroEphemeraB", + PrimePrice: 250, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/BaroQuantumBadgeItem", + PrimePrice: 400, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Masks/BaroPetMask", + PrimePrice: 500, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Tails/BaroPetTail", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Wings/BaroPetWings", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/BaroArmour/BaroArmourA", + PrimePrice: 350, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/EarpieceBaroB", + PrimePrice: 250, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/SolsticeBaroCape", + PrimePrice: 425, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/QuartersWallpapers/BaroWallpaper", + PrimePrice: 250, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MeleeDangles/BaroMeleeDangle", + PrimePrice: 250, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/BaroCape", + PrimePrice: 500, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageBaroIcon", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/BaroCape3Scarf", + PrimePrice: 500, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/VTEos/VTEosALArmor", + PrimePrice: 50, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/VTEos/VTEosLLArmor", + PrimePrice: 65, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetThreeWinged/VTSetThreeLegLeftArmor", + PrimePrice: 65, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetThreeWinged/VTSetThreeArmLeftArmor", + PrimePrice: 65, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetTwoSamurai/VTSetTwoLegLeftArmor", + PrimePrice: 100, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetTwoSamurai/VTSetTwoArmLeftArmor", + PrimePrice: 100, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Weapons/Staff/TnRibbonStaffSkin", + PrimePrice: 350, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Magician/LimboImmortalSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/InarosLisetSkin", + PrimePrice: 400, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Effects/LotusFlowers", + PrimePrice: 250, + RegularPrice: 450000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/Dragon2024BadgeItem", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/WeGameNewYearOxSigil", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/CNY2023EmblemItem", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/CNY2022EmblemItem", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/WeGameNewYearFreeTigerSigil", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/BaroScytheMacheteSkin", + PrimePrice: 375, + RegularPrice: 300000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Grineer/Melee/GrineerMachetteAndCleaver/WraithMacheteWeapon", + PrimePrice: 410, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationA", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/LisetInsectSkinInaros", + PrimePrice: 425, + RegularPrice: 320000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/LisetInsectSkinPrimeTrader", + PrimePrice: 230, + RegularPrice: 375000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/VoidTrader/VTDetron", + PrimePrice: 500, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/BodySuits/BodySuitNovaEngineer", + PrimePrice: 300, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Hoods/HoodNovaEngineer", + PrimePrice: 350, + RegularPrice: 375000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Leggings/LeggingsNovaEngineer", + PrimePrice: 300, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Sleeves/SleevesNovaEngineer", + PrimePrice: 300, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Cowgirl/MesaImmortallSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Harlequin/MirageAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/NecraArmor/NecraArmorC", + PrimePrice: 325, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/NecraArmor/NecraArmorA", + PrimePrice: 315, + RegularPrice: 215000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/NecraArmor/NecraArmorL", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Game/KubrowPet/Patterns/KubrowPetPatternPrimeTraderA", + PrimePrice: 150, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/Types/StoreItems/Packages/KavatColorPackNexus", + PrimePrice: 200, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Infestation/NidusAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisNikana", + PrimePrice: 375, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/ItzalArchwingBobbleHead", + PrimePrice: 90, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/ZealoidPrelateBobbleHead", + PrimePrice: 75, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/OctaviaBobbleHead", + PrimePrice: 50, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisOdonataSkin", + PrimePrice: 350, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisOpticor", + PrimePrice: 325, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpBFG/Vandal/VandalCrpBFG", + PrimePrice: 650, + RegularPrice: 550000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/OwlOrdisStatue", + PrimePrice: 350, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileOrokinExtraction", + PrimePrice: 325, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/BaroKubrowBadgeItem", + PrimePrice: 50, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/BaroKubrowSigil", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisBallasSword", + PrimePrice: 350, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Events/InfQuantaInfestedAladV", + PrimePrice: 325, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/ParazonPoster", + PrimePrice: 100, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Promo/Warframe/PromoParis", + PrimePrice: 315, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Peculiars/EvilSpiritMod", + PrimePrice: 250, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/PedistalPrime", + PrimePrice: 0, + RegularPrice: 1000000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/Pistols/CrpHandRL/PrismaAngstrum", + PrimePrice: 475, + RegularPrice: 210000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/PrismaArrow", + PrimePrice: 350, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/FurisArmor/PrismaFurisCArmor", + PrimePrice: 250, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/FurisArmor/PrismaFurisAArmor", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/FurisArmor/PrismaFurisLArmor", + PrimePrice: 225, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/KubrowKavatLowPolyPoster", + PrimePrice: 90, + RegularPrice: 110000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetThreeWinged/VTSetThreeChestArmor", + PrimePrice: 150, + RegularPrice: 100000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Grineer/Melee/GrineerMachetteAndCleaver/PrismaDualCleavers", + PrimePrice: 490, + RegularPrice: 200000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Tenno/Archwing/Primary/ArchwingHeavyPistols/Prisma/PrismaArchHeavyPistols", + PrimePrice: 525, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetTwoSamurai/VTSetTwoChestArmor", + PrimePrice: 225, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/LongGuns/VoidTraderGorgon/VTGorgon", + PrimePrice: 600, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/VoidTrader/PrismaGrakata", + PrimePrice: 610, + RegularPrice: 100000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Grineer/LongGuns/GrineerLeverActionRifle/PrismaGrinlokWeapon", + PrimePrice: 500, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/VTHornSkullScarf", + PrimePrice: 250, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Wings/PrismaJetWings", + PrimePrice: 300, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageLowPolyKavat", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Tails/PrismaFishTail", + PrimePrice: 200, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageLowPolyKubrow", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnLatronArmor/TnLatronChestArmorPrisma", + PrimePrice: 275, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnLatronArmor/TnLatronArmArmorPrisma", + PrimePrice: 325, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnLatronArmor/TnLatronLegArmorPrisma", + PrimePrice: 300, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/Bow/Longbow/PrismaLenz/PrismaLenzWeapon", + PrimePrice: 575, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/LisetSkinVoidTrader", + PrimePrice: 120, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/PrismaLotusVinesSigil", + PrimePrice: 55, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Clan/PrismaLotusEmblem", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/PrismaLotusFlamesSigil", + PrimePrice: 55, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageBaroTwoIcon", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/PrismaLotusSigil", + PrimePrice: 55, + RegularPrice: 45000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/Melee/GrineerMachetteAndCleaver/PrismaMachete", + PrimePrice: 400, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Masks/PrismaMechHeadMask", + PrimePrice: 175, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/Halloween2014Wings/PrismaNaberusArmArmor", + PrimePrice: 220, + RegularPrice: 140000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/Melee/KickAndPunch/PrismaObex", + PrimePrice: 500, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/Melee/CrpTonfa/CrpPrismaTonfa", + PrimePrice: 450, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Kubrows/Armor/KubrowArmorPrisma", + PrimePrice: 400, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/LisetBlueSkySkinPrimeTrader", + PrimePrice: 210, + RegularPrice: 450000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Sentinels/SentinelPowersuits/PrismaShadePowerSuit", + PrimePrice: 500, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/PrimeTraderSigil", + PrimePrice: 50, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/VoidTrader/PrismaSkana", + PrimePrice: 510, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/LongGuns/CorpusUMP/PrismaCorpusUMP", + PrimePrice: 400, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/ThraxSigil", + PrimePrice: 50, + RegularPrice: 55000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Grineer/Pistols/GrineerBulbousSMG/Prisma/PrismaTwinGremlinsWeapon", + PrimePrice: 500, + RegularPrice: 220000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/PrismaRazorScarf", + PrimePrice: 350, + RegularPrice: 275000 + }, + { + ItemType: + "/Lotus/StoreItems/Weapons/Tenno/Archwing/Melee/VoidTraderArchsword/VTArchSwordWeapon", + PrimePrice: 550, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/VTDinoSpikeScarf", + PrimePrice: 400, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/ClanTech/Energy/VandalElectroProd", + PrimePrice: 410, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationF", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MeleeDangles/FireMeleeDangle", + PrimePrice: 100, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/VTQuanta", + PrimePrice: 300, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpShockRifle/QuantaVandal", + PrimePrice: 450, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/HornSkullScarf", + PrimePrice: 325, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Weapons/Rapier/CrpRapierSkin", + PrimePrice: 375, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/RathuumEventPoster", + PrimePrice: 90, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/VTRedeemerSkin", + PrimePrice: 325, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/MeleeDangles/MoonWarfanSugatraMeleeDangle", + PrimePrice: 250, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Leverian/NezhaLeverian/NezhaLeverianPolearm", + PrimePrice: 350, + RegularPrice: 325000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/NezhaLeverianCape", + PrimePrice: 400, + RegularPrice: 350000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/HeartOfDeimosAlbumCoverPoster", + PrimePrice: 80, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sigils/RhinoDeluxeSigil", + PrimePrice: 45, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/VTEos/VTEosARArmor", + PrimePrice: 50, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/VTEos/VTEosLRArmor", + PrimePrice: 65, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetThreeWinged/VTSetThreeLegRightArmor", + PrimePrice: 65, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetThreeWinged/VTSetThreeArmRightArmor", + PrimePrice: 65, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetTwoSamurai/VTSetTwoLegRightArmor", + PrimePrice: 100, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/SetTwoSamurai/VTSetTwoArmRightArmor", + PrimePrice: 100, + RegularPrice: 55000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Factions/GlyphFactionScaldra", + PrimePrice: 93, + RegularPrice: 1906 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/LisetBlueSkySkinInaros", + PrimePrice: 375, + RegularPrice: 340000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Accessories/AshLevarianTiara", + PrimePrice: 550, + RegularPrice: 300000 + }, + { + ItemType: + "/Lotus/StoreItems/Types/Items/ShipDecos/Leverian/IvaraLeverianPovisRecordsDecoration", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationG", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisSonicor", + PrimePrice: 380, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Restoratives/Consumable/AssassinBait", + PrimePrice: 200, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Corpus/LongGuns/Machinegun/SupraVandal", + PrimePrice: 500, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropGrineerTaktis", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnShinaiArmor/TnShinaiArmorC", + PrimePrice: 300, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnShinaiArmor/TnShinaiArmorL", + PrimePrice: 275, + RegularPrice: 115000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Melee/Swords/TnShinaiSword/TnShinaiSwordSkin", + PrimePrice: 375, + RegularPrice: 280000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Armor/TnShinaiArmor/TnShinaiArmorA", + PrimePrice: 315, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Sentinels/Skins/DesertTaxonSkin", + PrimePrice: 200, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Factions/GlyphFactionTechrot", + PrimePrice: 98, + RegularPrice: 1901 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/OstronHeadStatue", + PrimePrice: 125, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropOstRugBaro", + PrimePrice: 225, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TNWTeshinBobbleHead", + PrimePrice: 75, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Hoods/HoodDuviriOperator", + PrimePrice: 550, + RegularPrice: 500000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisTiberon", + PrimePrice: 315, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/VoidTrader/ElixisTigris", + PrimePrice: 300, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Operator/Hoods/JaviExecutionHood", + PrimePrice: 450, + RegularPrice: 450000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/SummerSolstice/SummerSolsticeTwinGrakatas", + PrimePrice: 300, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/UmbraPedestal", + PrimePrice: 0, + RegularPrice: 1000000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/Melee/GunBlade/GrnGunBlade/GrnGunblade", + PrimePrice: 550, + RegularPrice: 325000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Melee/Warfan/TnMoonWarfan/MoonWarfanWeapon", + PrimePrice: 410, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TNWVesoBobbleHead", + PrimePrice: 75, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationH", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/Pistols/WraithSingleViper/WraithSingleViper", + PrimePrice: 400, + RegularPrice: 75000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageVoidAngelBaro", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/SuitCustomizations/ColourPickerKiteerItemB", + PrimePrice: 200, + RegularPrice: 250000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Events/OgrisOldSchool", + PrimePrice: 350, + RegularPrice: 325000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/Deimos/PlushyMoonMonsterCommon", + PrimePrice: 150, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/TwinSnakesGlyph", + PrimePrice: 80, + RegularPrice: 50000 + }, + { + ItemType: "/Lotus/StoreItems/Types/StoreItems/AvatarImages/Warframes/VorunaActionGlyph", + PrimePrice: 75, + RegularPrice: 60000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Grineer/LongGuns/GrineerSniperRifle/VulkarWraith", + PrimePrice: 450, + RegularPrice: 300000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCorpusWeaver", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Scarves/SolsticeNelumboCape", + PrimePrice: 325, + RegularPrice: 275000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Wisp/WispAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Catbrows/Armor/CatbrowArmorHalloweenA", + PrimePrice: 400, + RegularPrice: 175000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/TarotCardTennoConI", + PrimePrice: 75, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Liset/Gyroscope/LisetGyroscopeSkinPrimeTrader", + PrimePrice: 220, + RegularPrice: 400000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/ShipDecos/BaroKiTeerDecorationC", + PrimePrice: 100, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Restoratives/Consumable/AssassinBaitB", + PrimePrice: 200, + RegularPrice: 125000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Tengu/ZephyrAlternateSkin", + PrimePrice: 550, + RegularPrice: 100000 + }, + { + ItemType: "/Lotus/StoreItems/Weapons/Tenno/Pistols/ConclaveLeverPistol/ConclaveLeverPistol", + PrimePrice: 500, + RegularPrice: 200000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/TenthAnniversaryLoginSongItem", + PrimePrice: 145, + RegularPrice: 165000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/AbyssofDagathSongItem", + PrimePrice: 150, + RegularPrice: 155000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/ZarimanLoginSongItem", + PrimePrice: 160, + RegularPrice: 180000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/DanteUnboundLoginSongItem", + PrimePrice: 150, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/EmpyreanSongItem", + PrimePrice: 160, + RegularPrice: 155000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/DeimosLoginSongItem", + PrimePrice: 155, + RegularPrice: 160000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/JadeShadowsLoginSongItem", + PrimePrice: 150, + RegularPrice: 170000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/WhispersInTheWallLoginSongItem", + PrimePrice: 165, + RegularPrice: 170000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/CorpusRailjackLoginSongItem", + PrimePrice: 150, + RegularPrice: 165000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/LotusEatersSongItem", + PrimePrice: 165, + RegularPrice: 150000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Items/SongItems/KuvaLichLoginSongItem", + PrimePrice: 140, + RegularPrice: 170000 + }, + { + ItemType: "/Lotus/StoreItems/Types/Keys/MummyQuestKeyBlueprint", + PrimePrice: 100, + RegularPrice: 25000 + }, + { + ItemType: "/Lotus/StoreItems/Upgrades/Skins/Effects/FootstepsMaple", + PrimePrice: 15, + RegularPrice: 1000 + }, + { + ItemType: "/Lotus/StoreItems/Types/BoosterPacks/BaroTreasureBox", + PrimePrice: 0, + RegularPrice: 50000, + Limit: 1 + } + ] + }); + } + if (isBeforeNextExpectedWorldStateRefresh(timeMs, baroActualStart)) { + vt.Manifest = []; + if (config.baroFullyStocked) { + for (const armorSet of baro.armorSets) { + if (Array.isArray(armorSet[0])) { + for (const set of armorSet as IVoidTraderOffer[][]) { + for (const item of set) { + vt.Manifest.push(item); + } + } + } else { + for (const item of armorSet as IVoidTraderOffer[]) { + vt.Manifest.push(item); + } + } + } + for (const item of baro.rest) { + vt.Manifest.push(item); + } + } else { + const rng = new SRng(new SRng(baroIndex).randomInt(0, 100_000)); + // TOVERIFY: Constraint for upgrades amount? + // TOVERIFY: Constraint for weapon amount? + // TOVERIFY: Constraint for relics amount? + let armorSet = rng.randomElement(baro.armorSets)!; + if (Array.isArray(armorSet[0])) { + armorSet = rng.randomElement(baro.armorSets)!; + } + while (vt.Manifest.length + armorSet.length < 31) { + const item = rng.randomElement(baro.rest)!; + if (vt.Manifest.indexOf(item) == -1) { + const set = baro.allIfAny.find(set => set.indexOf(item.ItemType) != -1); + if (set) { + for (const itemType of set) { + vt.Manifest.push(baro.rest.find(x => x.ItemType == itemType)!); + } + } else { + vt.Manifest.push(item); + } + } + } + const overflow = 31 - (vt.Manifest.length + armorSet.length); + if (overflow > 0) { + vt.Manifest.splice(0, overflow); + } + for (const armor of armorSet) { + vt.Manifest.push(armor as IVoidTraderOffer); + } + } + for (const item of baro.evergreen) { + vt.Manifest.push(item); + } + } + } + + // Varzia + { + const pt: IPrimeVaultTrader = { + _id: { $oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "c36af423770eaa97" }, + Activation: { $date: { $numberLong: weekStart.toString() } }, + InitialStartDate: { $date: { $numberLong: "1662738144266" } }, + Node: "TradeHUB1", + Manifest: [], + Expiry: { $date: { $numberLong: weekEnd.toString() } }, + EvergreenManifest: varzia.evergreen, + ScheduleInfo: [] + }; + worldState.PrimeVaultTraders.push(pt); + const rotation = config.worldState?.varziaOverride || getVarziaRotation(week); + pt.Manifest = config.worldState?.varziaFullyStocked ? getAllVarziaManifests() : getVarziaManifest(rotation); + if (config.worldState?.varziaOverride || config.worldState?.varziaFullyStocked) { + pt.Expiry = { $date: { $numberLong: "2000000000000" } }; + } else { + pt.ScheduleInfo.push({ + Expiry: { $date: { $numberLong: (weekEnd + unixTimesInMs.week).toString() } }, + FeaturedItem: getVarziaRotation(week + 1) + }); + } + } + + // Sortie & syndicate missions cycling every day (at 16:00 or 17:00 UTC depending on if London, OT is observing DST) + { + const rollover = getSortieTime(day); + + if (timeMs < rollover) { + worldState.Sorties.push(getSortie(day - 1)); + } + if (isBeforeNextExpectedWorldStateRefresh(timeMs, rollover)) { + worldState.Sorties.push(getSortie(day)); + } + + // The client does not seem to respect activation for classic syndicate missions, so only pushing current ones. + const sdy = timeMs >= rollover ? day : day - 1; + const rng = new SRng(sdy); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa48049", "ArbitersSyndicate"); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa4804a", "CephalonSudaSyndicate"); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa4804e", "NewLokaSyndicate"); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa48050", "PerrinSyndicate"); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa4805e", "RedVeilSyndicate"); + pushSyndicateMissions(worldState, sdy, rng.randomInt(0, 100_000), "ba6f84724fa48061", "SteelMeridianSyndicate"); + } + + // Archon Hunt cycling every week + worldState.LiteSorties.push(getLiteSortie(week)); + if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) { + worldState.LiteSorties.push(getLiteSortie(week + 1)); + } + + // Circuit choices cycling every week + worldState.EndlessXpChoices.push({ + Category: "EXC_NORMAL", + Choices: [ + ["Nidus", "Octavia", "Harrow"], + ["Gara", "Khora", "Revenant"], + ["Garuda", "Baruuk", "Hildryn"], + ["Excalibur", "Trinity", "Ember"], + ["Loki", "Mag", "Rhino"], + ["Ash", "Frost", "Nyx"], + ["Saryn", "Vauban", "Nova"], + ["Nekros", "Valkyr", "Oberon"], + ["Hydroid", "Mirage", "Limbo"], + ["Mesa", "Chroma", "Atlas"], + ["Ivara", "Inaros", "Titania"] + ][week % 12] + }); + worldState.EndlessXpChoices.push({ + Category: "EXC_HARD", + Choices: [ + ["Boar", "Gammacor", "Angstrum", "Gorgon", "Anku"], + ["Bo", "Latron", "Furis", "Furax", "Strun"], + ["Lex", "Magistar", "Boltor", "Bronco", "CeramicDagger"], + ["Torid", "DualToxocyst", "DualIchor", "Miter", "Atomos"], + ["AckAndBrunt", "Soma", "Vasto", "NamiSolo", "Burston"], + ["Zylok", "Sibear", "Dread", "Despair", "Hate"], + ["Dera", "Sybaris", "Cestra", "Sicarus", "Okina"], + ["Braton", "Lato", "Skana", "Paris", "Kunai"] + ][week % 8] + }); + + // 1999 Calendar Season cycling every week + YearIteration every 4 weeks + worldState.KnownCalendarSeasons.push(getCalendarSeason(week)); + if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) { + worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1)); + } + + // Void Storms + const hour = Math.trunc(timeMs / unixTimesInMs.hour); + const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute; + const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute; + if (overLastHourStormExpiry > timeMs) { + pushVoidStorms(worldState.VoidStorms, hour - 2); + } + pushVoidStorms(worldState.VoidStorms, hour - 1); + if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) { + pushVoidStorms(worldState.VoidStorms, hour); + } + + // Sentient Anomaly + Xtra Cheese cycles + const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2)); + const hourInSeconds = 3600; + const cheeseInterval = hourInSeconds * 8; + const cheeseDuration = hourInSeconds * 2; + const cheeseIndex = Math.trunc(timeSecs / cheeseInterval); + let cheeseStart = cheeseIndex * cheeseInterval; + let cheeseEnd = cheeseStart + cheeseDuration; + let cheeseNext = (cheeseIndex + 1) * cheeseInterval; + // Live servers only update the start time once it happens, which makes the + // client show a negative countdown during off-hours. Optionally adjust the + // times so the next activation is always in the future. + if (config.unfaithfulBugFixes?.fixXtraCheeseTimer && timeSecs >= cheeseEnd) { + cheeseStart = cheeseNext; + cheeseEnd = cheeseStart + cheeseDuration; + cheeseNext += cheeseInterval; + } + const tmp: ITmp = { + cavabegin: "1690761600", + PurchasePlatformLockEnabled: true, + pgr: { + ts: "1732572900", + en: "CUSTOM DECALS @ ZEVILA", + fr: "DECALS CUSTOM @ ZEVILA", + it: "DECALCOMANIE PERSONALIZZATE @ ZEVILA", + de: "AUFKLEBER NACH WUNSCH @ ZEVILA", + es: "CALCOMANÍAS PERSONALIZADAS @ ZEVILA", + pt: "DECALQUES PERSONALIZADOS NA ZEVILA", + ru: "ПОЛЬЗОВАТЕЛЬСКИЕ НАКЛЕЙКИ @ ЗеВиЛа", + pl: "NOWE NAKLEJKI @ ZEVILA", + uk: "КОРИСТУВАЦЬКІ ДЕКОЛІ @ ЗІВІЛА", + tr: "ÖZEL ÇIKARTMALAR @ ZEVILA", + ja: "カスタムデカール @ ゼビラ", + zh: "定制贴花认准泽威拉", + ko: "커스텀 데칼 @ ZEVILA", + tc: "自訂貼花 @ ZEVILA", + th: "รูปลอกสั่งทำที่ ZEVILA" + }, + ennnd: true, + mbrt: true, + fbst: { + a: cheeseStart, + e: cheeseEnd, + n: cheeseNext + }, + sfn: [550, 553, 554, 555][halfHour % 4] + }; + if (Array.isArray(config.worldState?.circuitGameModes)) { + tmp.edg = config.worldState.circuitGameModes as TCircuitGameMode[]; + } + worldState.Tmp = JSON.stringify(tmp); + + return worldState; +}; + +export const populateFissures = async (worldState: IWorldState): Promise => { + if (config.worldState?.allTheFissures) { + let i = 0; + for (const [tier, nodes] of Object.entries(fissureMissions)) { + for (const node of nodes) { + const meta = ExportRegions[node]; + worldState.ActiveMissions.push({ + _id: { $oid: (i++).toString().padStart(8, "0") + "8e0c70ba050f1eb7" }, + Region: meta.systemIndex + 1, + Seed: 1337, + Activation: { $date: { $numberLong: "1000000000000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + Node: node, + MissionType: eMissionType[meta.missionIndex].tag, + Modifier: tier, + Hard: config.worldState.allTheFissures == "hard" + }); + } + } + } else { + const fissures = await Fissure.find({}); + for (const fissure of fissures) { + const meta = ExportRegions[fissure.Node]; + worldState.ActiveMissions.push({ + _id: toOid(fissure._id), + Region: meta.systemIndex + 1, + Seed: 1337, + Activation: toMongoDate(fissure.Activation), + Expiry: toMongoDate(fissure.Expiry), + Node: fissure.Node, + MissionType: eMissionType[meta.missionIndex].tag, + Modifier: fissure.Modifier, + Hard: fissure.Hard + }); + } + } +}; + +export const populateDailyDeal = async (worldState: IWorldState): Promise => { + const dailyDeals = await DailyDeal.find({}); + for (const dailyDeal of dailyDeals) { + if (dailyDeal.Expiry.getTime() > Date.now()) { + worldState.DailyDeals.push({ + StoreItem: dailyDeal.StoreItem, + Activation: toMongoDate(dailyDeal.Activation), + Expiry: toMongoDate(dailyDeal.Expiry), + Discount: dailyDeal.Discount, + OriginalPrice: dailyDeal.OriginalPrice, + SalePrice: dailyDeal.SalePrice, + AmountTotal: Math.round(dailyDeal.AmountTotal * (config.worldState?.darvoStockMultiplier ?? 1)), + AmountSold: dailyDeal.AmountSold + }); + } + } +}; + +export const idToBountyCycle = (id: string): number => { + return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000) / 9000_000); +}; + +export const idToDay = (id: string): number => { + return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000 - EPOCH) / 86400_000); +}; + +export const idToWeek = (id: string): number => { + return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000 - EPOCH) / 604800_000); +}; + +export const getLiteSortie = (week: number): ILiteSortie => { + const boss = (["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"] as const)[week % 3]; + const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3]; + const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth + + const nodes: string[] = []; + for (const [key, value] of Object.entries(ExportRegions)) { + if ( + value.systemIndex === systemIndex && + value.factionIndex !== undefined && + value.factionIndex < 2 && + !isArchwingMission(value) && + value.missionIndex != 0 && // Exclude MT_ASSASSINATION + value.missionIndex != 23 && // Exclude junctions + value.missionIndex != 28 && // Exclude open worlds + value.missionIndex != 32 // Exclude railjack + ) { + nodes.push(key); + } + } + + const seed = new SRng(week).randomInt(0, 100_000); + const rng = new SRng(seed); + const firstNodeIndex = rng.randomInt(0, nodes.length - 1); + const firstNode = nodes[firstNodeIndex]; + nodes.splice(firstNodeIndex, 1); + + const weekStart = EPOCH + week * 604800000; + const weekEnd = weekStart + 604800000; + return { + _id: { + $oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "5e23a244740a190c" + }, + Activation: { $date: { $numberLong: weekStart.toString() } }, + Expiry: { $date: { $numberLong: weekEnd.toString() } }, + Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards", + Seed: seed, + Boss: boss, + Missions: [ + { + missionType: rng.randomElement([ + "MT_INTEL", + "MT_MOBILE_DEFENSE", + "MT_EXTERMINATION", + "MT_SABOTAGE", + "MT_RESCUE" + ])!, + node: firstNode + }, + { + missionType: rng.randomElement([ + "MT_DEFENSE", + "MT_TERRITORY", + "MT_ARTIFACT", + "MT_EXCAVATE", + "MT_SURVIVAL" + ])!, + node: rng.randomElement(nodes)! + }, + { + missionType: "MT_ASSASSINATION", + node: showdownNode + } + ] + }; +}; + +export const isArchwingMission = (node: IRegion): boolean => { + if (node.name.indexOf("Archwing") != -1) { + return true; + } + // SettlementNode10 + if (node.missionIndex == 25) { + return true; + } + return false; +}; + +export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string | undefined => { + if (config.worldState?.nightwaveOverride) { + if (config.worldState.nightwaveOverride in nightwaveTagToSeason) { + return config.worldState.nightwaveOverride; + } + logger.warn(`ignoring invalid config value for worldState.nightwaveOverride`, { + value: config.worldState.nightwaveOverride, + valid_values: Object.keys(nightwaveTagToSeason) + }); + } + 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 = { + RadioLegionIntermission13Syndicate: 15, // Nora's Mix Vol. 9 + RadioLegionIntermission12Syndicate: 14, // Nora's Mix Vol. 8 + RadioLegionIntermission11Syndicate: 13, // Nora's Mix Vol. 7 + RadioLegionIntermission10Syndicate: 12, // Nora's Mix Vol. 6 + RadioLegionIntermission9Syndicate: 11, // Nora's Mix Vol. 5 + RadioLegionIntermission8Syndicate: 10, // Nora's Mix Vol. 4 + RadioLegionIntermission7Syndicate: 9, // Nora's Mix Vol. 3 + RadioLegionIntermission6Syndicate: 8, // Nora's Mix Vol. 2 + RadioLegionIntermission5Syndicate: 7, // Nora's Mix Vol. 1 + RadioLegionIntermission4Syndicate: 6, // Nora's Choice + RadioLegionIntermission3Syndicate: 5, // Intermission III + RadioLegion3Syndicate: 4, // Glassmaker + RadioLegionIntermission2Syndicate: 3, // Intermission II + RadioLegion2Syndicate: 2, // The Emissary + RadioLegionIntermissionSyndicate: 1, // Intermission I + RadioLegionSyndicate: 0 // The Wolf of Saturn Six +}; + +const updateFissures = async (): Promise => { + const fissures = await Fissure.find(); + + const activeNodes = new Set(); + const tierToFurthestExpiry: Record = { + VoidT1: 0, + VoidT2: 0, + VoidT3: 0, + VoidT4: 0, + VoidT5: 0, + VoidT6: 0, + VoidT1Hard: 0, + VoidT2Hard: 0, + VoidT3Hard: 0, + VoidT4Hard: 0, + VoidT5Hard: 0, + VoidT6Hard: 0 + }; + for (const fissure of fissures) { + activeNodes.add(fissure.Node); + + const key = fissure.Modifier + (fissure.Hard ? "Hard" : ""); + tierToFurthestExpiry[key] = Math.max(tierToFurthestExpiry[key], fissure.Expiry.getTime()); + } + + const deadline = Date.now() - 6 * unixTimesInMs.minute; + for (const [tier, expiry] of Object.entries(tierToFurthestExpiry)) { + if (expiry < deadline) { + const numFissures = getRandomInt(1, 3); + for (let i = 0; i != numFissures; ++i) { + const modifier = tier.replace("Hard", "") as + | "VoidT1" + | "VoidT2" + | "VoidT3" + | "VoidT4" + | "VoidT5" + | "VoidT6"; + let node: string; + do { + node = getRandomElement(fissureMissions[modifier])!; + } while (activeNodes.has(node)); + activeNodes.add(node); + await Fissure.insertOne({ + Activation: new Date(), + Expiry: new Date(Date.now() + getRandomInt(60, 120) * unixTimesInMs.minute), + Node: node, + Modifier: modifier, + Hard: tier.indexOf("Hard") != -1 ? true : undefined + }); + } + } + } +}; + +const updateDailyDeal = async (): Promise => { + let darvoIndex = Math.trunc((Date.now() - 25200000) / (26 * unixTimesInMs.hour)); + let darvoEnd; + do { + const darvoStart = darvoIndex * (26 * unixTimesInMs.hour) + 25200000; + darvoEnd = darvoStart + 26 * unixTimesInMs.hour; + const darvoOid = ((darvoStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "adc51a72f7324d95"; + if (!(await DailyDeal.findById(darvoOid))) { + const seed = new SRng(darvoIndex).randomInt(0, 100_000); + const rng = new SRng(seed); + let deal; + do { + deal = rng.randomReward(darvoDeals)!; // Using an actual sampling collected over roughly a year because I can't extrapolate an algorithm from it with enough certainty. + //const [storeItem, meta] = rng.randomElement(Object.entries(darvoDeals))!; + //const discount = Math.min(rng.randomInt(1, 9) * 10, (meta as { MaxDiscount?: number }).MaxDiscount ?? 1); + } while (await DailyDeal.exists({ StoreItem: deal.StoreItem })); + await DailyDeal.insertOne({ + _id: darvoOid, + StoreItem: deal.StoreItem, + Activation: new Date(darvoStart), + Expiry: new Date(darvoEnd), + Discount: deal.Discount, + OriginalPrice: deal.OriginalPrice, + SalePrice: deal.SalePrice, //Math.trunc(deal.OriginalPrice * (1 - discount)) + AmountTotal: deal.AmountTotal, + AmountSold: 0 + }); + } + } while (darvoEnd < Date.now() + 6 * unixTimesInMs.minute && ++darvoIndex); +}; + +export const updateWorldStateCollections = async (): Promise => { + await Promise.all([updateFissures(), updateDailyDeal()]); +}; diff --git a/zh.js b/zh.js new file mode 100644 index 00000000..c4bad6a0 --- /dev/null +++ b/zh.js @@ -0,0 +1,358 @@ +// Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang & Corvus +dict = { + general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场/中继站或重新登录客户端.`, + general_addButton: `添加`, + general_setButton: `设置`, + general_none: `无`, + general_bulkActions: `批量操作`, + general_loading: `加载中...`, + + code_loginFail: `登录失败.请检查邮箱和密码.`, + code_regFail: `注册失败.账号已存在.`, + code_changeNameConfirm: `您想将账户名称更改为?`, + code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME|(|EMAIL|)吗?此操作不可撤销。`, + code_archgun: `空战`, + code_melee: `近战`, + code_pistol: `手枪`, + code_rifle: `步枪`, + code_shotgun: `霰弹枪`, + code_kitgun: `组合枪`, + code_zaw: `自制近战`, + code_moteAmp: `微尘增幅器`, + code_amp: `增幅器`, + code_kDrive: `K式悬浮板`, + code_legendaryCore: `传奇核心`, + code_traumaticPeculiar: `创伤怪奇`, + code_starter: `|MOD|(有瑕疵的)`, + code_badItem: `(Imposter)`, + code_maxRank: `满级`, + code_rename: `重命名`, + code_renamePrompt: `输入新的自定义名称:`, + code_remove: `移除`, + code_addItemsConfirm: `确定要向账户添加|COUNT|件物品吗?`, + code_succRankUp: `等级已提升`, + code_noEquipmentToRankUp: `没有可升级的装备。`, + code_succAdded: `已成功添加。`, + code_succRemoved: `已成功移除。`, + code_buffsNumber: `增益数量`, + code_cursesNumber: `负面数量`, + code_rerollsNumber: `洗卡次数`, + code_viewStats: `查看属性`, + code_rank: `等级`, + code_rankUp: `等级提升`, + code_rankDown: `等级下降`, + code_count: `数量`, + code_focusAllUnlocked: `所有专精学派均已解锁。`, + code_focusUnlocked: `已解锁|COUNT|个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新.`, + code_addModsConfirm: `确定要向账户添加|COUNT|张MOD吗?`, + code_succImport: `导入成功。`, + code_succRelog: `完成. 需要重新登录游戏才能看到变化.`, + code_nothingToDo: `完成. 没有可执行的操作.`, + code_gild: `镀金`, + code_moa: `恐鸟`, + code_zanuka: `猎犬`, + code_stage: `阶段`, + code_complete: `完成`, + code_nextStage: `下一阶段`, + code_prevStage: `上一阶段`, + code_reset: `重置`, + code_setInactive: `使任务处于未激活状态`, + code_completed: `已完成`, + code_active: `正在执行`, + code_pigment: `颜料`, + code_mature: `成长并战备`, + code_unmature: `逆转衰老基因`, + code_succChange: `更改成功.`, + code_requiredInvigorationUpgrade: `您必须同时选择一个进攻型和一个功能型活化属性.`, + login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同).`, + login_emailLabel: `电子邮箱`, + login_passwordLabel: `密码`, + login_loginButton: `登录`, + login_registerButton: `注册账号`, + navbar_logout: `退出登录`, + navbar_renameAccount: `重命名账户`, + navbar_deleteAccount: `删除账户`, + navbar_inventory: `仓库`, + navbar_mods: `Mods`, + navbar_quests: `任务`, + navbar_cheats: `作弊选项`, + navbar_import: `导入`, + inventory_addItems: `添加物品`, + inventory_suits: `战甲`, + inventory_longGuns: `主要武器`, + inventory_pistols: `次要武器`, + inventory_melee: `近战武器`, + inventory_spaceSuits: `载具`, + inventory_spaceGuns: `载具主武器`, + inventory_spaceMelee: `载具近战武器`, + inventory_mechSuits: `殁世机甲`, + inventory_sentinels: `守护`, + inventory_sentinelWeapons: `守护武器`, + inventory_operatorAmps: `增幅器`, + inventory_hoverboards: `K式悬浮板`, + inventory_moaPets: `恐鸟`, + inventory_kubrowPets: `动物同伴`, + inventory_evolutionProgress: `灵化之源进度`, + inventory_Boosters: `加成器`, + inventory_bulkAddSuits: `添加缺失战甲`, + inventory_bulkAddWeapons: `添加缺失武器`, + inventory_bulkAddSpaceSuits: `添加缺失载具`, + inventory_bulkAddSpaceWeapons: `添加缺失载具武器`, + inventory_bulkAddSentinels: `添加缺失守护`, + inventory_bulkAddSentinelWeapons: `添加缺失守护武器`, + inventory_bulkAddEvolutionProgress: `添加缺失的灵化之源`, + inventory_bulkRankUpSuits: `所有战甲升满级`, + inventory_bulkRankUpWeapons: `所有武器升满级`, + inventory_bulkRankUpSpaceSuits: `所有载具升满级`, + inventory_bulkRankUpSpaceWeapons: `所有载具武器升满级`, + inventory_bulkRankUpSentinels: `所有守护升满级`, + inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`, + inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`, + inventory_maxPlexus: `最大深控等级`, + + quests_list: `任务`, + quests_completeAll: `完成所有任务`, + quests_resetAll: `重置所有任务`, + quests_giveAll: `授予所有任务`, + + currency_RegularCredits: `现金`, + currency_PremiumCredits: `白金`, + currency_FusionPoints: `内融核心`, + currency_PrimeTokens: `御品阿耶`, + currency_owned: `当前拥有 |COUNT|`, + + detailedView_archonShardsLabel: `执刑官源力石槽位`, + detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`, + detailedView_archonShardsDescription2: `请注意,在加载时,每个执政官源力石都需要一定的时间来生效。`, + detailedView_valenceBonusLabel: `效价加成`, + detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成.`, + detailedView_modularPartsLabel: `更换部件`, + detailedView_suitInvigorationLabel: `编辑战甲活化属性`, + + invigorations_offensive_AbilityStrength: `+200%技能强度`, + invigorations_offensive_AbilityRange: `+100%技能范围`, + invigorations_offensive_AbilityDuration: `+100%技能持续时间`, + invigorations_offensive_MeleeDamage: `+250%近战武器伤害`, + invigorations_offensive_PrimaryDamage: `+250%主要武器伤害`, + invigorations_offensive_SecondaryDamage: `+250%次要武器伤害`, + invigorations_offensive_PrimaryCritChance: `+200%主要武器暴击几率`, + invigorations_offensive_SecondaryCritChance: `+200%次要武器暴击几率`, + invigorations_offensive_MeleeCritChance: `+200%近战武器暴击几率`, + + invigorations_utility_AbilityEfficiency: `+75%技能效率`, + invigorations_utility_SprintSpeed: `+75%冲刺速度`, + invigorations_utility_ParkourVelocity: `+75%跑酷速度`, + invigorations_utility_HealthMax: `+1000生命值`, + invigorations_utility_EnergyMax: `+200%最大能量`, + invigorations_utility_StatusImmune: `异常状态免疫`, + invigorations_utility_ReloadSpeed: `+75%装填速度`, + invigorations_utility_HealthRegen: `+25/秒生命再生`, + invigorations_utility_ArmorMax: `+1000护甲值`, + invigorations_utility_Jumps: `+5跳跃次数`, + invigorations_utility_EnergyRegen: `+2/秒能量再生`, + + invigorations_offensiveLabel: `进攻型属性`, + invigorations_defensiveLabel: `功能型属性`, + invigorations_expiryLabel: `活化时效(可选)`, + + mods_addRiven: `添加裂罅MOD`, + mods_fingerprint: `印记`, + mods_fingerprintHelp: `需要印记相关的帮助?`, + mods_rivens: `裂罅MOD`, + mods_mods: `Mods`, + mods_addMax: `满级添加`, + mods_addMissingUnrankedMods: `添加所有缺失的Mods`, + mods_removeUnranked: `删除所有未升级的Mods`, + mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`, + cheats_administratorRequirement: `您必须是管理员才能使用此功能.要成为管理员,请将 |DISPLAYNAME| 添加到 config.json 的 administratorNames 中.`, + cheats_server: `服务器`, + cheats_skipTutorial: `跳过教程`, + cheats_skipAllDialogue: `跳过所有对话`, + cheats_unlockAllScans: `解锁所有扫描`, + cheats_unlockAllMissions: `解锁所有任务`, + cheats_unlockAllMissions_ok: `操作成功.请注意,您需要进入道场/中继站或重新登录客户端以刷新星图数据。`, + cheats_infiniteCredits: `无限现金`, + cheats_infinitePlatinum: `无限白金`, + cheats_infiniteEndo: `无限内融核心`, + cheats_infiniteRegalAya: `无限御品阿耶`, + cheats_infiniteHelminthMaterials: `无限Helminth材料`, + cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`, + cheats_dontSubtractPurchaseCreditCost: `购物时不减少现金花费`, + cheats_dontSubtractPurchasePlatinumCost: `购物时不减少白金花费`, + cheats_dontSubtractPurchaseItemCost: `购物时不减少物品花费`, + cheats_dontSubtractPurchaseStandingCost: `购物时不减少声望花费`, + cheats_dontSubtractVoidTraces: `虚空光体无消耗`, + cheats_dontSubtractConsumables: `消耗物品使用时无损耗`, + cheats_unlockAllShipFeatures: `解锁所有飞船功能`, + cheats_unlockAllShipDecorations: `解锁所有飞船装饰`, + cheats_unlockAllFlavourItems: `解锁所有装饰物品`, + cheats_unlockAllSkins: `解锁所有外观`, + cheats_unlockAllCapturaScenes: `解锁所有Captura场景`, + cheats_unlockAllDecoRecipes: `解锁所有道场配方`, + cheats_universalPolarityEverywhere: `全局万用极性`, + cheats_unlockDoubleCapacityPotatoesEverywhere: `全物品自带Orokin反应堆`, + cheats_unlockExilusEverywhere: `全物品自带适配器`, + cheats_unlockArcanesEverywhere: `全物品自带赋能适配器`, + cheats_noDailyStandingLimits: `无每日声望限制`, + cheats_noDailyFocusLimit: `指挥官专精无每日获取上限`, + cheats_noArgonCrystalDecay: `氩结晶无衰变`, + cheats_noMasteryRankUpCooldown: `段位考核无冷却时间`, + cheats_noVendorPurchaseLimits: `商城或商人无购买限制`, + cheats_noDeathMarks: `无死亡标记(不会被 Stalker/Grustrag 三霸/Zanuka 猎人等标记)`, + cheats_noKimCooldowns: `即时通无冷却时间`, + cheats_fullyStockedVendors: `商人贩卖所有商品`, + cheats_baroAlwaysAvailable: `虚空商人可永久访问`, + cheats_baroFullyStocked: `虚空商人贩卖所有商品`, + cheats_syndicateMissionsRepeatable: `集团任务可重复完成`, + cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`, + cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`, + cheats_instantResourceExtractorDrones: `资源无人机即时完成`, + cheats_noResourceExtractorDronesDamage: `资源无人机不会损毁`, + cheats_skipClanKeyCrafting: `跳过氏族钥匙制作, 进入道场无需氏族钥匙`, + cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`, + cheats_noDojoDecoBuildStage: `道场装饰建造立即完成`, + cheats_fastDojoRoomDestruction: `快速拆除道场房间`, + cheats_noDojoResearchCosts: `无视道场研究消耗`, + cheats_noDojoResearchTime: `无视道场研究时间`, + cheats_fastClanAscension: `快速升级氏族`, + cheats_missionsCanGiveAllRelics: `任务可获取所有遗物`, + cheats_exceptionalRelicsAlwaysGiveBronzeReward: `优良遗物必定掉落青铜奖励`, + cheats_flawlessRelicsAlwaysGiveSilverReward: `无瑕遗物必定掉落白银奖励`, + cheats_radiantRelicsAlwaysGiveGoldReward: `光辉遗物必定掉落黄金奖励`, + cheats_unlockAllSimarisResearchEntries: `解锁所有Simaris研究条目`, + cheats_disableDailyTribute: `禁用每日登录奖励`, + cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, + cheats_relicRewardItemCountMultiplier: `虚空遗物奖励物品数量倍率`, + cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`, + cheats_save: `保存`, + cheats_account: `账户`, + cheats_unlockAllFocusSchools: `解锁所有专精学派`, + cheats_helminthUnlockAll: `完全升级Helminth`, + cheats_addMissingSubsumedAbilities: `添加Helminth未汲取的战甲技能`, + cheats_intrinsicsUnlockAll: `所有内源之力最大等级`, + cheats_changeSupportedSyndicate: `支持的集团`, + cheats_changeButton: `更改`, + cheats_markAllAsRead: `收件箱全部标记为已读`, + + worldState: `世界状态配置`, + worldState_creditBoost: `现金加成`, + worldState_affinityBoost: `经验加成`, + worldState_resourceBoost: `资源加成`, + worldState_starDays: `活动:星日`, + worldState_TennoCon: `TennoCon中继站`, + worldState_Fomorian: `破坏巨人战舰`, + worldState_BellyoftheBeast: `行动代号: 兽之腹`, + worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`, + worldState_RecurringGhoul: `尸鬼净化`, + worldState_HeatFissures: `热美亚裂缝`, + disabled: `关闭/取消配置`, + worldState_we1: `活动阶段:第一周`, + worldState_we2: `活动阶段:第二周`, + worldState_we3: `活动阶段:第三周`, + worldState_eidolonOverride: `夜灵平原/魔胎之境状态`, + worldState_day: `白昼/FASS`, + worldState_night: `黑夜/VOME`, + worldState_vallisOverride: `奥布山谷状态`, + worldState_warm: `温暖`, + worldState_cold: `寒冷`, + worldState_duviriOverride: `双衍王镜状态`, + worldState_joy: `喜悦`, + worldState_anger: `愤怒`, + worldState_envy: `嫉妒`, + worldState_sorrow: `悲伤`, + worldState_fear: `恐惧`, + worldState_nightwaveOverride: `午夜电波系列`, + worldState_RadioLegionIntermission13Syndicate: `诺拉的混选VOL.9`, + worldState_RadioLegionIntermission12Syndicate: `诺拉的混选VOL.8`, + worldState_RadioLegionIntermission11Syndicate: `诺拉的混选VOL.7`, + worldState_RadioLegionIntermission10Syndicate: `诺拉的混选VOL.6`, + worldState_RadioLegionIntermission9Syndicate: `诺拉的混选VOL.5`, + worldState_RadioLegionIntermission8Syndicate: `诺拉的混选VOL.4`, + worldState_RadioLegionIntermission7Syndicate: `诺拉的混选VOL.3`, + worldState_RadioLegionIntermission6Syndicate: `诺拉的混选VOL.2`, + worldState_RadioLegionIntermission5Syndicate: `诺拉的混选VOL.1`, + worldState_RadioLegionIntermission4Syndicate: `诺拉的精选`, + worldState_RadioLegionIntermission3Syndicate: `间歇III`, + worldState_RadioLegion3Syndicate: `系列3 — 玻璃匠`, + worldState_RadioLegionIntermission2Syndicate: `间歇II`, + worldState_RadioLegion2Syndicate: `系列2 — 使徒`, + worldState_RadioLegionIntermissionSyndicate: `间歇I`, + worldState_RadioLegionSyndicate: `系列1 — 土星六号之狼`, + worldState_fissures: `虚空裂缝难度设定`, + normal: `正常`, + worldState_allAtOnceNormal: `全部开启(普通)`, + worldState_allAtOnceSteelPath: `全部开启(钢铁之路)`, + worldState_theCircuitOverride: `无尽回廊任务循环配置:`, + worldState_darvoStockMultiplier: `Darvo特惠库存倍率`, + worldState_varziaFullyStocked: `瓦奇娅开启全部库存商品`, + worldState_varziaOverride: `瓦奇娅(Prime重生)轮换状态`, + + import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示).支持的所有字段将被覆盖到您的账户中.`, + import_submit: `提交`, + import_samples: `示例:`, + import_samples_maxFocus: `所有专精学派完全精通`, + + upgrade_Equilibrium: `拾取生命球+|VAL|%能量,拾取能量球+|VAL|%生命`, + upgrade_MeleeCritDamage: `+|VAL|%近战暴击伤害`, + upgrade_PrimaryStatusChance: `+|VAL|%主要武器触发几率`, + upgrade_SecondaryCritChance: `+|VAL|%次要武器暴击几率`, + upgrade_WarframeAbilityDuration: `+|VAL|%技能持续时间`, + upgrade_WarframeAbilityStrength: `+|VAL|%技能强度`, + upgrade_WarframeArmorMax: `+|VAL|护甲`, + upgrade_WarframeBlastProc: `使用爆炸伤害击杀敌人时恢复+|VAL|护盾`, + upgrade_WarframeCastingSpeed: `+|VAL|%施放速度`, + upgrade_WarframeCorrosiveDamageBoost: `对受腐蚀异常影响的敌人+|VAL|%额外技能伤害`, + upgrade_WarframeCorrosiveStack: `腐蚀异常最大堆叠层数+|VAL|`, + upgrade_WarframeCritDamageBoost: `+|VAL|%近战暴击伤害(最大能量超过500时伤害翻倍)`, + upgrade_WarframeElectricDamage: `主要武器获得+|VAL1|%电击伤害(每装备一颗深红,蔚蓝,紫晶源力石+|VAL2|%额外电击伤害)`, + upgrade_WarframeElectricDamageBoost: `对受电击异常影响的敌人+|VAL|%额外技能伤害`, + upgrade_WarframeEnergyMax: `+|VAL|最大能量`, + upgrade_WarframeGlobeEffectEnergy: `+|VAL|%能量球效果`, + upgrade_WarframeGlobeEffectHealth: `+|VAL|%生命球效果`, + upgrade_WarframeHealthMax: `+|VAL|生命值`, + upgrade_WarframeHPBoostFromImpact: `通过爆炸伤害击杀的每个敌人可增加|VAL1|生命上限(最大|VAL2|生命上限)`, + upgrade_WarframeParkourVelocity: `+|VAL|%跑酷速度`, + upgrade_WarframeRadiationDamageBoost: `对受辐射状态影响的敌人+|VAL|%技能伤害`, + upgrade_WarframeHealthRegen: `+|VAL|/秒生命再生`, + upgrade_WarframeShieldMax: `+|VAL|护盾值`, + upgrade_WarframeStartingEnergy: `进任务时+|VAL|%初始能量`, + upgrade_WarframeToxinDamage: `毒素伤害额外+|VAL|%伤害`, + upgrade_WarframeToxinHeal: `每当敌人受到毒素伤害时回复|VAL|生命值`, + upgrade_WeaponCritBoostFromHeat: `每个被火焰伤害杀死的敌人,增加|VAL1|%次要武器暴击几率(最大|VAL2|%)`, + upgrade_AvatarAbilityRange: `+7.5%技能范围`, + upgrade_AvatarAbilityEfficiency: `+5%技能效率`, + upgrade_AvatarEnergyRegen: `+0.5/秒能量再生`, + upgrade_AvatarEnemyRadar: `+5米侦敌雷达`, + upgrade_AvatarLootRadar: `+7米寻物雷达`, + upgrade_WeaponAmmoMax: `+15%弹药最大容量`, + upgrade_EnemyArmorReductionAura: `-3%敌方护甲`, + upgrade_OnExecutionAmmo: `怜悯之击可装填100%主要武器和次要武器弹匣容量`, + upgrade_OnExecutionHealthDrop: `怜悯之击有100%几率掉落生命球`, + upgrade_OnExecutionEnergyDrop: `怜悯之击有50%几率掉落能量球`, + upgrade_OnFailHackReset: `入侵失败后有50%几率重新尝试`, + upgrade_DamageReductionOnHack: `入侵时,+75%伤害减免`, + upgrade_OnExecutionReviveCompanion: `怜悯之击减少15秒同伴复苏时间`, + upgrade_OnExecutionParkourSpeed: `怜悯之击后+60%跑酷速度,持续15秒`, + upgrade_AvatarTimeLimitIncrease: `+8秒入侵时间`, + upgrade_ElectrifyOnHack: `入侵时震慑20米之内的敌人`, + upgrade_OnExecutionTerrify: `怜悯之击有50%几率让15米以内的敌人进入恐惧状态8秒`, + upgrade_OnHackLockers: `入侵后解锁20米内的5个储物柜`, + upgrade_OnExecutionBlind: `怜悯之击致盲18米范围内的敌人`, + upgrade_OnExecutionDrainPower: `怜悯之击有100%机率使下一个技能获得50%技能强度`, + upgrade_OnHackSprintSpeed: `入侵后+75%冲刺速度,持续15秒`, + upgrade_SwiftExecute: `怜悯之击施放速度+50%`, + upgrade_OnHackInvis: `入侵后隐身15秒`, + + damageType_Electricity: `电击`, + damageType_Fire: `火焰`, + damageType_Freeze: `冰冻`, + damageType_Impact: `冲击`, + damageType_Magnetic: `磁力`, + damageType_Poison: `毒素`, + damageType_Radiation: `辐射`, + + theme_dark: `暗色主题`, + theme_light: `亮色主题`, + + prettier_sucks_ass: `` +};