diff --git a/src/controllers/api/genericUpdateController.ts b/src/controllers/api/genericUpdateController.ts index 79b6ba448..e5f0b5938 100644 --- a/src/controllers/api/genericUpdateController.ts +++ b/src/controllers/api/genericUpdateController.ts @@ -10,8 +10,7 @@ import { IGenericUpdate } from "@/src/types/genericUpdate"; const genericUpdateController: RequestHandler = async (request, response) => { const accountId = await getAccountIdForRequest(request); const update = getJSONfromString(String(request.body)); - await updateGeneric(update, accountId); - response.json(update); + response.json(await updateGeneric(update, accountId)); }; export { genericUpdateController }; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index e6bc21beb..0f2b9ea56 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -28,7 +28,7 @@ import { IUpgradeClient, ICrewShipWeaponClient } from "@/src/types/inventoryTypes/inventoryTypes"; -import { IGenericUpdate } from "../types/genericUpdate"; +import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate"; import { IMissionInventoryUpdateRequest, IThemeUpdateRequest, @@ -574,6 +574,39 @@ export const addItem = async ( }; } break; + + case "Stickers": + { + const entry = inventory.RawUpgrades.find(x => x.ItemType == typeName); + if (entry && entry.ItemCount >= 10) { + const miscItemChanges = [ + { + ItemType: "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + ItemCount: 1 + } + ]; + addMiscItems(inventory, miscItemChanges); + return { + InventoryChanges: { + MiscItems: miscItemChanges + } + }; + } else { + const changes = [ + { + ItemType: typeName, + ItemCount: quantity + } + ]; + addMods(inventory, changes); + return { + InventoryChanges: { + RawUpgrades: changes + } + }; + } + } + break; } break; } @@ -876,14 +909,27 @@ export const updateStandingLimit = ( }; // TODO: AffiliationMods support (Nightwave). -export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise => { - const inventory = await getInventory(accountId); +export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise => { + const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems"); // Make it an array for easier parsing. if (typeof data.NodeIntrosCompleted === "string") { data.NodeIntrosCompleted = [data.NodeIntrosCompleted]; } + const inventoryChanges: IInventoryChanges = {}; + for (const node of data.NodeIntrosCompleted) { + if (node == "KayaFirstVisitPack") { + inventoryChanges.MiscItems = [ + { + ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack", + ItemCount: 1 + } + ]; + addMiscItems(inventory, inventoryChanges.MiscItems); + } + } + // Combine the two arrays into one. data.NodeIntrosCompleted = inventory.NodeIntrosCompleted.concat(data.NodeIntrosCompleted); @@ -892,6 +938,11 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string): Pr inventory.NodeIntrosCompleted = nodes; await inventory.save(); + + return { + MissionRewards: [], + InventoryChanges: inventoryChanges + }; }; export const updateTheme = async (data: IThemeUpdateRequest, accountId: string): Promise => { diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index ef7a97b7c..72e1701cc 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -54,11 +54,16 @@ export const handlePurchase = async ( if (purchaseRequest.PurchaseParams.Source == 7) { const manifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!); if (manifest) { - const ItemId = (JSON.parse(purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson!) as { ItemId: string }) - .ItemId; - const offer = manifest.VendorInfo.ItemManifest.find(x => x.Id.$oid == ItemId); + let ItemId: string | undefined; + if (purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) { + ItemId = (JSON.parse(purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) as { ItemId: string }) + .ItemId; + } + const offer = ItemId + ? manifest.VendorInfo.ItemManifest.find(x => x.Id.$oid == ItemId) + : manifest.VendorInfo.ItemManifest.find(x => x.StoreItem == purchaseRequest.PurchaseParams.StoreItem); if (!offer) { - throw new Error(`unknown vendor offer: ${ItemId}`); + throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`); } if (offer.ItemPrices) { handleItemPrices( @@ -68,7 +73,7 @@ export const handlePurchase = async ( prePurchaseInventoryChanges ); } - if (!config.noVendorPurchaseLimits) { + if (!config.noVendorPurchaseLimits && ItemId) { inventory.RecentVendorPurchases ??= []; let vendorPurchases = inventory.RecentVendorPurchases.find( x => x.VendorType == manifest.VendorInfo.TypeName @@ -410,16 +415,26 @@ const handleBoosterPackPurchase = async ( "attempt to roll over 100 booster packs in a single go. possible but unlikely to be desirable for the user or the server." ); } - for (let i = 0; i != quantity; ++i) { - for (const weights of pack.rarityWeightsPerRoll) { - const result = getRandomWeightedRewardUc(pack.components, weights); - if (result) { - logger.debug(`booster pack rolled`, result); - purchaseResponse.BoosterPackItems += toStoreItem(result.Item) + ',{"lvl":0};'; - combineInventoryChanges( - purchaseResponse.InventoryChanges, - (await addItem(inventory, result.Item, 1)).InventoryChanges - ); + if (typeName == "/Lotus/Types/BoosterPacks/1999StickersPackEchoesArchimedeaFixed") { + for (const result of pack.components) { + purchaseResponse.BoosterPackItems += toStoreItem(result.Item) + ',{"lvl":0};'; + combineInventoryChanges( + purchaseResponse.InventoryChanges, + (await addItem(inventory, result.Item, 1)).InventoryChanges + ); + } + } else { + for (let i = 0; i != quantity; ++i) { + for (const weights of pack.rarityWeightsPerRoll) { + const result = getRandomWeightedRewardUc(pack.components, weights); + if (result) { + logger.debug(`booster pack rolled`, result); + purchaseResponse.BoosterPackItems += toStoreItem(result.Item) + ',{"lvl":0};'; + combineInventoryChanges( + purchaseResponse.InventoryChanges, + (await addItem(inventory, result.Item, 1)).InventoryChanges + ); + } } } } diff --git a/src/services/serversideVendorsService.ts b/src/services/serversideVendorsService.ts index cae48e6ef..79e22ef38 100644 --- a/src/services/serversideVendorsService.ts +++ b/src/services/serversideVendorsService.ts @@ -19,6 +19,7 @@ import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorI import HubsPerrinSequenceWeaponVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsPerrinSequenceWeaponVendorManifest.json"; import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json"; import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json"; +import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json"; import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json"; import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json"; import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json"; @@ -69,6 +70,7 @@ const vendorManifests: IVendorManifest[] = [ HubsPerrinSequenceWeaponVendorManifest, HubsRailjackCrewMemberVendorManifest, MaskSalesmanManifest, + Nova1999ConquestShopManifest, OstronFishmongerVendorManifest, OstronPetVendorManifest, OstronProspectorVendorManifest, diff --git a/src/types/genericUpdate.ts b/src/types/genericUpdate.ts index fa231be93..93551b05c 100644 --- a/src/types/genericUpdate.ts +++ b/src/types/genericUpdate.ts @@ -1,4 +1,11 @@ +import { IInventoryChanges } from "./purchaseTypes"; + export interface IGenericUpdate { NodeIntrosCompleted: string | string[]; // AffiliationMods: any[]; } + +export interface IUpdateNodeIntrosResponse { + MissionRewards: []; + InventoryChanges: IInventoryChanges; +} diff --git a/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json b/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json new file mode 100644 index 000000000..b2971efe2 --- /dev/null +++ b/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json @@ -0,0 +1,188 @@ +{ + "VendorInfo": { + "_id": { + "$oid": "67dadc30e4b6e0e5979c8d6a" + }, + "TypeName": "/Lotus/Types/Game/VendorManifests/TheHex/Nova1999ConquestShopManifest", + "ItemManifest": [ + { + "StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedea", + "ItemPrices": [ + { + "ItemCount": 10, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_0", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "AllowMultipurchase": true, + "Id": { + "$oid": "67db32b983b2ad79a9c1c18c" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedeaFree", + "ItemPrices": [ + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/MiscItems/1999FreeStickersPack", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_0", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "AllowMultipurchase": true, + "Id": { + "$oid": "67db32b983b2ad79a9c1c18d" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedeaFixed", + "ItemPrices": [ + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/MiscItems/1999FixedStickersPack", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_0", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "AllowMultipurchase": true, + "Id": { + "$oid": "67db32b983b2ad79a9c1c18e" + } + }, + { + "StoreItem": "/Lotus/Types/StoreItems/Packages/SyndicateVosforPack", + "ItemPrices": [ + { + "ItemCount": 6, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_0", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "AllowMultipurchase": true, + "Id": { + "$oid": "67db32b983b2ad79a9c1c18f" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/StickerPictureFrame", + "ItemPrices": [ + { + "ItemCount": 10, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_0", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "AllowMultipurchase": true, + "Id": { + "$oid": "67db32b983b2ad79a9c1c190" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Utility/AbilityRadiationProcsCreateUniversalOrbsOnKill", + "ItemPrices": [ + { + "ItemCount": 5, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_1", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "PurchaseQuantityLimit": 1, + "AllowMultipurchase": false, + "Id": { + "$oid": "67db32b983b2ad79a9c1c191" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Offensive/AbilityHeatProcsGiveCritChance", + "ItemPrices": [ + { + "ItemCount": 5, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_1", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "PurchaseQuantityLimit": 1, + "AllowMultipurchase": false, + "Id": { + "$oid": "67db32b983b2ad79a9c1c192" + } + }, + { + "StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Defensive/InvulnerabilityOnDeathOnMercyKill", + "ItemPrices": [ + { + "ItemCount": 5, + "ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks", + "ProductCategory": "MiscItems" + } + ], + "Bin": "BIN_1", + "QuantityMultiplier": 1, + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + }, + "PurchaseQuantityLimit": 1, + "AllowMultipurchase": false, + "Id": { + "$oid": "67db32b983b2ad79a9c1c193" + } + } + ], + "PropertyTextHash": "CB7D0E807FD5E2BCD059195201D963B9", + "RequiredGoalTag": "", + "Expiry": { + "$date": { + "$numberLong": "2051240400000" + } + } + } +} \ No newline at end of file