diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index b29a5241..efd291cc 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -2,7 +2,7 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import new_inventory from "@/static/fixed_responses/postTutorialInventory.json"; import { config } from "@/src/services/configService"; import { Types } from "mongoose"; -import { SlotNames } from "@/src/types/purchaseTypes"; +import { SlotNames, IInventoryChanges } from "@/src/types/purchaseTypes"; import { IChallengeProgress, IConsumable, @@ -26,7 +26,7 @@ import { logger } from "@/src/utils/logger"; import { WeaponTypeInternal, getWeaponType, getExalted } from "@/src/services/itemDataService"; import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes"; import { IEquipmentClient } from "../types/inventoryTypes/commonInventoryTypes"; -import { ExportRecipes } from "warframe-public-export-plus"; +import { ExportRecipes, ExportResources } from "warframe-public-export-plus"; export const createInventory = async ( accountOwnerId: Types.ObjectId, @@ -70,7 +70,7 @@ export const addItem = async ( accountId: string, typeName: string, quantity: number = 1 -): Promise<{ InventoryChanges: object }> => { +): Promise<{ InventoryChanges: IInventoryChanges }> => { // Strict typing if (typeName in ExportRecipes) { const inventory = await getInventory(accountId); @@ -88,6 +88,22 @@ export const addItem = async ( } }; } + if (typeName in ExportResources) { + const inventory = await getInventory(accountId); + const miscItemChanges = [ + { + ItemType: typeName, + ItemCount: quantity + } satisfies IMiscItem + ]; + addMiscItems(inventory, miscItemChanges); + await inventory.save(); + return { + InventoryChanges: { + MiscItems: miscItemChanges + } + }; + } // Path-based duck typing switch (typeName.substr(1).split("/")[1]) { diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 0f96055c..9fb4a675 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -1,7 +1,7 @@ import { parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers"; import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers"; import { addItem, addBooster, updateCurrency, updateSlots } from "@/src/services/inventoryService"; -import { IPurchaseRequest, SlotPurchase } from "@/src/types/purchaseTypes"; +import { IPurchaseRequest, SlotPurchase, IInventoryChanges, IBinChanges } from "@/src/types/purchaseTypes"; import { logger } from "@/src/utils/logger"; import { ExportBundles, TRarity } from "warframe-public-export-plus"; @@ -46,12 +46,37 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI return purchaseResponse; }; +const addInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => { + for (const key in delta) { + if (!(key in InventoryChanges)) { + InventoryChanges[key] = delta[key]; + } else if (Array.isArray(delta[key])) { + const left = InventoryChanges[key] as object[]; + const right = delta[key] as object[]; + for (const item of right) { + left.push(item); + } + } else { + console.assert(key.substring(-3) == "Bin"); + const left = InventoryChanges[key] as IBinChanges; + const right = delta[key] as IBinChanges; + left.count += right.count; + left.platinum += right.platinum; + left.Slots += right.Slots; + if (right.Extra) { + left.Extra ??= 0; + left.Extra += right.Extra; + } + } + } +}; + const handleStoreItemAcquisition = async ( storeItemName: string, accountId: string, quantity: number, durability: TRarity -): Promise<{ InventoryChanges: object }> => { +): Promise<{ InventoryChanges: IInventoryChanges }> => { let purchaseResponse = { InventoryChanges: {} }; @@ -60,15 +85,17 @@ const handleStoreItemAcquisition = async ( const bundle = ExportBundles[storeItemName]; logger.debug("acquiring bundle", bundle); for (const component of bundle.components) { - purchaseResponse = { - ...purchaseResponse, - ...(await handleStoreItemAcquisition( - component.typeName, - accountId, - component.purchaseQuantity, - component.durability - )) - }; + addInventoryChanges( + purchaseResponse.InventoryChanges, + ( + await handleStoreItemAcquisition( + component.typeName, + accountId, + component.purchaseQuantity, + component.durability + ) + ).InventoryChanges + ); } } else { const storeCategory = getStoreItemCategory(storeItemName); @@ -106,7 +133,10 @@ export const slotPurchaseNameToSlotName: SlotPurchase = { // // new slot above base = extra + 1 and slots +1 // // new frame = slots -1 // // number of frames = extra - slots + 2 -const handleSlotPurchase = async (slotPurchaseNameFull: string, accountId: string) => { +const handleSlotPurchase = async ( + slotPurchaseNameFull: string, + accountId: string +): Promise<{ InventoryChanges: IInventoryChanges }> => { logger.debug(`slot name ${slotPurchaseNameFull}`); const slotPurchaseName = parseSlotPurchaseName( slotPurchaseNameFull.substring(slotPurchaseNameFull.lastIndexOf("/") + 1) @@ -133,7 +163,11 @@ const handleSlotPurchase = async (slotPurchaseNameFull: string, accountId: strin }; //TODO: change to getInventory, apply changes then save at the end -const handleTypesPurchase = async (typesName: string, accountId: string, quantity: number) => { +const handleTypesPurchase = async ( + typesName: string, + accountId: string, + quantity: number +): Promise<{ InventoryChanges: IInventoryChanges }> => { const typeCategory = getStoreItemTypesCategory(typesName); logger.debug(`type category ${typeCategory}`); switch (typeCategory) { @@ -158,7 +192,11 @@ const boosterDuration: Record = { LEGENDARY: 90 * 86400 }; -const handleBoostersPurchase = async (boosterStoreName: string, accountId: string, durability: TRarity) => { +const handleBoostersPurchase = async ( + boosterStoreName: string, + accountId: string, + durability: TRarity +): Promise<{ InventoryChanges: IInventoryChanges }> => { const ItemType = boosterStoreName.replace("StoreItem", ""); if (!boosterCollection.find(x => x == ItemType)) { logger.error(`unknown booster type: ${ItemType}`); diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index db143470..0d04114e 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -1,6 +1,3 @@ -import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes"; -import { IEquipmentClient } from "./inventoryTypes/commonInventoryTypes"; - export interface IPurchaseRequest { PurchaseParams: IPurchaseParams; buildLabel: string; @@ -17,22 +14,7 @@ export interface IPurchaseParams { ExpectedPrice: number; } -export interface IPurchaseResponse { - InventoryChanges: { - SuitBin?: IBinChanges; - WeaponBin?: IBinChanges; - MechBin?: IBinChanges; - MechSuits?: IEquipmentClient[]; - Suits?: IEquipmentClient[]; - LongGuns?: IEquipmentClient[]; - Pistols?: IEquipmentClient[]; - Melee?: IEquipmentClient[]; - PremiumCredits?: number; - PremiumCreditsFree?: number; - RegularCredits?: number; - FlavourItems?: IFlavourItem[]; - }; -} +export type IInventoryChanges = Record; export type IBinChanges = { count: number;