From 9731004de6f8a362c2523eec5138a3454df25968 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:51:47 -0700 Subject: [PATCH] feat: autogenerate railjack crew member vendor (#2170) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2170 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/serversideVendorsService.ts | 44 +++- .../HubsRailjackCrewMemberVendorManifest.json | 244 ------------------ 2 files changed, 40 insertions(+), 248 deletions(-) delete mode 100644 static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json diff --git a/src/services/serversideVendorsService.ts b/src/services/serversideVendorsService.ts index 701b85b4..295759b2 100644 --- a/src/services/serversideVendorsService.ts +++ b/src/services/serversideVendorsService.ts @@ -20,7 +20,6 @@ import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/Deim import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json"; import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json"; import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.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 OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json"; @@ -42,7 +41,6 @@ const rawVendorManifests: IVendorManifest[] = [ DuviriAcrithisVendorManifest, EntratiLabsEntratiLabsCommisionsManifest, EntratiLabsEntratiLabVendorManifest, - HubsRailjackCrewMemberVendorManifest, MaskSalesmanManifest, Nova1999ConquestShopManifest, OstronPetVendorManifest, @@ -273,20 +271,39 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani const offersToAdd: IVendorOffer[] = []; if (!manifest.isOneBinPerCycle) { const remainingItemCapacity: Record = {}; + const missingItemsPerBin: Record = {}; + let numOffersThatNeedToMatchABin = 0; + if (manifest.numItemsPerBin) { + for (let bin = 0; bin != manifest.numItemsPerBin.length; ++bin) { + missingItemsPerBin[bin] = manifest.numItemsPerBin[bin]; + numOffersThatNeedToMatchABin += manifest.numItemsPerBin[bin]; + } + } for (const item of manifest.items) { remainingItemCapacity[item.storeItem] = 1 + item.duplicates; } for (const offer of info.ItemManifest) { remainingItemCapacity[offer.StoreItem] -= 1; + const bin = parseInt(offer.Bin.substring(4)); + if (missingItemsPerBin[bin]) { + missingItemsPerBin[bin] -= 1; + numOffersThatNeedToMatchABin -= 1; + } } if (manifest.numItems && manifest.items.length != manifest.numItems.minValue) { const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue); while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) { - // TODO: Consider per-bin item limits // TODO: Consider item probability weightings const item = rng.randomElement(manifest.items)!; - if (remainingItemCapacity[item.storeItem] != 0) { + if ( + remainingItemCapacity[item.storeItem] != 0 && + (numOffersThatNeedToMatchABin == 0 || missingItemsPerBin[item.bin]) + ) { remainingItemCapacity[item.storeItem] -= 1; + if (missingItemsPerBin[item.bin]) { + missingItemsPerBin[item.bin] -= 1; + numOffersThatNeedToMatchABin -= 1; + } offersToAdd.push(item); } } @@ -383,6 +400,12 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani info.ItemManifest.push(item); } + info.ItemManifest.sort((a, b) => { + const aBin = parseInt(a.Bin.substring(4)); + const bBin = parseInt(b.Bin.substring(4)); + return aBin == bBin ? 0 : aBin < bBin ? +1 : -1; + }); + // Update vendor expiry let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER; for (const offer of info.ItemManifest) { @@ -424,4 +447,17 @@ if (isDev) { ) { logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest`); } + + const cms = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest")! + .VendorInfo.ItemManifest; + if ( + cms.length != 9 || + cms[0].Bin != "BIN_2" || + cms[8].Bin != "BIN_0" || + cms.reduce((a, x) => a + (x.Bin == "BIN_2" ? 1 : 0), 0) < 2 || + cms.reduce((a, x) => a + (x.Bin == "BIN_1" ? 1 : 0), 0) < 2 || + cms.reduce((a, x) => a + (x.Bin == "BIN_0" ? 1 : 0), 0) < 4 + ) { + logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest`); + } } diff --git a/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json b/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json deleted file mode 100644 index 16506360..00000000 --- a/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json +++ /dev/null @@ -1,244 +0,0 @@ -{ - "VendorInfo": { - "_id": { - "$oid": "5fb70313c96976e97d6be787" - }, - "TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest", - "ItemManifest": [ - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/SteelMeridianCrewMemberGeneratorStrong", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem", - "ItemCount": 2220, - "ProductCategory": "MiscItems" - } - ], - "RegularPrice": [2180000, 2180000], - "Bin": "BIN_2", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "SteelMeridianSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 4185144421, - "Id": { - "$oid": "670daf92d21f34757a5e73da" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorStrong", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem", - "ItemCount": 2130, - "ProductCategory": "MiscItems" - } - ], - "RegularPrice": [1890000, 1890000], - "Bin": "BIN_2", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "NewLokaSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 496053258, - "Id": { - "$oid": "670daf92d21f34757a5e73db" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/SteelMeridianCrewMemberGeneratorMediumVersionTwo", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem", - "ItemCount": 440, - "ProductCategory": "MiscItems" - } - ], - "Bin": "BIN_1", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "SteelMeridianSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 2078883475, - "Id": { - "$oid": "670daf92d21f34757a5e73dc" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorMediumVersionTwo", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/AsteriteRailjackItem", - "ItemCount": 730, - "ProductCategory": "MiscItems" - } - ], - "Bin": "BIN_1", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "NewLokaSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 3890380934, - "Id": { - "$oid": "670daf92d21f34757a5e73dd" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/CephalonSudaCrewMemberGeneratorMediumVersionTwo", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/AsteriteRailjackItem", - "ItemCount": 720, - "ProductCategory": "MiscItems" - } - ], - "Bin": "BIN_1", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "CephalonSudaSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 3425148044, - "Id": { - "$oid": "670daf92d21f34757a5e73de" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/ArbitersCrewMemberGeneratorMediumVersionTwo", - "ItemPrices": [ - { - "ItemType": "/Lotus/Types/Items/RailjackMiscItems/CubicsRailjackItem", - "ItemCount": 6500, - "ProductCategory": "MiscItems" - } - ], - "Bin": "BIN_1", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "ArbitersSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 2472754512, - "Id": { - "$oid": "670daf92d21f34757a5e73df" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/PerrinCrewMemberGeneratorVersionTwo", - "RegularPrice": [105000, 105000], - "Bin": "BIN_0", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "PerrinSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 966238763, - "Id": { - "$oid": "670daf92d21f34757a5e73e0" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorVersionTwo", - "RegularPrice": [120000, 120000], - "Bin": "BIN_0", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "NewLokaSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 356717213, - "Id": { - "$oid": "670daf92d21f34757a5e73e1" - } - }, - { - "StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/ArbitersCrewMemberGeneratorVersionTwo", - "RegularPrice": [120000, 120000], - "Bin": "BIN_0", - "QuantityMultiplier": 1, - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - }, - "PurchaseQuantityLimit": 1, - "Affiliation": "ArbitersSyndicate", - "MinAffiliationRank": 0, - "ReductionPerPositiveRank": 0.1, - "IncreasePerNegativeRank": 0.5, - "AllowMultipurchase": false, - "LocTagRandSeed": 1969797050, - "Id": { - "$oid": "670daf92d21f34757a5e73e2" - } - } - ], - "PropertyTextHash": "BE543CCC0A4F50A1D80CD2B523796EAE", - "RandomSeedType": "VRST_FLAVOUR_TEXT", - "Expiry": { - "$date": { - "$numberLong": "9999999000000" - } - } - } -}