diff --git a/package-lock.json b/package-lock.json index 13edcb84..99bdfa62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.40", + "warframe-public-export-plus": "^0.5.41", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -4083,9 +4083,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.40", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.40.tgz", - "integrity": "sha512-/qr46LE/KqDdEkW4z52EG0vZP0Z8U26FscFJ2G5K5ewbQdlSVxtf5fpOnzRkAO7jWWKfgoqx7l5WUgaLSPDj0g==" + "version": "0.5.41", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.41.tgz", + "integrity": "sha512-qVOUY4UjF1cyBrBbMwD25xHSdSf9q57/CJgjHsfSE7NUu/6pBDSZzwS0iAetAukws/1V2kDvsuy8AGtOec2L1w==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index 6fcb225d..50710c25 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.40", + "warframe-public-export-plus": "^0.5.41", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" diff --git a/src/controllers/api/artifactTransmutationController.ts b/src/controllers/api/artifactTransmutationController.ts new file mode 100644 index 00000000..3fd52535 --- /dev/null +++ b/src/controllers/api/artifactTransmutationController.ts @@ -0,0 +1,124 @@ +import { toOid } from "@/src/helpers/inventoryHelpers"; +import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper"; +import { addMiscItems, addMods, getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "@/src/services/rngService"; +import { IOid } from "@/src/types/commonTypes"; +import { RequestHandler } from "express"; +import { ExportBoosterPacks, ExportUpgrades, TRarity } from "warframe-public-export-plus"; + +export const artifactTransmutationController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + const payload = JSON.parse(String(req.body)) as IArtifactTransmutationRequest; + + inventory.RegularCredits -= payload.Cost; + inventory.FusionPoints -= payload.FusionPointCost; + + if (payload.RivenTransmute) { + addMiscItems(inventory, [ + { + ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientSecretItem", + ItemCount: -1 + } + ]); + + payload.Consumed.forEach(upgrade => { + inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid }); + }); + + const rawRivenType = getRandomRawRivenType(); + const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]); + const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]); + + const upgradeIndex = + inventory.Upgrades.push({ + ItemType: rivenType, + UpgradeFingerprint: JSON.stringify(fingerprint) + }) - 1; + await inventory.save(); + res.json({ + NewMods: [ + { + ItemId: toOid(inventory.Upgrades[upgradeIndex]._id), + ItemType: rivenType, + UpgradeFingerprint: fingerprint + } + ] + }); + } else { + const counts: Record = { + COMMON: 0, + UNCOMMON: 0, + RARE: 0, + LEGENDARY: 0 + }; + payload.Consumed.forEach(upgrade => { + const meta = ExportUpgrades[upgrade.ItemType]; + counts[meta.rarity] += upgrade.ItemCount; + addMods(inventory, [ + { + ItemType: upgrade.ItemType, + ItemCount: upgrade.ItemCount * -1 + } + ]); + }); + + // Based on the table on https://wiki.warframe.com/w/Transmutation + const weights: Record = { + COMMON: counts.COMMON * 95 + counts.UNCOMMON * 15 + counts.RARE * 4, + UNCOMMON: counts.COMMON * 4 + counts.UNCOMMON * 80 + counts.RARE * 10, + RARE: counts.COMMON * 1 + counts.UNCOMMON * 5 + counts.RARE * 50, + LEGENDARY: 0 + }; + + const options: { uniqueName: string; rarity: TRarity }[] = []; + Object.entries(ExportUpgrades).forEach(([uniqueName, upgrade]) => { + if (upgrade.canBeTransmutation) { + options.push({ uniqueName, rarity: upgrade.rarity }); + } + }); + + const newModType = getRandomWeightedReward(options, weights)!.uniqueName; + addMods(inventory, [ + { + ItemType: newModType, + ItemCount: 1 + } + ]); + + await inventory.save(); + res.json({ + NewMods: [ + { + ItemType: newModType, + ItemCount: 1 + } + ] + }); + } +}; + +const getRandomRawRivenType = (): string => { + const pack = ExportBoosterPacks["/Lotus/Types/BoosterPacks/CalendarRivenPack"]; + return getRandomWeightedRewardUc(pack.components, pack.rarityWeightsPerRoll[0])!.Item; +}; + +interface IArtifactTransmutationRequest { + Upgrade: IAgnosticUpgradeClient; + LevelDiff: number; + Consumed: IAgnosticUpgradeClient[]; + Cost: number; + FusionPointCost: number; + RivenTransmute?: boolean; +} + +interface IAgnosticUpgradeClient { + ItemType: string; + ItemId: IOid; + FromSKU: boolean; + UpgradeFingerprint: string; + PendingRerollFingerprint: string; + ItemCount: number; + LastAdded: IOid; +} diff --git a/src/routes/api.ts b/src/routes/api.ts index bb63982e..964ebd5d 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -7,6 +7,7 @@ import { addFriendImageController } from "@/src/controllers/api/addFriendImageCo import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController"; import { archonFusionController } from "@/src/controllers/api/archonFusionController"; import { artifactsController } from "@/src/controllers/api/artifactsController"; +import { artifactTransmutationController } from "@/src/controllers/api/artifactTransmutationController"; import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController"; import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; @@ -150,6 +151,7 @@ apiRouter.post("/addFriendImage.php", addFriendImageController); apiRouter.post("/arcaneCommon.php", arcaneCommonController); apiRouter.post("/archonFusion.php", archonFusionController); apiRouter.post("/artifacts.php", artifactsController); +apiRouter.post("/artifactTransmutation.php", artifactTransmutationController); apiRouter.post("/changeDojoRoot.php", changeDojoRootController); apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController); apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);