merge upstream
This commit is contained in:
commit
cfff91ca5d
@ -69,6 +69,7 @@
|
||||
"affinityBoost": false,
|
||||
"resourceBoost": false,
|
||||
"starDays": true,
|
||||
"galleonOfGhouls": 0,
|
||||
"eidolonOverride": "",
|
||||
"vallisOverride": "",
|
||||
"duviriOverride": "",
|
||||
|
80
package-lock.json
generated
80
package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/websocket": "^1.0.10",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20250625.1",
|
||||
"crc-32": "^1.2.2",
|
||||
"express": "^5",
|
||||
"json-with-bigint": "^3.4.4",
|
||||
@ -21,7 +22,7 @@
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"undici": "^7.10.0",
|
||||
"warframe-public-export-plus": "^0.5.69",
|
||||
"warframe-public-export-plus": "^0.5.71",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
@ -30,7 +31,6 @@
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20250523.1",
|
||||
"chokidar": "^4.0.3",
|
||||
"eslint": "^8",
|
||||
"eslint-plugin-prettier": "^5.2.5",
|
||||
@ -605,10 +605,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-CgdgP/gmyaMThY7Fho19nDaTVryn9QV/zD/6w1KfDCn3M4Rq4WvkSc7Ob1ohc4V1XjCSIzg6Ul+HbLEc7xvV4Q==",
|
||||
"dev": true,
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-7781zmsKURCHknc37H4U4la4kZduyxmmUshZLBzNhPHhV5DKo++K8MF69kxhRG3/vS4HBhozf0YI0mZMIbkSDA==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsgo": "bin/tsgo.js"
|
||||
@ -617,23 +616,22 @@
|
||||
"node": ">=20.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20250523.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20250523.1"
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20250625.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20250625.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-arm64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-oWJMPD+lfH9/dvHhPSZdTv43lfyZGrn7crytefhkiQPSwP0MIUCpnDkofGP/ML1nv0xx0pwWhH+Ein88NW3LuA==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-JcLCql0O6+0iHIMllvax02kqpNtY1RUckGKomuO5kSbrOo9PsR+6r5MEcspfj47gwOl7AS0vrGhBCFFogF+KGw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -644,13 +642,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-x64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-Yk8bJEsYsRKgRqYlwPvh7DPdgBMC/oPN60X0LWeuMLci65+4kyqF8Cv6K/W3ABc005cB4tYn4iR+9T6zipvrKw==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-0vCkk3FdS92W625JyzA8Slu/0vgkeu10fRQNfgIbf+E29DKMKnwXW56WhHSdGXAivU44Mewwc589+CbsABq3Sw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -661,13 +658,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-B+8CRIv6ebL8gzAagnJP8wml3baFV2FtFWuXYl6jlAcLGoQOh/yGdcAueZoJjJKNod4gAOl8OJoTicuC0BVIxw==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-MumU7p+09ikH/x5IOJRV6DUj6N5/0kSlI4IsAUPtpT2WGkQdDtL2CC523/94YvOfWB1/+9r01636LVCGOJ135g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -678,13 +674,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-IErNI08z9qE6mHaJaT6tM7il8j21ryH3DNVyFP4yz5FTKnkXFj1Kb4NcI41Q8w226LTQgBR8kNErVlbUWr7ywA==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-IgnoWQSKeoeL7Y7tvlbcDQx0nidK3UWa/bbm1zJv+AfQlAGMrEMygp+ZzocmycUCYOVM0dcIbymjoiI/QRHTng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -695,13 +690,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-x64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-TCZtknsLUgPRaEfX9CvBZNgrHhMRZPYYZgF1Aasdv0PONv9mB8w0Xforgxoo4UFjdF5ZzOu2icgc7sKJJeu5vw==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-6fE8piqPfzPPqmQ37ewTSbm4HW0cNqOEhfLG2F37zJd4525mefhIpWvj2iCkEHWp+BDlF2dYCbB4cY2nmfrNNw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -712,13 +706,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-arm64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-bulwrkLEkoY4Jqeuvfz24RiVOiZZ7Rr9TblFqZAgZFZOnyXuhjM1jE8F1hnJFC5AghJe2HdLD3EKfabqlffrIw==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-ppCkjBAFotPxL8j9Vk5cNSwMreOvAt02AMa5Hko3JQGSVA2TQCIlvTFn+SHSIWzYbzomc9j4j5WOcOR0rmAAHg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -729,13 +722,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-x64": {
|
||||
"version": "7.0.0-dev.20250523.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20250523.1.tgz",
|
||||
"integrity": "sha512-ztzfO0oF/rj8xO5y3SyAcigmgvgczrqobCugEWFqiYumteWZPN2MYWcNYk2k8Y5LAgg1fN1xHIg8RRSPoo6XUg==",
|
||||
"version": "7.0.0-dev.20250625.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20250625.1.tgz",
|
||||
"integrity": "sha512-BsnJqso5MKAW4Y7fPmcamJ+EIrWOTqwLjeZP74NNFvTqCsA4RkITCw4NpLwD0lzrv9VsQcQ+bNwB8DrT+oDqoQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@ -3396,9 +3388,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/warframe-public-export-plus": {
|
||||
"version": "0.5.69",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.69.tgz",
|
||||
"integrity": "sha512-vTU1tUzqpihzpseUSJMrM82pYbCDZCfW40jXIi+Ol9B3a3Acz0DccfP7i4eoXf7Abahu4H/sjRt/nSHLNBvLHA=="
|
||||
"version": "0.5.71",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.71.tgz",
|
||||
"integrity": "sha512-TCS2wPRsBzuURJlIMDhygAHaLsKVZ7dGuC73WZ/iMyn3gKVwA98nnaIj24D+UceWS08fwq4ilWAfUzHJd6X29A=="
|
||||
},
|
||||
"node_modules/warframe-riven-info": {
|
||||
"version": "0.1.2",
|
||||
|
10
package.json
10
package.json
@ -5,8 +5,10 @@
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
||||
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||
"build:dev": "tsc --incremental --sourceMap",
|
||||
"build": "tsgo --sourceMap && ncp static/webui build/static/webui",
|
||||
"build:tsc": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||
"build:dev": "tsgo --sourceMap",
|
||||
"build:dev:tsc": "tsc --incremental --sourceMap",
|
||||
"build-and-start": "npm run build && npm run start",
|
||||
"build-and-start:bun": "npm run verify && npm run bun-run",
|
||||
"dev": "node scripts/dev.js",
|
||||
@ -25,6 +27,7 @@
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/websocket": "^1.0.10",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20250625.1",
|
||||
"crc-32": "^1.2.2",
|
||||
"express": "^5",
|
||||
"json-with-bigint": "^3.4.4",
|
||||
@ -33,7 +36,7 @@
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"undici": "^7.10.0",
|
||||
"warframe-public-export-plus": "^0.5.69",
|
||||
"warframe-public-export-plus": "^0.5.71",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
@ -42,7 +45,6 @@
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20250523.1",
|
||||
"chokidar": "^4.0.3",
|
||||
"eslint": "^8",
|
||||
"eslint-plugin-prettier": "^5.2.5",
|
||||
|
@ -0,0 +1,35 @@
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||
import { RequestHandler } from "express";
|
||||
import { ExportChallenges } from "warframe-public-export-plus";
|
||||
|
||||
export const claimJunctionChallengeRewardController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId);
|
||||
const data = getJSONfromString<IClaimJunctionChallengeRewardRequest>(String(req.body));
|
||||
const challengeProgress = inventory.ChallengeProgress.find(x => x.Name == data.Challenge)!;
|
||||
if (challengeProgress.ReceivedJunctionReward) {
|
||||
throw new Error(`attempt to double-claim junction reward`);
|
||||
}
|
||||
challengeProgress.ReceivedJunctionReward = true;
|
||||
inventory.ClaimedJunctionChallengeRewards ??= [];
|
||||
inventory.ClaimedJunctionChallengeRewards.push(data.Challenge);
|
||||
const challengeMeta = Object.entries(ExportChallenges).find(arr => arr[0].endsWith("/" + data.Challenge))![1];
|
||||
const inventoryChanges = {};
|
||||
for (const reward of challengeMeta.countedRewards!) {
|
||||
combineInventoryChanges(
|
||||
inventoryChanges,
|
||||
(await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount)).InventoryChanges
|
||||
);
|
||||
}
|
||||
await inventory.save();
|
||||
res.json({
|
||||
inventoryChanges: inventoryChanges // Yeah, it's "inventoryChanges" in the response here.
|
||||
});
|
||||
};
|
||||
|
||||
interface IClaimJunctionChallengeRewardRequest {
|
||||
Challenge: string;
|
||||
}
|
@ -22,7 +22,8 @@ import { getNemesisManifest } from "@/src/helpers/nemesisHelpers";
|
||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||
import { Ship } from "@/src/models/shipModel";
|
||||
import { toLegacyOid, version_compare } from "@/src/helpers/inventoryHelpers";
|
||||
import { toLegacyOid, toOid, version_compare } from "@/src/helpers/inventoryHelpers";
|
||||
import { Inbox } from "@/src/models/inboxModel";
|
||||
|
||||
export const inventoryController: RequestHandler = async (request, response) => {
|
||||
const account = await getAccountForRequest(request);
|
||||
@ -128,13 +129,21 @@ export const getInventoryResponse = async (
|
||||
xpBasedLevelCapDisabled: boolean,
|
||||
buildLabel: string | undefined
|
||||
): Promise<IInventoryClient> => {
|
||||
const [inventoryWithLoadOutPresets, ships] = await Promise.all([
|
||||
const [inventoryWithLoadOutPresets, ships, latestMessage] = await Promise.all([
|
||||
inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets"),
|
||||
Ship.find({ ShipOwnerId: inventory.accountOwnerId })
|
||||
Ship.find({ ShipOwnerId: inventory.accountOwnerId }),
|
||||
Inbox.findOne({ ownerId: inventory.accountOwnerId }, "_id").sort({ date: -1 })
|
||||
]);
|
||||
const inventoryResponse = inventoryWithLoadOutPresets.toJSON<IInventoryClient>();
|
||||
inventoryResponse.Ships = ships.map(x => x.toJSON<IShipInventory>());
|
||||
|
||||
// In case mission inventory update added an inbox message, we need to send the Mailbox part so the client knows to refresh it.
|
||||
if (latestMessage) {
|
||||
inventoryResponse.Mailbox = {
|
||||
LastInboxId: toOid(latestMessage._id)
|
||||
};
|
||||
}
|
||||
|
||||
if (config.infiniteCredits) {
|
||||
inventoryResponse.RegularCredits = 999999999;
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { getInventory, addRecipes } from "@/src/services/inventoryService";
|
||||
import { RequestHandler } from "express";
|
||||
import { ExportRecipes } from "warframe-public-export-plus";
|
||||
|
||||
export const addMissingHelminthBlueprintsController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "Recipes");
|
||||
const allHelminthRecipes = Object.keys(ExportRecipes).filter(
|
||||
key => ExportRecipes[key].secretIngredientAction === "SIA_WARFRAME_ABILITY"
|
||||
);
|
||||
const inventoryHelminthRecipes = inventory.Recipes.filter(recipe =>
|
||||
recipe.ItemType.startsWith("/Lotus/Types/Recipes/AbilityOverrides/")
|
||||
).map(recipe => recipe.ItemType);
|
||||
|
||||
const missingHelminthRecipes = allHelminthRecipes
|
||||
.filter(key => !inventoryHelminthRecipes.includes(key))
|
||||
.map(ItemType => ({ ItemType, ItemCount: 1 }));
|
||||
|
||||
addRecipes(inventory, missingHelminthRecipes);
|
||||
|
||||
await inventory.save();
|
||||
res.end();
|
||||
};
|
@ -12,18 +12,24 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
|
||||
const inventory = await getInventory(accountId);
|
||||
const MissionRewards: IMissionReward[] = [];
|
||||
for (const [tag, node] of Object.entries(ExportRegions)) {
|
||||
if (!inventory.Missions.find(x => x.Tag == tag)) {
|
||||
inventory.Missions.push({
|
||||
Completes: 1,
|
||||
Tier: 1,
|
||||
Tag: tag
|
||||
});
|
||||
|
||||
let mission = inventory.Missions.find(x => x.Tag == tag);
|
||||
if (!mission) {
|
||||
mission =
|
||||
inventory.Missions[
|
||||
inventory.Missions.push({
|
||||
Completes: 0,
|
||||
Tier: 0,
|
||||
Tag: tag
|
||||
}) - 1
|
||||
];
|
||||
}
|
||||
if (mission.Completes == 0) {
|
||||
mission.Completes++;
|
||||
if (node.missionReward) {
|
||||
console.log(node.missionReward);
|
||||
addFixedLevelRewards(node.missionReward, inventory, MissionRewards);
|
||||
}
|
||||
}
|
||||
mission.Tier = 1;
|
||||
}
|
||||
for (const reward of MissionRewards) {
|
||||
await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount, undefined, true);
|
||||
|
@ -21,13 +21,14 @@ import mongoose from "mongoose";
|
||||
import { JSONStringify } from "json-with-bigint";
|
||||
import { startWebServer } from "./services/webService";
|
||||
|
||||
import { validateConfig } from "@/src/services/configWatcherService";
|
||||
import { syncConfigWithDatabase, validateConfig } from "@/src/services/configWatcherService";
|
||||
import { updateWorldStateCollections } from "./services/worldStateService";
|
||||
|
||||
// Patch JSON.stringify to work flawlessly with Bigints.
|
||||
JSON.stringify = JSONStringify;
|
||||
|
||||
validateConfig();
|
||||
syncConfigWithDatabase();
|
||||
|
||||
mongoose
|
||||
.connect(config.mongodbUrl)
|
||||
|
@ -27,11 +27,12 @@ export interface IMessage {
|
||||
icon?: string;
|
||||
highPriority?: boolean;
|
||||
lowPrioNewPlayers?: boolean;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
transmission?: string;
|
||||
att?: string[];
|
||||
countedAtt?: ITypeCount[];
|
||||
transmission?: string;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
goalTag?: string;
|
||||
CrossPlatform?: boolean;
|
||||
arg?: Arg[];
|
||||
gifts?: IGift[];
|
||||
@ -107,6 +108,7 @@ const messageSchema = new Schema<IMessageDatabase>(
|
||||
lowPrioNewPlayers: Boolean,
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
goalTag: String,
|
||||
date: { type: Date, required: true },
|
||||
r: Boolean,
|
||||
CrossPlatform: Boolean,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Document, HydratedDocument, Model, Schema, Types, model } from "mongoose";
|
||||
import { Document, Model, Schema, Types, model } from "mongoose";
|
||||
import {
|
||||
IFlavourItem,
|
||||
IRawUpgrade,
|
||||
@ -7,7 +7,6 @@ import {
|
||||
IBooster,
|
||||
IInventoryClient,
|
||||
ISlots,
|
||||
IMailboxDatabase,
|
||||
IDuviriInfo,
|
||||
IPendingRecipeDatabase,
|
||||
IPendingRecipeClient,
|
||||
@ -54,7 +53,6 @@ import {
|
||||
IUpgradeDatabase,
|
||||
ICrewShipMemberDatabase,
|
||||
ICrewShipMemberClient,
|
||||
IMailboxClient,
|
||||
TEquipmentKey,
|
||||
equipmentKeys,
|
||||
IKubrowPetDetailsDatabase,
|
||||
@ -99,7 +97,9 @@ import {
|
||||
IAccolades,
|
||||
IHubNpcCustomization,
|
||||
ILotusCustomization,
|
||||
IEndlessXpReward
|
||||
IEndlessXpReward,
|
||||
IPersonalGoalProgressDatabase,
|
||||
IPersonalGoalProgressClient
|
||||
} from "../../types/inventoryTypes/inventoryTypes";
|
||||
import { IOid } from "../../types/commonTypes";
|
||||
import {
|
||||
@ -371,7 +371,7 @@ FlavourItemSchema.set("toJSON", {
|
||||
}
|
||||
});
|
||||
|
||||
const MailboxSchema = new Schema<IMailboxDatabase>(
|
||||
/*const MailboxSchema = new Schema<IMailboxDatabase>(
|
||||
{
|
||||
LastInboxId: Schema.Types.ObjectId
|
||||
},
|
||||
@ -384,7 +384,7 @@ MailboxSchema.set("toJSON", {
|
||||
delete mailboxDatabase.__v;
|
||||
(returnedObject as IMailboxClient).LastInboxId = toOid(mailboxDatabase.LastInboxId);
|
||||
}
|
||||
});
|
||||
});*/
|
||||
|
||||
const DuviriInfoSchema = new Schema<IDuviriInfo>(
|
||||
{
|
||||
@ -457,11 +457,35 @@ const discoveredMarkerSchema = new Schema<IDiscoveredMarker>(
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const personalGoalProgressSchema = new Schema<IPersonalGoalProgressDatabase>(
|
||||
{
|
||||
Best: Number,
|
||||
Count: Number,
|
||||
Tag: String,
|
||||
goalId: Types.ObjectId
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
personalGoalProgressSchema.set("toJSON", {
|
||||
virtuals: true,
|
||||
transform(_doc, obj) {
|
||||
const db = obj as IPersonalGoalProgressDatabase;
|
||||
const client = obj as IPersonalGoalProgressClient;
|
||||
|
||||
client._id = toOid(db.goalId);
|
||||
|
||||
delete obj.goalId;
|
||||
delete obj.__v;
|
||||
}
|
||||
});
|
||||
|
||||
const challengeProgressSchema = new Schema<IChallengeProgress>(
|
||||
{
|
||||
Progress: Number,
|
||||
Name: String,
|
||||
Completed: [String]
|
||||
Completed: { type: [String], default: undefined },
|
||||
ReceivedJunctionReward: Boolean,
|
||||
Name: { type: String, required: true }
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
@ -1630,7 +1654,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
//CompletedJobs: [Schema.Types.Mixed],
|
||||
|
||||
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
|
||||
//PersonalGoalProgress: [Schema.Types.Mixed],
|
||||
PersonalGoalProgress: { type: [personalGoalProgressSchema], default: undefined },
|
||||
|
||||
//Setting interface Style
|
||||
ThemeStyle: String,
|
||||
@ -1701,7 +1725,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
//Unknown and system
|
||||
DuviriInfo: DuviriInfoSchema,
|
||||
LastInventorySync: Schema.Types.ObjectId,
|
||||
Mailbox: MailboxSchema,
|
||||
//Mailbox: MailboxSchema,
|
||||
HandlerPoints: Number,
|
||||
ChallengesFixVersion: Number,
|
||||
PlayedParkourTutorial: Boolean,
|
||||
@ -1754,7 +1778,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined },
|
||||
LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined },
|
||||
|
||||
HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined }
|
||||
HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined },
|
||||
|
||||
ClaimedJunctionChallengeRewards: { type: [String], default: undefined }
|
||||
},
|
||||
{ timestamps: { createdAt: "Created", updatedAt: false } }
|
||||
);
|
||||
|
@ -40,6 +40,7 @@ const placedDecosSchema = new Schema<IPlacedDecosDatabase>(
|
||||
Pos: [Number],
|
||||
Rot: [Number],
|
||||
Scale: Number,
|
||||
Sockets: Number,
|
||||
PictureFrameInfo: { type: pictureFrameInfoSchema, default: undefined }
|
||||
},
|
||||
{ id: false }
|
||||
|
@ -19,6 +19,7 @@ import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootCo
|
||||
import { changeGuildRankController } from "@/src/controllers/api/changeGuildRankController";
|
||||
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
|
||||
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
|
||||
import { claimJunctionChallengeRewardController } from "@/src/controllers/api/claimJunctionChallengeRewardController";
|
||||
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
|
||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
||||
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
|
||||
@ -237,6 +238,7 @@ apiRouter.post("/artifacts.php", artifactsController);
|
||||
apiRouter.post("/artifactTransmutation.php", artifactTransmutationController);
|
||||
apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
|
||||
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
|
||||
apiRouter.post("/claimJunctionChallengeReward.php", claimJunctionChallengeRewardController);
|
||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
|
||||
apiRouter.post("/clearNewEpisodeReward.php", clearNewEpisodeRewardController);
|
||||
apiRouter.post("/commitStoryModeDecision.php", (_req, res) => { res.end(); }); // U14 (maybe wanna actually unlock the ship features?)
|
||||
|
@ -13,6 +13,7 @@ import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAl
|
||||
import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController";
|
||||
import { webuiFileChangeDetectedController } from "@/src/controllers/custom/webuiFileChangeDetectedController";
|
||||
import { completeAllMissionsController } from "@/src/controllers/custom/completeAllMissionsController";
|
||||
import { addMissingHelminthBlueprintsController } from "@/src/controllers/custom/addMissingHelminthBlueprintsController";
|
||||
|
||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
||||
@ -42,6 +43,7 @@ customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
|
||||
customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController);
|
||||
customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController);
|
||||
customRouter.get("/completeAllMissions", completeAllMissionsController);
|
||||
customRouter.get("/addMissingHelminthBlueprints", addMissingHelminthBlueprintsController);
|
||||
|
||||
customRouter.post("/createAccount", createAccountController);
|
||||
customRouter.post("/createMessage", createMessageController);
|
||||
|
@ -76,6 +76,7 @@ export interface IConfig {
|
||||
affinityBoost?: boolean;
|
||||
resourceBoost?: boolean;
|
||||
starDays?: boolean;
|
||||
galleonOfGhouls?: number;
|
||||
eidolonOverride?: string;
|
||||
vallisOverride?: string;
|
||||
duviriOverride?: string;
|
||||
|
@ -3,6 +3,7 @@ import fsPromises from "fs/promises";
|
||||
import { logger } from "../utils/logger";
|
||||
import { config, configPath, loadConfig } from "./configService";
|
||||
import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
|
||||
import { Inbox } from "../models/inboxModel";
|
||||
|
||||
let amnesia = false;
|
||||
fs.watchFile(configPath, (now, then) => {
|
||||
@ -22,6 +23,7 @@ fs.watchFile(configPath, (now, then) => {
|
||||
process.exit(1);
|
||||
}
|
||||
validateConfig();
|
||||
syncConfigWithDatabase();
|
||||
|
||||
const webPorts = getWebPorts();
|
||||
if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
|
||||
@ -51,6 +53,15 @@ export const validateConfig = (): void => {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
config.worldState?.galleonOfGhouls &&
|
||||
config.worldState.galleonOfGhouls != 1 &&
|
||||
config.worldState.galleonOfGhouls != 2 &&
|
||||
config.worldState.galleonOfGhouls != 3
|
||||
) {
|
||||
config.worldState.galleonOfGhouls = 0;
|
||||
modified = true;
|
||||
}
|
||||
if (modified) {
|
||||
logger.info(`Updating config file to fix some issues with it.`);
|
||||
void saveConfig();
|
||||
@ -61,3 +72,10 @@ export const saveConfig = async (): Promise<void> => {
|
||||
amnesia = true;
|
||||
await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
|
||||
};
|
||||
|
||||
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.
|
||||
if (!config.worldState?.galleonOfGhouls) {
|
||||
void Inbox.deleteMany({ goalTag: "GalleonRobbery" }).then(() => {}); // For some reason, I can't just do `Inbox.deleteMany(...)`; it needs this whole circus.
|
||||
}
|
||||
};
|
||||
|
@ -54,6 +54,22 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
|
||||
});
|
||||
}
|
||||
|
||||
// BUG: Deleting the inbox message manually means it'll just be automatically re-created. This is because we don't use startDate/endDate for these config-toggled events.
|
||||
if (config.worldState?.galleonOfGhouls) {
|
||||
if (!(await Inbox.exists({ ownerId: account._id, goalTag: "GalleonRobbery" }))) {
|
||||
newEventMessages.push({
|
||||
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
|
||||
sub: "/Lotus/Language/Events/GalleonRobberyIntroMsgTitle",
|
||||
msg: "/Lotus/Language/Events/GalleonRobberyIntroMsgDesc",
|
||||
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png",
|
||||
transmission: "/Lotus/Sounds/Dialog/GalleonOfGhouls/DGhoulsWeekOneInbox0010VayHek",
|
||||
att: ["/Lotus/Upgrades/Skins/Events/OgrisOldSchool"],
|
||||
startDate: new Date(),
|
||||
goalTag: "GalleonRobbery"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (newEventMessages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ import {
|
||||
import { updateQuestKey } from "@/src/services/questService";
|
||||
import { Types } from "mongoose";
|
||||
import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||
import { fromStoreItem, getLevelKeyRewards, toStoreItem } from "@/src/services/itemDataService";
|
||||
import { fromStoreItem, getLevelKeyRewards, isStoreItem, toStoreItem } from "@/src/services/itemDataService";
|
||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||
@ -609,6 +609,47 @@ export const addMissionInventoryUpdates = async (
|
||||
inventoryChanges.RegularCredits -= value;
|
||||
break;
|
||||
}
|
||||
case "GoalProgress": {
|
||||
for (const uploadProgress of value) {
|
||||
const goal = getWorldState().Goals.find(x => x._id.$oid == uploadProgress._id.$oid);
|
||||
if (goal && goal.Personal) {
|
||||
inventory.PersonalGoalProgress ??= [];
|
||||
const goalProgress = inventory.PersonalGoalProgress.find(x => x.goalId.equals(goal._id.$oid));
|
||||
if (goalProgress) {
|
||||
goalProgress.Best = Math.max(goalProgress.Best, uploadProgress.Best);
|
||||
goalProgress.Count += uploadProgress.Count;
|
||||
} else {
|
||||
inventory.PersonalGoalProgress.push({
|
||||
Best: uploadProgress.Best,
|
||||
Count: uploadProgress.Count,
|
||||
Tag: goal.Tag,
|
||||
goalId: new Types.ObjectId(goal._id.$oid)
|
||||
});
|
||||
|
||||
if (
|
||||
goal.Reward &&
|
||||
goal.Reward.items &&
|
||||
goal.MissionKeyName &&
|
||||
goal.MissionKeyName in goalMessagesByKey
|
||||
) {
|
||||
// Send reward via inbox
|
||||
const info = goalMessagesByKey[goal.MissionKeyName];
|
||||
await createMessage(inventory.accountOwnerId, [
|
||||
{
|
||||
sndr: info.sndr,
|
||||
msg: info.msg,
|
||||
att: goal.Reward.items.map(x => (isStoreItem(x) ? fromStoreItem(x) : x)),
|
||||
sub: info.sub,
|
||||
icon: info.icon,
|
||||
highPriority: true
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "InvasionProgress": {
|
||||
for (const clientProgress of value) {
|
||||
const dbProgress = inventory.QualifyingInvasions.find(x =>
|
||||
@ -962,6 +1003,14 @@ export const addMissionRewards = async (
|
||||
|
||||
let missionCompletionCredits = 0;
|
||||
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
||||
|
||||
if (rewardInfo.goalId) {
|
||||
const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
|
||||
if (goal?.MissionKeyName) {
|
||||
levelKeyName = goal.MissionKeyName;
|
||||
}
|
||||
}
|
||||
|
||||
if (levelKeyName) {
|
||||
const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
|
||||
//logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
|
||||
@ -1978,3 +2027,24 @@ const getHexBounties = (seed: number): { nodes: string[]; buddies: string[] } =>
|
||||
}
|
||||
return { nodes, buddies };
|
||||
};*/
|
||||
|
||||
const goalMessagesByKey: Record<string, { sndr: string; msg: string; sub: string; icon: string }> = {
|
||||
"/Lotus/Types/Keys/GalleonRobberyAlert": {
|
||||
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
|
||||
msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgA",
|
||||
sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleA",
|
||||
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
|
||||
},
|
||||
"/Lotus/Types/Keys/GalleonRobberyAlertB": {
|
||||
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
|
||||
msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgB",
|
||||
sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleB",
|
||||
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
|
||||
},
|
||||
"/Lotus/Types/Keys/GalleonRobberyAlertC": {
|
||||
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
|
||||
msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgC",
|
||||
sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleC",
|
||||
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
|
||||
}
|
||||
};
|
||||
|
@ -107,6 +107,16 @@ export class SRng {
|
||||
return arr[this.randomInt(0, arr.length - 1)];
|
||||
}
|
||||
|
||||
randomElementPop<T>(arr: T[]): T | undefined {
|
||||
if (arr.length != 0) {
|
||||
const index = this.randomInt(0, arr.length - 1);
|
||||
const elm = arr[index];
|
||||
arr.splice(index, 1);
|
||||
return elm;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
randomFloat(): number {
|
||||
this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn;
|
||||
return (Number(this.state >> 38n) & 0xffffff) * 0.000000059604645;
|
||||
|
@ -8,11 +8,12 @@ import {
|
||||
} from "@/src/types/shipTypes";
|
||||
import { logger } from "@/src/utils/logger";
|
||||
import { Types } from "mongoose";
|
||||
import { addShipDecorations, getInventory } from "./inventoryService";
|
||||
import { addFusionTreasures, addShipDecorations, getInventory } from "./inventoryService";
|
||||
import { config } from "./configService";
|
||||
import { Guild } from "../models/guildModel";
|
||||
import { hasGuildPermission } from "./guildService";
|
||||
import { GuildPermission } from "../types/guildTypes";
|
||||
import { ExportResources } from "warframe-public-export-plus";
|
||||
|
||||
export const setShipCustomizations = async (
|
||||
accountId: string,
|
||||
@ -101,6 +102,7 @@ export const handleSetShipDecorations = async (
|
||||
Pos: placedDecoration.Pos,
|
||||
Rot: placedDecoration.Rot,
|
||||
Scale: placedDecoration.Scale,
|
||||
Sockets: placedDecoration.Sockets,
|
||||
_id: placedDecoration.MoveId
|
||||
};
|
||||
|
||||
@ -116,12 +118,19 @@ export const handleSetShipDecorations = async (
|
||||
}
|
||||
|
||||
if (placedDecoration.RemoveId) {
|
||||
roomToPlaceIn.PlacedDecos.pull({ _id: placedDecoration.RemoveId });
|
||||
const decoIndex = roomToPlaceIn.PlacedDecos.findIndex(x => x._id.equals(placedDecoration.RemoveId));
|
||||
const deco = roomToPlaceIn.PlacedDecos[decoIndex];
|
||||
roomToPlaceIn.PlacedDecos.splice(decoIndex, 1);
|
||||
await personalRooms.save();
|
||||
|
||||
if (!config.unlockAllShipDecorations) {
|
||||
const inventory = await getInventory(accountId);
|
||||
addShipDecorations(inventory, [{ ItemType: placedDecoration.Type, ItemCount: 1 }]);
|
||||
const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)![0];
|
||||
if (deco.Sockets !== undefined) {
|
||||
addFusionTreasures(inventory, [{ ItemType: itemType, Sockets: deco.Sockets, ItemCount: 1 }]);
|
||||
} else {
|
||||
addShipDecorations(inventory, [{ ItemType: itemType, ItemCount: 1 }]);
|
||||
}
|
||||
await inventory.save();
|
||||
}
|
||||
|
||||
@ -134,7 +143,14 @@ export const handleSetShipDecorations = async (
|
||||
} else {
|
||||
if (!config.unlockAllShipDecorations) {
|
||||
const inventory = await getInventory(accountId);
|
||||
addShipDecorations(inventory, [{ ItemType: placedDecoration.Type, ItemCount: -1 }]);
|
||||
const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)![0];
|
||||
if (placedDecoration.Sockets !== undefined) {
|
||||
addFusionTreasures(inventory, [
|
||||
{ ItemType: itemType, Sockets: placedDecoration.Sockets, ItemCount: -1 }
|
||||
]);
|
||||
} else {
|
||||
addShipDecorations(inventory, [{ ItemType: itemType, ItemCount: -1 }]);
|
||||
}
|
||||
await inventory.save();
|
||||
}
|
||||
}
|
||||
@ -148,6 +164,7 @@ export const handleSetShipDecorations = async (
|
||||
Pos: placedDecoration.Pos,
|
||||
Rot: placedDecoration.Rot,
|
||||
Scale: placedDecoration.Scale,
|
||||
Sockets: placedDecoration.Sockets,
|
||||
_id: decoId
|
||||
});
|
||||
|
||||
|
@ -101,7 +101,7 @@ const sortieBossNode: Record<Exclude<TSortieBoss, "SORTIE_BOSS_CORRUPTED_VOR">,
|
||||
SORTIE_BOSS_VOR: "SolNode108"
|
||||
};
|
||||
|
||||
const eidolonJobs = [
|
||||
const eidolonJobs: readonly string[] = [
|
||||
"/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyAss",
|
||||
"/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyCap",
|
||||
"/Lotus/Types/Gameplay/Eidolon/Jobs/AttritionBountySab",
|
||||
@ -117,14 +117,14 @@ const eidolonJobs = [
|
||||
"/Lotus/Types/Gameplay/Eidolon/Jobs/RescueBountyResc"
|
||||
];
|
||||
|
||||
const eidolonNarmerJobs = [
|
||||
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 = [
|
||||
const venusJobs: readonly string[] = [
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobAmbush",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobExcavation",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobRecovery",
|
||||
@ -150,14 +150,14 @@ const venusJobs = [
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusWetworkJobSpy"
|
||||
];
|
||||
|
||||
const venusNarmerJobs = [
|
||||
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 = [
|
||||
const microplanetJobs: readonly string[] = [
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosAreaDefenseBounty",
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosAssassinateBounty",
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosCrpSurvivorBounty",
|
||||
@ -167,7 +167,7 @@ const microplanetJobs = [
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosPurifyBounty"
|
||||
];
|
||||
|
||||
const microplanetEndlessJobs = [
|
||||
const microplanetEndlessJobs: readonly string[] = [
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessAreaDefenseBounty",
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessExcavateBounty",
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty"
|
||||
@ -498,6 +498,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
|
||||
{
|
||||
const rng = new SRng(seed);
|
||||
const pool = [...eidolonJobs];
|
||||
syndicateMissions.push({
|
||||
_id: {
|
||||
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
|
||||
@ -509,7 +510,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
Nodes: [],
|
||||
Jobs: [
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierATable${table}Rewards`,
|
||||
masteryReq: 0,
|
||||
minEnemyLevel: 5,
|
||||
@ -517,7 +518,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 3, 1000, 1500)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierBTable${table}Rewards`,
|
||||
masteryReq: 1,
|
||||
minEnemyLevel: 10,
|
||||
@ -525,7 +526,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 3, 1750, 2250)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierCTable${table}Rewards`,
|
||||
masteryReq: 2,
|
||||
minEnemyLevel: 20,
|
||||
@ -533,7 +534,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 4, 2500, 3000)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierDTable${table}Rewards`,
|
||||
masteryReq: 3,
|
||||
minEnemyLevel: 30,
|
||||
@ -541,7 +542,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 5, 3250, 3750)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierETable${table}Rewards`,
|
||||
masteryReq: 5,
|
||||
minEnemyLevel: 40,
|
||||
@ -549,7 +550,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 5, 4000, 4500)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(eidolonJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierETable${table}Rewards`,
|
||||
masteryReq: 10,
|
||||
minEnemyLevel: 100,
|
||||
@ -570,6 +571,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
|
||||
{
|
||||
const rng = new SRng(seed);
|
||||
const pool = [...venusJobs];
|
||||
syndicateMissions.push({
|
||||
_id: {
|
||||
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000025"
|
||||
@ -581,7 +583,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
Nodes: [],
|
||||
Jobs: [
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierATable${table}Rewards`,
|
||||
masteryReq: 0,
|
||||
minEnemyLevel: 5,
|
||||
@ -589,7 +591,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 3, 1000, 1500)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierBTable${table}Rewards`,
|
||||
masteryReq: 1,
|
||||
minEnemyLevel: 10,
|
||||
@ -597,7 +599,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 3, 1750, 2250)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierCTable${table}Rewards`,
|
||||
masteryReq: 2,
|
||||
minEnemyLevel: 20,
|
||||
@ -605,7 +607,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 4, 2500, 3000)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierDTable${table}Rewards`,
|
||||
masteryReq: 3,
|
||||
minEnemyLevel: 30,
|
||||
@ -613,7 +615,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 5, 3250, 3750)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
||||
masteryReq: 5,
|
||||
minEnemyLevel: 40,
|
||||
@ -621,7 +623,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 5, 4000, 4500)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(venusJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
||||
masteryReq: 10,
|
||||
minEnemyLevel: 100,
|
||||
@ -642,6 +644,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
|
||||
{
|
||||
const rng = new SRng(seed);
|
||||
const pool = [...microplanetJobs];
|
||||
syndicateMissions.push({
|
||||
_id: {
|
||||
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000002"
|
||||
@ -653,7 +656,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
Nodes: [],
|
||||
Jobs: [
|
||||
{
|
||||
jobType: rng.randomElement(microplanetJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierATable${table}Rewards`,
|
||||
masteryReq: 0,
|
||||
minEnemyLevel: 5,
|
||||
@ -661,7 +664,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 3, 12, 18)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(microplanetJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierCTable${table}Rewards`,
|
||||
masteryReq: 1,
|
||||
minEnemyLevel: 15,
|
||||
@ -678,7 +681,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: [14, 14, 14]
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(microplanetJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierDTable${deimosDTable}Rewards`,
|
||||
masteryReq: 2,
|
||||
minEnemyLevel: 30,
|
||||
@ -686,7 +689,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 4, 72, 88)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(microplanetJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierETableARewards`,
|
||||
masteryReq: 3,
|
||||
minEnemyLevel: 40,
|
||||
@ -694,7 +697,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
||||
xpAmounts: generateXpAmounts(rng, 5, 115, 135)
|
||||
},
|
||||
{
|
||||
jobType: rng.randomElement(microplanetJobs),
|
||||
jobType: rng.randomElementPop(pool),
|
||||
rewards: `/Lotus/Types/Game/MissionDecks/DeimosMissionRewards/TierETableARewards`,
|
||||
masteryReq: 10,
|
||||
minEnemyLevel: 100,
|
||||
@ -1146,6 +1149,77 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
Node: "SolarisUnitedHub1"
|
||||
});
|
||||
}
|
||||
// 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);
|
||||
|
@ -56,6 +56,7 @@ export interface IInventoryDatabase
|
||||
| "QualifyingInvasions"
|
||||
| "LastInventorySync"
|
||||
| "EndlessXP"
|
||||
| "PersonalGoalProgress"
|
||||
| TEquipmentKey
|
||||
>,
|
||||
InventoryDatabaseEquipment {
|
||||
@ -63,7 +64,7 @@ export interface IInventoryDatabase
|
||||
Created: Date;
|
||||
TrainingDate: Date;
|
||||
LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population
|
||||
Mailbox?: IMailboxDatabase;
|
||||
//Mailbox?: IMailboxDatabase;
|
||||
GuildId?: Types.ObjectId;
|
||||
PendingRecipes: IPendingRecipeDatabase[];
|
||||
QuestKeys: IQuestKeyDatabase[];
|
||||
@ -95,6 +96,7 @@ export interface IInventoryDatabase
|
||||
QualifyingInvasions: IInvasionProgressDatabase[];
|
||||
LastInventorySync?: Types.ObjectId;
|
||||
EndlessXP?: IEndlessXpProgressDatabase[];
|
||||
PersonalGoalProgress?: IPersonalGoalProgressDatabase[];
|
||||
}
|
||||
|
||||
export interface IQuestKeyDatabase {
|
||||
@ -150,9 +152,9 @@ export interface IMailboxClient {
|
||||
LastInboxId: IOid;
|
||||
}
|
||||
|
||||
export interface IMailboxDatabase {
|
||||
/*export interface IMailboxDatabase {
|
||||
LastInboxId: Types.ObjectId;
|
||||
}
|
||||
}*/
|
||||
|
||||
export type TSolarMapRegion =
|
||||
| "Earth"
|
||||
@ -306,7 +308,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
HWIDProtectEnabled?: boolean;
|
||||
//KubrowPetPrints: IKubrowPetPrint[];
|
||||
AlignmentReplay?: IAlignment;
|
||||
//PersonalGoalProgress: IPersonalGoalProgress[];
|
||||
PersonalGoalProgress?: IPersonalGoalProgressClient[];
|
||||
ThemeStyle: string;
|
||||
ThemeBackground: string;
|
||||
ThemeSounds: string;
|
||||
@ -378,6 +380,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
LockedWeaponGroup?: ILockedWeaponGroupClient;
|
||||
HubNpcCustomizations?: IHubNpcCustomization[];
|
||||
Ship?: IOrbiter; // U22 and below, response only
|
||||
ClaimedJunctionChallengeRewards?: string[]; // U39
|
||||
}
|
||||
|
||||
export interface IAffiliation {
|
||||
@ -446,8 +449,9 @@ export interface IVendorPurchaseHistoryEntryDatabase {
|
||||
|
||||
export interface IChallengeProgress {
|
||||
Progress: number;
|
||||
Name: string;
|
||||
Completed?: string[];
|
||||
ReceivedJunctionReward?: boolean; // U39
|
||||
Name: string;
|
||||
}
|
||||
|
||||
export interface ICollectibleEntry {
|
||||
@ -1015,13 +1019,17 @@ export interface IPeriodicMissionCompletionResponse extends Omit<IPeriodicMissio
|
||||
date: IMongoDate;
|
||||
}
|
||||
|
||||
export interface IPersonalGoalProgress {
|
||||
export interface IPersonalGoalProgressClient {
|
||||
Best: number;
|
||||
Count: number;
|
||||
Tag: string;
|
||||
Best?: number;
|
||||
_id: IOid;
|
||||
ReceivedClanReward0?: boolean;
|
||||
ReceivedClanReward1?: boolean;
|
||||
//ReceivedClanReward0?: boolean;
|
||||
//ReceivedClanReward1?: boolean;
|
||||
}
|
||||
|
||||
export interface IPersonalGoalProgressDatabase extends Omit<IPersonalGoalProgressClient, "_id"> {
|
||||
goalId: Types.ObjectId;
|
||||
}
|
||||
|
||||
export interface IPersonalTechProjectDatabase {
|
||||
|
@ -139,6 +139,14 @@ export type IMissionInventoryUpdateRequest = {
|
||||
};
|
||||
wagerTier?: number; // the index
|
||||
creditsFee?: number; // the index
|
||||
GoalProgress?: {
|
||||
_id: IOid;
|
||||
Count: number;
|
||||
Best: number;
|
||||
Tag: string;
|
||||
IsMultiProgress: boolean;
|
||||
MultiProgress: unknown[];
|
||||
}[];
|
||||
InvasionProgress?: IInvasionProgressClient[];
|
||||
ConquestMissionsCompleted?: number;
|
||||
duviriSuitSelection?: string;
|
||||
@ -156,6 +164,8 @@ export type IMissionInventoryUpdateRequest = {
|
||||
|
||||
export interface IRewardInfo {
|
||||
node: string;
|
||||
goalId?: string;
|
||||
goalManifest?: string;
|
||||
invasionId?: string;
|
||||
invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
|
||||
sortieId?: string;
|
||||
|
@ -96,6 +96,7 @@ export interface IPlacedDecosDatabase {
|
||||
Pos: [number, number, number];
|
||||
Rot: [number, number, number];
|
||||
Scale?: number;
|
||||
Sockets?: number;
|
||||
PictureFrameInfo?: IPictureFrameInfo;
|
||||
_id: Types.ObjectId;
|
||||
}
|
||||
@ -136,6 +137,7 @@ export interface IShipDecorationsRequest {
|
||||
MoveId?: string;
|
||||
OldRoom?: string;
|
||||
Scale?: number;
|
||||
Sockets?: number;
|
||||
}
|
||||
|
||||
export interface IShipDecorationsResponse {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { IMissionReward } from "warframe-public-export-plus";
|
||||
import { IMongoDate, IOid } from "./commonTypes";
|
||||
|
||||
export interface IWorldState {
|
||||
@ -37,11 +38,15 @@ export interface IGoal {
|
||||
Goal: number;
|
||||
Success: number;
|
||||
Personal: boolean;
|
||||
Bounty?: boolean;
|
||||
ClampNodeScores?: boolean;
|
||||
Desc: string;
|
||||
ToolTip: string;
|
||||
ToolTip?: string;
|
||||
Icon: string;
|
||||
Tag: string;
|
||||
Node: string;
|
||||
MissionKeyName?: string;
|
||||
Reward?: IMissionReward;
|
||||
}
|
||||
|
||||
export interface ISyndicateMissionInfo {
|
||||
|
@ -794,6 +794,7 @@
|
||||
<button class="btn btn-primary" onclick="debounce(doUnlockAllMissions);" data-loc="cheats_unlockAllMissions"></button>
|
||||
<button class="btn btn-primary" onclick="doUnlockAllFocusSchools();" data-loc="cheats_unlockAllFocusSchools"></button>
|
||||
<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="inventory_maxPlexus"></button>
|
||||
</div>
|
||||
|
@ -1449,6 +1449,11 @@ function addMissingEquipment(categories) {
|
||||
}
|
||||
}
|
||||
|
||||
async function addMissingHelminthRecipes() {
|
||||
await revalidateAuthz();
|
||||
await fetch("/custom/addMissingHelminthBlueprints?" + window.authz);
|
||||
}
|
||||
|
||||
function addMissingEvolutionProgress() {
|
||||
const requests = [];
|
||||
document.querySelectorAll("#datalist-EvolutionProgress option").forEach(elm => {
|
||||
|
@ -181,6 +181,7 @@ dict = {
|
||||
cheats_account: `Account`,
|
||||
cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`,
|
||||
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
|
||||
cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `Alle Inhärenzen auf Max. Rang`,
|
||||
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
||||
cheats_changeButton: `Ändern`,
|
||||
|
@ -180,6 +180,7 @@ dict = {
|
||||
cheats_account: `Account`,
|
||||
cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
|
||||
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
|
||||
cheats_addMissingSubsumedAbilities: `Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `Max Rank All Intrinsics`,
|
||||
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
||||
cheats_changeButton: `Change`,
|
||||
|
@ -181,6 +181,7 @@ dict = {
|
||||
cheats_account: `Cuenta`,
|
||||
cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`,
|
||||
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
|
||||
cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `Maximizar todos los intrínsecos`,
|
||||
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
|
||||
cheats_changeButton: `Cambiar`,
|
||||
|
@ -3,8 +3,8 @@ dict = {
|
||||
general_inventoryUpdateNote: `Note : Les changements effectués ici seront appliqués lors de la syncrhonisation. Visiter la navigation appliquera les changements apportés à l'inventaire.`,
|
||||
general_addButton: `Ajouter`,
|
||||
general_bulkActions: `Action groupée`,
|
||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||
code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
|
||||
code_regFail: `Enregistrement impossible. Compte existant?`,
|
||||
code_changeNameConfirm: `Nouveau nom du compte :`,
|
||||
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
|
||||
code_archgun: `Archgun`,
|
||||
@ -85,7 +85,7 @@ dict = {
|
||||
inventory_moaPets: `Moas`,
|
||||
inventory_kubrowPets: `Bêtes`,
|
||||
inventory_evolutionProgress: `Progrès de l'évolution Incarnon`,
|
||||
inventory_Boosters: `[UNTRANSLATED] Boosters`,
|
||||
inventory_Boosters: `Boosters`,
|
||||
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
|
||||
inventory_bulkAddWeapons: `Ajouter les armes manquantes`,
|
||||
inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`,
|
||||
@ -100,7 +100,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: `[UNTRANSLATED] Max Rank Plexus`,
|
||||
inventory_maxPlexus: `Plexus au rang max`,
|
||||
|
||||
quests_list: `Quêtes`,
|
||||
quests_completeAll: `Compléter toutes les quêtes`,
|
||||
@ -135,10 +135,10 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Aya Raffiné infini`,
|
||||
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
|
||||
cheats_claimingBlueprintRefundsIngredients: `Récupérer les items rend les ressources`,
|
||||
cheats_dontSubtractPurchaseCreditCost: `[UNTRANSLATED] Don't Subtract Purchase Credit Cost`,
|
||||
cheats_dontSubtractPurchasePlatinumCost: `[UNTRANSLATED] Don't Subtract Purchase Platinum Cost`,
|
||||
cheats_dontSubtractPurchaseItemCost: `[UNTRANSLATED] Don't Subtract Purchase Item Cost`,
|
||||
cheats_dontSubtractPurchaseStandingCost: `[UNTRANSLATED] Don't Subtract Purchase Standing Cost`,
|
||||
cheats_dontSubtractPurchaseCreditCost: `Ne pas retirer le coût en crédits`,
|
||||
cheats_dontSubtractPurchasePlatinumCost: `Ne pas retirer le coût en platines`,
|
||||
cheats_dontSubtractPurchaseItemCost: `Ne pas retirer le coût d'achat`,
|
||||
cheats_dontSubtractPurchaseStandingCost: `Ne pas retirer le coût en réputation`,
|
||||
cheats_dontSubtractVoidTraces: `Ne pas consommer de Void Traces`,
|
||||
cheats_dontSubtractConsumables: `Ne pas retirer de consommables`,
|
||||
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
|
||||
@ -158,11 +158,11 @@ dict = {
|
||||
cheats_noVendorPurchaseLimits: `Aucune limite d'achat chez les PNJ`,
|
||||
cheats_noDeathMarks: `Aucune marque d'assassin`,
|
||||
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
|
||||
cheats_fullyStockedVendors: `[UNTRANSLATED] Fully Stocked Vendors`,
|
||||
cheats_fullyStockedVendors: `Les vendeurs ont un stock à 100%`,
|
||||
cheats_baroAlwaysAvailable: `[UNTRANSLATED] Baro Always Available`,
|
||||
cheats_baroFullyStocked: `[UNTRANSLATED] Baro Fully Stocked`,
|
||||
cheats_syndicateMissionsRepeatable: `Mission syndicat répétables`,
|
||||
cheats_unlockAllProfitTakerStages: `[UNTRANSLATED] Unlock All Profit Taker Stages`,
|
||||
cheats_unlockAllProfitTakerStages: `Débloquer toutes les étapes du Preneur de Profit`,
|
||||
cheats_instantFinishRivenChallenge: `Débloquer le challenge Riven instantanément`,
|
||||
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
|
||||
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
|
||||
@ -173,73 +173,74 @@ dict = {
|
||||
cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`,
|
||||
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
|
||||
cheats_fastClanAscension: `Ascension de clan rapide`,
|
||||
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
|
||||
cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`,
|
||||
cheats_missionsCanGiveAllRelics: `Les missions donnent toutes les reliques`,
|
||||
cheats_unlockAllSimarisResearchEntries: `Débloquer toute les recherches chez Simaris`,
|
||||
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
|
||||
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||
cheats_save: `[UNTRANSLATED] Save`,
|
||||
cheats_nightwaveStandingMultiplier: `Multiplicateur de réputation d'Ondes Nocturnes`,
|
||||
cheats_save: `Sauvegarder`,
|
||||
cheats_account: `Compte`,
|
||||
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
|
||||
cheats_helminthUnlockAll: `Helminth niveau max`,
|
||||
cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `Inhérences niveau max`,
|
||||
cheats_changeSupportedSyndicate: `Allégeance`,
|
||||
cheats_changeButton: `Changer`,
|
||||
cheats_none: `Aucun`,
|
||||
import_importNote: `Import manuel. Toutes les modifcations supportées par l'inventaire <b>écraseront celles présentes dans la base de données</b>.`,
|
||||
import_submit: `Soumettre`,
|
||||
import_samples: `[UNTRANSLATED] Samples:`,
|
||||
import_samples_maxFocus: `[UNTRANSLATED] All Focus Schools Maxed Out`,
|
||||
import_samples: `Echantillons :`,
|
||||
import_samples_maxFocus: `Toutes les écoles de focus au rang max`,
|
||||
|
||||
upgrade_Equilibrium: `[UNTRANSLATED] +|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`,
|
||||
upgrade_MeleeCritDamage: `[UNTRANSLATED] +|VAL|% Melee Critical Damage`,
|
||||
upgrade_PrimaryStatusChance: `[UNTRANSLATED] +|VAL|% Primary Status Chance`,
|
||||
upgrade_SecondaryCritChance: `[UNTRANSLATED] +|VAL|% Secondary Critical Chance`,
|
||||
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
|
||||
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`,
|
||||
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on kill with Blast Damage`,
|
||||
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`,
|
||||
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
upgrade_WarframeCritDamageBoost: `[UNTRANSLATED] +|VAL|% Melee Critical Damage (Doubles over 500 Energy)`,
|
||||
upgrade_WarframeElectricDamage: `[UNTRANSLATED] +|VAL1|% Primary Electricity Damage (+|VAL2|% per additional Shard)`,
|
||||
upgrade_WarframeElectricDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Electricity Status`,
|
||||
upgrade_WarframeEnergyMax: `[UNTRANSLATED] +|VAL| Energy Max`,
|
||||
upgrade_WarframeGlobeEffectEnergy: `[UNTRANSLATED] +|VAL|% Energy Orb Effectiveness`,
|
||||
upgrade_WarframeGlobeEffectHealth: `[UNTRANSLATED] +|VAL|% Health Orb Effectiveness`,
|
||||
upgrade_WarframeHealthMax: `[UNTRANSLATED] +|VAL| Health`,
|
||||
upgrade_WarframeHPBoostFromImpact: `[UNTRANSLATED] +|VAL1| Health per enemy killed with Blast Damage (Max |VAL2| Health)`,
|
||||
upgrade_WarframeParkourVelocity: `[UNTRANSLATED] +|VAL|% Parkour Velocity`,
|
||||
upgrade_WarframeRadiationDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Radiation Status`,
|
||||
upgrade_WarframeRegen: `[UNTRANSLATED] +|VAL| Health Regen/s`,
|
||||
upgrade_WarframeShieldMax: `[UNTRANSLATED] +|VAL| Shield`,
|
||||
upgrade_WarframeStartingEnergy: `[UNTRANSLATED] +|VAL|% Energy on Spawn`,
|
||||
upgrade_WarframeToxinDamage: `[UNTRANSLATED] +|VAL|% Toxin Status Effect Damage`,
|
||||
upgrade_WarframeToxinHeal: `[UNTRANSLATED] +|VAL| Health on damaging enemies with Toxin Status`,
|
||||
upgrade_WeaponCritBoostFromHeat: `[UNTRANSLATED] +|VAL1|% Secondary Critical Chance per Heat-affected enemy killed (Max |VAL2|%)`,
|
||||
upgrade_AvatarAbilityRange: `[UNTRANSLATED] +7.5% Ability Range`,
|
||||
upgrade_AvatarAbilityEfficiency: `[UNTRANSLATED] +5% Ability Efficiency`,
|
||||
upgrade_AvatarEnergyRegen: `[UNTRANSLATED] +0.5 Energy Regen/s`,
|
||||
upgrade_AvatarEnemyRadar: `[UNTRANSLATED] +5m Enemy Radar`,
|
||||
upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`,
|
||||
upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`,
|
||||
upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`,
|
||||
upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`,
|
||||
upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`,
|
||||
upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`,
|
||||
upgrade_Equilibrium: `Ramasser de la santé donne +|VAL|% d'énergie supplémentaire. Ramasser de l'énergie donne +|VAL|% de santé supplémentaire.`,
|
||||
upgrade_MeleeCritDamage: `+|VAL|% de dégâts critique en mêlée`,
|
||||
upgrade_PrimaryStatusChance: `+|VAL|% de chance de statut sur arme primaire`,
|
||||
upgrade_SecondaryCritChance: `+|VAL|% de chance critique sur arme secondaire`,
|
||||
upgrade_WarframeAbilityDuration: `+|VAL|% de durée de pouvoir`,
|
||||
upgrade_WarframeAbilityStrength: `+|VAL|% de puissance de pouvoir`,
|
||||
upgrade_WarframeArmourMax: `+|VAL| d'armure`,
|
||||
upgrade_WarframeBlastProc: `+|VAL| de boucliers sur élimination avec des dégats d'explosion`,
|
||||
upgrade_WarframeCastingSpeed: `+|VAL|% de vitesse de lancement de pouvoir`,
|
||||
upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% de dégâts de pouvoir sur les ennemis affectés par du statut corrosif`,
|
||||
upgrade_WarframeCorrosiveStack: `+|VAL| de cumuls maximum de Statut Corrosif`,
|
||||
upgrade_WarframeCritDamageBoost: `+|VAL|% de dégâts critique en mêlée (Doublé si l'énergie dépasse 500)`,
|
||||
upgrade_WarframeElectricDamage: `+|VAL1|% de dégâts électrique sur arme primaire (+|VAL2|% par fragment supplémentaire)`,
|
||||
upgrade_WarframeElectricDamageBoost: `+|VAL|% de dégâts de pouvoir sur les ennemis affectés par du statut électrique`,
|
||||
upgrade_WarframeEnergyMax: `+|VAL| d'énergie max`,
|
||||
upgrade_WarframeGlobeEffectEnergy: `+|VAL|% d'efficacité d'orbe d'énergie`,
|
||||
upgrade_WarframeGlobeEffectHealth: `+|VAL|% d'efficacité d'orbe de santé`,
|
||||
upgrade_WarframeHealthMax: `+|VAL| de santé`,
|
||||
upgrade_WarframeHPBoostFromImpact: `+|VAL1| de santé par ennemi tué avec des dégâts explosifs (Max |VAL2| de santé)`,
|
||||
upgrade_WarframeParkourVelocity: `+|VAL|% de vélocité de parkour`,
|
||||
upgrade_WarframeRadiationDamageBoost: `+|VAL|% de dégâts de pouvoir sur les ennemis affectés par du statut radiation`,
|
||||
upgrade_WarframeRegen: `+|VAL| régénération de santé/s`,
|
||||
upgrade_WarframeShieldMax: `+|VAL| de boucliers`,
|
||||
upgrade_WarframeStartingEnergy: `+|VAL|% d'énergie sur apparition`,
|
||||
upgrade_WarframeToxinDamage: `+|VAL|% de dégâts sur le statut poison`,
|
||||
upgrade_WarframeToxinHeal: `+|VAL| de santé récupérée à chaque dégât de statut poison`,
|
||||
upgrade_WeaponCritBoostFromHeat: `+|VAL1|% de chance critique sur arme secondaire pour chaque ennemi affecté puis tué par du feu (Max |VAL2|%)`,
|
||||
upgrade_AvatarAbilityRange: `+7.5% de portée de pouvoir`,
|
||||
upgrade_AvatarAbilityEfficiency: `+5% d'efficacité de pouvoir`,
|
||||
upgrade_AvatarEnergyRegen: `+0.5 de régénération d'énergie/s`,
|
||||
upgrade_AvatarEnemyRadar: `+5m de radar ennemi`,
|
||||
upgrade_AvatarLootRadar: `+7m de radar à butin`,
|
||||
upgrade_WeaponAmmoMax: `+15% de munitions max`,
|
||||
upgrade_EnemyArmorReductionAura: `-3% d'armure ennemi`,
|
||||
upgrade_OnExecutionAmmo: `100% de rechargement des armes primaires et secondaires sur une une miséricorde`,
|
||||
upgrade_OnExecutionHealthDrop: `100% de chance de drop une orbe de santé sur une miséricorde`,
|
||||
upgrade_OnExecutionEnergyDrop: `50% de chance de drop une orbe d'énergie sur une miséricorde`,
|
||||
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`,
|
||||
upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`,
|
||||
upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`,
|
||||
upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`,
|
||||
upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`,
|
||||
upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`,
|
||||
upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
|
||||
upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`,
|
||||
upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`,
|
||||
upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
|
||||
upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`,
|
||||
upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`,
|
||||
upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`,
|
||||
upgrade_DamageReductionOnHack: `75% de réduction de dégâts pendant un piratage`,
|
||||
upgrade_OnExecutionReviveCompanion: `Les miséricordes réduisent le temps de récupération du compagnon de 15s`,
|
||||
upgrade_OnExecutionParkourSpeed: `+60% de vitesse de parkour pendant 15s après une miséricorde`,
|
||||
upgrade_AvatarTimeLimitIncrease: `+8s de temps de piratage`,
|
||||
upgrade_ElectrifyOnHack: `Electrifie les ennemis dans un rayon de 20m pendant un piratage`,
|
||||
upgrade_OnExecutionTerrify: `Les ennemis dans un rayon de 15m ont 50% de chance de s'enfuir après une miséricorde`,
|
||||
upgrade_OnHackLockers: `5 casiers s'ouvrent dans un rayon de 20m après un piratage`,
|
||||
upgrade_OnExecutionBlind: `Les ennemis sont aveuglés dans un rayon de 18 après une miséricorde`,
|
||||
upgrade_OnExecutionDrainPower: `100% pour le prochain pouvoir de gagner +50% de puissance de pouvoir sur miséricorde`,
|
||||
upgrade_OnHackSprintSpeed: `+75% de vitesse de course pendant 15s après un piratage`,
|
||||
upgrade_SwiftExecute: `Vitesse des miséricordes augmentée de 50%`,
|
||||
upgrade_OnHackInvis: `Invisible pendant 15 secondes après un piratage`,
|
||||
|
||||
prettier_sucks_ass: ``
|
||||
};
|
||||
|
@ -181,6 +181,7 @@ dict = {
|
||||
cheats_account: `Аккаунт`,
|
||||
cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
|
||||
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
|
||||
cheats_addMissingSubsumedAbilities: `Добавить отсутствующие поглощённые способности`,
|
||||
cheats_intrinsicsUnlockAll: `Полностью улучшить Модуляры`,
|
||||
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
||||
cheats_changeButton: `Изменить`,
|
||||
|
@ -181,6 +181,7 @@ dict = {
|
||||
cheats_account: `账户`,
|
||||
cheats_unlockAllFocusSchools: `解锁所有专精学派`,
|
||||
cheats_helminthUnlockAll: `完全升级Helminth`,
|
||||
cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `所有内源之力最大等级`,
|
||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||
cheats_changeButton: `更改`,
|
||||
|
Loading…
x
Reference in New Issue
Block a user