diff --git a/src/controllers/api/projectionManagerController.ts b/src/controllers/api/projectionManagerController.ts new file mode 100644 index 000000000..0872cde0f --- /dev/null +++ b/src/controllers/api/projectionManagerController.ts @@ -0,0 +1,64 @@ +import { RequestHandler } from "express"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { addMiscItems, getInventory } from "@/src/services/inventoryService"; +import { ExportRelics, IRelic } from "warframe-public-export-plus"; + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const projectionManagerController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + const request = JSON.parse(String(req.body)) as IProjectionUpgradeRequest; + const [era, category, currentQuality] = parseProjection(request.projectionType); + const upgradeCost = (request.qualityTag - qualityKeywordToNumber[currentQuality]) * 25; + const newProjectionType = findProjection(era, category, qualityNumberToKeyword[request.qualityTag]); + addMiscItems(inventory, [ + { + ItemType: request.projectionType, + ItemCount: -1 + }, + { + ItemType: newProjectionType, + ItemCount: 1 + }, + { + ItemType: "/Lotus/Types/Items/MiscItems/VoidTearDrop", + ItemCount: -upgradeCost + } + ]); + await inventory.save(); + res.json({ + prevProjection: request.projectionType, + upgradedProjection: newProjectionType, + upgradeCost: upgradeCost + }); +}; + +interface IProjectionUpgradeRequest { + projectionType: string; + qualityTag: number; +} + +type VoidProjectionQuality = "VPQ_BRONZE" | "VPQ_SILVER" | "VPQ_GOLD" | "VPQ_PLATINUM"; + +const qualityNumberToKeyword: VoidProjectionQuality[] = ["VPQ_BRONZE", "VPQ_SILVER", "VPQ_GOLD", "VPQ_PLATINUM"]; +const qualityKeywordToNumber: Record = { + VPQ_BRONZE: 0, + VPQ_SILVER: 1, + VPQ_GOLD: 2, + VPQ_PLATINUM: 3 +}; + +// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"] +const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => { + const relic: IRelic | undefined = ExportRelics[typeName]; + if (!relic) { + throw new Error(`Unknown projection ${typeName}`); + } + return [relic.era, relic.category, relic.quality]; +}; + +const findProjection = (era: string, category: string, quality: VoidProjectionQuality): string => { + return Object.entries(ExportRelics).find( + ([_, relic]) => relic.era == era && relic.category == category && relic.quality == quality + )![0]; +}; diff --git a/src/routes/api.ts b/src/routes/api.ts index 5c1472244..ff6c72861 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -40,6 +40,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController"; import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController"; import { nameWeaponController } from "@/src/controllers/api/nameWeaponController"; +import { projectionManagerController } from "../controllers/api/projectionManagerController"; import { purchaseController } from "@/src/controllers/api/purchaseController"; import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController"; import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController"; @@ -118,6 +119,7 @@ apiRouter.post("/login.php", loginController); apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController); apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController); apiRouter.post("/nameWeapon.php", nameWeaponController); +apiRouter.post("/projectionManager.php", projectionManagerController); apiRouter.post("/purchase.php", purchaseController); apiRouter.post("/rerollRandomMod.php", rerollRandomModController); apiRouter.post("/saveLoadout.php", saveLoadoutController);