Compare commits

..

2 Commits
main ... German

Author SHA1 Message Date
50405f36a7 merge upstream 2025-10-29 11:18:54 -07:00
2f87725282 static/webui/translations/de.js aktualisiert
All checks were successful
Build / build (pull_request) Successful in 1m5s
2025-10-29 08:30:27 -07:00
35 changed files with 269 additions and 1327 deletions

View File

@ -1,5 +1,3 @@
export const EPOCH = 1734307200_000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be the start of winter in 1999 iteration 0
const millisecondsPerSecond = 1000;
const secondsPerMinute = 60;
const minutesPerHour = 60;

View File

@ -1,17 +1,9 @@
import type { RequestHandler } from "express";
import { deleteSession } from "../../managers/sessionManager.ts";
import { getAccountForRequest } from "../../services/loginService.ts";
import { version_compare } from "../../helpers/inventoryHelpers.ts";
const deleteSessionController: RequestHandler = async (_req, res) => {
const account = await getAccountForRequest(_req);
const deleteSessionController: RequestHandler = (_req, res) => {
deleteSession(_req.query.sessionId as string);
if (account.BuildLabel && version_compare(account.BuildLabel, "2016.07.08.16.56") < 0) {
// Pre-Specters of the Rail
res.send(_req.query.sessionId as string); // Unsure if this is correct, but the client is chill with it
} else {
res.sendStatus(200);
}
res.sendStatus(200);
};
export { deleteSessionController };

View File

@ -1,8 +1,8 @@
import type { RequestHandler } from "express";
import { getAccountIdForRequest } from "../../services/loginService.ts";
import { getInventory } from "../../services/inventoryService.ts";
import { getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
import { EPOCH, unixTimesInMs } from "../../constants/timeConstants.ts";
import { EPOCH, getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
import { unixTimesInMs } from "../../constants/timeConstants.ts";
import type { ISeasonChallenge } from "../../types/worldStateTypes.ts";
import { ExportChallenges } from "warframe-public-export-plus";

View File

@ -13,8 +13,8 @@ const hostSessionController: RequestHandler = async (req, res) => {
const session = createNewSession(hostSessionRequest, account._id);
logger.debug(`New Session Created`, { session });
if (account.BuildLabel && version_compare(account.BuildLabel, "2016.07.08.16.56") < 0) {
// Pre-Specters of the Rail
if (account.BuildLabel && version_compare(account.BuildLabel, "2015.03.21.08.17") < 0) {
// U15 or below
res.send(session.sessionId.toString());
} else {
res.json({ sessionId: toOid2(session.sessionId, account.BuildLabel), rewardSeed: 99999999 });

View File

@ -310,13 +310,12 @@ export const getInventoryResponse = async (
}
if (inventory.skipAllDialogue) {
inventoryResponse.TauntHistory ??= [];
if (!inventoryResponse.TauntHistory.find(x => x.node == "TreasureTutorial")) {
inventoryResponse.TauntHistory.push({
inventoryResponse.TauntHistory = [
{
node: "TreasureTutorial",
state: "TS_COMPLETED"
});
}
}
];
for (const str of allDialogue) {
addString(inventoryResponse.NodeIntrosCompleted, str);
}
@ -354,11 +353,11 @@ export const getInventoryResponse = async (
if (!xpBasedLevelCapDisabled) {
// This client has not been patched to accept any mastery rank, need to fake the XP.
inventoryResponse.XPInfo = [];
let numFrames = getExpRequiredForMr(Math.min(inventory.spoofMasteryRank, 5030)) / (30 * 200);
let numFrames = getExpRequiredForMr(Math.min(inventory.spoofMasteryRank, 5030)) / 6000;
while (numFrames-- > 0) {
inventoryResponse.XPInfo.push({
ItemType: "/Lotus/Powersuits/Mag/Mag",
XP: 900_000 // Enough for rank 30 as per https://wiki.warframe.com/w/Affinity
XP: 1_600_000
});
}
}

View File

@ -109,19 +109,12 @@ const createLoginResponse = (
const resp: ILoginResponse = {
id: account.id,
DisplayName: account.DisplayName,
CountryCode: account.CountryCode,
AmazonAuthToken: account.AmazonAuthToken,
AmazonRefreshToken: account.AmazonRefreshToken,
Nonce: account.Nonce,
BuildLabel: buildLabel
};
if (version_compare(buildLabel, "2014.10.24.08.24") >= 0) {
// U15 and up
resp.CountryCode = account.CountryCode;
} else {
// U8
resp.NatHash = "0";
resp.SteamId = "0";
}
if (version_compare(buildLabel, "2015.02.13.10.41") >= 0) {
resp.NRS = [config.nrsAddress ?? myAddress];
}

View File

@ -36,11 +36,6 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
}
addString(inventory.NodeIntrosCompleted, "TeshinHardModeUnlocked");
addString(inventory.NodeIntrosCompleted, "CetusSyndicate_IntroJob");
let syndicate = inventory.Affiliations.find(x => x.Tag == "CetusSyndicate");
if (!syndicate) {
syndicate =
inventory.Affiliations[inventory.Affiliations.push({ Tag: "CetusSyndicate", Standing: 250, Title: 0 })]; // Non-zero standing avoids Konzu's "prove yourself" text. 250 is identical to newbie bounty + bonus
}
await inventory.save();
res.end();
};

View File

@ -37,7 +37,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
switch (operation) {
case "completeAll": {
for (const questKey of inventory.QuestKeys) {
await completeQuest(inventory, questKey.ItemType, undefined);
await completeQuest(inventory, questKey.ItemType);
}
break;
}
@ -61,7 +61,6 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
break;
}
inventory.QuestKeys.pull({ ItemType: questItemType });
if (inventory.ActiveQuest == questItemType) inventory.ActiveQuest = "";
break;
}
case "completeKey": {
@ -72,7 +71,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
break;
}
await completeQuest(inventory, questItemType, undefined);
await completeQuest(inventory, questItemType);
}
break;
}
@ -137,7 +136,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
if (currentStage + 1 == questManifest.chainStages?.length) {
logger.debug(`Trying to complete last stage with nextStage, calling completeQuest instead`);
await completeQuest(inventory, questKey.ItemType, undefined, true);
await completeQuest(inventory, questKey.ItemType, true);
} else {
if (run > 0) {
questKey.Progress[currentStage + 1].c = run;
@ -151,14 +150,10 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
});
if (currentStage > 0) {
await giveKeyChainMissionReward(
inventory,
{
KeyChain: questKey.ItemType,
ChainStage: currentStage
},
undefined
);
await giveKeyChainMissionReward(inventory, {
KeyChain: questKey.ItemType,
ChainStage: currentStage
});
}
}
}

View File

@ -10,7 +10,6 @@ import { addPendingFriendController } from "../controllers/api/addPendingFriendC
import { addToAllianceController } from "../controllers/api/addToAllianceController.ts";
import { addToGuildController } from "../controllers/api/addToGuildController.ts";
import { adoptPetController } from "../controllers/api/adoptPetController.ts";
import { aggregateSessionsController } from "../controllers/dynamic/aggregateSessionsController.ts";
import { apartmentController } from "../controllers/api/apartmentController.ts";
import { arcaneCommonController } from "../controllers/api/arcaneCommonController.ts";
import { archonFusionController } from "../controllers/api/archonFusionController.ts";
@ -171,7 +170,6 @@ import { upgradeOperatorController } from "../controllers/api/upgradeOperatorCon
import { upgradesController } from "../controllers/api/upgradesController.ts";
import { valenceSwapController } from "../controllers/api/valenceSwapController.ts";
import { wishlistController } from "../controllers/api/wishlistController.ts";
import { worldStateController } from "../controllers/dynamic/worldStateController.ts";
const apiRouter = express.Router();
@ -237,7 +235,6 @@ apiRouter.get("/surveys.php", surveysController);
apiRouter.get("/trading.php", tradingController);
apiRouter.get("/updateSession.php", updateSessionGetController);
apiRouter.get("/upgradeOperator.php", upgradeOperatorController);
apiRouter.get("/worldState.php", worldStateController); // U8
// post
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
@ -249,7 +246,6 @@ apiRouter.post("/addPendingFriend.php", addPendingFriendController);
apiRouter.post("/addToAlliance.php", addToAllianceController);
apiRouter.post("/addToGuild.php", addToGuildController);
apiRouter.post("/adoptPet.php", adoptPetController);
apiRouter.post("/aggregateSessions.php", aggregateSessionsController); // Pre-Specters of the Rail builds
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
apiRouter.post("/archonFusion.php", archonFusionController);
apiRouter.post("/artifacts.php", artifactsController);

View File

@ -1,6 +1,5 @@
import express from "express";
import path from "path";
import fs from "fs/promises";
import { repoDir, rootDir } from "../helpers/pathHelper.ts";
import { args } from "../helpers/commandLineArguments.ts";
@ -22,62 +21,50 @@ webuiRouter.use("/webui", (req, res, next) => {
});
// Serve virtual routes
webuiRouter.get("/webui/inventory", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/inventory", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/detailedView", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/detailedView", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/mods", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/mods", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/settings", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/settings", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/quests", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/quests", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/cheats", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/cheats", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/import", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/import", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/guildView", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, "static/webui/index.html")));
webuiRouter.get("/webui/guildView", (_req, res) => {
res.sendFile(path.join(baseDir, "static/webui/index.html"));
});
// Serve static files
webuiRouter.use("/webui", express.static(path.join(baseDir, "static/webui")));
// Serve favicon
webuiRouter.get("/favicon.ico", async (_req, res) => {
res.set("Content-Type", "image/vnd.microsoft.icon");
res.send(await fs.readFile(path.join(repoDir, "static/fixed_responses/favicon.ico")));
webuiRouter.get("/favicon.ico", (_req, res) => {
res.sendFile(path.join(repoDir, "static/fixed_responses/favicon.ico"));
});
// Serve warframe-riven-info
webuiRouter.get("/webui/riven-tool/", async (_req, res) => {
res.set("Content-Type", "text/html;charset=utf8");
res.send(await fs.readFile(path.join(repoDir, "node_modules/warframe-riven-info/index.html")));
webuiRouter.get("/webui/riven-tool/", (_req, res) => {
res.sendFile(path.join(repoDir, "node_modules/warframe-riven-info/index.html"));
});
webuiRouter.get("/webui/riven-tool/RivenParser.js", async (_req, res) => {
res.set("Content-Type", "text/javascript;charset=utf8");
res.send(await fs.readFile(path.join(repoDir, "node_modules/warframe-riven-info/RivenParser.js")));
webuiRouter.get("/webui/riven-tool/RivenParser.js", (_req, res) => {
res.sendFile(path.join(repoDir, "node_modules/warframe-riven-info/RivenParser.js"));
});
// Serve translations
webuiRouter.get("/translations/:file", async (req, res) => {
res.set("Content-Type", "text/javascript;charset=utf8");
res.send(await fs.readFile(path.join(baseDir, `static/webui/translations/${req.params.file}`)));
webuiRouter.get("/translations/:file", (req, res) => {
res.sendFile(path.join(baseDir, `static/webui/translations/${req.params.file}`));
});
export { webuiRouter };

View File

@ -1,425 +0,0 @@
import type { TFaction, TMissionType } from "warframe-public-export-plus";
import type { CalendarSeasonType, IConquest, IConquestMission, TConquestType } from "../types/worldStateTypes.ts";
import { mixSeeds, SRng } from "./rngService.ts";
import { EPOCH } from "../constants/timeConstants.ts";
const missionAndFactionTypes: Record<TConquestType, Partial<Record<TMissionType, TFaction[]>>> = {
CT_LAB: {
MT_EXTERMINATION: ["FC_MITW"],
MT_SURVIVAL: ["FC_MITW"],
MT_ALCHEMY: ["FC_MITW"],
MT_DEFENSE: ["FC_MITW"],
MT_ARTIFACT: ["FC_MITW"]
},
CT_HEX: {
MT_EXTERMINATION: ["FC_SCALDRA", "FC_TECHROT"],
MT_SURVIVAL: ["FC_SCALDRA", "FC_TECHROT"],
MT_DEFENSE: ["FC_SCALDRA"],
MT_ENDLESS_CAPTURE: ["FC_TECHROT"]
}
};
const assassinationFactionOptions: Record<TConquestType, TFaction[]> = {
CT_LAB: ["FC_MITW"],
CT_HEX: ["FC_SCALDRA"]
};
type TConquestDifficulty = "CD_NORMAL" | "CD_HARD";
interface IConquestConditional {
tag: string;
missionType?: TMissionType;
conquest?: TConquestType;
difficulty?: TConquestDifficulty;
season?: CalendarSeasonType;
}
const deviations: readonly IConquestConditional[] = [
{
tag: "AlchemicalShields",
missionType: "MT_ALCHEMY"
},
{
tag: "ContaminationZone",
missionType: "MT_SURVIVAL",
conquest: "CT_HEX"
},
{
tag: "DoubleTrouble",
missionType: "MT_ARTIFACT"
},
{
tag: "EscalateImmediately",
missionType: "MT_EXTERMINATION",
conquest: "CT_HEX"
},
{
tag: "EximusGrenadiers",
missionType: "MT_ALCHEMY"
},
{
tag: "FortifiedFoes",
missionType: "MT_EXTERMINATION"
},
{
tag: "FragileNodes",
missionType: "MT_ARTIFACT"
},
{
tag: "GrowingIncursion",
missionType: "MT_EXTERMINATION",
conquest: "CT_LAB"
},
{
tag: "HarshWords",
missionType: "MT_DEFENSE",
conquest: "CT_LAB"
},
{
tag: "HighScalingLegacyte",
missionType: "MT_ENDLESS_CAPTURE",
conquest: "CT_HEX"
},
{
tag: "DoubleTroubleLegacyte",
missionType: "MT_ENDLESS_CAPTURE",
conquest: "CT_HEX"
},
{
tag: "HostileSecurity",
missionType: "MT_DEFENSE",
conquest: "CT_LAB"
},
{
tag: "InfiniteTide",
missionType: "MT_ASSASSINATION",
conquest: "CT_LAB"
},
{
tag: "LostInTranslation",
missionType: "MT_DEFENSE",
conquest: "CT_LAB"
},
{
tag: "MutatedEnemies",
missionType: "MT_ENDLESS_CAPTURE",
conquest: "CT_HEX"
},
{
tag: "NecramechActivation",
missionType: "MT_SURVIVAL",
conquest: "CT_LAB"
},
{
tag: "Reinforcements",
missionType: "MT_ASSASSINATION",
conquest: "CT_LAB"
},
{
tag: "StickyFingers",
missionType: "MT_ARTIFACT",
conquest: "CT_LAB"
},
{
tag: "TankStrongArmor",
missionType: "MT_ASSASSINATION",
conquest: "CT_HEX"
},
{
tag: "TankReinforcements",
missionType: "MT_ASSASSINATION",
conquest: "CT_HEX"
},
{
tag: "TankSuperToxic",
missionType: "MT_ASSASSINATION",
conquest: "CT_HEX"
},
{
tag: "TechrotConjunction",
missionType: "MT_SURVIVAL",
conquest: "CT_HEX"
},
{
tag: "UnpoweredCapsules",
missionType: "MT_SURVIVAL",
conquest: "CT_LAB"
},
{
tag: "VolatileGrenades",
missionType: "MT_ALCHEMY"
},
{
tag: "GestatingTumors",
missionType: "MT_SURVIVAL",
conquest: "CT_HEX"
},
{
tag: "ChemicalNoise",
missionType: "MT_DEFENSE",
conquest: "CT_HEX"
},
{
tag: "ExplosiveEnergy",
missionType: "MT_DEFENSE",
conquest: "CT_HEX"
},
{
tag: "DisruptiveSounds",
missionType: "MT_DEFENSE",
conquest: "CT_HEX"
}
];
const risks: readonly IConquestConditional[] = [
{
tag: "Voidburst"
},
{
tag: "RegeneratingEnemies"
},
{
tag: "VoidAberration"
},
{
tag: "ShieldedFoes"
},
{
tag: "PointBlank"
},
{
tag: "Deflectors",
conquest: "CT_LAB"
},
{
tag: "AcceleratedEnemies"
},
{
tag: "DrainingResiduals"
},
{
tag: "Quicksand"
},
{
tag: "AntiMaterialWeapons",
conquest: "CT_LAB"
},
{
tag: "ExplosiveCrawlers",
conquest: "CT_LAB"
},
{
tag: "EMPBlackHole",
conquest: "CT_LAB"
},
{
tag: "ArtilleryBeacons",
conquest: "CT_HEX"
},
{
tag: "InfectedTechrot",
conquest: "CT_HEX"
},
{
tag: "BalloonFest",
conquest: "CT_HEX"
},
{
tag: "MiasmiteHive",
conquest: "CT_HEX"
},
{
tag: "CompetitionSpillover",
conquest: "CT_HEX"
},
{
tag: "HostileOvergrowth",
conquest: "CT_HEX"
},
{
tag: "MurmurIncursion",
conquest: "CT_HEX"
},
{
tag: "FactionSwarm_Techrot",
conquest: "CT_HEX",
difficulty: "CD_NORMAL"
},
{
tag: "FactionSwarm_Scaldra",
conquest: "CT_HEX",
difficulty: "CD_NORMAL"
},
{
tag: "HeavyWarfare",
conquest: "CT_HEX"
},
{
tag: "ArcadeAutomata",
conquest: "CT_HEX",
difficulty: "CD_NORMAL"
},
{
tag: "EfervonFog",
conquest: "CT_HEX"
},
{
tag: "WinterFrost",
conquest: "CT_HEX",
season: "CST_WINTER"
},
{
tag: "JadeSpring",
conquest: "CT_HEX",
season: "CST_SPRING"
},
{
tag: "ExplosiveSummer",
conquest: "CT_HEX",
season: "CST_SUMMER"
},
{
tag: "FallFog",
conquest: "CT_HEX",
season: "CST_FALL"
}
];
const filterConditionals = (
arr: readonly IConquestConditional[],
missionType: TMissionType | null,
conquest: TConquestType | null,
difficulty: TConquestDifficulty | null,
season: CalendarSeasonType | null
): string[] => {
const applicable = [];
for (const cond of arr) {
if (
(!cond.missionType || cond.missionType == missionType) &&
(!cond.conquest || cond.conquest == conquest) &&
(!cond.difficulty || cond.difficulty == difficulty) &&
(!cond.season || cond.season == season)
) {
applicable.push(cond.tag);
}
}
return applicable;
};
const buildMission = (
rng: SRng,
conquest: TConquestType,
missionType: TMissionType,
faction: TFaction,
season: CalendarSeasonType | null
): IConquestMission => {
const deviation = rng.randomElement(filterConditionals(deviations, missionType, conquest, null, season))!;
const easyRisk = rng.randomElement(filterConditionals(risks, missionType, conquest, "CD_NORMAL", season))!;
const hardRiskOptions = filterConditionals(risks, missionType, conquest, "CD_HARD", season);
{
const i = hardRiskOptions.indexOf(easyRisk);
if (i != -1) {
hardRiskOptions.splice(i, 1);
}
}
const hardRisk = rng.randomElement(hardRiskOptions)!;
return {
faction,
missionType,
difficulties: [
{
type: "CD_NORMAL",
deviation,
risks: [easyRisk]
},
{
type: "CD_HARD",
deviation,
risks: [easyRisk, hardRisk]
}
]
};
};
const conquestStartingDay: Record<TConquestType, number> = {
CT_LAB: 3703,
CT_HEX: 4053
};
// This function produces identical results to clients pre-40.0.0.
const getFrameVariables = (conquestType: TConquestType, time: number): [string, string, string, string] => {
const day = Math.floor((time - 1391990400_000) / 86400_000) - conquestStartingDay[conquestType];
const week = Math.floor(day / 7) + 1;
const frameVariables = [
"Framecurse",
"Knifestep",
"Exhaustion",
"Gearless",
"TimeDilation",
"Armorless",
"Starvation",
"ShieldDelay",
"Withering",
"ContactDamage",
"AbilityLockout",
"OperatorLockout",
"EnergyStarved",
"OverSensitive",
"AntiGuard",
"DecayingFlesh",
"VoidEnergyOverload",
"DullBlades",
"Undersupplied"
];
const mag = Math.floor(frameVariables.length / 4);
const rng = new SRng(conquestStartingDay[conquestType] + Math.floor(week / mag));
rng.shuffleArray(frameVariables);
const i = week % mag;
return [frameVariables[i], frameVariables[i + 1], frameVariables[i + 2], frameVariables[i + 3]];
};
export const getConquest = (
conquestType: TConquestType,
week: number,
season: CalendarSeasonType | null
): IConquest => {
const rng = new SRng(mixSeeds(conquestStartingDay[conquestType], week));
const missions: IConquestMission[] = [];
{
const missionOptions = Object.entries(missionAndFactionTypes[conquestType]);
{
const i = rng.randomInt(0, missionOptions.length - 1);
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
missions.push(
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
);
}
{
const i = rng.randomInt(0, missionOptions.length - 1);
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
missions.push(
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
);
}
missionOptions.push(["MT_ASSASSINATION", assassinationFactionOptions[conquestType]]);
{
const i = rng.randomInt(0, missionOptions.length - 1);
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
missions.push(
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
);
}
}
const weekStart = EPOCH + week * 604800000;
const weekEnd = weekStart + 604800000;
return {
Activation: { $date: { $numberLong: weekStart.toString() } },
Expiry: { $date: { $numberLong: weekEnd.toString() } },
Type: conquestType,
Missions: missions,
Variables: getFrameVariables(conquestType, weekStart),
RandomSeed: rng.randomInt(0, 1_000_000)
};
};

View File

@ -116,8 +116,8 @@ export const createInventory = async (
if (config.skipTutorial) {
inventory.PlayedParkourTutorial = true;
await addStartingGear(inventory);
await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain", undefined);
await completeQuest(inventory, "/Lotus/Types/Keys/ModQuest/ModQuestKeyChain", undefined);
await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
await completeQuest(inventory, "/Lotus/Types/Keys/ModQuest/ModQuestKeyChain");
const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"];
@ -473,9 +473,7 @@ export const addItem = async (
return addCustomization(inventory, typeName);
}
if (typeName in ExportUpgrades || typeName in ExportArcanes) {
if (targetFingerprint && typeName.startsWith("/Lotus/Upgrades/Mods/Randomized/Raw")) {
logger.debug(`ignoring fingerprint for raw riven mod`);
} else if (targetFingerprint) {
if (targetFingerprint) {
if (quantity != 1) {
logger.warn(`adding 1 of ${typeName} ${targetFingerprint} even tho quantity ${quantity} was requested`);
}
@ -1571,7 +1569,6 @@ const addCrewShip = async (
const questChanges = await completeQuest(
inventory,
"/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestKeyChain",
undefined,
false
);
if (questChanges) {

View File

@ -40,8 +40,6 @@ import {
} from "warframe-public-export-plus";
import type { IMessage } from "../models/inboxModel.ts";
import { logger } from "../utils/logger.ts";
import { version_compare } from "../helpers/inventoryHelpers.ts";
import vorsPrizePreU40Rewards from "../../static/fixed_responses/vorsPrizePreU40Rewards.json" with { type: "json" };
export type WeaponTypeInternal =
| "LongGuns"
@ -229,13 +227,12 @@ export const getKeyChainItems = ({ KeyChain, ChainStage }: IKeyChainRequest): st
};
export const getLevelKeyRewards = (
levelKey: string,
buildLabel: string | undefined
levelKey: string
): { levelKeyRewards?: IMissionReward; levelKeyRewards2?: TReward[] } => {
const key = ExportKeys[levelKey] as IKey | undefined;
const levelKeyRewards = key?.missionReward;
let levelKeyRewards2 = key?.rewards;
const levelKeyRewards2 = key?.rewards;
if (!levelKeyRewards && !levelKeyRewards2) {
logger.warn(
@ -243,12 +240,6 @@ export const getLevelKeyRewards = (
);
}
if (buildLabel && version_compare(buildLabel, "2025.10.14.16.10") < 0) {
if (levelKey in vorsPrizePreU40Rewards) {
levelKeyRewards2 = vorsPrizePreU40Rewards[levelKey as keyof typeof vorsPrizePreU40Rewards] as TReward[];
}
}
return {
levelKeyRewards,
levelKeyRewards2

View File

@ -41,8 +41,8 @@ export const createAccount = async (accountData: IDatabaseAccountRequiredFields)
await account.save();
const loadoutId = await createLoadout(account._id);
const shipId = await createShip(account._id);
await createPersonalRooms(account._id, shipId);
await createInventory(account._id, { loadOutPresetId: loadoutId, ship: shipId });
await createPersonalRooms(account._id, shipId);
await createStats(account._id.toString());
return account.toJSON();
} catch (error) {
@ -64,6 +64,17 @@ export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Typ
personalRoomsOwnerId: accountId,
activeShipId: shipId
});
if (config.skipTutorial) {
// unlocked during Vor's Prize and The Teacher quests
const defaultFeatures = [
"/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem",
"/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem",
"/Lotus/Types/Items/ShipFeatureItems/SocialMenuFeatureItem",
"/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem",
"/Lotus/Types/Items/ShipFeatureItems/ModsFeatureItem"
];
personalRooms.Ship.Features.push(...defaultFeatures);
}
await personalRooms.save();
};

View File

@ -1133,8 +1133,7 @@ export const addMissionRewards = async (
VoidTearParticipantsCurrWave: voidTearWave,
StrippedItems: strippedItems,
AffiliationChanges: AffiliationMods,
InvasionProgress: invasionProgress,
EndOfMatchUpload: endOfMatchUpload
InvasionProgress: invasionProgress
}: IMissionInventoryUpdateRequest,
firstCompletion: boolean
): Promise<AddMissionRewardsReturnType> => {
@ -1219,7 +1218,7 @@ export const addMissionRewards = async (
}
if (levelKeyName) {
const fixedLevelRewards = getLevelKeyRewards(levelKeyName, account.BuildLabel);
const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
//logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
if (fixedLevelRewards.levelKeyRewards) {
missionCompletionCredits += addFixedLevelRewards(
@ -1393,77 +1392,73 @@ export const addMissionRewards = async (
}
if (strippedItems) {
if (endOfMatchUpload) {
for (const si of strippedItems) {
if (si.DropTable in droptableAliases) {
logger.debug(`rewriting ${si.DropTable} to ${droptableAliases[si.DropTable]}`);
si.DropTable = droptableAliases[si.DropTable];
}
const droptables = ExportEnemies.droptables[si.DropTable] ?? [];
if (si.DROP_MOD) {
const modDroptable = droptables.find(x => x.type == "mod");
if (modDroptable) {
for (let i = 0; i != si.DROP_MOD.length; ++i) {
const reward = getRandomReward(modDroptable.items)!;
logger.debug(`stripped droptable (mods pool) rolled`, reward);
await addItem(inventory, reward.type);
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_MOD`);
for (const si of strippedItems) {
if (si.DropTable in droptableAliases) {
logger.debug(`rewriting ${si.DropTable} to ${droptableAliases[si.DropTable]}`);
si.DropTable = droptableAliases[si.DropTable];
}
const droptables = ExportEnemies.droptables[si.DropTable] ?? [];
if (si.DROP_MOD) {
const modDroptable = droptables.find(x => x.type == "mod");
if (modDroptable) {
for (let i = 0; i != si.DROP_MOD.length; ++i) {
const reward = getRandomReward(modDroptable.items)!;
logger.debug(`stripped droptable (mods pool) rolled`, reward);
await addItem(inventory, reward.type);
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
}
if (si.DROP_BLUEPRINT) {
const blueprintDroptable = droptables.find(x => x.type == "blueprint");
if (blueprintDroptable) {
for (let i = 0; i != si.DROP_BLUEPRINT.length; ++i) {
const reward = getRandomReward(blueprintDroptable.items)!;
logger.debug(`stripped droptable (blueprints pool) rolled`, reward);
await addItem(inventory, reward.type);
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_BLUEPRINT`);
}
}
// e.g. H-09 Apex Turret Sumdali
if (si.DROP_MISC_ITEM) {
const resourceDroptable = droptables.find(x => x.type == "resource");
if (resourceDroptable) {
for (let i = 0; i != si.DROP_MISC_ITEM.length; ++i) {
const reward = getRandomReward(resourceDroptable.items)!;
logger.debug(`stripped droptable (resources pool) rolled`, reward);
if (Object.keys(await addItem(inventory, reward.type)).length == 0) {
logger.debug(`item already owned, skipping`);
} else {
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
}
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_MISC_ITEM`);
}
}
if (si.DropTable == "/Lotus/Types/DropTables/ContainerDropTables/VoidVaultMissionRewardsDropTable") {
// Consume netracells search pulse; only when the container reward was picked up. Discussed in https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2673
updateEntratiVault(inventory);
inventory.EntratiVaultCountLastPeriod! += 1;
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_MOD`);
}
}
} else {
logger.debug(`ignoring StrippedItems in intermediate inventory update, deferring until extraction`);
if (si.DROP_BLUEPRINT) {
const blueprintDroptable = droptables.find(x => x.type == "blueprint");
if (blueprintDroptable) {
for (let i = 0; i != si.DROP_BLUEPRINT.length; ++i) {
const reward = getRandomReward(blueprintDroptable.items)!;
logger.debug(`stripped droptable (blueprints pool) rolled`, reward);
await addItem(inventory, reward.type);
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_BLUEPRINT`);
}
}
// e.g. H-09 Apex Turret Sumdali
if (si.DROP_MISC_ITEM) {
const resourceDroptable = droptables.find(x => x.type == "resource");
if (resourceDroptable) {
for (let i = 0; i != si.DROP_MISC_ITEM.length; ++i) {
const reward = getRandomReward(resourceDroptable.items)!;
logger.debug(`stripped droptable (resources pool) rolled`, reward);
if (Object.keys(await addItem(inventory, reward.type)).length == 0) {
logger.debug(`item already owned, skipping`);
} else {
MissionRewards.push({
StoreItem: toStoreItem(reward.type),
ItemCount: 1,
FromEnemyCache: true // to show "identified"
});
}
}
} else {
logger.error(`unknown droptable ${si.DropTable} for DROP_MISC_ITEM`);
}
}
if (si.DropTable == "/Lotus/Types/DropTables/ContainerDropTables/VoidVaultMissionRewardsDropTable") {
// Consume netracells search pulse; only when the container reward was picked up. Discussed in https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2673
updateEntratiVault(inventory);
inventory.EntratiVaultCountLastPeriod! += 1;
}
}
}

View File

@ -2,25 +2,16 @@ import type { IKeyChainRequest } from "../types/requestTypes.ts";
import { isEmptyObject } from "../helpers/general.ts";
import type { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel.ts";
import { createMessage } from "./inboxService.ts";
import {
addEquipment,
addItem,
addItems,
addKeyChainItems,
addPowerSuit,
setupKahlSyndicate
} from "./inventoryService.ts";
import { addItem, addItems, addKeyChainItems, setupKahlSyndicate } from "./inventoryService.ts";
import { fromStoreItem, getKeyChainMessage, getLevelKeyRewards } from "./itemDataService.ts";
import type { IQuestKeyClient, IQuestKeyDatabase, IQuestStage } from "../types/inventoryTypes/inventoryTypes.ts";
import { logger } from "../utils/logger.ts";
import { ExportKeys, ExportRecipes } from "warframe-public-export-plus";
import { ExportKeys } from "warframe-public-export-plus";
import { addFixedLevelRewards } from "./missionInventoryUpdateService.ts";
import type { IInventoryChanges } from "../types/purchaseTypes.ts";
import questCompletionItems from "../../static/fixed_responses/questCompletionRewards.json" with { type: "json" };
import type { ITypeCount } from "../types/commonTypes.ts";
import { addString } from "../helpers/stringHelpers.ts";
import { unlockShipFeature } from "./personalRoomsService.ts";
import { EquipmentFeatures } from "../types/equipmentTypes.ts";
export interface IUpdateQuestRequest {
QuestKeys: IQuestKeyClient[];
@ -113,10 +104,14 @@ export const resetQuestKeyToStage = (
quest.Progress ??= [];
const run = quest.Progress[0]?.c ?? 0;
if (run >= 0) {
for (let i = ChainStage; i < quest.Progress.length; ++i) {
quest.Progress[i].c = run - 1;
quest.Progress.splice(1 + ChainStage); // remove stages past the target
const questStage = quest.Progress[ChainStage];
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (questStage) {
const run = quest.Progress[0].c;
if (run >= 0) {
questStage.c = run - 1;
}
}
};
@ -149,7 +144,6 @@ export const addQuestKey = (
export const completeQuest = async (
inventory: TInventoryDatabaseDocument,
questKey: string,
buildLabel: string | undefined,
sendMessages: boolean = false
): Promise<void | IQuestKeyClient> => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@ -198,8 +192,7 @@ export const completeQuest = async (
if (stage.c <= run) {
stage.c = run;
await giveKeyChainStageTriggered(inventory, { KeyChain: questKey, ChainStage: i }, sendMessages);
await giveKeyChainMissionReward(inventory, { KeyChain: questKey, ChainStage: i }, buildLabel);
await installShipFeatures(inventory, { KeyChain: questKey, ChainStage: i }, buildLabel);
await giveKeyChainMissionReward(inventory, { KeyChain: questKey, ChainStage: i });
}
}
@ -336,9 +329,6 @@ const handleQuestCompletion = async (
logger.debug(`quest completion items`, questCompletionItems);
if (questCompletionItems) {
await addItems(inventory, questCompletionItems, inventoryChanges);
for (const item of questCompletionItems) {
await removeRequiredItems(inventory, item.ItemType);
}
}
};
@ -388,12 +378,7 @@ export const giveKeyChainMessage = async (
await createMessage(inventory.accountOwnerId, [keyChainMessage]);
} else {
if (keyChainMessage.countedAtt?.length) await addItems(inventory, keyChainMessage.countedAtt);
if (keyChainMessage.att?.length) {
await addItems(inventory, keyChainMessage.att);
for (const reward of keyChainMessage.att) {
await removeRequiredItems(inventory, reward);
}
}
if (keyChainMessage.att?.length) await addItems(inventory, keyChainMessage.att);
}
updateQuestStage(inventory, keyChainInfo, { m: true });
@ -401,8 +386,7 @@ export const giveKeyChainMessage = async (
export const giveKeyChainMissionReward = async (
inventory: TInventoryDatabaseDocument,
keyChainInfo: IKeyChainRequest,
buildLabel: string | undefined
keyChainInfo: IKeyChainRequest
): Promise<void> => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const chainStages = ExportKeys[keyChainInfo.KeyChain]?.chainStages;
@ -411,7 +395,7 @@ export const giveKeyChainMissionReward = async (
const missionName = chainStages[keyChainInfo.ChainStage].key;
const questKey = inventory.QuestKeys.find(q => q.ItemType === keyChainInfo.KeyChain);
if (missionName && questKey) {
const fixedLevelRewards = getLevelKeyRewards(missionName, buildLabel);
const fixedLevelRewards = getLevelKeyRewards(missionName);
const run = questKey.Progress?.[0]?.c ?? 0;
if (fixedLevelRewards.levelKeyRewards) {
const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
@ -419,7 +403,6 @@ export const giveKeyChainMissionReward = async (
for (const reward of missionRewards) {
await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
await removeRequiredItems(inventory, fromStoreItem(reward.StoreItem));
}
updateQuestStage(inventory, keyChainInfo, { c: run });
@ -433,7 +416,6 @@ export const giveKeyChainMissionReward = async (
await addItem(inventory, fromStoreItem(reward.itemType), reward.amount);
} else {
await addItem(inventory, fromStoreItem(reward.itemType));
await removeRequiredItems(inventory, fromStoreItem(reward.itemType));
}
}
@ -462,338 +444,3 @@ export const giveKeyChainStageTriggered = async (
}
}
};
export const installShipFeatures = async (
inventory: TInventoryDatabaseDocument,
keyChainInfo: IKeyChainRequest,
buildLabel: string | undefined
): Promise<void> => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const chainStages = ExportKeys[keyChainInfo.KeyChain]?.chainStages;
const questKey = inventory.QuestKeys.find(qk => qk.ItemType === keyChainInfo.KeyChain);
if (chainStages && questKey) {
if (keyChainInfo.ChainStage - 1 >= 0) {
const prevStage = chainStages[keyChainInfo.ChainStage - 1];
for (const item of prevStage.itemsToGiveWhenTriggered) {
if (item.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")) {
logger.debug(`installing ship feature ${fromStoreItem(item)}`);
await unlockShipFeature(inventory, fromStoreItem(item));
}
}
if (prevStage.key) {
const fixedLevelRewards = getLevelKeyRewards(prevStage.key, buildLabel);
if (fixedLevelRewards.levelKeyRewards?.items) {
for (const item of fixedLevelRewards.levelKeyRewards.items) {
if (item.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")) {
logger.debug(`installing ship feature ${fromStoreItem(item)}`);
await unlockShipFeature(inventory, fromStoreItem(item));
}
}
}
if (fixedLevelRewards.levelKeyRewards2) {
for (const item of fixedLevelRewards.levelKeyRewards2) {
if (
item.rewardType == "RT_STORE_ITEM" &&
item.itemType.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")
) {
logger.debug(`installing ship feature ${fromStoreItem(item.itemType)}`);
await unlockShipFeature(inventory, fromStoreItem(item.itemType));
}
}
}
}
}
}
};
export const removeRequiredItems = async (inventory: TInventoryDatabaseDocument, typeName: string): Promise<void> => {
switch (typeName) {
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianHelmetBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboHelmetKeyBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
}
}
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianSystemsBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboSystemsKeyBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
}
}
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianChassisBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboChassisKeyBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
}
}
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/BrawlerBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Recipes/Components/InfestedIrradiatedBaitBallBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
await addItem(inventory, recipe.resultType, -1, false, undefined, undefined, true);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
}
}
break;
}
case "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
await addItems(inventory, [
{
ItemType:
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingWingsBlueprint",
ItemCount: -1
},
{
ItemType:
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingChassisBlueprint",
ItemCount: -1
},
{
ItemType:
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingSystemsBlueprint",
ItemCount: -1
}
]);
}
}
break;
}
case "/Lotus/Types/Keys/ModQuest/ModQuestKeyChain": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Recipes/Components/VorBoltRemoverBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
}
}
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/ChromaBlueprint": {
await addItems(inventory, [
{
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconABlueprint",
ItemCount: -1
},
{
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconBBlueprint",
ItemCount: -1
},
{
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconCBlueprint",
ItemCount: -1
}
]);
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/OctaviaBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Keys/BardQuest/BardQuestSequencerBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
await addItems(inventory, [
{
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartA",
ItemCount: -1
},
{
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartB",
ItemCount: -1
},
{
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartC",
ItemCount: -1
}
]);
}
}
break;
}
case "/Lotus/Types/Game/CrewShip/Ships/RailJack": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Recipes/Railjack/RailjackCephalonBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
await unlockShipFeature(inventory, recipe.resultType);
}
}
break;
}
case "/Lotus/Types/Items/ShipDecos/MummyQuestVessel": {
const gearItem = inventory.Consumables.find(
i => i.ItemType == "/Lotus/Types/Keys/MummyQuest/MummyArtifact01GearItem"
);
if (gearItem && gearItem.ItemCount > 0) {
await addItem(inventory, gearItem.ItemType, gearItem.ItemCount * -1);
}
break;
}
case "/Lotus/Types/Recipes/WarframeRecipes/ConcreteFrameBlueprint": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Gameplay/EntratiLab/Quest/GargoyleRecipeItem"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
await addItem(inventory, recipe.resultType);
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
}
}
break;
}
case "/Lotus/Upgrades/Skins/Umbra/UmbraAltHelmet": {
const recipeItem = inventory.Recipes.find(
i => i.ItemType == "/Lotus/Types/Recipes/WarframeRecipes/ExcaliburUmbraBlueprint"
);
if (recipeItem && recipeItem.ItemCount > 0) {
const recipe = ExportRecipes[recipeItem.ItemType];
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
const umbraModA = (
await addItem(
inventory,
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModA",
1,
false,
undefined,
`{"lvl":5}`
)
).Upgrades![0];
const umbraModB = (
await addItem(
inventory,
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModB",
1,
false,
undefined,
`{"lvl":5}`
)
).Upgrades![0];
const umbraModC = (
await addItem(
inventory,
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModC",
1,
false,
undefined,
`{"lvl":5}`
)
).Upgrades![0];
const sacrificeModA = (
await addItem(
inventory,
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModA",
1,
false,
undefined,
`{"lvl":5}`
)
).Upgrades![0];
const sacrificeModB = (
await addItem(
inventory,
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModB",
1,
false,
undefined,
`{"lvl":5}`
)
).Upgrades![0];
await addPowerSuit(inventory, "/Lotus/Powersuits/Excalibur/ExcaliburUmbra", {
Configs: [
{
Upgrades: [
"",
"",
"",
"",
"",
umbraModA.ItemId.$oid,
umbraModB.ItemId.$oid,
umbraModC.ItemId.$oid
]
}
],
XP: 900_000,
Features: EquipmentFeatures.DOUBLE_CAPACITY
});
inventory.XPInfo.push({
ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
XP: 900_000
});
addEquipment(inventory, "Melee", "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana", {
Configs: [
{
Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid]
}
],
XP: 450_000,
Features: EquipmentFeatures.DOUBLE_CAPACITY
});
inventory.XPInfo.push({
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
XP: 450_000
});
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
}
}
break;
}
default:
break;
}
};

View File

@ -12,8 +12,8 @@ let httpServer: http.Server | undefined;
let httpsServer: https.Server | undefined;
const tlsOptions = {
key: fs.readFileSync("static/cert/key.pem"),
cert: fs.readFileSync("static/cert/cert.pem")
key: fs.readFileSync("static/certs/key.pem"),
cert: fs.readFileSync("static/certs/cert.pem")
};
export const startWebServer = (): void => {

View File

@ -10,7 +10,7 @@ import invasionNodes from "../../static/fixed_responses/worldState/invasionNodes
import invasionRewards from "../../static/fixed_responses/worldState/invasionRewards.json" with { type: "json" };
import pvpChallenges from "../../static/fixed_responses/worldState/pvpChallenges.json" with { type: "json" };
import { buildConfig } from "./buildConfigService.ts";
import { EPOCH, unixTimesInMs } from "../constants/timeConstants.ts";
import { unixTimesInMs } from "../constants/timeConstants.ts";
import { config } from "./configService.ts";
import { getRandomElement, getRandomInt, sequentiallyUniqueRandomElement, SRng } from "./rngService.ts";
import type { IMissionReward, IRegion, TFaction } from "warframe-public-export-plus";
@ -41,7 +41,6 @@ import type {
import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers.ts";
import { logger } from "../utils/logger.ts";
import { DailyDeal, Fissure } from "../models/worldStateModel.ts";
import { getConquest } from "./conquestService.ts";
const sortieBosses = [
"SORTIE_BOSS_HYENA",
@ -277,6 +276,8 @@ const microplanetEndlessJobs: readonly string[] = [
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty"
];
export 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;
};
@ -3181,7 +3182,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
// Nightwave Challenges
const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
if (nightwaveSyndicateTag) {
const nightwaveStartTimestamp = nightwaveTagToActivation[nightwaveSyndicateTag] ?? 1747851300000;
const nightwaveStartTimestamp = 1747851300000;
const nightwaveSeason = nightwaveTagToSeason[nightwaveSyndicateTag];
worldState.SeasonInfo = {
Activation: { $date: { $numberLong: nightwaveStartTimestamp.toString() } },
@ -3468,18 +3469,6 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
}
}
// 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);
}
// 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);
@ -3562,18 +3551,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
}
if (!buildLabel || version_compare(buildLabel, "2025.10.14.16.10") >= 0) {
worldState.Conquests = [];
{
const season = (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[week % 4];
worldState.Conquests.push(getConquest("CT_LAB", week, null));
worldState.Conquests.push(getConquest("CT_HEX", week, season));
}
if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) {
const season = (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[(week + 1) % 4];
worldState.Conquests.push(getConquest("CT_LAB", week, null));
worldState.Conquests.push(getConquest("CT_HEX", week, season));
}
// 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
@ -3822,10 +3809,6 @@ const nightwaveTagToSeason: Record<string, number> = {
RadioLegionSyndicate: 0 // The Wolf of Saturn Six
};
const nightwaveTagToActivation: Record<string, number> = {
RadioLegionIntermission14Syndicate: 1761589199000
};
const updateFissures = async (): Promise<void> => {
const fissures = await Fissure.find();

View File

@ -14,7 +14,6 @@ import type { IOrbiterClient } from "../personalRoomsTypes.ts";
import type { ICountedStoreItem } from "warframe-public-export-plus";
import type { IEquipmentClient, IEquipmentDatabase, ITraits } from "../equipmentTypes.ts";
import type { ILoadOutPresets } from "../saveLoadoutTypes.ts";
import type { CalendarSeasonType } from "../worldStateTypes.ts";
export type InventoryDatabaseEquipment = {
[_ in TEquipmentKey]: IEquipmentDatabase[];
@ -1181,7 +1180,7 @@ export interface IMarker {
}
export interface ISeasonProgress {
SeasonType: CalendarSeasonType;
SeasonType: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
LastCompletedDayIdx: number;
LastCompletedChallengeDayIdx: number;
ActivatedChallenges: string[];

View File

@ -55,8 +55,6 @@ export interface ILoginResponse extends IAccountAndLoginResponseCommons {
DTLS?: number;
IRC?: string[];
HUB?: string;
NatHash?: string;
SteamId?: string;
}
export interface IGroup {

View File

@ -32,7 +32,6 @@ export interface IWorldState {
ActiveChallenges: ISeasonChallenge[];
};
KnownCalendarSeasons: ICalendarSeason[];
Conquests?: IConquest[];
Tmp?: string;
}
@ -353,11 +352,10 @@ export interface ISeasonChallenge {
Challenge: string;
}
export type CalendarSeasonType = "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
export interface ICalendarSeason {
Activation: IMongoDate;
Expiry: IMongoDate;
Season: CalendarSeasonType;
Season: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
Days: ICalendarDay[];
YearIteration: number;
Version: number;
@ -418,33 +416,6 @@ export interface IGameMarketCategory {
Items?: string[];
}
// >= 40.0.0
export type TConquestType = "CT_LAB" | "CT_HEX";
export interface IConquest {
Activation: IMongoDate;
Expiry: IMongoDate;
Type: TConquestType;
Missions: IConquestMission[];
Variables: [string, string, string, string];
RandomSeed: number;
}
export interface IConquestMission {
faction: TFaction;
missionType: TMissionType;
difficulties: [
{
type: "CD_NORMAL";
deviation: string;
risks: [string];
},
{
type: "CD_HARD";
deviation: string;
risks: [string, string];
}
];
}
export interface ITmp {
cavabegin: string;
PurchasePlatformLockEnabled: boolean; // Seems unused
@ -452,8 +423,6 @@ export interface ITmp {
ennnd?: boolean; // True if 1999 demo is available (no effect for >=38.6.0)
mbrt?: boolean; // Related to mobile app rating request
fbst: IFbst;
lqo?: IConquestOverride;
hqo?: IConquestOverride;
sfn: number;
edg?: TCircuitGameMode[]; // The Circuit game modes overwrite
}
@ -482,12 +451,3 @@ interface IFbst {
e: number;
n: number;
}
// < 40.0.0
interface IConquestOverride {
mt?: string[]; // mission types but "Exterminate" instead of "MT_EXTERMINATION", etc. and "DualDefense" instead of "Defense" for hex conquest
mv?: string[];
mf?: number[]; // hex conquest only
c?: [string, string][];
fv?: string[];
}

View File

@ -1,70 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIF/DCCBGSgAwIBAgIQH1nGumKdC869SnXDdjpRizANBgkqhkiG9w0BAQsFADBg
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
Ey5TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gQ0EgRFYgUjM2
MB4XDTI1MTAzMTAwMDAwMFoXDTI2MDMwNjIzNTk1OVowGDEWMBQGA1UEAwwNKi5m
YWtldGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZt+8pe
ZABBMSORWDlJBKykSbbNeEX2vPNrsQBqa3aBzQLdp6dm8qw099a5mn/vuQzdtFhc
QbaemxoVViszzM3dpTlOgLyl2r4cr8KMXJ/rRMqLeaYks+BVYJyxKAlVIduJCpP+
cxYUIiz+zNGMucuFdanzeNfCRhakDkzHH/LKZFYDHeqdR8vdUnOH8n9xuGR7sC6I
PbfML8SXCnazMpcPAeIFzJeZW3fbFIQ5R6B7X38k9+wUzKXrJo0+Q8U1mIAsV7fh
4gn+xgrFOJ7T2Vd8EtHgnr5nzNRDk4prE+ecTxBveL4QGuNoPaABtor6OLBR54AQ
8ycj29lQ094BrJcCAwEAAaOCAngwggJ0MB8GA1UdIwQYMBaAFGjAEhYYDq/O9oem
MlejRlFdywcnMB0GA1UdDgQWBBRqYi9dBjbiV9wE6GEtzyzUM6cQmjAOBgNVHQ8B
Af8EBAMCBaAwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATBJBgNV
HSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2Vj
dGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEEeDB2ME8GCCsGAQUF
BzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNTZXJ2ZXJB
dXRoZW50aWNhdGlvbkNBRFZSMzYuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz
cC5zZWN0aWdvLmNvbTAlBgNVHREEHjAcgg0qLmZha2V0bHMuY29tggtmYWtldGxz
LmNvbTCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AJaXZL9VWJet90OHaDcIQnfp
8DrV9qTzNm5GpD8PyqnGAAABmjqerq4AAAQDAEcwRQIgY1YdLRDkbq9U9qGLpX5M
IESNpCLFKVgoPLyNQQejtPUCIQCGlFB13fGO7GpVZLXyuOrXIWRZQUxnm1GqhvOP
BoovPgB2ANFuqaVoB35mNaA/N6XdvAOlPEESFNSIGPXpMbMjy5UEAAABmjqerwkA
AAQDAEcwRQIhAMxyLWnCpof354KMPYiWQmqd+2D+yyV5ZL7rmvIJw0ojAiAxxsid
se3hTmdo39MJLKyVqlZKUua5dmLckUYUImsogTANBgkqhkiG9w0BAQsFAAOCAYEA
ByJlO00LMIgL6d5xfouZHl1OL2w0DDiWHQa87BM9AqUFSgE1IsWyUAMTVoxNp3bM
c4fiBoJ9P32hDft2gJRCtJ+xOlU9ufQqCfpN9pBxe8eEldJdnHi7q9Y1dIVwRA+y
xY2r1xgTmjYgv1Uo5mQoOjgvrRdUNTyW0Rkp9+9zr6NFxi4orqypt4KKOFY2DlV9
wKmS4HPXSNR6QEylUR1+IsCP7iQzgTcZDYYLH2vAekJ1vFJkxZyB8a1vjuUxohPi
JoXnOqBu5T9JdE81/Rm01bHQ6XAiAHpQRCyZZ3TBUgpPd10DrV8K/gMuBduKOkgk
BnwNZjOCcCwgI66F5kmoeT95ovn8ApKO9aT3EfYXx3XM+xaWjEQRpXulB9AYjQvg
wxdW+cpHAa/ttPEnrb4y2Az4uYMM2016U5p1o6SP3/feGbWSsJ33OF4VvSaS1x0h
DgzfqIX4/8yeYsfNNsoSpcwV9UGBZ7Zs0Avy1Mm5ah0Z6CGGKVWb7Qqse1YR9MSa
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGTDCCBDSgAwIBAgIQOXpmzCdWNi4NqofKbqvjsTANBgkqhkiG9w0BAQwFADBf
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
HhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5WjBgMQswCQYDVQQGEwJHQjEY
MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFB1Ymxp
YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gQ0EgRFYgUjM2MIIBojANBgkqhkiG9w0B
AQEFAAOCAY8AMIIBigKCAYEAljZf2HIz7+SPUPQCQObZYcrxLTHYdf1ZtMRe7Yeq
RPSwygz16qJ9cAWtWNTcuICc++p8Dct7zNGxCpqmEtqifO7NvuB5dEVexXn9RFFH
12Hm+NtPRQgXIFjx6MSJcNWuVO3XGE57L1mHlcQYj+g4hny90aFh2SCZCDEVkAja
EMMfYPKuCjHuuF+bzHFb/9gV8P9+ekcHENF2nR1efGWSKwnfG5RawlkaQDpRtZTm
M64TIsv/r7cyFO4nSjs1jLdXYdz5q3a4L0NoabZfbdxVb+CUEHfB0bpulZQtH1Rv
38e/lIdP7OTTIlZh6OYL6NhxP8So0/sht/4J9mqIGxRFc0/pC8suja+wcIUna0HB
pXKfXTKpzgis+zmXDL06ASJf5E4A2/m+Hp6b84sfPAwQ766rI65mh50S0Di9E3Pn
2WcaJc+PILsBmYpgtmgWTR9eV9otfKRUBfzHUHcVgarub/XluEpRlTtZudU5xbFN
xx/DgMrXLUAPaI60fZ6wA+PTAgMBAAGjggGBMIIBfTAfBgNVHSMEGDAWgBRWc1hk
lfmSGrASKgRieaFAFYghSTAdBgNVHQ4EFgQUaMASFhgOr872h6YyV6NGUV3LBycw
DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEw
VAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdv
UHVibGljU2VydmVyQXV0aGVudGljYXRpb25Sb290UjQ2LmNybDCBhAYIKwYBBQUH
AQEEeDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3Rp
Z29QdWJsaWNTZXJ2ZXJBdXRoZW50aWNhdGlvblJvb3RSNDYucDdjMCMGCCsGAQUF
BzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA
YtOC9Fy+TqECFw40IospI92kLGgoSZGPOSQXMBqmsGWZUQ7rux7cj1du6d9rD6C8
ze1B2eQjkrGkIL/OF1s7vSmgYVafsRoZd/IHUrkoQvX8FZwUsmPu7amgBfaY3g+d
q1x0jNGKb6I6Bzdl6LgMD9qxp+3i7GQOnd9J8LFSietY6Z4jUBzVoOoz8iAU84OF
h2HhAuiPw1ai0VnY38RTI+8kepGWVfGxfBWzwH9uIjeooIeaosVFvE8cmYUB4TSH
5dUyD0jHct2+8ceKEtIoFU/FfHq/mDaVnvcDCZXtIgitdMFQdMZaVehmObyhRdDD
4NQCs0gaI9AAgFj4L9QtkARzhQLNyRf87Kln+YU0lgCGr9HLg3rGO8q+Y4ppLsOd
unQZ6ZxPNGIfOApbPVf5hCe58EZwiWdHIMn9lPP6+F404y8NNugbQixBber+x536
WrZhFZLjEkhp7fFXf9r32rNPfb74X/U90Bdy4lzp3+X1ukh1BuMxA/EEhDoTOS3l
7ABvc7BYSQubQ2490OcdkIzUh3ZwDrakMVrbaTxUM2p24N6dB+ns2zptWCva6jzW
r8IWKIMxzxLPv5Kt3ePKcUdvkBU/smqujSczTzzSjIoR5QqQA6lN1ZRSnuHIWCvh
JEltkYnTAH41QJ6SAWO66GrrUESwN/cgZzL4JLEqz1Y=
-----END CERTIFICATE-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmbfvKXmQAQTEj
kVg5SQSspEm2zXhF9rzza7EAamt2gc0C3aenZvKsNPfWuZp/77kM3bRYXEG2npsa
FVYrM8zN3aU5ToC8pdq+HK/CjFyf60TKi3mmJLPgVWCcsSgJVSHbiQqT/nMWFCIs
/szRjLnLhXWp83jXwkYWpA5Mxx/yymRWAx3qnUfL3VJzh/J/cbhke7AuiD23zC/E
lwp2szKXDwHiBcyXmVt32xSEOUege19/JPfsFMyl6yaNPkPFNZiALFe34eIJ/sYK
xTie09lXfBLR4J6+Z8zUQ5OKaxPnnE8Qb3i+EBrjaD2gAbaK+jiwUeeAEPMnI9vZ
UNPeAayXAgMBAAECggEAOYwMJVRwFZp1KExIij5STHPePURc0yxW94CESpWBpQ+K
2PPV1c+GF7+U9v1ki9pTTTyX8HmuCzxaezFngza9GW4LhH49i3153oTCzW2FVZKf
Tb3eiXFldStwZZ3oLxntxCBltPilyLubeZ19KvQTBmmWXvaeEVTOsWN2wluUE3oT
QEEFJmvWSj6Ow5HwA2xZP5dD4gv7nCY1swTePVLgWtJDC3AWDmKv3mB28brmtaDw
wP/Oq9LLlHJDK+AzJEuUs+VDFQi7j6yqXWglSjO3Jwkkfkqg/SSoZ9BKdd6i0DLs
UnUWHHATpv0Lwsa7w8csQBwfskUxsXECZpwzpCgsIQKBgQDYl2wvwjjG6qZtr060
rj4PDkFLxFbtlmBiyW9ShM6iqK6FWQJJ1FNr6MdM2zBqw+n4tldpU3DnuZQphgZK
57jejWFsHH5DYkS8k0k021AYT2IyCFHoEF43LlbRDXQguw1fADnoy6FpJBaRzuxx
jPEHdB/aYqngmTXglFYkizN2BwKBgQDEthR1FV5iPdQXKSR+Yu2irBzpxY1xhdd2
V5082etd2vBvAT7e4k8MroNMuYqL8miu2SeTJEyNkpCVoxQPF4uavandoRuEFIZl
8VPVvG5xqYIqXAJ4XlSImEgUww+jJfyLzHT0TZi6rrdHV/8zUXEimjc6OBZVafDg
FP6Lqo/w8QKBgQCxx3B8rv3tgDNFOqzur0qvDvNXnnv/nfvVeiPO5sW5S52cRJgV
Q5uJqlLUaeGO8Oo+RGTxRhUZjwDnKGRH3XWn7wI1PBoDc0iaRIbFRPK0UYx3Js8c
HTtILdgC1fko2IA8JzJhO6tsYrvHyMHY3mgExzNSDMQFX5ySjw86BawixwKBgBGc
J0qwBgoPdOw53618179HXzNCXz45eCd9AnOPIrX9Qqb9Wo6DfgYpnVGCDrgmlF6K
zDMs/bly1ITA26vaNMI+lnVj1d3GJJ39s76fpteAEEoQgJwb/b9YuqM5Ly4w2WH+
hL3WMIUN3RSC+TKz6MfrPGR23vD4kfrNhlgkhcxRAoGAEb6nXwyWe5hg9+qE2fcf
W27VApoalmnDOGFHtGhUitbBw7mHPb6wsSh4mx5Ucccfb5WUO3Cq5aW3qsDdkM+a
YrBDbvw7PPcAX0vokpyFQvHH35AsIXQuYlQyGzcCdZkpFPIB5gVbLvbgxpBvEbVZ
mGJpw7X/6Pg0ux0Ze11cr2c=
-----END PRIVATE KEY-----

71
static/certs/cert.pem Normal file
View File

@ -0,0 +1,71 @@
-----BEGIN CERTIFICATE-----
MIIGMDCCBRigAwIBAgIQX4800cgswlDH/QexMSnnnjANBgkqhkiG9w0BAQsFADCB
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
MB4XDTI1MDMwNjAwMDAwMFoXDTI2MDMwNjIzNTk1OVowGDEWMBQGA1UEAwwNKi5m
YWtldGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMe42XWK
HJuR7doFTX79zrEKfTlD2hjRIif3dHKJNTJNvZa52mIoHelP7RVUuFOhp7aZCNLh
IEzDyZObl8vwO6L2PVu5tbBEEoNixbpfhc8ZICEBuVo2UAhnJFcMJtuvtrCq+7ye
oczM/k/nh8FBz2WnLzWs4CZt1sa5knZXFmBmsHJQtQIC6vx7QzVcKGOlAosIEHSK
X4nIz5fLgWSzor1Gay56j31PTk+qRvlPQM2aKiLWnlLfRED4zHJqLe94itu8llPX
b6g+cLxxRKUpMqtG/15cDdBZwv40Dja7bmNfe1u4w2QCVLjvHVaVpNXbcRay/Mhn
M1w5LzDZmV58b18CAwEAAaOCAvwwggL4MB8GA1UdIwQYMBaAFI2MXsRUrYrhd+mb
+ZsF4bgBjWHhMB0GA1UdDgQWBBS6/x/N38wMJrQq/cE1oIcRERMonTAOBgNVHQ8B
Af8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
BQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICBzAlMCMGCCsGAQUFBwIBFhdo
dHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEwgYQGCCsGAQUFBwEBBHgw
djBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNB
RG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEFBQcwAYYX
aHR0cDovL29jc3Auc2VjdGlnby5jb20wJQYDVR0RBB4wHIINKi5mYWtldGxzLmNv
bYILZmFrZXRscy5jb20wggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AJaXZL9V
WJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnGAAABlWsz5fgAAAQDAEcwRQIgTN7Y
/mDqiD3RbGVLEOQK2wvXsboBolBRwGJFuFEsDScCIQCQ0qfb/0V8qqSxrkx/PiVS
1lSn5gBEnQUiQOkefcnW0gB2ABmG1Mcoqm/+ugNveCpNAZGqzi1yMQ+uzl1wQS0l
TMfUAAABlWsz5dAAAAQDAEcwRQIhAJnQJyrSCWWdi9Kyoa7XuMGyDKt183jJMY0E
71abTuBOAiBC+WnK1esG6xr8aVGHRcc+1U/I7LiaG3LCRMYtCKrTGwB2AMs49xWJ
fIShRF9bwd37yW7ymlnNRwppBYWwyxTDFFjnAAABlWsz5f4AAAQDAEcwRQIhAJUs
4PWDwyQJnCxCyEwFlFUY2uYQkGrQPA9f9Sw5Xk1fAiB63eQtZQGjvzvhOghy6z9a
8oGYbDfDQ/zfisMYO7rM6zANBgkqhkiG9w0BAQsFAAOCAQEAEHnSoeBbWiK3CS3a
px0BL+YXxRxdUcTMHgn5o+LlI9sWlpf+JLXmn7Z4QA6fAwT4k/Ue7xsmIq0OraDk
/pEVXWm1HO/9wUkGQg0DBi77BpfHircd7OWIMdt250Q8UAmZkOyhVgnwBcScqMwq
2T5CPaYvYGgYWx/qkIBv7JqhVbrP82rnF9b9ZUZ8GIE31chBmtMva9AsnAN5dmRw
81bVvPWXUfX30CYu5sxeWL06Zpy9nfJumxZri1SWXNTBjSvud2jsZ8tSCUAWLL/4
ui3Vien9m2oMOpaA8xbS88ZTk9Alm/o5febEKJZUPlytQzij8gQpiovFw2v+Cdei
+tFXKw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
-----END CERTIFICATE-----

28
static/certs/key.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHuNl1ihybke3a
BU1+/c6xCn05Q9oY0SIn93RyiTUyTb2WudpiKB3pT+0VVLhToae2mQjS4SBMw8mT
m5fL8Dui9j1bubWwRBKDYsW6X4XPGSAhAblaNlAIZyRXDCbbr7awqvu8nqHMzP5P
54fBQc9lpy81rOAmbdbGuZJ2VxZgZrByULUCAur8e0M1XChjpQKLCBB0il+JyM+X
y4Fks6K9Rmsueo99T05Pqkb5T0DNmioi1p5S30RA+Mxyai3veIrbvJZT12+oPnC8
cUSlKTKrRv9eXA3QWcL+NA42u25jX3tbuMNkAlS47x1WlaTV23EWsvzIZzNcOS8w
2ZlefG9fAgMBAAECggEAT1Tti/LASks8300b60WFxG0WMJjzGMh5eMaiSpyVtNWM
aUKJrFOjDfnhgoeUcCPWKoG/L4Sc/+EFQMydDzTte120IasysEFZ2TZytAUdcZXZ
XUMCDQNl5vCRTsJU7Q5u0t4YAGRCgMcsfTDKi8lISGiQKBHzN1CJ74Xm13rgOInd
lAc0wd5S89sL6RYmRTj1LvuZ95EHXHqQGdv0fIFEyP3pF1iPwcoTuIVEeICqnEvW
vd8CVO68eH3HFIwioqjp4qW3pxPZMhVq4161805uAMkoQlE+7MtEVenmP++1u1gM
FjvAs3j9CZqOHZKcLlOtcGSwDlD++fCMMT4slLgLgQKBgQDy58E5nuYXdxlFQQk4
QccUKpyJ2aVXyp9xvTFBot/5Pik1SkuDzv2XU1OTxdxf3EongLy91nMJ2/6/39Je
lf0/2MjzCtJ/lSzZ/zpJAu86UkBkWBAA5loGIof6OKedbEIgqpJqtK59S+j3ExO9
eqa+uFrtt1UfaJG4A7TT+dIvIwKBgQDSfSOdSM5Dh3KsQHVnIWcIkzwTtlJlO+rG
6rDEADxw6Kp8VIL/dq4Foe8yW4VqLVrWUuZsU6jzC9GdnyYi6VaqZ/iSUtGkBMOT
WTTYhqXlURaQ13jhqdwCZJRbVI72JbXn2OGEv8DgXnk//QKED/8VdKqAzCSr1t1f
3yfwei0AlQKBgD19KU66yKg7/+umEP1quUiDmOjUbaSRqFcUe3mQD356m9ffnMob
BdrevxNzTNv/Wc4yKpUryic+x3gu4oQLF/annAbaQHsHejkdANYmpgRvedls6XAw
360Z5K4U1WlmVD8Mrs/QOTOCmdChxad7euZgqLPwat3ujKS2W3oljW1dAoGBAM4/
AB6lsDZLCfnuTxt2h1bHrh5CkAnR5AJ1BC+Ja6/WyvZ4eMOIroumWJKnStr3BgLr
yAxtDSbZddNUljGvIdRnfBEkRXbJlDlVN4rSpMtF4S6bcz7rCUDu/M9g05Qs70j2
IkPJAFzZNUWVzFlKs096uXbqkSQvrUq7ho8DqAThAoGBAL7Nrbr5LWcBgvwEhEla
VRfYb0FUrDwLIrVWntJjW566/pVQQ4BmatsblLjlQYWk9MCIYXWZbnB+2fRx9yjQ
Adggez7Dws/Mrh/wVudKgayHCy5Lgd8rYjNgC+VZf8XGrWX3QXMJ6UWAyQLTeoO7
hToW9o9CQMIhaR43G8di1kjF
-----END PRIVATE KEY-----

View File

@ -1,165 +0,0 @@
{
"/Lotus/Types/Keys/VorsPrize/MissionOne": [
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Types/Items/ShipFeatureItems/SocialMenuFeatureItem"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponMeleeDamageMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponDamageAmountMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Pistol/WeaponDamageAmountMod"
},
{
"rewardType": "RT_CREDITS",
"amount": 2500
}
],
"/Lotus/Types/Keys/VorsPrize/MissionTwo": [
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Types/Items/ShipFeatureItems/ModsFeatureItem"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarHealthMaxMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarShieldMaxMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarAbilityRangeMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarAbilityStrengthMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarAbilityDurationMod"
},
{
"rewardType": "RT_CREDITS",
"amount": 2500
}
],
"/Lotus/Types/Keys/VorsPrize/MissionThree": {
"name": "/Lotus/Language/G1Quests/VorsPrize3",
"parentName": "/Lotus/Types/Keys/TestKeyA",
"codexSecret": true,
"rewards": [
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Types/Items/ShipFeatureItems/FoundryFeatureItem"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponFireRateMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponFactionDamageCorpus"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponFactionDamageGrineer"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Pistol/WeaponFireDamageMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Pistol/WeaponElectricityDamageMod"
},
{
"rewardType": "RT_CREDITS",
"amount": 2500
}
]
},
"/Lotus/Types/Keys/VorsPrize/MissionFour": [
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarPickupBonusMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarPowerMaxMod"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarEnemyRadarMod"
},
{
"rewardType": "RT_CREDITS",
"amount": 2500
}
],
"/Lotus/Types/Keys/VorsPrize/MissionFive": [
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_STORE_ITEM",
"itemType": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CommonFusionBundle"
},
{
"rewardType": "RT_CREDITS",
"amount": 5000
}
]
}

View File

@ -1152,7 +1152,7 @@
<button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
<button class="btn btn-primary" onclick="debounce(addMissingHelminthRecipes);" data-loc="cheats_addMissingSubsumedAbilities"></button>
<button class="btn btn-primary" onclick="doIntrinsicsUnlockAll();" data-loc="cheats_intrinsicsUnlockAll"></button>
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="cheats_maxPlexus"></button>
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="inventory_maxPlexus"></button>
<button class="btn btn-primary" onclick="debounce(unlockAllProfitTakerStages);" data-loc="cheats_unlockAllProfitTakerStages"></button>
<button class="btn btn-primary" onclick="debounce(unlockAllSimarisResearchEntries);" data-loc="cheats_unlockAllSimarisResearchEntries"></button>
</div>

View File

@ -169,7 +169,6 @@ function renameAccount(taken_name) {
} else {
$(".displayname").text(newname);
updateLocElements();
toast(loc("code_succRelog"));
}
});
});
@ -647,7 +646,7 @@ function fetchItemList() {
if ("badReason" in item) {
if (item.badReason == "starter") {
item.name = loc("code_starter").split("|MOD|").join(item.name);
} else if (item.badReason != "notraw") {
} else {
item.name += " " + loc("code_badItem");
}
}
@ -1455,11 +1454,7 @@ function updateInventory() {
{
const td = document.createElement("td");
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
if (itemMap[item.ItemType]?.badReason == "notraw") {
// Assuming this is a riven with a pending challenge, so rank would be N/A, but otherwise it's fine.
} else {
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
}
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
tr.appendChild(td);
}
{

View File

@ -51,7 +51,7 @@ dict = {
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden.`,
code_addModsConfirm: `Bist du sicher, dass du |COUNT| Mods zu deinem Account hinzufügen möchtest?`,
code_succImport: `Erfolgreich importiert.`,
code_succRelog: `Fertig. Bitte beachte, dass du dich neu anmelden musst, damit die Änderung im Spiel sichtbar wird.`,
code_succRelog: `Fertig. Bitte beachte, dass du dich neu anmelden musst, um Änderungen im Spiel zu sehen.`,
code_nothingToDo: `Fertig. Es gab nichts zu tun.`,
code_gild: `Veredeln`,
code_moa: `Moa`,
@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
inventory_maxPlexus: `Plexus auf Max. Rang`,
inventory_removeIsNew: `Entferne Ausrufezeichen bei neuem Equipment`,
quests_list: `Quests`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
cheats_addMissingSubsumedAbilities: `Fehlende konsumierte Fähigkeiten hinzufügen`,
cheats_intrinsicsUnlockAll: `Alle Inhärenzen auf Max. Rang`,
cheats_maxPlexus: `Plexus auf Max. Rang`,
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
cheats_changeButton: `Ändern`,
cheats_markAllAsRead: `Posteingang als gelesen markieren`,

View File

@ -133,6 +133,7 @@ dict = {
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
inventory_maxPlexus: `Max Rank Plexus`,
inventory_removeIsNew: `Remove New Equipment Exclamation Icon`,
quests_list: `Quests`,
@ -258,7 +259,6 @@ dict = {
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
cheats_addMissingSubsumedAbilities: `Add Missing Subsumed Abilities`,
cheats_intrinsicsUnlockAll: `Max Rank All Intrinsics`,
cheats_maxPlexus: `Max Rank Plexus`,
cheats_changeSupportedSyndicate: `Supported syndicate`,
cheats_changeButton: `Change`,
cheats_markAllAsRead: `Mark Inbox As Read`,

View File

@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
inventory_maxPlexus: `Rango máximo de Plexus`,
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
quests_list: `Misiones`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
cheats_addMissingSubsumedAbilities: `Agregar habilidades subsumidas faltantes`,
cheats_intrinsicsUnlockAll: `Maximizar todos los intrínsecos`,
cheats_maxPlexus: `Rango máximo de Plexus`,
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
cheats_changeButton: `Cambiar`,
cheats_markAllAsRead: `Marcar bandeja de entrada como leída`,

View File

@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
inventory_maxPlexus: `Plexus au rang max`,
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
quests_list: `Quêtes`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `Helminth niveau max`,
cheats_addMissingSubsumedAbilities: `Ajouter les capacités subsumées manquantes`,
cheats_intrinsicsUnlockAll: `Inhérences niveau max`,
cheats_maxPlexus: `Plexus au rang max`,
cheats_changeSupportedSyndicate: `Allégeance`,
cheats_changeButton: `Changer`,
cheats_markAllAsRead: `Marquer la boîte de réception comme lue`,

View File

@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `Макс. ранг всех Стражей`,
inventory_bulkRankUpSentinelWeapons: `Макс. ранг всего оружия Стражей`,
inventory_bulkRankUpEvolutionProgress: `Макс. ранг всех эволюций Инкарнонов`,
inventory_maxPlexus: `Макс. ранг Плексуса`,
inventory_removeIsNew: `Удалить значок восклицательного знака нового снаряжения`,
quests_list: `Квесты`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
cheats_addMissingSubsumedAbilities: `Добавить отсутствующие поглощённые способности`,
cheats_intrinsicsUnlockAll: `Полностью улучшить Модуляры`,
cheats_maxPlexus: `Макс. ранг Плексуса`,
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
cheats_changeButton: `Изменить`,
cheats_markAllAsRead: `Пометить все входящие как прочитанные`,

View File

@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `Макс. рівень всіх Вартових`,
inventory_bulkRankUpSentinelWeapons: `Макс. рівень всієї зброї Вартових`,
inventory_bulkRankUpEvolutionProgress: `Макс. рівень всіх еволюцій Інкарнонів`,
inventory_maxPlexus: `Макс. рівень Плексу`,
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
quests_list: `Пригоди`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `Повністю покращити Гельмінта`,
cheats_addMissingSubsumedAbilities: `Додати відсутні поглинуті здібності`,
cheats_intrinsicsUnlockAll: `Повністю покращити Кваліфікації`,
cheats_maxPlexus: `Макс. рівень Плексу`,
cheats_changeSupportedSyndicate: `Підтримуваний синдикат`,
cheats_changeButton: `Змінити`,
cheats_markAllAsRead: `Помітити всі вхідні як прочитані`,

View File

@ -134,6 +134,7 @@ dict = {
inventory_bulkRankUpSentinels: `所有守护升满级`,
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
inventory_bulkRankUpEvolutionProgress: `所有灵化之源进度最大等级`,
inventory_maxPlexus: `最大深控等级`,
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
quests_list: `系列任务`,
@ -259,7 +260,6 @@ dict = {
cheats_helminthUnlockAll: `完全升级Helminth`,
cheats_addMissingSubsumedAbilities: `添加Helminth未汲取的战甲技能`,
cheats_intrinsicsUnlockAll: `所有内源之力最大等级`,
cheats_maxPlexus: `最大深控等级`,
cheats_changeSupportedSyndicate: `支持的集团`,
cheats_changeButton: `更改`,
cheats_markAllAsRead: `收件箱全部标记为已读`,