From f1c0c5a4297affdc1f013aa02486887f2c6fd141 Mon Sep 17 00:00:00 2001 From: Sainan Date: Fri, 3 Jan 2025 05:22:56 +0100 Subject: [PATCH] feat: subsuming warframes (#686) --- .../api/infestedFoundryController.ts | 97 ++++++++++++++++++- src/controllers/api/inventoryController.ts | 12 ++- src/models/inventoryModels/inventoryModel.ts | 24 ++++- src/types/inventoryTypes/inventoryTypes.ts | 7 +- 4 files changed, 130 insertions(+), 10 deletions(-) diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index b819cf47..a01ae16b 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -1,10 +1,17 @@ import { RequestHandler } from "express"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; -import { getInventory, addMiscItems } from "@/src/services/inventoryService"; +import { getInventory, addMiscItems, updateCurrency, addRecipes } from "@/src/services/inventoryService"; import { IOid } from "@/src/types/commonTypes"; -import { IInfestedFoundry, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; -import { ExportMisc } from "warframe-public-export-plus"; +import { + IConsumedSuit, + IInfestedFoundry, + IInventoryDatabaseDocument, + IMiscItem, + ITypeCount +} from "@/src/types/inventoryTypes/inventoryTypes"; +import { ExportMisc, ExportRecipes } from "warframe-public-export-plus"; +import { getRecipe } from "@/src/services/itemDataService"; export const infestedFoundryController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -110,6 +117,67 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { res.status(404).end(); break; + case "a": { + // subsume warframe + const request = getJSONfromString(String(req.body)) as IHelminthSubsumeRequest; + const inventory = await getInventory(accountId); + const recipe = getRecipe(request.Recipe)!; + for (const ingredient of recipe.secretIngredients!) { + const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType); + if (resource) { + resource.Count -= ingredient.ItemCount; + } + } + const suit = inventory.Suits.find(x => x._id.toString() == request.SuitId.$oid)!; + inventory.Suits.pull(suit); + const consumedSuit: IConsumedSuit = { s: suit.ItemType }; + if (suit.Configs && suit.Configs[0] && suit.Configs[0].pricol) { + consumedSuit.c = suit.Configs[0].pricol; + } + inventory.InfestedFoundry!.Slots!--; + inventory.InfestedFoundry!.ConsumedSuits ??= []; + inventory.InfestedFoundry!.ConsumedSuits?.push(consumedSuit); + inventory.InfestedFoundry!.LastConsumedSuit = suit; + inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = new Date( + new Date().getTime() + 24 * 60 * 60 * 1000 + ); + addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00); + await inventory.save(); + console.log(inventory.toJSON().InfestedFoundry); + res.json({ + InventoryChanges: { + RemovedIdItems: [ + { + ItemId: request.SuitId + } + ], + SuitBin: { + count: -1, + platinum: 0, + Slots: 1 + }, + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); + break; + } + + case "r": { + // rush subsume + const inventory = await getInventory(accountId); + const currencyChanges = updateCurrency(inventory, 50, true); + const recipeChanges = handleSubsumeCompletion(inventory); + await inventory.save(); + res.json({ + InventoryChanges: { + ...currencyChanges, + Recipes: recipeChanges, + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); + break; + } + default: throw new Error(`unhandled infestedFoundry mode: ${String(req.query.mode)}`); } @@ -165,3 +233,26 @@ const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundry, delta: number): infestedFoundry.Slots += 20; } }; + +interface IHelminthSubsumeRequest { + SuitId: IOid; + Recipe: string; +} + +export const handleSubsumeCompletion = (inventory: IInventoryDatabaseDocument): ITypeCount[] => { + const [recipeType] = Object.entries(ExportRecipes).find( + ([_recipeType, recipe]) => + recipe.secretIngredientAction == "SIA_WARFRAME_ABILITY" && + recipe.secretIngredients![0].ItemType == inventory.InfestedFoundry!.LastConsumedSuit!.ItemType + )!; + inventory.InfestedFoundry!.LastConsumedSuit = undefined; + inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = undefined; + const recipeChanges: ITypeCount[] = [ + { + ItemType: recipeType, + ItemCount: 1 + } + ]; + addRecipes(inventory, recipeChanges); + return recipeChanges; +}; diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 59b3af5c..f38fe0ec 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -5,7 +5,7 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { config } from "@/src/services/configService"; import allDialogue from "@/static/fixed_responses/allDialogue.json"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; -import { IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; +import { IInventoryDatabaseDocument, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; import { IPolarity, ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { ExportCustoms, @@ -15,6 +15,7 @@ import { ExportResources, ExportVirtuals } from "warframe-public-export-plus"; +import { handleSubsumeCompletion } from "./infestedFoundryController"; export const inventoryController: RequestHandler = async (request, response) => { let account; @@ -57,6 +58,15 @@ export const inventoryController: RequestHandler = async (request, response) => await inventory.save(); } + if ( + inventory.InfestedFoundry && + inventory.InfestedFoundry.AbilityOverrideUnlockCooldown && + new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown + ) { + handleSubsumeCompletion(inventory as unknown as IInventoryDatabaseDocument); + await inventory.save(); + } + //TODO: make a function that converts from database representation to client const inventoryJSON = inventory.toJSON(); diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 5e5a1680..ee2b7a88 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -459,10 +459,13 @@ const settingsSchema = new Schema({ TradingRulesConfirmed: Boolean }); -const consumedSchuitsSchema = new Schema({ - s: String, - c: colorSchema -}); +const consumedSchuitsSchema = new Schema( + { + s: String, + c: colorSchema + }, + { _id: false } +); const helminthResourceSchema = new Schema({ ItemType: String, Count: Number }, { _id: false }); @@ -475,11 +478,22 @@ const infestedFoundrySchema = new Schema( ConsumedSuits: { type: [consumedSchuitsSchema], default: undefined }, InvigorationIndex: Number, InvigorationSuitOfferings: { type: [String], default: undefined }, - InvigorationsApplied: Number + InvigorationsApplied: Number, + LastConsumedSuit: { type: EquipmentSchema, default: undefined }, + AbilityOverrideUnlockCooldown: Date }, { _id: false } ); +infestedFoundrySchema.set("toJSON", { + transform(_doc, ret, _options) { + if (ret.AbilityOverrideUnlockCooldown) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + ret.AbilityOverrideUnlockCooldown = toMongoDate(ret.AbilityOverrideUnlockCooldown); + } + } +}); + const questProgressSchema = new Schema({ c: Number, i: Boolean, diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 94a46650..d4f33cf9 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -518,10 +518,13 @@ export interface IFusionTreasure { Sockets: number; } -// Like ITypeCount except 'Count' instead of 'ItemCount' export interface IHelminthResource { ItemType: string; Count: number; + RecentlyConvertedResources?: { + ItemType: string; + Date: number; + }[]; } export interface IInfestedFoundry { @@ -533,6 +536,8 @@ export interface IInfestedFoundry { InvigorationIndex?: number; InvigorationSuitOfferings?: string[]; InvigorationsApplied?: number; + LastConsumedSuit?: IEquipmentDatabase; + AbilityOverrideUnlockCooldown?: Date; } export interface IConsumedSuit {