From 1ab411e3cc960b89dacb205a6405282100d268f1 Mon Sep 17 00:00:00 2001 From: OrdisPrime <134585663+OrdisPrime@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:24:52 +0100 Subject: [PATCH] Purchase Loadouts and Inventory Slots (#105) --- config.json | 3 +- src/controllers/api/getCreditsController.ts | 28 ++++- .../api/inventorySlotsController.ts | 36 +++++++ src/controllers/api/purchaseController.ts | 4 +- src/controllers/api/saveLoadout.ts | 14 ++- src/helpers/general.ts | 4 + src/helpers/purchaseHelpers.ts | 16 ++- src/routes/api.ts | 2 + src/services/inventoryService.ts | 68 +++++++----- src/services/purchaseService.ts | 102 ++++++++++++++---- src/services/saveLoadoutService.ts | 30 ++++-- src/types/inventoryTypes/SuitTypes.ts | 2 +- src/types/inventoryTypes/inventoryTypes.ts | 2 +- src/types/purchaseTypes.ts | 44 +++++++- src/types/requestTypes.ts | 10 +- 15 files changed, 285 insertions(+), 80 deletions(-) create mode 100644 src/controllers/api/inventorySlotsController.ts diff --git a/config.json b/config.json index 158a6821..64ad5d3c 100644 --- a/config.json +++ b/config.json @@ -7,5 +7,6 @@ "skipStoryModeChoice": true, "skipTutorial": true, "testMission": true, - "testQuestKey": true + "testQuestKey": true, + "infinitePlatinum": false } diff --git a/src/controllers/api/getCreditsController.ts b/src/controllers/api/getCreditsController.ts index 9981fa47..a2a2ea6e 100644 --- a/src/controllers/api/getCreditsController.ts +++ b/src/controllers/api/getCreditsController.ts @@ -1,7 +1,27 @@ import { RequestHandler } from "express"; +import config from "@/config.json"; +import { getInventory } from "@/src/services/inventoryService"; +import { parseString } from "@/src/helpers/general"; -const getCreditsController: RequestHandler = (_req, res) => { - res.json({ RegularCredits: 42069, TradesRemaining: 1, PremiumCreditsFree: 42069, PremiumCredits: 42069 }); +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const getCreditsController: RequestHandler = async (req, res) => { + if (config.infinitePlatinum) { + res.json({ + RegularCredits: 999999999, + TradesRemaining: 999999999, + PremiumCreditsFree: 999999999, + PremiumCredits: 999999999 + }); + return; + } + + const accountId = parseString(req.query.accountId); + + const inventory = await getInventory(accountId); + res.json({ + RegularCredits: inventory.RegularCredits, + TradesRemaining: inventory.TradesRemaining, + PremiumCreditsFree: inventory.PremiumCreditsFree, + PremiumCredits: inventory.PremiumCredits + }); }; - -export { getCreditsController }; diff --git a/src/controllers/api/inventorySlotsController.ts b/src/controllers/api/inventorySlotsController.ts new file mode 100644 index 00000000..9da2751f --- /dev/null +++ b/src/controllers/api/inventorySlotsController.ts @@ -0,0 +1,36 @@ +import { parseString } from "@/src/helpers/general"; +import { getInventory, updateCurrency } from "@/src/services/inventoryService"; +import { RequestHandler } from "express"; +import { updateSlots } from "@/src/services/inventoryService"; +import { SlotNameToInventoryName } from "@/src/types/purchaseTypes"; + +/* + loadout slots are additionally purchased slots only + 1 slot per mastery rank is automatically given above mr10, without database needing to save the mastery slots + extra = everything above the base + 2 slots (e.g. for warframes) + new slot = extra + 1 and slots +1 + using slot = slots -1, except for when purchased with platinum, then slots are included in price + + e.g. number of frames: + 19 slots, 71 extra + = 71 - 19 + 2 = 54 + 19 actually available slots in ingame inventory = 17 extra + 2 Base (base amount depends on slot) (+ 1 for every mastery rank above 10) + number of frames = extra - slots + 2 +*/ + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const inventorySlotsController: RequestHandler = async (req, res) => { + const accountId = parseString(req.query.accountId); + //const body = JSON.parse(req.body as string) as IInventorySlotsRequest; + + //console.log(body); + + //TODO: check which slot was purchased because pvpBonus is also possible + + const currencyChanges = await updateCurrency(-20, true, accountId); + await updateSlots(accountId, SlotNameToInventoryName.LOADOUT, 1, 1); + + //console.log({ InventoryChanges: currencyChanges }, " added loadout changes:"); + + res.json({ InventoryChanges: currencyChanges }); +}; diff --git a/src/controllers/api/purchaseController.ts b/src/controllers/api/purchaseController.ts index c73581ca..c0c34e47 100644 --- a/src/controllers/api/purchaseController.ts +++ b/src/controllers/api/purchaseController.ts @@ -3,11 +3,9 @@ import { toPurchaseRequest } from "@/src/helpers/purchaseHelpers"; import { handlePurchase } from "@/src/services/purchaseService"; import { Request, Response } from "express"; -const purchaseController = async (req: Request, res: Response) => { +export const purchaseController = async (req: Request, res: Response) => { const purchaseRequest = toPurchaseRequest(JSON.parse(String(req.body))); const accountId = parseString(req.query.accountId); const response = await handlePurchase(purchaseRequest, accountId); res.json(response); }; - -export { purchaseController }; diff --git a/src/controllers/api/saveLoadout.ts b/src/controllers/api/saveLoadout.ts index 31431798..85a88a5d 100644 --- a/src/controllers/api/saveLoadout.ts +++ b/src/controllers/api/saveLoadout.ts @@ -5,7 +5,7 @@ import { handleInventoryItemConfigChange } from "@/src/services/saveLoadoutServi import { parseString } from "@/src/helpers/general"; // eslint-disable-next-line @typescript-eslint/no-misused-promises -const saveLoadoutController: RequestHandler = async (req, res) => { +export const saveLoadoutController: RequestHandler = async (req, res) => { //validate here const accountId = parseString(req.query.accountId); @@ -15,13 +15,19 @@ const saveLoadoutController: RequestHandler = async (req, res) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { UpgradeVer, ...equipmentChanges } = body; - await handleInventoryItemConfigChange(equipmentChanges, accountId); + const newLoadoutId = await handleInventoryItemConfigChange(equipmentChanges, accountId); + + //send back new loadout id, if new loadout was added + if (newLoadoutId) { + res.send(newLoadoutId); + } res.status(200).end(); } catch (error: unknown) { if (error instanceof Error) { + console.log("error in saveLoadoutController", error.message); res.status(400).json({ error: error.message }); + } else { + res.status(400).json({ error: "unknown error" }); } } }; - -export { saveLoadoutController }; diff --git a/src/helpers/general.ts b/src/helpers/general.ts index cc13e4ec..afc52fd8 100644 --- a/src/helpers/general.ts +++ b/src/helpers/general.ts @@ -1,3 +1,7 @@ +export const isEmptyObject = (obj: unknown): boolean => { + return Boolean(obj && Object.keys(obj).length === 0 && obj.constructor === Object); +}; + const isString = (text: unknown): text is string => { return typeof text === "string" || text instanceof String; }; diff --git a/src/helpers/purchaseHelpers.ts b/src/helpers/purchaseHelpers.ts index 2dee9668..47016abe 100644 --- a/src/helpers/purchaseHelpers.ts +++ b/src/helpers/purchaseHelpers.ts @@ -1,9 +1,10 @@ import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general"; import { WeaponTypeInternal } from "@/src/services/inventoryService"; -import { IPurchaseRequest } from "@/src/types/purchaseTypes"; +import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService"; +import { IPurchaseRequest, SlotPurchaseName } from "@/src/types/purchaseTypes"; import { weapons } from "@/static/data/items"; -const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => { +export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => { if (!purchaseRequest || typeof purchaseRequest !== "object") { throw new Error("incorrect or missing purchase request data"); } @@ -40,7 +41,7 @@ const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => { throw new Error("invalid purchaseRequest"); }; -const getWeaponType = (weaponName: string) => { +export const getWeaponType = (weaponName: string) => { const weaponInfo = weapons.find(i => i.uniqueName === weaponName); if (!weaponInfo) { @@ -56,4 +57,11 @@ const getWeaponType = (weaponName: string) => { return weaponType; }; -export { toPurchaseRequest, getWeaponType }; +export const isSlotPurchaseName = (slotPurchaseName: string): slotPurchaseName is SlotPurchaseName => { + return slotPurchaseName in slotPurchaseNameToSlotName; +}; + +export const parseSlotPurchaseName = (slotPurchaseName: string) => { + if (!isSlotPurchaseName(slotPurchaseName)) throw new Error(`invalid slot name ${slotPurchaseName}`); + return slotPurchaseName; +}; diff --git a/src/routes/api.ts b/src/routes/api.ts index 66f55d0f..7ffd3bc5 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -34,6 +34,7 @@ import { artifactsController } from "../controllers/api/artifactsController"; import express from "express"; import { setBootLocationController } from "@/src/controllers/api/setBootLocationController"; import { focusController } from "@/src/controllers/api/focusController"; +import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController"; const apiRouter = express.Router(); @@ -61,6 +62,7 @@ apiRouter.get("/logout.php", logoutController); apiRouter.get("/setBootLocation.php", setBootLocationController); // post +apiRouter.post("/inventorySlots.php", inventorySlotsController); apiRouter.post("/focus.php", focusController); apiRouter.post("/artifacts.php", artifactsController); apiRouter.post("/findSessions.php", findSessionsController); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 93d62603..e50da9d3 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -2,9 +2,9 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import new_inventory from "@/static/fixed_responses/postTutorialInventory.json"; import config from "@/config.json"; import { Types } from "mongoose"; -import { ISuitDatabase, ISuitClient } from "@/src/types/inventoryTypes/SuitTypes"; -import { SlotType } from "@/src/types/purchaseTypes"; -import { IWeaponDatabase, IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; +import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes"; +import { SlotNames } from "@/src/types/purchaseTypes"; +import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; import { IChallengeProgress, IConsumable, @@ -41,8 +41,6 @@ export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPre } }; -//const updateInventory = async (accountOwnerId: Types.ObjectId, inventoryChanges: any) => {}; - export const getInventory = async (accountOwnerId: string) => { const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }); @@ -53,7 +51,7 @@ export const getInventory = async (accountOwnerId: string) => { return inventory; }; -//TODO: genericMethod for all the add methods, they share a lot of logic +//TODO: maybe genericMethod for all the add methods, they share a lot of logic export const addSentinel = async (sentinelName: string, accountId: string) => { const inventory = await getInventory(accountId); const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 }); @@ -75,32 +73,54 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => { return changedInventory.MechSuits[suitIndex - 1].toJSON(); }; -export const updateSlots = async (slotType: SlotType, accountId: string, slots: number) => { +export const updateSlots = async (accountId: string, slotName: SlotNames, slotAmount: number, extraAmount: number) => { const inventory = await getInventory(accountId); - switch (slotType) { - case SlotType.SUIT: - inventory.SuitBin.Slots += slots; - break; - case SlotType.WEAPON: - inventory.WeaponBin.Slots += slots; - break; - case SlotType.MECHSUIT: - inventory.MechBin.Slots += slots; - break; - default: - throw new Error("invalid slot type"); + inventory[slotName].Slots += slotAmount; + if (inventory[slotName].Extra === undefined) { + inventory[slotName].Extra = extraAmount; + } else { + inventory[slotName].Extra += extraAmount; } + await inventory.save(); }; export const updateCurrency = async (price: number, usePremium: boolean, accountId: string) => { - const currencyName = usePremium ? "PremiumCredits" : "RegularCredits"; - const inventory = await getInventory(accountId); - inventory[currencyName] = inventory[currencyName] - price; + + if (usePremium) { + if (inventory.PremiumCreditsFree > 0) { + inventory.PremiumCreditsFree += price; + } + inventory.PremiumCredits += price; + } else { + inventory.RegularCredits += price; + } + + const modifiedPaths = inventory.modifiedPaths(); + + type currencyKeys = "RegularCredits" | "PremiumCredits" | "PremiumCreditsFree"; + + const currencyChanges = {} as Record; + modifiedPaths.forEach(path => { + currencyChanges[path as currencyKeys] = -price; + }); + + console.log(currencyChanges, "changes"); + + //let changes = {} as keyof currencyKeys; + + // const obj2 = modifiedPaths.reduce( + // (obj, key) => { + // obj[key as keyof currencyKeys] = price; + // return obj; + // }, + // {} as Record + // ); + await inventory.save(); - return { [currencyName]: -price }; + return currencyChanges; }; // TODO: AffiliationMods support (Nightwave). @@ -157,7 +177,7 @@ export const addCustomization = async (customizatonName: string, accountId: stri const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizatonName }) - 1; const changedInventory = await inventory.save(); - return changedInventory.FlavourItems[flavourItemIndex].toJSON(); //mongoose bug forces as FlavourItem + return changedInventory.FlavourItems[flavourItemIndex].toJSON(); }; const addGearExpByCategory = ( diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index b6d80c21..caf3375b 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -1,4 +1,4 @@ -import { getWeaponType } from "@/src/helpers/purchaseHelpers"; +import { getWeaponType, parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers"; import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers"; import { addBooster, @@ -7,9 +7,10 @@ import { addPowerSuit, addSentinel, addWeapon, + updateCurrency, updateSlots } from "@/src/services/inventoryService"; -import { IPurchaseRequest, SlotType } from "@/src/types/purchaseTypes"; +import { IPurchaseRequest, IPurchaseResponse, SlotNameToInventoryName, SlotPurchase } from "@/src/types/purchaseTypes"; export const getStoreItemCategory = (storeItem: string) => { const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/"); @@ -32,57 +33,109 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI const internalName = purchaseRequest.PurchaseParams.StoreItem.replace("/StoreItems", ""); console.log("Store category", storeCategory); - let purchaseResponse; + let inventoryChanges; switch (storeCategory) { case "Powersuits": - purchaseResponse = await handlePowersuitPurchase(internalName, accountId); + inventoryChanges = await handlePowersuitPurchase(internalName, accountId); break; case "Weapons": - purchaseResponse = await handleWeaponsPurchase(internalName, accountId); + inventoryChanges = await handleWeaponsPurchase(internalName, accountId); break; case "Types": - purchaseResponse = await handleTypesPurchase(internalName, accountId); + inventoryChanges = await handleTypesPurchase(internalName, accountId); break; case "Boosters": - purchaseResponse = await handleBoostersPurchase(internalName, accountId); + inventoryChanges = await handleBoostersPurchase(internalName, accountId); break; default: throw new Error(`unknown store category: ${storeCategory} not implemented or new`); } - // const currencyResponse = await updateCurrency( - // purchaseRequest.PurchaseParams.ExpectedPrice, - // purchaseRequest.PurchaseParams.UsePremium, - // accountId - // ); + if (!inventoryChanges) throw new Error("purchase response was undefined"); - // (purchaseResponse as IPurchaseResponse).InventoryChanges = { - // ...purchaseResponse.InventoryChanges, - // ...currencyResponse - // }; + const currencyChanges = await updateCurrency( + purchaseRequest.PurchaseParams.ExpectedPrice, + purchaseRequest.PurchaseParams.UsePremium, + accountId + ); - return purchaseResponse; + inventoryChanges.InventoryChanges = { + ...currencyChanges, + ...inventoryChanges.InventoryChanges + }; + + return inventoryChanges; +}; + +export const slotPurchaseNameToSlotName: SlotPurchase = { + SuitSlotItem: { name: "SuitBin", slotsPerPurchase: 1 }, + TwoSentinelSlotItem: { name: "SentinelBin", slotsPerPurchase: 2 }, + TwoWeaponSlotItem: { name: "WeaponBin", slotsPerPurchase: 2 }, + SpaceSuitSlotItem: { name: "SpaceSuitBin", slotsPerPurchase: 1 }, + TwoSpaceWeaponSlotItem: { name: "SpaceWeaponBin", slotsPerPurchase: 2 }, + MechSlotItem: { name: "MechBin", slotsPerPurchase: 1 }, + TwoOperatorWeaponSlotItem: { name: "OperatorAmpBin", slotsPerPurchase: 2 }, + RandomModSlotItem: { name: "RandomModBin", slotsPerPurchase: 3 }, + TwoCrewShipSalvageSlotItem: { name: "CrewShipSalvageBin", slotsPerPurchase: 2 }, + CrewMemberSlotItem: { name: "CrewMemberBin", slotsPerPurchase: 1 } +}; + +// // extra = everything above the base +2 slots (depending on slot type) +// // 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) => { + console.log("slot name", slotPurchaseNameFull); + const slotPurchaseName = parseSlotPurchaseName( + slotPurchaseNameFull.substring(slotPurchaseNameFull.lastIndexOf("/") + 1) + ); + console.log(slotPurchaseName, "slot purchase name"); + + await updateSlots( + accountId, + slotPurchaseNameToSlotName[slotPurchaseName].name, + slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase, + slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase + ); + + console.log( + slotPurchaseNameToSlotName[slotPurchaseName].name, + slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase, + "slots added" + ); + + return { + InventoryChanges: { + [slotPurchaseNameToSlotName[slotPurchaseName].name]: { + count: 0, + platinum: 1, + Slots: slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase, + Extra: slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase + } + } + }; }; const handleWeaponsPurchase = async (weaponName: string, accountId: string) => { const weaponType = getWeaponType(weaponName); const addedWeapon = await addWeapon(weaponType, weaponName, accountId); - await updateSlots(SlotType.WEAPON, accountId, -1); + await updateSlots(accountId, SlotNameToInventoryName.WEAPON, 0, 1); return { InventoryChanges: { WeaponBin: { count: 1, platinum: 0, Slots: -1 }, [weaponType]: [addedWeapon] } - }; + } as IPurchaseResponse; }; const handlePowersuitPurchase = async (powersuitName: string, accountId: string) => { if (powersuitName.includes("EntratiMech")) { const mechSuit = await addMechSuit(powersuitName, accountId); - await updateSlots(SlotType.MECHSUIT, accountId, -1); + + await updateSlots(accountId, SlotNameToInventoryName.MECHSUIT, 0, 1); console.log("mech suit", mechSuit); return { @@ -94,11 +147,11 @@ const handlePowersuitPurchase = async (powersuitName: string, accountId: string) }, MechSuits: [mechSuit] } - }; + } as IPurchaseResponse; } const suit = await addPowerSuit(powersuitName, accountId); - await updateSlots(SlotType.SUIT, accountId, -1); + await updateSlots(accountId, SlotNameToInventoryName.SUIT, 0, 1); return { InventoryChanges: { @@ -112,6 +165,7 @@ const handlePowersuitPurchase = async (powersuitName: string, accountId: string) }; }; +//TODO: change to getInventory, apply changes then save at the end const handleTypesPurchase = async (typesName: string, accountId: string) => { const typeCategory = getStoreItemTypesCategory(typesName); console.log("type category", typeCategory); @@ -122,6 +176,8 @@ const handleTypesPurchase = async (typesName: string, accountId: string) => { // break; case "Sentinels": return await handleSentinelPurchase(typesName, accountId); + case "SlotItems": + return await handleSlotPurchase(typesName, accountId); default: throw new Error(`unknown Types category: ${typeCategory} not implemented or new`); } @@ -130,6 +186,8 @@ const handleTypesPurchase = async (typesName: string, accountId: string) => { const handleSentinelPurchase = async (sentinelName: string, accountId: string) => { const sentinel = await addSentinel(sentinelName, accountId); + await updateSlots(accountId, SlotNameToInventoryName.SENTINEL, 0, 1); + return { InventoryChanges: { SentinelBin: { count: 1, platinum: 0, Slots: -1 }, diff --git a/src/services/saveLoadoutService.ts b/src/services/saveLoadoutService.ts index 43006cc9..59733931 100644 --- a/src/services/saveLoadoutService.ts +++ b/src/services/saveLoadoutService.ts @@ -8,10 +8,8 @@ import { import { LoadoutModel } from "@/src/models/inventoryModels/loadoutModel"; import { getInventory } from "@/src/services/inventoryService"; import { IOid } from "@/src/types/commonTypes"; - -export const isEmptyObject = (obj: unknown): boolean => { - return Boolean(obj && Object.keys(obj).length === 0 && obj.constructor === Object); -}; +import { Types } from "mongoose"; +import { isEmptyObject } from "@/src/helpers/general"; //TODO: setup default items on account creation or like originally in giveStartingItems.php @@ -24,7 +22,7 @@ itemconfig has multiple config ids export const handleInventoryItemConfigChange = async ( equipmentChanges: ISaveLoadoutRequestNoUpgradeVer, accountId: string -) => { +): Promise => { const inventory = await getInventory(accountId); for (const [_equipmentName, _equipment] of Object.entries(equipmentChanges)) { @@ -40,7 +38,7 @@ export const handleInventoryItemConfigChange = async ( case "AdultOperatorLoadOuts": { const operatorConfig = equipment as IOperatorConfigEntry; const operatorLoadout = inventory[equipmentName]; - //console.log("loadout received", equipmentName, operatorConfig); + console.log("operator loadout received", equipmentName, operatorConfig); // all non-empty entries are one loadout slot for (const [loadoutId, loadoutConfig] of Object.entries(operatorConfig)) { // console.log("loadoutId", loadoutId, "loadoutconfig", loadoutConfig); @@ -60,12 +58,13 @@ export const handleInventoryItemConfigChange = async ( break; } case "LoadOuts": { - //console.log("loadout received"); + console.log("loadout received"); const loadout = await LoadoutModel.findOne({ loadoutOwnerId: accountId }); if (!loadout) { throw new Error("loadout not found"); } + let newLoadoutId: Types.ObjectId | undefined; for (const [_loadoutSlot, _loadout] of Object.entries(equipment)) { const loadoutSlot = _loadoutSlot as keyof ILoadoutClient; const newLoadout = _loadout as ILoadoutEntry; @@ -84,6 +83,16 @@ export const handleInventoryItemConfigChange = async ( // if no config with this id exists, create a new one if (!oldLoadoutConfig) { const { ItemId, ...loadoutConfigItemIdRemoved } = loadoutConfig; + + //save the new object id and assign it for every ffff return at the end + if (ItemId.$oid === "ffffffffffffffffffffffff") { + if (!newLoadoutId) { + newLoadoutId = new Types.ObjectId(); + } + loadout[loadoutSlot].push({ _id: newLoadoutId, ...loadoutConfigItemIdRemoved }); + continue; + } + loadout[loadoutSlot].push({ _id: ItemId.$oid, ...loadoutConfigItemIdRemoved @@ -101,6 +110,11 @@ export const handleInventoryItemConfigChange = async ( } } await loadout.save(); + + //only return an id if a new loadout was added + if (newLoadoutId) { + return newLoadoutId.toString(); + } break; } case "LongGuns": @@ -112,7 +126,7 @@ export const handleInventoryItemConfigChange = async ( case "DrifterMelee": case "Sentinels": case "Horses": { - //console.log("general Item config saved", equipmentName, equipment); + console.log("general Item config saved", equipmentName, equipment); const itemEntries = equipment as IItemEntry; for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) { diff --git a/src/types/inventoryTypes/SuitTypes.ts b/src/types/inventoryTypes/SuitTypes.ts index f075587c..22b543a8 100644 --- a/src/types/inventoryTypes/SuitTypes.ts +++ b/src/types/inventoryTypes/SuitTypes.ts @@ -3,7 +3,7 @@ import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { Types } from "mongoose"; import { IItemConfig } from "./commonInventoryTypes"; -export interface ISuitClient extends ISuitDatabase { +export interface ISuitClient extends Omit { ItemId: IOid; } diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 2674599a..114a4211 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -341,7 +341,7 @@ export interface ICrewShipHarnessConfig { } export interface ISlots { - Extra?: number; + Extra: number; // can be undefined, but not if used via mongoose Slots: number; } diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index ce1e6270..bbbf8c89 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -1,4 +1,5 @@ -import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; +import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService"; +import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes"; import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; @@ -22,11 +23,14 @@ export interface IPurchaseResponse { InventoryChanges: { SuitBin?: IBinChanges; WeaponBin?: IBinChanges; - Suits?: ISuitDatabase[]; + MechBin?: IBinChanges; + MechSuits?: ISuitClient[]; + Suits?: ISuitClient[]; LongGuns?: IWeaponClient[]; Pistols?: IWeaponClient[]; Melee?: IWeaponClient[]; PremiumCredits?: number; + PremiumCreditsFree?: number; RegularCredits?: number; FlavourItems?: IFlavourItem[]; }; @@ -36,10 +40,42 @@ export type IBinChanges = { count: number; platinum: number; Slots: number; + Extra?: number; }; -export enum SlotType { +export enum SlotNameToInventoryName { SUIT = "SuitBin", WEAPON = "WeaponBin", - MECHSUIT = "MechBin" + MECHSUIT = "MechBin", + LOADOUT = "PveBonusLoadoutBin", + SENTINEL = "SentinelBin" } + +export type SlotPurchaseName = + | "SuitSlotItem" + | "TwoSentinelSlotItem" + | "TwoWeaponSlotItem" + | "SpaceSuitSlotItem" + | "TwoSpaceWeaponSlotItem" + | "MechSlotItem" + | "TwoOperatorWeaponSlotItem" + | "RandomModSlotItem" + | "TwoCrewShipSalvageSlotItem" + | "CrewMemberSlotItem"; + +export type SlotNames = + | "SuitBin" + | "WeaponBin" + | "MechBin" + | "PveBonusLoadoutBin" + | "SentinelBin" + | "SpaceSuitBin" + | "SpaceWeaponBin" + | "OperatorAmpBin" + | "RandomModBin" + | "CrewShipSalvageBin" + | "CrewMemberBin"; + +export type SlotPurchase = { + [P in SlotPurchaseName]: { name: SlotNames; slotsPerPurchase: number }; +}; diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index ecbd35e0..e4f94980 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -10,14 +10,14 @@ import { import { IWeaponClient } from "./inventoryTypes/weaponTypes"; import { ISuitClient } from "./inventoryTypes/SuitTypes"; -interface IArtifactsRequest { +export interface IArtifactsRequest { Upgrade: ICrewShipSalvagedWeaponSkin; LevelDiff: number; Cost: number; FusionPointCost: number; } -interface IMissionInventoryUpdateRequest { +export interface IMissionInventoryUpdateRequest { rewardsMultiplier?: number; ActiveBoosters?: IBooster[]; LongGuns?: IWeaponClient[]; @@ -35,7 +35,7 @@ interface IMissionInventoryUpdateRequest { Missions?: IMission; } -interface IMissionInventoryUpdateRequestRewardInfo { +export interface IMissionInventoryUpdateRequestRewardInfo { node: string; rewardTier?: number; nightmareMode?: boolean; @@ -50,4 +50,6 @@ interface IMissionInventoryUpdateRequestRewardInfo { rewardSeed?: number; } -export { IArtifactsRequest, IMissionInventoryUpdateRequest }; +export interface IInventorySlotsRequest { + Bin: "PveBonusLoadoutBin"; +}