2024-06-01 18:22:02 +02:00
|
|
|
import { RequestHandler } from "express";
|
|
|
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
2025-03-16 04:33:48 -07:00
|
|
|
import { getInventory, addMiscItems, addEquipment, occupySlot } from "@/src/services/inventoryService";
|
|
|
|
import { IMiscItem, TFocusPolarity, TEquipmentKey, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
2024-06-01 18:22:02 +02:00
|
|
|
import { logger } from "@/src/utils/logger";
|
2024-06-22 02:39:51 +02:00
|
|
|
import { ExportFocusUpgrades } from "warframe-public-export-plus";
|
2025-01-04 00:25:09 +01:00
|
|
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
2025-03-16 16:41:39 +01:00
|
|
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
2023-12-14 17:34:15 +01:00
|
|
|
|
2024-06-01 18:22:02 +02:00
|
|
|
export const focusController: RequestHandler = async (req, res) => {
|
|
|
|
const accountId = await getAccountIdForRequest(req);
|
|
|
|
switch (req.query.op) {
|
|
|
|
default:
|
2024-12-30 00:07:53 +01:00
|
|
|
logger.error("Unhandled focus op type: " + String(req.query.op));
|
2024-12-29 21:41:56 +01:00
|
|
|
logger.debug(String(req.body));
|
2024-06-01 18:22:02 +02:00
|
|
|
res.end();
|
|
|
|
break;
|
2024-10-15 16:27:11 +02:00
|
|
|
case FocusOperation.InstallLens: {
|
|
|
|
const request = JSON.parse(String(req.body)) as ILensInstallRequest;
|
|
|
|
const inventory = await getInventory(accountId);
|
2025-03-31 04:15:32 -07:00
|
|
|
const item = inventory[request.Category].id(request.WeaponId);
|
|
|
|
if (item) {
|
|
|
|
item.FocusLens = request.LensType;
|
|
|
|
addMiscItems(inventory, [
|
|
|
|
{
|
|
|
|
ItemType: request.LensType,
|
|
|
|
ItemCount: -1
|
|
|
|
} satisfies IMiscItem
|
|
|
|
]);
|
2024-10-15 16:27:11 +02:00
|
|
|
}
|
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
weaponId: request.WeaponId,
|
|
|
|
lensType: request.LensType
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2024-06-01 18:22:02 +02:00
|
|
|
case FocusOperation.UnlockWay: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
2024-06-01 18:22:02 +02:00
|
|
|
const focusPolarity = focusTypeToPolarity(focusType);
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const cost = inventory.FocusAbility ? 50_000 : 0;
|
|
|
|
inventory.FocusAbility ??= focusType;
|
|
|
|
inventory.FocusUpgrades.push({ ItemType: focusType });
|
|
|
|
if (inventory.FocusXP) {
|
|
|
|
inventory.FocusXP[focusPolarity] -= cost;
|
|
|
|
}
|
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
FocusUpgrade: { ItemType: focusType },
|
|
|
|
FocusPointCosts: { [focusPolarity]: cost }
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FocusOperation.ActivateWay: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
2025-03-16 16:41:39 +01:00
|
|
|
|
|
|
|
await Inventory.updateOne(
|
|
|
|
{
|
|
|
|
accountOwnerId: accountId
|
|
|
|
},
|
|
|
|
{
|
|
|
|
FocusAbility: focusType
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2024-06-01 18:22:02 +02:00
|
|
|
res.end();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FocusOperation.UnlockUpgrade: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const request = JSON.parse(String(req.body)) as IUnlockUpgradeRequest;
|
2024-06-01 18:22:02 +02:00
|
|
|
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
let cost = 0;
|
|
|
|
for (const focusType of request.FocusTypes) {
|
2024-06-22 02:39:51 +02:00
|
|
|
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
2024-06-01 18:22:02 +02:00
|
|
|
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
|
|
|
}
|
2025-01-20 12:21:39 +01:00
|
|
|
inventory.FocusXP![focusPolarity] -= cost;
|
2024-06-01 18:22:02 +02:00
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
FocusTypes: request.FocusTypes,
|
|
|
|
FocusPointCosts: { [focusPolarity]: cost }
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FocusOperation.LevelUpUpgrade: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const request = JSON.parse(String(req.body)) as ILevelUpUpgradeRequest;
|
2024-06-01 18:22:02 +02:00
|
|
|
const focusPolarity = focusTypeToPolarity(request.FocusInfos[0].ItemType);
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
let cost = 0;
|
|
|
|
for (const focusUpgrade of request.FocusInfos) {
|
|
|
|
cost += focusUpgrade.FocusXpCost;
|
|
|
|
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
|
|
|
focusUpgradeDb.Level = focusUpgrade.Level;
|
|
|
|
}
|
2025-01-20 12:21:39 +01:00
|
|
|
inventory.FocusXP![focusPolarity] -= cost;
|
2024-06-01 18:22:02 +02:00
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
FocusInfos: request.FocusInfos,
|
|
|
|
FocusPointCosts: { [focusPolarity]: cost }
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2024-06-29 14:49:40 +03:00
|
|
|
case FocusOperation.SentTrainingAmplifier: {
|
|
|
|
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
|
|
|
const parts: string[] = [
|
|
|
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
|
|
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
|
|
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
|
|
|
];
|
2025-01-04 00:25:09 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts);
|
2025-03-16 04:33:48 -07:00
|
|
|
occupySlot(inventory, InventorySlot.AMPS, false);
|
2025-01-04 00:25:09 +01:00
|
|
|
await inventory.save();
|
|
|
|
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
2024-06-29 14:49:40 +03:00
|
|
|
break;
|
|
|
|
}
|
2024-06-22 03:01:05 +02:00
|
|
|
case FocusOperation.UnbindUpgrade: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
2024-06-22 03:01:05 +02:00
|
|
|
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
|
|
|
const inventory = await getInventory(accountId);
|
2025-01-20 12:21:39 +01:00
|
|
|
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length;
|
2024-06-22 03:01:05 +02:00
|
|
|
addMiscItems(inventory, [
|
|
|
|
{
|
|
|
|
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
|
|
|
ItemCount: request.FocusTypes.length * -1
|
|
|
|
}
|
|
|
|
]);
|
|
|
|
request.FocusTypes.forEach(type => {
|
|
|
|
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == type)!;
|
|
|
|
focusUpgradeDb.IsUniversal = true;
|
|
|
|
});
|
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
FocusTypes: request.FocusTypes,
|
|
|
|
FocusPointCosts: {
|
2024-06-22 17:55:30 +02:00
|
|
|
[focusPolarity]: 750_000 * request.FocusTypes.length
|
2024-06-22 03:01:05 +02:00
|
|
|
},
|
|
|
|
MiscItemCosts: [
|
|
|
|
{
|
|
|
|
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
|
|
|
ItemCount: request.FocusTypes.length
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
2024-06-01 18:22:02 +02:00
|
|
|
case FocusOperation.ConvertShard: {
|
2024-06-24 12:37:28 +02:00
|
|
|
const request = JSON.parse(String(req.body)) as IConvertShardRequest;
|
2024-06-01 18:22:02 +02:00
|
|
|
// Tally XP
|
|
|
|
let xp = 0;
|
|
|
|
for (const shard of request.Shards) {
|
|
|
|
xp += shardValues[shard.ItemType as keyof typeof shardValues] * shard.ItemCount;
|
|
|
|
}
|
|
|
|
// Send response
|
|
|
|
res.json({
|
|
|
|
FocusPointGains: {
|
|
|
|
[request.Polarity]: xp
|
|
|
|
},
|
|
|
|
MiscItemCosts: request.Shards
|
|
|
|
});
|
|
|
|
// Commit added XP and removed shards to DB
|
|
|
|
for (const shard of request.Shards) {
|
|
|
|
shard.ItemCount *= -1;
|
|
|
|
}
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
inventory.FocusXP ??= { AP_POWER: 0, AP_TACTIC: 0, AP_DEFENSE: 0, AP_ATTACK: 0, AP_WARD: 0 };
|
|
|
|
inventory.FocusXP[request.Polarity] += xp;
|
|
|
|
addMiscItems(inventory, request.Shards);
|
|
|
|
await inventory.save();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum FocusOperation {
|
2024-10-15 16:27:11 +02:00
|
|
|
InstallLens = "1",
|
2024-06-01 18:22:02 +02:00
|
|
|
UnlockWay = "2",
|
|
|
|
UnlockUpgrade = "3",
|
|
|
|
LevelUpUpgrade = "4",
|
|
|
|
ActivateWay = "5",
|
2024-06-29 14:49:40 +03:00
|
|
|
SentTrainingAmplifier = "7",
|
2024-06-22 03:01:05 +02:00
|
|
|
UnbindUpgrade = "8",
|
2024-06-01 18:22:02 +02:00
|
|
|
ConvertShard = "9"
|
|
|
|
}
|
|
|
|
|
|
|
|
// For UnlockWay & ActivateWay
|
|
|
|
interface IWayRequest {
|
|
|
|
FocusType: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IUnlockUpgradeRequest {
|
|
|
|
FocusTypes: string[];
|
|
|
|
}
|
|
|
|
|
|
|
|
interface ILevelUpUpgradeRequest {
|
|
|
|
FocusInfos: {
|
|
|
|
ItemType: string;
|
|
|
|
FocusXpCost: number;
|
|
|
|
IsUniversal: boolean;
|
|
|
|
Level: number;
|
|
|
|
IsActiveAbility: boolean;
|
|
|
|
}[];
|
|
|
|
}
|
|
|
|
|
2024-06-22 03:01:05 +02:00
|
|
|
interface IUnbindUpgradeRequest {
|
|
|
|
ShardTypes: string[];
|
|
|
|
FocusTypes: string[];
|
|
|
|
}
|
|
|
|
|
2024-06-01 18:22:02 +02:00
|
|
|
interface IConvertShardRequest {
|
|
|
|
Shards: IMiscItem[];
|
|
|
|
Polarity: TFocusPolarity;
|
|
|
|
}
|
|
|
|
|
2024-06-29 14:49:40 +03:00
|
|
|
interface ISentTrainingAmplifierRequest {
|
|
|
|
StartingWeaponType: string;
|
|
|
|
}
|
|
|
|
|
2024-10-15 16:27:11 +02:00
|
|
|
interface ILensInstallRequest {
|
|
|
|
LensType: string;
|
|
|
|
Category: TEquipmentKey;
|
|
|
|
WeaponId: string;
|
|
|
|
}
|
|
|
|
|
2024-06-01 18:22:02 +02:00
|
|
|
// Works for ways & upgrades
|
|
|
|
const focusTypeToPolarity = (type: string): TFocusPolarity => {
|
|
|
|
return ("AP_" + type.substr(1).split("/")[3].toUpperCase()) as TFocusPolarity;
|
|
|
|
};
|
|
|
|
|
|
|
|
const shardValues = {
|
|
|
|
"/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardCommonItem": 2_500,
|
|
|
|
"/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardSynthesizedItem": 5_000,
|
|
|
|
"/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem": 25_000,
|
|
|
|
"/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantTierTwoItem": 40_000
|
2023-12-14 17:34:15 +01:00
|
|
|
};
|