merge upstream
This commit is contained in:
9
package-lock.json
generated
9
package-lock.json
generated
@@ -552,6 +552,7 @@
|
||||
"integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.41.0",
|
||||
"@typescript-eslint/types": "8.41.0",
|
||||
@@ -1180,6 +1181,7 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -2057,6 +2059,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -2223,6 +2226,7 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -4362,6 +4366,7 @@
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -5203,6 +5208,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -5421,6 +5427,7 @@
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -5480,6 +5487,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.3.0"
|
||||
},
|
||||
@@ -5675,6 +5683,7 @@
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
|
||||
"integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@dabh/diagnostics": "^2.0.2",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
||||
import { toOid2 } from "../../helpers/inventoryHelpers.ts";
|
||||
import {
|
||||
createVeiledRivenFingerprint,
|
||||
createUnveiledRivenFingerprint,
|
||||
@@ -6,13 +6,14 @@ import {
|
||||
} from "../../helpers/rivenHelper.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import { addMods, getInventory } from "../../services/inventoryService.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { getRandomElement } from "../../services/rngService.ts";
|
||||
import type { RequestHandler } from "express";
|
||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
||||
|
||||
export const activateRandomModController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
const accountId = account._id.toString();
|
||||
const inventory = await getInventory(accountId, "RawUpgrades Upgrades instantFinishRivenChallenge");
|
||||
const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
|
||||
addMods(inventory, [
|
||||
@@ -36,7 +37,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
|
||||
NewMod: {
|
||||
UpgradeFingerprint: fingerprint,
|
||||
ItemType: rivenType,
|
||||
ItemId: toOid(inventory.Upgrades[upgradeIndex]._id)
|
||||
ItemId: toOid2(inventory.Upgrades[upgradeIndex]._id, account.BuildLabel)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fromOid, toOid } from "../../helpers/inventoryHelpers.ts";
|
||||
import { fromOid, toOid2 } from "../../helpers/inventoryHelpers.ts";
|
||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "../../helpers/rivenHelper.ts";
|
||||
import { addMiscItems, addMods, getInventory } from "../../services/inventoryService.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "../../services/rngService.ts";
|
||||
import type { IUpgradeFromClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import type { RequestHandler } from "express";
|
||||
@@ -9,12 +9,15 @@ import type { TRarity } from "warframe-public-export-plus";
|
||||
import { ExportBoosterPacks, ExportUpgrades } from "warframe-public-export-plus";
|
||||
|
||||
export const artifactTransmutationController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
const accountId = account._id.toString();
|
||||
const inventory = await getInventory(accountId);
|
||||
const payload = JSON.parse(String(req.body)) as IArtifactTransmutationRequest;
|
||||
|
||||
inventory.RegularCredits -= payload.Cost;
|
||||
inventory.FusionPoints -= payload.FusionPointCost;
|
||||
if (payload.FusionPointCost) {
|
||||
inventory.FusionPoints -= payload.FusionPointCost;
|
||||
}
|
||||
|
||||
if (payload.RivenTransmute) {
|
||||
addMiscItems(inventory, [
|
||||
@@ -41,7 +44,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
||||
res.json({
|
||||
NewMods: [
|
||||
{
|
||||
ItemId: toOid(inventory.Upgrades[upgradeIndex]._id),
|
||||
ItemId: toOid2(inventory.Upgrades[upgradeIndex]._id, account.BuildLabel),
|
||||
ItemType: rivenType,
|
||||
UpgradeFingerprint: fingerprint
|
||||
}
|
||||
@@ -56,9 +59,10 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
||||
};
|
||||
let forcedPolarity: string | undefined;
|
||||
payload.Consumed.forEach(upgrade => {
|
||||
upgrade.ItemCount ??= 1;
|
||||
const meta = ExportUpgrades[upgrade.ItemType];
|
||||
counts[meta.rarity] += upgrade.ItemCount;
|
||||
if (fromOid(upgrade.ItemId) != "000000000000000000000000") {
|
||||
if (fromOid(upgrade.ItemId) != "" && fromOid(upgrade.ItemId) != "000000000000000000000000") {
|
||||
inventory.Upgrades.pull({ _id: fromOid(upgrade.ItemId) });
|
||||
} else {
|
||||
addMods(inventory, [
|
||||
@@ -133,7 +137,7 @@ interface IArtifactTransmutationRequest {
|
||||
LevelDiff: number;
|
||||
Consumed: IUpgradeFromClient[];
|
||||
Cost: number;
|
||||
FusionPointCost: number;
|
||||
FusionPointCost?: number;
|
||||
RivenTransmute?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,63 +1,126 @@
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import type { RequestHandler } from "express";
|
||||
import type { IInventoryClient, IUpgradeClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import type {
|
||||
IInventoryClient,
|
||||
IUpgradeClient,
|
||||
IUpgradeFromClient
|
||||
} from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { addMods, getInventory } from "../../services/inventoryService.ts";
|
||||
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
|
||||
import { fromOid, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
|
||||
export const artifactsController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
const accountId = account._id.toString();
|
||||
const artifactsData = getJSONfromString<IArtifactsRequest>(String(req.body));
|
||||
|
||||
const { Upgrade, LevelDiff, Cost, FusionPointCost } = artifactsData;
|
||||
const { Upgrade, LevelDiff, Cost, FusionPointCost, Consumed, Fingerprint } = artifactsData;
|
||||
|
||||
const inventory = await getInventory(accountId);
|
||||
const { Upgrades } = inventory;
|
||||
const { ItemType, UpgradeFingerprint, ItemId } = Upgrade;
|
||||
|
||||
const safeUpgradeFingerprint = UpgradeFingerprint || '{"lvl":0}';
|
||||
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint) as { lvl: number };
|
||||
parsedUpgradeFingerprint.lvl += LevelDiff;
|
||||
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
|
||||
if (!account.BuildLabel || version_compare(account.BuildLabel, "2016.08.19.17.12") >= 0) {
|
||||
const safeUpgradeFingerprint = UpgradeFingerprint || '{"lvl":0}';
|
||||
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint) as { lvl: number };
|
||||
parsedUpgradeFingerprint.lvl += LevelDiff;
|
||||
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
|
||||
|
||||
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id.equals(ItemId.$oid));
|
||||
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id.equals(fromOid(ItemId)));
|
||||
|
||||
if (itemIndex !== -1) {
|
||||
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
||||
if (itemIndex !== -1) {
|
||||
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
||||
} else {
|
||||
itemIndex =
|
||||
Upgrades.push({
|
||||
UpgradeFingerprint: stringifiedUpgradeFingerprint,
|
||||
ItemType
|
||||
}) - 1;
|
||||
|
||||
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
||||
}
|
||||
|
||||
if (!inventory.infiniteCredits) {
|
||||
inventory.RegularCredits -= Cost;
|
||||
}
|
||||
if (!inventory.infiniteEndo) {
|
||||
inventory.FusionPoints -= FusionPointCost;
|
||||
}
|
||||
|
||||
if (artifactsData.LegendaryFusion) {
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser",
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
const changedInventory = (await inventory.save()).toJSON<IInventoryClient>();
|
||||
const itemId =
|
||||
changedInventory.Upgrades[itemIndex].ItemId.$oid ?? changedInventory.Upgrades[itemIndex].ItemId.$id;
|
||||
|
||||
if (!itemId) {
|
||||
throw new Error("Item Id not found in upgradeMod");
|
||||
}
|
||||
|
||||
res.send(itemId);
|
||||
} else {
|
||||
itemIndex =
|
||||
Upgrades.push({
|
||||
UpgradeFingerprint: stringifiedUpgradeFingerprint,
|
||||
ItemType
|
||||
}) - 1;
|
||||
// Pre-U18.18.0 uses the old pre-Endo fusion system which uses a different UpgradeFingerprint format
|
||||
// that has to be converted and consumes upgrades in the fusion proccess
|
||||
const safeUpgradeFingerprint = `{"lvl":${Fingerprint?.substring(4, Fingerprint.lastIndexOf("|"))}}`;
|
||||
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint) as { lvl: number };
|
||||
if (LevelDiff) {
|
||||
parsedUpgradeFingerprint.lvl += LevelDiff;
|
||||
}
|
||||
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
|
||||
|
||||
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
||||
}
|
||||
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id.equals(ItemId.$id));
|
||||
|
||||
if (!inventory.infiniteCredits) {
|
||||
inventory.RegularCredits -= Cost;
|
||||
}
|
||||
if (!inventory.infiniteEndo) {
|
||||
inventory.FusionPoints -= FusionPointCost;
|
||||
}
|
||||
if (itemIndex !== -1) {
|
||||
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
||||
} else {
|
||||
itemIndex =
|
||||
Upgrades.push({
|
||||
UpgradeFingerprint: stringifiedUpgradeFingerprint,
|
||||
ItemType
|
||||
}) - 1;
|
||||
|
||||
if (artifactsData.LegendaryFusion) {
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser",
|
||||
ItemCount: -1
|
||||
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
||||
}
|
||||
|
||||
const itemId = Upgrades[itemIndex]._id.toString();
|
||||
if (!itemId) {
|
||||
throw new Error("Item Id not found in upgradeMod");
|
||||
}
|
||||
|
||||
if (!inventory.infiniteCredits) {
|
||||
inventory.RegularCredits -= Cost;
|
||||
}
|
||||
if (Consumed && Consumed.length > 0) {
|
||||
for (const upgrade of Consumed) {
|
||||
// The client does not send the expected information about the mods, so we have to check if it's an Upgrade or RawUpgrade manually.
|
||||
if (Upgrades.id(fromOid(upgrade.ItemId))) {
|
||||
Upgrades.pull({ _id: upgrade.ItemId.$id });
|
||||
} else {
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: upgrade.ItemType,
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
itemIndex = Upgrades.findIndex(upgrade => upgrade._id.equals(itemId));
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
|
||||
res.send(itemId);
|
||||
}
|
||||
|
||||
const changedInventory = await inventory.save();
|
||||
const itemId = changedInventory.toJSON<IInventoryClient>().Upgrades[itemIndex].ItemId.$oid;
|
||||
|
||||
if (!itemId) {
|
||||
throw new Error("Item Id not found in upgradeMod");
|
||||
}
|
||||
|
||||
res.send(itemId);
|
||||
broadcastInventoryUpdate(req);
|
||||
};
|
||||
|
||||
@@ -67,4 +130,6 @@ interface IArtifactsRequest {
|
||||
Cost: number;
|
||||
FusionPointCost: number;
|
||||
LegendaryFusion?: boolean;
|
||||
Fingerprint?: string;
|
||||
Consumed?: IUpgradeFromClient[];
|
||||
}
|
||||
|
||||
@@ -262,9 +262,9 @@ const claimCompletedRecipe = async (
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
umbraModA.ItemId.$oid,
|
||||
umbraModB.ItemId.$oid,
|
||||
umbraModC.ItemId.$oid
|
||||
fromOid(umbraModA.ItemId),
|
||||
fromOid(umbraModB.ItemId),
|
||||
fromOid(umbraModC.ItemId)
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -284,7 +284,18 @@ const claimCompletedRecipe = async (
|
||||
"/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||
{
|
||||
Configs: [
|
||||
{ Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid] }
|
||||
{
|
||||
Upgrades: [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
fromOid(sacrificeModA.ItemId),
|
||||
fromOid(sacrificeModB.ItemId)
|
||||
]
|
||||
}
|
||||
],
|
||||
XP: 450_000,
|
||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||
|
||||
@@ -6,7 +6,7 @@ import { config } from "../../services/configService.ts";
|
||||
import allDialogue from "../../../static/fixed_responses/allDialogue.json" with { type: "json" };
|
||||
import allPopups from "../../../static/fixed_responses/allPopups.json" with { type: "json" };
|
||||
import type { ILoadoutDatabase } from "../../types/saveLoadoutTypes.ts";
|
||||
import type { IInventoryClient, IShipInventory } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import type { IInventoryClient, IShipInventory, IUpgradeClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { equipmentKeys } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import type { IPolarity } from "../../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import { ArtifactPolarity } from "../../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
@@ -30,7 +30,7 @@ import { getNemesisManifest } from "../../helpers/nemesisHelpers.ts";
|
||||
import { getPersonalRooms } from "../../services/personalRoomsService.ts";
|
||||
import type { IPersonalRoomsClient } from "../../types/personalRoomsTypes.ts";
|
||||
import { Ship } from "../../models/shipModel.ts";
|
||||
import { toLegacyOid, toOid, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
import { toLegacyOid, toOid, toOid2, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
import { Inbox } from "../../models/inboxModel.ts";
|
||||
import { unixTimesInMs } from "../../constants/timeConstants.ts";
|
||||
import { DailyDeal } from "../../models/worldStateModel.ts";
|
||||
@@ -454,28 +454,140 @@ export const getInventoryResponse = async (
|
||||
inventoryResponse.Nemesis = undefined;
|
||||
}
|
||||
|
||||
if (version_compare(buildLabel, "2018.02.22.14.34") < 0) {
|
||||
const personalRoomsDb = await getPersonalRooms(inventory.accountOwnerId.toString());
|
||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRoomsClient>();
|
||||
inventoryResponse.Ship = personalRooms.Ship;
|
||||
if (version_compare(buildLabel, "2019.03.07.20.21") < 0) {
|
||||
// Builds before U24.4.0 handle equipment features differently
|
||||
for (const category of equipmentKeys) {
|
||||
for (const item of inventoryResponse[category]) {
|
||||
if (item.Features && item.Features & EquipmentFeatures.DOUBLE_CAPACITY) {
|
||||
item.UnlockLevel = 1;
|
||||
}
|
||||
if (item.Features && item.Features & EquipmentFeatures.UTILITY_SLOT) {
|
||||
item.UtilityUnlocked = 1;
|
||||
}
|
||||
if (item.Features && item.Features & EquipmentFeatures.GILDED) {
|
||||
item.Gild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version_compare(buildLabel, "2016.12.21.19.13") <= 0) {
|
||||
// U19.5 and below use $id instead of $oid
|
||||
for (const category of equipmentKeys) {
|
||||
for (const item of inventoryResponse[category]) {
|
||||
toLegacyOid(item.ItemId);
|
||||
if (version_compare(buildLabel, "2018.02.22.14.34") < 0) {
|
||||
const personalRoomsDb = await getPersonalRooms(inventory.accountOwnerId.toString());
|
||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRoomsClient>();
|
||||
inventoryResponse.Ship = personalRooms.Ship;
|
||||
|
||||
if (version_compare(buildLabel, "2016.12.21.19.13") <= 0) {
|
||||
// U19.5 and below use $id instead of $oid
|
||||
for (const category of equipmentKeys) {
|
||||
for (const item of inventoryResponse[category]) {
|
||||
toLegacyOid(item.ItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const upgrade of inventoryResponse.Upgrades) {
|
||||
toLegacyOid(upgrade.ItemId);
|
||||
}
|
||||
if (inventoryResponse.BrandedSuits) {
|
||||
for (const id of inventoryResponse.BrandedSuits) {
|
||||
toLegacyOid(id);
|
||||
|
||||
if (version_compare(buildLabel, "2014.02.05.00.00") < 0) {
|
||||
// Pre-U12 builds store mods in an array called Cards, and have no concept of RawUpgrades
|
||||
inventoryResponse.Cards = [];
|
||||
for (const rawUpgrade of inventoryResponse.RawUpgrades) {
|
||||
const id = inventory.RawUpgrades.find(x => x.ItemType == rawUpgrade.ItemType)?._id;
|
||||
if (id) {
|
||||
for (let i = 0; i < rawUpgrade.ItemCount; i++) {
|
||||
const card = {
|
||||
ItemType: rawUpgrade.ItemType,
|
||||
ItemId: toOid2(id, buildLabel),
|
||||
Rank: 0,
|
||||
AmountRemaining: rawUpgrade.ItemCount
|
||||
} as IUpgradeClient;
|
||||
// Client doesn't see the mods unless they are in both Cards and Upgrades
|
||||
inventoryResponse.Cards.push(card);
|
||||
inventoryResponse.Upgrades.push(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inventoryResponse.RawUpgrades = [];
|
||||
|
||||
for (const category of equipmentKeys) {
|
||||
for (const item of inventoryResponse[category]) {
|
||||
for (const config of item.Configs) {
|
||||
if (config.Upgrades) {
|
||||
// Convert installed upgrades for U10-U11
|
||||
const convertedUpgrades: { $id: string }[] = [];
|
||||
config.Upgrades.forEach(upgrade => {
|
||||
const upgradeId = upgrade as string;
|
||||
convertedUpgrades.push({ $id: upgradeId });
|
||||
});
|
||||
config.Upgrades = convertedUpgrades;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const upgrade of inventoryResponse.Upgrades) {
|
||||
toLegacyOid(upgrade.ItemId);
|
||||
if (version_compare(buildLabel, "2016.08.19.17.12") < 0) {
|
||||
// Pre-U18.18 builds use a different UpgradeFingerprint format
|
||||
let rank: number = 0;
|
||||
if (upgrade.UpgradeFingerprint) {
|
||||
rank = Number.parseFloat(
|
||||
upgrade.UpgradeFingerprint.substring(
|
||||
upgrade.UpgradeFingerprint.indexOf(":") + 1,
|
||||
upgrade.UpgradeFingerprint.lastIndexOf("}")
|
||||
)
|
||||
);
|
||||
}
|
||||
upgrade.UpgradeFingerprint = `lvl=${rank}|`;
|
||||
if (version_compare(buildLabel, "2014.04.10.17.47") < 0) {
|
||||
// Pre-U10 builds
|
||||
if (
|
||||
!upgrade.AmountRemaining ||
|
||||
(upgrade.AmountRemaining && upgrade.AmountRemaining <= 0)
|
||||
) {
|
||||
upgrade.AmountRemaining = 1;
|
||||
}
|
||||
upgrade.Rank = rank;
|
||||
if (inventoryResponse.Cards) {
|
||||
inventoryResponse.Cards.push(upgrade);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version_compare(buildLabel, "2014.02.05.00.00") < 0) {
|
||||
// Convert installed mods for pre-U12 builds
|
||||
for (const category of equipmentKeys) {
|
||||
for (const item of inventoryResponse[category]) {
|
||||
for (const config of item.Configs) {
|
||||
if (config.Upgrades) {
|
||||
for (let i = 0; i < config.Upgrades.length; i++) {
|
||||
const id = config.Upgrades[i] as { $id: string | undefined };
|
||||
const invUpgrade = inventoryResponse.Upgrades.find(
|
||||
x => x.ItemId.$id == id.$id
|
||||
);
|
||||
if (invUpgrade) {
|
||||
if (id.$id?.startsWith("/Lotus")) {
|
||||
// Pre-U12 builds have no concept of RawUpgrades, have to convert the db entry to the closest id of an unranked copy
|
||||
id.$id = inventoryResponse.Upgrades.find(
|
||||
x => x.ItemType == id.$id
|
||||
)?.ItemId.$id;
|
||||
}
|
||||
// Pre-U10
|
||||
invUpgrade.ParentId = item.ItemId;
|
||||
invUpgrade.Slot = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inventoryResponse.BrandedSuits) {
|
||||
for (const id of inventoryResponse.BrandedSuits) {
|
||||
toLegacyOid(id);
|
||||
}
|
||||
}
|
||||
if (inventoryResponse.GuildId) {
|
||||
toLegacyOid(inventoryResponse.GuildId);
|
||||
}
|
||||
}
|
||||
if (inventoryResponse.GuildId) {
|
||||
toLegacyOid(inventoryResponse.GuildId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,16 @@ const createLoginResponse = (
|
||||
if (version_compare(buildLabel, "2022.09.06.19.24") >= 0) {
|
||||
resp.CrossPlatformAllowed = account.CrossPlatformAllowed;
|
||||
resp.HUB = `${myUrlBase}/api/`;
|
||||
resp.MatchmakingBuildId = buildConfig.matchmakingBuildId;
|
||||
|
||||
// The MatchmakingBuildId is a 64-bit integer represented as a decimal string. On live, the value is seemingly random per build, but really any value that is different across builds should work.
|
||||
const [year, month, day, hour, minute] = buildLabel.split(".").map(x => parseInt(x));
|
||||
resp.MatchmakingBuildId = (
|
||||
year * 1_00_00_00_00 +
|
||||
month * 1_00_00_00 +
|
||||
day * 1_00_00 +
|
||||
hour * 1_00 +
|
||||
minute
|
||||
).toString();
|
||||
}
|
||||
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
|
||||
if (version_compare(buildLabel, "2025.08.26.09.49") >= 0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fromDbOid, toMongoDate, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
import { fromDbOid, fromOid, toMongoDate, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
import type { IKnifeResponse } from "../../helpers/nemesisHelpers.ts";
|
||||
import {
|
||||
antivirusMods,
|
||||
@@ -21,7 +21,7 @@ import { Loadout } from "../../models/inventoryModels/loadoutModel.ts";
|
||||
import { addMods, freeUpSlot, getInventory } from "../../services/inventoryService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { SRng } from "../../services/rngService.ts";
|
||||
import type { IMongoDate, IOid } from "../../types/commonTypes.ts";
|
||||
import type { IMongoDate, IOid, IOidWithLegacySupport } from "../../types/commonTypes.ts";
|
||||
import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
|
||||
import type {
|
||||
IInnateDamageFingerprint,
|
||||
@@ -420,7 +420,7 @@ interface IKnife {
|
||||
const consumeModCharge = (
|
||||
response: IKnifeResponse,
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
upgrade: { ItemId: IOid; ItemType: string },
|
||||
upgrade: { ItemId: IOidWithLegacySupport; ItemType: string },
|
||||
dataknifeUpgrades: string[]
|
||||
): void => {
|
||||
response.UpgradeIds ??= [];
|
||||
@@ -429,13 +429,13 @@ const consumeModCharge = (
|
||||
response.UpgradeNew ??= [];
|
||||
response.HasKnife = true;
|
||||
|
||||
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
||||
const dbUpgrade = inventory.Upgrades.id(upgrade.ItemId.$oid)!;
|
||||
if (fromOid(upgrade.ItemId) != "000000000000000000000000") {
|
||||
const dbUpgrade = inventory.Upgrades.id(fromOid(upgrade.ItemId))!;
|
||||
const fingerprint = JSON.parse(dbUpgrade.UpgradeFingerprint!) as { lvl: number };
|
||||
fingerprint.lvl += 1;
|
||||
dbUpgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
|
||||
|
||||
response.UpgradeIds.push(upgrade.ItemId.$oid);
|
||||
response.UpgradeIds.push(fromOid(upgrade.ItemId));
|
||||
response.UpgradeTypes.push(upgrade.ItemType);
|
||||
response.UpgradeFingerprints.push(fingerprint);
|
||||
response.UpgradeNew.push(false);
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import type { RivenFingerprint } from "../../helpers/rivenHelper.ts";
|
||||
import { createUnveiledRivenFingerprint, randomiseRivenStats } from "../../helpers/rivenHelper.ts";
|
||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
||||
import type { IOid } from "../../types/commonTypes.ts";
|
||||
import type { IOidWithLegacySupport } from "../../types/commonTypes.ts";
|
||||
import { toObjectId, toOid2 } from "../../helpers/inventoryHelpers.ts";
|
||||
|
||||
export const rerollRandomModController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
const accountId = account._id.toString();
|
||||
const request = getJSONfromString<RerollRandomModRequest>(String(req.body));
|
||||
if ("ItemIds" in request) {
|
||||
const inventory = await getInventory(accountId, "Upgrades MiscItems");
|
||||
@@ -40,7 +42,7 @@ export const rerollRandomModController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
|
||||
changes.push({
|
||||
ItemId: { $oid: request.ItemIds[0] },
|
||||
ItemId: toOid2(toObjectId(request.ItemIds[0]), account.BuildLabel),
|
||||
UpgradeFingerprint: upgrade.UpgradeFingerprint,
|
||||
PendingRerollFingerprint: upgrade.PendingRerollFingerprint
|
||||
});
|
||||
@@ -76,7 +78,7 @@ interface AwDangitRequest {
|
||||
}
|
||||
|
||||
interface IChange {
|
||||
ItemId: IOid;
|
||||
ItemId: IOidWithLegacySupport;
|
||||
UpgradeFingerprint?: string;
|
||||
PendingRerollFingerprint?: string;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import type { ISaveLoadoutRequest } from "../../types/saveLoadoutTypes.ts";
|
||||
import { handleInventoryItemConfigChange } from "../../services/saveLoadoutService.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
|
||||
export const saveLoadoutController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const account = await getAccountForRequest(req);
|
||||
|
||||
const body: ISaveLoadoutRequest = getJSONfromString<ISaveLoadoutRequest>(String(req.body));
|
||||
// console.log(util.inspect(body, { showHidden: false, depth: null, colors: true }));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { UpgradeVer, ...equipmentChanges } = body;
|
||||
const newLoadoutId = await handleInventoryItemConfigChange(equipmentChanges, accountId);
|
||||
const newLoadoutId = await handleInventoryItemConfigChange(
|
||||
equipmentChanges,
|
||||
account._id.toString(),
|
||||
account.BuildLabel
|
||||
);
|
||||
|
||||
//send back new loadout id, if new loadout was added
|
||||
if (newLoadoutId) {
|
||||
|
||||
@@ -1,155 +1,288 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import type { IUpgradesRequest } from "../../types/requestTypes.ts";
|
||||
import { fromOid, version_compare } from "../../helpers/inventoryHelpers.ts";
|
||||
import type { IUpgradesRequest, IUpgradesRequestLegacy } from "../../types/requestTypes.ts";
|
||||
import type { ArtifactPolarity, IAbilityOverride } from "../../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import type { IInventoryClient, IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { addMiscItems, addRecipes, getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import { addMiscItems, addMods, addRecipes, getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
||||
import { getRecipeByResult } from "../../services/itemDataService.ts";
|
||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
||||
import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "../../services/infestedFoundryService.ts";
|
||||
import { sendWsBroadcastTo } from "../../services/wsService.ts";
|
||||
import type { IEquipmentDatabase } from "../../types/equipmentTypes.ts";
|
||||
import { EquipmentFeatures } from "../../types/equipmentTypes.ts";
|
||||
import { Types } from "mongoose";
|
||||
|
||||
export const upgradesController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const payload = JSON.parse(String(req.body)) as IUpgradesRequest;
|
||||
const account = await getAccountForRequest(req);
|
||||
const accountId = account._id.toString();
|
||||
const inventory = await getInventory(accountId);
|
||||
const inventoryChanges: IInventoryChanges = {};
|
||||
for (const operation of payload.Operations) {
|
||||
if (
|
||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/ModSlotUnlocker" ||
|
||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
|
||||
) {
|
||||
updateCurrency(inventory, 10, true);
|
||||
} else if (
|
||||
operation.OperationType != "UOT_SWAP_POLARITY" &&
|
||||
operation.OperationType != "UOT_ABILITY_OVERRIDE"
|
||||
) {
|
||||
if (!operation.UpgradeRequirement) {
|
||||
throw new Error(`${operation.OperationType} operation should be free?`);
|
||||
}
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: operation.UpgradeRequirement,
|
||||
ItemCount: -1
|
||||
} satisfies IMiscItem
|
||||
]);
|
||||
}
|
||||
|
||||
if (operation.OperationType == "UOT_ABILITY_OVERRIDE") {
|
||||
console.assert(payload.ItemCategory == "Suits");
|
||||
const suit = inventory.Suits.id(payload.ItemId.$oid)!;
|
||||
|
||||
let newAbilityOverride: IAbilityOverride | undefined;
|
||||
let totalPercentagePointsConsumed = 0;
|
||||
if (operation.UpgradeRequirement != "") {
|
||||
newAbilityOverride = {
|
||||
Ability: operation.UpgradeRequirement,
|
||||
Index: operation.PolarizeSlot
|
||||
};
|
||||
|
||||
const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
|
||||
for (const ingredient of recipe.ingredients) {
|
||||
totalPercentagePointsConsumed += ingredient.ItemCount / 10;
|
||||
if (!inventory.infiniteHelminthMaterials) {
|
||||
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
|
||||
ingredient.ItemCount;
|
||||
if (account.BuildLabel && version_compare(account.BuildLabel, "2019.03.07.20.21") < 0) {
|
||||
// Builds before U24.4.0 have a different request format
|
||||
const payload = JSON.parse(String(req.body)) as IUpgradesRequestLegacy;
|
||||
const itemId = fromOid(payload.Weapon.ItemId);
|
||||
if (itemId) {
|
||||
if (payload.IsSwappingOperation === true) {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
for (let i = 0; i != payload.PolarityRemap.length; ++i) {
|
||||
// Can't really be selective here like the newer format, it pushes everything in a way that the comparison fails against...
|
||||
setSlotPolarity(item, i, payload.PolarityRemap[i].Value);
|
||||
}
|
||||
} else {
|
||||
if (payload.PolarizeReq) {
|
||||
switch (payload.PolarizeReq) {
|
||||
case "/Lotus/Types/Items/MiscItems/Forma":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaUmbra": {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
item.XP = 0;
|
||||
setSlotPolarity(item, payload.PolarizeSlot, payload.PolarizeValue);
|
||||
item.Polarized ??= 0;
|
||||
item.Polarized += 1;
|
||||
sendWsBroadcastTo(accountId, { update_inventory: true });
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported polarize item: " + payload.PolarizeReq);
|
||||
}
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: payload.PolarizeReq,
|
||||
ItemCount: -1
|
||||
} satisfies IMiscItem
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
for (const entry of operation.PolarityRemap) {
|
||||
suit.Configs[entry.Slot] ??= {};
|
||||
suit.Configs[entry.Slot].AbilityOverride = newAbilityOverride;
|
||||
}
|
||||
|
||||
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, totalPercentagePointsConsumed * 8);
|
||||
addRecipes(inventory, recipeChanges);
|
||||
|
||||
inventoryChanges.Recipes = recipeChanges;
|
||||
inventoryChanges.InfestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry;
|
||||
applyCheatsToInfestedFoundry(inventory, inventoryChanges.InfestedFoundry!);
|
||||
} else
|
||||
switch (operation.UpgradeRequirement) {
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinReactor":
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinCatalyst": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/UtilityUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponUtilityUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.UTILITY_SLOT;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/HeavyWeaponCatalyst": {
|
||||
console.assert(payload.ItemCategory == "SpaceGuns");
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.GRAVIMAG_INSTALLED;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponAmpArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponArchGunArcaneUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
if (operation.OperationType == "UOT_ARCANE_UNLOCK_1") {
|
||||
item.Features |= EquipmentFeatures.SECOND_ARCANE_SLOT;
|
||||
} else {
|
||||
item.Features |= EquipmentFeatures.ARCANE_SLOT;
|
||||
if (payload.UtilityReq) {
|
||||
switch (payload.UtilityReq) {
|
||||
case "/Lotus/Types/Items/MiscItems/UtilityUnlocker": {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.UTILITY_SLOT;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported utility item: " + payload.UtilityReq);
|
||||
}
|
||||
break;
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: payload.UtilityReq,
|
||||
ItemCount: -1
|
||||
} satisfies IMiscItem
|
||||
]);
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/ValenceAdapter": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.VALENCE_SWAP;
|
||||
break;
|
||||
if (payload.UpgradeReq) {
|
||||
switch (payload.UpgradeReq) {
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinReactor":
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinCatalyst": {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported upgrade: " + payload.UpgradeReq);
|
||||
}
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: payload.UpgradeReq,
|
||||
ItemCount: -1
|
||||
} satisfies IMiscItem
|
||||
]);
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/Forma":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaUmbra":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaAura":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaStance": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.XP = 0;
|
||||
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
|
||||
item.Polarized ??= 0;
|
||||
item.Polarized += 1;
|
||||
sendWsBroadcastTo(accountId, { update_inventory: true }); // webui may need to to re-add "max rank" button
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle attaching/detaching mods in U7-U8
|
||||
if (payload.UpgradesToAttach && payload.UpgradesToAttach.length > 0) {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
if (!item.Configs[0]) {
|
||||
item.Configs.push({ Upgrades: ["", "", "", "", "", "", "", "", "", "", ""] });
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.ModSlotPurchases ??= 0;
|
||||
item.ModSlotPurchases += 1;
|
||||
break;
|
||||
if (item.Configs[0].Upgrades && item.Configs[0].Upgrades.length < 11) {
|
||||
item.Configs[0].Upgrades.length = 11;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.CustomizationSlotPurchases ??= 0;
|
||||
item.CustomizationSlotPurchases += 1;
|
||||
break;
|
||||
}
|
||||
case "": {
|
||||
console.assert(operation.OperationType == "UOT_SWAP_POLARITY");
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
for (let i = 0; i != operation.PolarityRemap.length; ++i) {
|
||||
if (operation.PolarityRemap[i].Slot != i) {
|
||||
setSlotPolarity(item, i, operation.PolarityRemap[i].Value);
|
||||
payload.UpgradesToAttach.forEach(upgrade => {
|
||||
if (item.Configs[0].Upgrades && upgrade.ItemId.$id && upgrade.Slot) {
|
||||
const arr = item.Configs[0].Upgrades;
|
||||
if (arr.indexOf(upgrade.ItemId.$id) != -1) {
|
||||
// Handle swapping mod to a different slot
|
||||
arr[arr.indexOf(upgrade.ItemId.$id)] = "";
|
||||
}
|
||||
// We need to convert RawUpgrade into Upgrade once it's attached
|
||||
const rawUpgrade = inventory.RawUpgrades.id(upgrade.ItemId.$id);
|
||||
if (rawUpgrade) {
|
||||
const newId = new Types.ObjectId().toString();
|
||||
arr[upgrade.Slot - 1] = newId;
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: upgrade.ItemType,
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
inventory.Upgrades.push({
|
||||
UpgradeFingerprint: `{"lvl":0}`,
|
||||
ItemType: upgrade.ItemType,
|
||||
_id: newId
|
||||
});
|
||||
} else {
|
||||
arr[upgrade.Slot - 1] = upgrade.ItemId.$id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported upgrade: " + operation.UpgradeRequirement);
|
||||
});
|
||||
}
|
||||
if (payload.UpgradesToDetach && payload.UpgradesToDetach.length > 0) {
|
||||
const item = inventory[payload.Category].id(itemId)!;
|
||||
if (item.Configs[0].Upgrades && item.Configs[0].Upgrades.length < 11) {
|
||||
item.Configs[0].Upgrades.length = 11;
|
||||
}
|
||||
payload.UpgradesToDetach.forEach(upgrade => {
|
||||
if (item.Configs[0].Upgrades && upgrade.ItemId.$id) {
|
||||
const arr = item.Configs[0].Upgrades;
|
||||
arr[arr.indexOf(upgrade.ItemId.$id)] = "";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const payload = JSON.parse(String(req.body)) as IUpgradesRequest;
|
||||
for (const operation of payload.Operations) {
|
||||
if (
|
||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/ModSlotUnlocker" ||
|
||||
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
|
||||
) {
|
||||
updateCurrency(inventory, 10, true);
|
||||
} else if (
|
||||
operation.OperationType != "UOT_SWAP_POLARITY" &&
|
||||
operation.OperationType != "UOT_ABILITY_OVERRIDE"
|
||||
) {
|
||||
if (!operation.UpgradeRequirement) {
|
||||
throw new Error(`${operation.OperationType} operation should be free?`);
|
||||
}
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: operation.UpgradeRequirement,
|
||||
ItemCount: -1
|
||||
} satisfies IMiscItem
|
||||
]);
|
||||
}
|
||||
|
||||
if (operation.OperationType == "UOT_ABILITY_OVERRIDE") {
|
||||
console.assert(payload.ItemCategory == "Suits");
|
||||
const suit = inventory.Suits.id(payload.ItemId.$oid)!;
|
||||
|
||||
let newAbilityOverride: IAbilityOverride | undefined;
|
||||
let totalPercentagePointsConsumed = 0;
|
||||
if (operation.UpgradeRequirement != "") {
|
||||
newAbilityOverride = {
|
||||
Ability: operation.UpgradeRequirement,
|
||||
Index: operation.PolarizeSlot
|
||||
};
|
||||
|
||||
const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
|
||||
for (const ingredient of recipe.ingredients) {
|
||||
totalPercentagePointsConsumed += ingredient.ItemCount / 10;
|
||||
if (!inventory.infiniteHelminthMaterials) {
|
||||
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
|
||||
ingredient.ItemCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const entry of operation.PolarityRemap) {
|
||||
suit.Configs[entry.Slot] ??= {};
|
||||
suit.Configs[entry.Slot].AbilityOverride = newAbilityOverride;
|
||||
}
|
||||
|
||||
const recipeChanges = addInfestedFoundryXP(
|
||||
inventory.InfestedFoundry!,
|
||||
totalPercentagePointsConsumed * 8
|
||||
);
|
||||
addRecipes(inventory, recipeChanges);
|
||||
|
||||
inventoryChanges.Recipes = recipeChanges;
|
||||
inventoryChanges.InfestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry;
|
||||
applyCheatsToInfestedFoundry(inventory, inventoryChanges.InfestedFoundry!);
|
||||
} else
|
||||
switch (operation.UpgradeRequirement) {
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinReactor":
|
||||
case "/Lotus/Types/Items/MiscItems/OrokinCatalyst": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/UtilityUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponUtilityUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.UTILITY_SLOT;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/HeavyWeaponCatalyst": {
|
||||
console.assert(payload.ItemCategory == "SpaceGuns");
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.GRAVIMAG_INSTALLED;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponAmpArcaneUnlocker":
|
||||
case "/Lotus/Types/Items/MiscItems/WeaponArchGunArcaneUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
if (operation.OperationType == "UOT_ARCANE_UNLOCK_1") {
|
||||
item.Features |= EquipmentFeatures.SECOND_ARCANE_SLOT;
|
||||
} else {
|
||||
item.Features |= EquipmentFeatures.ARCANE_SLOT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/ValenceAdapter": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.Features ??= 0;
|
||||
item.Features |= EquipmentFeatures.VALENCE_SWAP;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/Forma":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaUmbra":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaAura":
|
||||
case "/Lotus/Types/Items/MiscItems/FormaStance": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.XP = 0;
|
||||
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
|
||||
item.Polarized ??= 0;
|
||||
item.Polarized += 1;
|
||||
sendWsBroadcastTo(accountId, { update_inventory: true }); // webui may need to to re-add "max rank" button
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.ModSlotPurchases ??= 0;
|
||||
item.ModSlotPurchases += 1;
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker": {
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
item.CustomizationSlotPurchases ??= 0;
|
||||
item.CustomizationSlotPurchases += 1;
|
||||
break;
|
||||
}
|
||||
case "": {
|
||||
console.assert(operation.OperationType == "UOT_SWAP_POLARITY");
|
||||
const item = inventory[payload.ItemCategory].id(payload.ItemId.$oid)!;
|
||||
for (let i = 0; i != operation.PolarityRemap.length; ++i) {
|
||||
if (operation.PolarityRemap[i].Slot != i) {
|
||||
setSlotPolarity(item, i, operation.PolarityRemap[i].Value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported upgrade: " + operation.UpgradeRequirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
await inventory.save();
|
||||
res.json({ InventoryChanges: inventoryChanges });
|
||||
|
||||
@@ -13,33 +13,41 @@ export const importController: RequestHandler = async (req, res) => {
|
||||
const request = req.body as IImportRequest;
|
||||
|
||||
let anyKnownKey = false;
|
||||
try {
|
||||
const inventory = await getInventory(accountId);
|
||||
if (importInventory(inventory, request.inventory)) {
|
||||
anyKnownKey = true;
|
||||
await inventory.save();
|
||||
}
|
||||
|
||||
const inventory = await getInventory(accountId);
|
||||
if (importInventory(inventory, request.inventory)) {
|
||||
anyKnownKey = true;
|
||||
await inventory.save();
|
||||
if ("LoadOutPresets" in request.inventory && request.inventory.LoadOutPresets) {
|
||||
anyKnownKey = true;
|
||||
const loadout = await getLoadout(accountId);
|
||||
importLoadOutPresets(loadout, request.inventory.LoadOutPresets);
|
||||
await loadout.save();
|
||||
}
|
||||
|
||||
if (
|
||||
request.inventory.Ship?.Rooms || // very old accounts may have Ship with { Features: [ ... ] }
|
||||
"Apartment" in request.inventory ||
|
||||
"TailorShop" in request.inventory
|
||||
) {
|
||||
anyKnownKey = true;
|
||||
const personalRooms = await getPersonalRooms(accountId);
|
||||
importPersonalRooms(personalRooms, request.inventory);
|
||||
await personalRooms.save();
|
||||
}
|
||||
|
||||
if (!anyKnownKey) {
|
||||
res.send("noKnownKey").end();
|
||||
}
|
||||
|
||||
broadcastInventoryUpdate(req);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.send((e as Error).message);
|
||||
}
|
||||
|
||||
if ("LoadOutPresets" in request.inventory && request.inventory.LoadOutPresets) {
|
||||
anyKnownKey = true;
|
||||
const loadout = await getLoadout(accountId);
|
||||
importLoadOutPresets(loadout, request.inventory.LoadOutPresets);
|
||||
await loadout.save();
|
||||
}
|
||||
|
||||
if (
|
||||
request.inventory.Ship?.Rooms || // very old accounts may have Ship with { Features: [ ... ] }
|
||||
"Apartment" in request.inventory ||
|
||||
"TailorShop" in request.inventory
|
||||
) {
|
||||
anyKnownKey = true;
|
||||
const personalRooms = await getPersonalRooms(accountId);
|
||||
importPersonalRooms(personalRooms, request.inventory);
|
||||
await personalRooms.save();
|
||||
}
|
||||
|
||||
res.json(anyKnownKey);
|
||||
broadcastInventoryUpdate(req);
|
||||
res.end();
|
||||
};
|
||||
|
||||
interface IImportRequest {
|
||||
|
||||
@@ -20,6 +20,10 @@ export const version_compare = (a: string, b: string): number => {
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const toObjectId = (s: string): Types.ObjectId => {
|
||||
return new Types.ObjectId(s);
|
||||
};
|
||||
|
||||
export const toOid = (objectId: Types.ObjectId): IOid => {
|
||||
return { $oid: objectId.toString() };
|
||||
};
|
||||
|
||||
@@ -1060,7 +1060,6 @@ const EquipmentSchema = new Schema<IEquipmentDatabase>(
|
||||
InfestationDays: Number,
|
||||
InfestationType: String,
|
||||
ModularParts: { type: [String], default: undefined },
|
||||
UnlockLevel: Number,
|
||||
Expiry: Date,
|
||||
SkillTree: String,
|
||||
OffensiveUpgrade: String,
|
||||
@@ -1493,6 +1492,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
relicRewardItemCountMultiplier: { type: Number, default: 1 },
|
||||
nightwaveStandingMultiplier: { type: Number, default: 1 },
|
||||
|
||||
Created: Date,
|
||||
|
||||
SubscribedToEmails: { type: Number, default: 0 },
|
||||
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
|
||||
RewardSeed: BigInt,
|
||||
|
||||
@@ -9,6 +9,7 @@ statsRouter.get("/view.php", viewController);
|
||||
statsRouter.get("/profileStats.php", viewController);
|
||||
statsRouter.get("/leaderboard.php", leaderboardGetController);
|
||||
statsRouter.post("/upload.php", uploadController);
|
||||
statsRouter.post("/view.php", viewController);
|
||||
statsRouter.post("/leaderboardWeekly.php", leaderboardPostController);
|
||||
statsRouter.post("/leaderboardArchived.php", leaderboardPostController);
|
||||
|
||||
|
||||
@@ -5,13 +5,11 @@ import { repoDir } from "../helpers/pathHelper.ts";
|
||||
interface IBuildConfig {
|
||||
version: string;
|
||||
buildLabel: string;
|
||||
matchmakingBuildId: string;
|
||||
}
|
||||
|
||||
export const buildConfig: IBuildConfig = {
|
||||
version: "",
|
||||
buildLabel: "",
|
||||
matchmakingBuildId: ""
|
||||
buildLabel: ""
|
||||
};
|
||||
|
||||
const buildConfigPath = path.join(repoDir, "static/data/buildConfig.json");
|
||||
|
||||
@@ -33,7 +33,7 @@ import type { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/generic
|
||||
import type { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import { convertInboxMessage, fromStoreItem, getKeyChainItems } from "./itemDataService.ts";
|
||||
import type { IFlavourItem, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import type { IFlavourItem, IItemConfig, IItemConfigDatabase } from "../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import type { IDefaultUpgrade, IPowersuit, ISentinel, TStandingLimitBin } from "warframe-public-export-plus";
|
||||
import {
|
||||
ExportArcanes,
|
||||
@@ -922,9 +922,9 @@ export const addItems = async (
|
||||
export const applyDefaultUpgrades = (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
defaultUpgrades: IDefaultUpgrade[] | undefined
|
||||
): IItemConfig[] => {
|
||||
): IItemConfigDatabase[] => {
|
||||
const modsToGive: IRawUpgrade[] = [];
|
||||
const configs: IItemConfig[] = [];
|
||||
const configs: IItemConfigDatabase[] = [];
|
||||
if (defaultUpgrades) {
|
||||
const upgrades = [];
|
||||
for (const defaultUpgrade of defaultUpgrades) {
|
||||
|
||||
@@ -84,7 +84,7 @@ import {
|
||||
import { config } from "./configService.ts";
|
||||
import libraryDailyTasks from "../../static/fixed_responses/libraryDailyTasks.json" with { type: "json" };
|
||||
import type { IGoal, ISyndicateMissionInfo } from "../types/worldStateTypes.ts";
|
||||
import { fromOid } from "../helpers/inventoryHelpers.ts";
|
||||
import { fromOid, version_compare } from "../helpers/inventoryHelpers.ts";
|
||||
import type { TAccountDocument } from "./loginService.ts";
|
||||
import type { ITypeCount } from "../types/commonTypes.ts";
|
||||
import type { IEquipmentClient } from "../types/equipmentTypes.ts";
|
||||
@@ -480,9 +480,32 @@ export const addMissionInventoryUpdates = async (
|
||||
case "Upgrades":
|
||||
value.forEach(clientUpgrade => {
|
||||
const id = fromOid(clientUpgrade.ItemId);
|
||||
if (id == "") {
|
||||
// Really old builds (tested U7-U8) do not have the UpgradeFingerprint set for unranked mod drops
|
||||
clientUpgrade.UpgradeFingerprint ??= "lvl=0|";
|
||||
// U11 and below also don't initialize ItemCount since RawUpgrade doesn't exist in them
|
||||
clientUpgrade.ItemCount ??= 1;
|
||||
if (account.BuildLabel && version_compare(account.BuildLabel, "2016.08.19.17.12") < 0) {
|
||||
// Acquired Mods have a different UpgradeFingerprint format in pre-U18.18.0 builds, this converts them to the format the database expects
|
||||
clientUpgrade.UpgradeFingerprint = `{"lvl":${clientUpgrade.UpgradeFingerprint.substring(
|
||||
clientUpgrade.UpgradeFingerprint.indexOf("=") + 1,
|
||||
clientUpgrade.UpgradeFingerprint.lastIndexOf("|")
|
||||
)}}`;
|
||||
}
|
||||
// Handle Fusion Core drops
|
||||
const parsedFingerprint = JSON.parse(clientUpgrade.UpgradeFingerprint) as { lvl: number };
|
||||
if (parsedFingerprint.lvl != 0) {
|
||||
inventory.Upgrades.push({
|
||||
ItemType: clientUpgrade.ItemType,
|
||||
UpgradeFingerprint: clientUpgrade.UpgradeFingerprint
|
||||
});
|
||||
} else if (id == "") {
|
||||
// U19 does not provide RawUpgrades and instead interleaves them with riven progress here
|
||||
addMods(inventory, [clientUpgrade]);
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: clientUpgrade.ItemType,
|
||||
ItemCount: clientUpgrade.ItemCount
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
const upgrade = inventory.Upgrades.id(id)!;
|
||||
upgrade.UpgradeFingerprint = clientUpgrade.UpgradeFingerprint; // primitive way to copy over the riven challenge progress
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { IQuestKeyClient, IQuestKeyDatabase, IQuestStage } from "../types/i
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import { ExportKeys, ExportRecipes } from "warframe-public-export-plus";
|
||||
import { addFixedLevelRewards } from "./missionInventoryUpdateService.ts";
|
||||
import { fromOid } from "../helpers/inventoryHelpers.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";
|
||||
@@ -761,9 +762,9 @@ export const removeRequiredItems = async (inventory: TInventoryDatabaseDocument,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
umbraModA.ItemId.$oid,
|
||||
umbraModB.ItemId.$oid,
|
||||
umbraModC.ItemId.$oid
|
||||
fromOid(umbraModA.ItemId),
|
||||
fromOid(umbraModB.ItemId),
|
||||
fromOid(umbraModC.ItemId)
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -778,7 +779,16 @@ export const removeRequiredItems = async (inventory: TInventoryDatabaseDocument,
|
||||
addEquipment(inventory, "Melee", "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana", {
|
||||
Configs: [
|
||||
{
|
||||
Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid]
|
||||
Upgrades: [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
fromOid(sacrificeModA.ItemId),
|
||||
fromOid(sacrificeModB.ItemId)
|
||||
]
|
||||
}
|
||||
],
|
||||
XP: 450_000,
|
||||
|
||||
@@ -6,14 +6,15 @@ import type {
|
||||
ISaveLoadoutRequestNoUpgradeVer
|
||||
} from "../types/saveLoadoutTypes.ts";
|
||||
import { Loadout } from "../models/inventoryModels/loadoutModel.ts";
|
||||
import { getInventory } from "./inventoryService.ts";
|
||||
import { addMods, getInventory } from "./inventoryService.ts";
|
||||
import type { IOid } from "../types/commonTypes.ts";
|
||||
import { Types } from "mongoose";
|
||||
import { isEmptyObject } from "../helpers/general.ts";
|
||||
import { version_compare } from "../helpers/inventoryHelpers.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import type { TEquipmentKey } from "../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { equipmentKeys } from "../types/inventoryTypes/inventoryTypes.ts";
|
||||
import type { IItemConfig } from "../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import type { IItemConfig, IItemConfigDatabase } from "../types/inventoryTypes/commonInventoryTypes.ts";
|
||||
import { importCrewShipMembers, importCrewShipWeapon, importLoadOutConfig } from "./importService.ts";
|
||||
|
||||
//TODO: setup default items on account creation or like originally in giveStartingItems.php
|
||||
@@ -26,7 +27,8 @@ itemconfig has multiple config ids
|
||||
*/
|
||||
export const handleInventoryItemConfigChange = async (
|
||||
equipmentChanges: ISaveLoadoutRequestNoUpgradeVer,
|
||||
accountId: string
|
||||
accountId: string,
|
||||
buildLabel: string | undefined
|
||||
): Promise<string | void> => {
|
||||
const inventory = await getInventory(accountId);
|
||||
|
||||
@@ -196,7 +198,36 @@ export const handleInventoryItemConfigChange = async (
|
||||
|
||||
for (const [configId, config] of Object.entries(itemConfigEntries)) {
|
||||
if (/^[0-9]+$/.test(configId)) {
|
||||
inventoryItem.Configs[parseInt(configId)] = config as IItemConfig;
|
||||
const c = config as IItemConfig;
|
||||
if (buildLabel && version_compare(buildLabel, "2014.04.10.17.47") < 0) {
|
||||
if (c.Upgrades) {
|
||||
// U10-U11 store mods in the item config as $id instead of a string, need to convert that here
|
||||
const convertedUpgrades: string[] = [];
|
||||
c.Upgrades.forEach(upgrade => {
|
||||
const upgradeId = upgrade as { $id: string };
|
||||
const rawUpgrade = inventory.RawUpgrades.id(upgradeId.$id);
|
||||
if (rawUpgrade) {
|
||||
const newId = new Types.ObjectId();
|
||||
convertedUpgrades.push(newId.toString());
|
||||
addMods(inventory, [
|
||||
{
|
||||
ItemType: rawUpgrade.ItemType,
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
inventory.Upgrades.push({
|
||||
UpgradeFingerprint: `{"lvl":0}`,
|
||||
ItemType: rawUpgrade.ItemType,
|
||||
_id: newId
|
||||
});
|
||||
} else {
|
||||
convertedUpgrades.push(upgradeId.$id);
|
||||
}
|
||||
});
|
||||
c.Upgrades = convertedUpgrades;
|
||||
}
|
||||
}
|
||||
inventoryItem.Configs[parseInt(configId)] = c as IItemConfigDatabase;
|
||||
}
|
||||
}
|
||||
if ("Favorite" in itemConfigEntries) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
ICrewShipCustomization,
|
||||
IFlavourItem,
|
||||
IItemConfig,
|
||||
IItemConfigDatabase,
|
||||
IPolarity
|
||||
} from "./inventoryTypes/commonInventoryTypes.ts";
|
||||
|
||||
@@ -33,7 +34,7 @@ export enum EquipmentFeatures {
|
||||
export interface IEquipmentDatabase {
|
||||
ItemType: string;
|
||||
ItemName?: string;
|
||||
Configs: IItemConfig[];
|
||||
Configs: IItemConfigDatabase[];
|
||||
UpgradeVer?: number;
|
||||
XP?: number;
|
||||
Features?: number;
|
||||
@@ -48,7 +49,6 @@ export interface IEquipmentDatabase {
|
||||
InfestationDays?: number;
|
||||
InfestationType?: string;
|
||||
ModularParts?: string[];
|
||||
UnlockLevel?: number;
|
||||
Expiry?: Date;
|
||||
SkillTree?: string;
|
||||
OffensiveUpgrade?: string;
|
||||
@@ -69,9 +69,18 @@ export interface IEquipmentDatabase {
|
||||
export interface IEquipmentClient
|
||||
extends Omit<
|
||||
IEquipmentDatabase,
|
||||
"_id" | "InfestationDate" | "Expiry" | "UpgradesExpiry" | "UmbraDate" | "Weapon" | "CrewMembers" | "Details"
|
||||
| "_id"
|
||||
| "Configs"
|
||||
| "InfestationDate"
|
||||
| "Expiry"
|
||||
| "UpgradesExpiry"
|
||||
| "UmbraDate"
|
||||
| "Weapon"
|
||||
| "CrewMembers"
|
||||
| "Details"
|
||||
> {
|
||||
ItemId: IOidWithLegacySupport;
|
||||
Configs: IItemConfig[];
|
||||
InfestationDate?: IMongoDate;
|
||||
Expiry?: IMongoDate;
|
||||
UpgradesExpiry?: IMongoDate;
|
||||
@@ -79,6 +88,10 @@ export interface IEquipmentClient
|
||||
Weapon?: ICrewShipWeaponClient;
|
||||
CrewMembers?: ICrewShipMembersClient;
|
||||
Details?: IKubrowPetDetailsClient;
|
||||
// For Pre-U24.4.0 builds
|
||||
UnlockLevel?: number;
|
||||
UtilityUnlocked?: number;
|
||||
Gild?: boolean;
|
||||
}
|
||||
|
||||
export interface IArchonCrystalUpgrade {
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface IItemConfig {
|
||||
facial?: IColor;
|
||||
syancol?: IColor;
|
||||
cloth?: IColor;
|
||||
Upgrades?: string[];
|
||||
Upgrades?: string[] | { $id: string }[];
|
||||
Name?: string;
|
||||
OperatorAmp?: IOid;
|
||||
Songs?: ISong[];
|
||||
@@ -56,13 +56,17 @@ export interface IItemConfig {
|
||||
ugly?: boolean;
|
||||
}
|
||||
|
||||
export interface IItemConfigDatabase extends Omit<IItemConfig, "Upgrades"> {
|
||||
Upgrades?: string[];
|
||||
}
|
||||
|
||||
export interface ISong {
|
||||
m?: string;
|
||||
b?: string;
|
||||
p?: string;
|
||||
s: string;
|
||||
}
|
||||
export interface IOperatorConfigDatabase extends IItemConfig {
|
||||
export interface IOperatorConfigDatabase extends IItemConfigDatabase {
|
||||
_id: Types.ObjectId;
|
||||
}
|
||||
|
||||
|
||||
@@ -318,6 +318,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
Accolades?: IAccolades;
|
||||
Counselor?: boolean;
|
||||
Upgrades: IUpgradeClient[];
|
||||
Cards?: IUpgradeClient[]; // U8
|
||||
EquippedGear: string[];
|
||||
DeathMarks: string[];
|
||||
FusionTreasures: IFusionTreasure[];
|
||||
@@ -592,10 +593,16 @@ export interface IUpgradeClient {
|
||||
ItemType: string;
|
||||
UpgradeFingerprint?: string;
|
||||
PendingRerollFingerprint?: string;
|
||||
ItemId: IOid;
|
||||
ItemId: IOidWithLegacySupport;
|
||||
// Stuff for U7-U8
|
||||
ParentId?: IOidWithLegacySupport;
|
||||
Slot?: number;
|
||||
AmountRemaining?: number;
|
||||
Rank?: number;
|
||||
}
|
||||
|
||||
export interface IUpgradeDatabase extends Omit<IUpgradeClient, "ItemId"> {
|
||||
export interface IUpgradeDatabase
|
||||
extends Omit<IUpgradeClient, "ItemId" | "ParentId" | "Slot" | "AmountRemaining" | "Rank"> {
|
||||
_id: Types.ObjectId;
|
||||
}
|
||||
|
||||
@@ -603,9 +610,9 @@ export interface IUpgradeFromClient {
|
||||
ItemType: string;
|
||||
ItemId: IOidWithLegacySupport;
|
||||
FromSKU?: boolean;
|
||||
UpgradeFingerprint: string;
|
||||
UpgradeFingerprint?: string;
|
||||
PendingRerollFingerprint: string;
|
||||
ItemCount: number;
|
||||
ItemCount?: number;
|
||||
LastAdded: IOidWithLegacySupport;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { IOid, ITypeCount } from "./commonTypes.ts";
|
||||
import type { IOid, IOidWithLegacySupport, ITypeCount } from "./commonTypes.ts";
|
||||
import type { ArtifactPolarity, IPolarity } from "./inventoryTypes/commonInventoryTypes.ts";
|
||||
import type {
|
||||
IBooster,
|
||||
@@ -21,7 +21,8 @@ import type {
|
||||
IInvasionProgressClient,
|
||||
IWeaponSkinClient,
|
||||
IKubrowPetEggClient,
|
||||
INemesisClient
|
||||
INemesisClient,
|
||||
IUpgradeClient
|
||||
} from "./inventoryTypes/inventoryTypes.ts";
|
||||
import type { IGroup } from "./loginTypes.ts";
|
||||
import type { ILoadOutPresets } from "./saveLoadoutTypes.ts";
|
||||
@@ -227,6 +228,24 @@ export interface IUpgradesRequest {
|
||||
UpgradeVersion: number;
|
||||
Operations: IUpgradeOperation[];
|
||||
}
|
||||
export interface IUpgradesRequestLegacy {
|
||||
Category: TEquipmentKey;
|
||||
Weapon: { ItemType: string; ItemId: IOidWithLegacySupport };
|
||||
UpgradeVer: number;
|
||||
UnlockLevel: number;
|
||||
Polarized: number;
|
||||
UtilityUnlocked: number;
|
||||
FocusLens?: string;
|
||||
UpgradeReq?: string;
|
||||
UtilityReq?: string;
|
||||
IsSwappingOperation: boolean;
|
||||
PolarizeReq?: string;
|
||||
PolarizeSlot: number;
|
||||
PolarizeValue: ArtifactPolarity;
|
||||
PolarityRemap: IPolarity[];
|
||||
UpgradesToAttach?: IUpgradeClient[];
|
||||
UpgradesToDetach?: IUpgradeClient[];
|
||||
}
|
||||
export interface IUpgradeOperation {
|
||||
OperationType: string;
|
||||
UpgradeRequirement: string; // uniqueName of item being consumed
|
||||
|
||||
@@ -31,7 +31,7 @@ export interface ISession {
|
||||
export interface IFindSessionRequest {
|
||||
id?: string;
|
||||
originalSessionId?: string;
|
||||
buildId?: number;
|
||||
buildId?: number | bigint;
|
||||
gameModeId?: number;
|
||||
regionId?: number;
|
||||
maxEloDifference?: number;
|
||||
|
||||
@@ -426,9 +426,25 @@ function fetchItemList() {
|
||||
};
|
||||
|
||||
// Add mods missing in data sources
|
||||
data.mods.push({
|
||||
uniqueName: "/Lotus/Upgrades/Mods/Fusers/CommonModFuser",
|
||||
name: loc("code_fusionCoreCommon"),
|
||||
fusionLimit: 3
|
||||
});
|
||||
data.mods.push({
|
||||
uniqueName: "/Lotus/Upgrades/Mods/Fusers/UncommonModFuser",
|
||||
name: loc("code_fusionCoreUncommon"),
|
||||
fusionLimit: 5
|
||||
});
|
||||
data.mods.push({
|
||||
uniqueName: "/Lotus/Upgrades/Mods/Fusers/RareModFuser",
|
||||
name: loc("code_fusionCoreRare"),
|
||||
fusionLimit: 5
|
||||
});
|
||||
data.mods.push({
|
||||
uniqueName: "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser",
|
||||
name: loc("code_legendaryCore")
|
||||
name: loc("code_legendaryCore"),
|
||||
fusionLimit: 0
|
||||
});
|
||||
data.mods.push({
|
||||
uniqueName: "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod",
|
||||
@@ -1507,7 +1523,9 @@ function updateInventory() {
|
||||
{
|
||||
const td = document.createElement("td");
|
||||
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ 0/" + maxRank + "</span>";
|
||||
if (maxRank > 0) {
|
||||
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ 0/" + maxRank + "</span>";
|
||||
}
|
||||
if (item.ItemCount > 1) {
|
||||
td.innerHTML +=
|
||||
" <span title='" + loc("code_count") + "'>🗍 " + parseInt(item.ItemCount) + "</span>";
|
||||
@@ -3463,6 +3481,9 @@ function doAddAllMods() {
|
||||
for (const child of document.getElementById("datalist-mods").children) {
|
||||
modsAll.add(child.getAttribute("data-key"));
|
||||
}
|
||||
modsAll.delete("/Lotus/Upgrades/Mods/Fusers/CommonModFuser");
|
||||
modsAll.delete("/Lotus/Upgrades/Mods/Fusers/UncommonModFuser");
|
||||
modsAll.delete("/Lotus/Upgrades/Mods/Fusers/RareModFuser");
|
||||
modsAll.delete("/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser");
|
||||
|
||||
revalidateAuthz().then(() => {
|
||||
@@ -3625,8 +3646,12 @@ function doImport() {
|
||||
data: JSON.stringify({
|
||||
inventory: JSON.parse($("#import-inventory").val())
|
||||
})
|
||||
}).then(function (anyKnownKey) {
|
||||
toast(loc(anyKnownKey ? "code_succImport" : "code_nothingToDo"));
|
||||
}).then(function (err) {
|
||||
if (err) {
|
||||
toast(err == "noKnownKey" ? loc("code_nothingToDo") : err);
|
||||
} else {
|
||||
toast(loc("code_succImport"));
|
||||
}
|
||||
updateInventory();
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `Anfangsverstärker`,
|
||||
code_amp: `Verstärker`,
|
||||
code_kDrive: `K-Drive`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Legendärer Kern`,
|
||||
code_traumaticPeculiar: `Kuriose Mod: Traumatisch`,
|
||||
code_starter: `|MOD| (Defekt)`,
|
||||
|
||||
@@ -22,6 +22,9 @@ dict = {
|
||||
code_moteAmp: `Mote Amp`,
|
||||
code_amp: `Amp`,
|
||||
code_kDrive: `K-Drive`,
|
||||
code_fusionCoreCommon: `Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Legendary Core`,
|
||||
code_traumaticPeculiar: `Traumatic Peculiar`,
|
||||
code_starter: `|MOD| (Flawed)`,
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `Amp Mota`,
|
||||
code_amp: `Amp`,
|
||||
code_kDrive: `K-Drive`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Núcleo legendario`,
|
||||
code_traumaticPeculiar: `Traumatismo peculiar`,
|
||||
code_starter: `|MOD| (Defectuoso)`,
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `Amplificateur Faible`,
|
||||
code_amp: `Amplificateur`,
|
||||
code_kDrive: `K-Drive`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Coeur Légendaire`,
|
||||
code_traumaticPeculiar: `Traumatisme Atypique`,
|
||||
code_starter: `|MOD| (Défectueux)`,
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `Пылинка`,
|
||||
code_amp: `Усилитель`,
|
||||
code_kDrive: `К-Драйв`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Легендарное ядро`,
|
||||
code_traumaticPeculiar: `Травмирующая Странность`,
|
||||
code_starter: `|MOD| (Повреждённый)`,
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `Порошинка`,
|
||||
code_amp: `Підсилювач`,
|
||||
code_kDrive: `К-Драйв`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `Легендарне ядро`,
|
||||
code_traumaticPeculiar: `Особливе травмування`,
|
||||
code_starter: `|MOD| (Пошкоджений)`,
|
||||
|
||||
@@ -23,6 +23,9 @@ dict = {
|
||||
code_moteAmp: `微尘增幅器`,
|
||||
code_amp: `增幅器`,
|
||||
code_kDrive: `K式悬浮板`,
|
||||
code_fusionCoreCommon: `[UNTRANSLATED] Fusion Core (Common)`,
|
||||
code_fusionCoreUncommon: `[UNTRANSLATED] Fusion Core (Uncommon)`,
|
||||
code_fusionCoreRare: `[UNTRANSLATED] Fusion Core (Rare)`,
|
||||
code_legendaryCore: `传奇核心`,
|
||||
code_traumaticPeculiar: `创伤怪奇`,
|
||||
code_starter: `|MOD| (有瑕疵的)`,
|
||||
|
||||
Reference in New Issue
Block a user