From 1bab76f58b9a0cf8cd37e36ac37c24bccb33eb8a Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 12:37:08 +0100 Subject: [PATCH 01/10] fix: unlockAllScans not fully working with blacklisted enemies (#723) --- static/fixed_responses/allScans.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/static/fixed_responses/allScans.json b/static/fixed_responses/allScans.json index 8f186d29..938f7dd8 100644 --- a/static/fixed_responses/allScans.json +++ b/static/fixed_responses/allScans.json @@ -4346,5 +4346,17 @@ { "scans": 9999, "type": "/Lotus/Weapons/Infested/Melee/InfBoomerang/InfBoomerangSpawnAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/DeepSpace/GrineerDSDestroyerAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/Saturn/GrineerSaturnDestroyerAvatar" + }, + { + "scans": 9999, + "type": "/Lotus/Types/Game/CrewShip/GrineerDestroyer/GrineerDestroyerAvatar" } ] -- 2.47.2 From 101d6435f62a0dad1e63e5cbb963e46c5b10cc19 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 13:18:01 +0100 Subject: [PATCH 02/10] feat: leveling up intrinsics --- src/controllers/api/playerSkillsController.ts | 29 +++++++++++++++++++ src/models/inventoryModels/inventoryModel.ts | 25 ++++++++-------- src/routes/api.ts | 2 ++ src/types/inventoryTypes/inventoryTypes.ts | 3 +- 4 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 src/controllers/api/playerSkillsController.ts diff --git a/src/controllers/api/playerSkillsController.ts b/src/controllers/api/playerSkillsController.ts new file mode 100644 index 00000000..a82052d0 --- /dev/null +++ b/src/controllers/api/playerSkillsController.ts @@ -0,0 +1,29 @@ +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes"; +import { RequestHandler } from "express"; + +export const playerSkillsController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + const request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest; + + const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]; + const cost = (1 << oldRank) * 1000; + inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost; + inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++; + await inventory.save(); + + res.json({ + Pool: request.Pool, + PoolInc: -cost, + Skill: request.Skill, + Rank: oldRank + 1 + }); +}; + +interface IPlayerSkillsRequest { + Pool: string; + Skill: string; +} diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 7c8d5b75..62544cd5 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -438,18 +438,17 @@ const seasonChallengeHistorySchema = new Schema( //TODO: check whether this is complete const playerSkillsSchema = new Schema( { - LPP_SPACE: Number, - LPP_DRIFTER: Number, - LPS_NONE: Number, - LPS_PILOTING: Number, - LPS_GUNNERY: Number, - LPS_TACTICAL: Number, - LPS_ENGINEERING: Number, - LPS_COMMAND: Number, - LPS_DRIFT_COMBAT: Number, - LPS_DRIFT_RIDING: Number, - LPS_DRIFT_OPPORTUNITY: Number, - LPS_DRIFT_ENDURANCE: Number + LPP_SPACE: { type: Number, default: 0 }, + LPS_PILOTING: { type: Number, default: 0 }, + LPS_GUNNERY: { type: Number, default: 0 }, + LPS_TACTICAL: { type: Number, default: 0 }, + LPS_ENGINEERING: { type: Number, default: 0 }, + LPS_COMMAND: { type: Number, default: 0 }, + LPP_DRIFTER: { type: Number, default: 0 }, + LPS_DRIFT_COMBAT: { type: Number, default: 0 }, + LPS_DRIFT_RIDING: { type: Number, default: 0 }, + LPS_DRIFT_OPPORTUNITY: { type: Number, default: 0 }, + LPS_DRIFT_ENDURANCE: { type: Number, default: 0 } }, { _id: false } ); @@ -1003,7 +1002,7 @@ const inventorySchema = new Schema( //Modulars lvl and exp(Railjack|Duviri) //https://warframe.fandom.com/wiki/Intrinsics - PlayerSkills: playerSkillsSchema, + PlayerSkills: { type: playerSkillsSchema, default: {} }, //TradeBannedUntil data TradeBannedUntil: Schema.Types.Mixed, diff --git a/src/routes/api.ts b/src/routes/api.ts index 4194f44c..f88b527f 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -44,6 +44,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController"; import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController"; import { nameWeaponController } from "@/src/controllers/api/nameWeaponController"; +import { playerSkillsController } from "@/src/controllers/api/playerSkillsController"; import { projectionManagerController } from "../controllers/api/projectionManagerController"; import { purchaseController } from "@/src/controllers/api/purchaseController"; import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController"; @@ -130,6 +131,7 @@ apiRouter.post("/login.php", loginController); apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController); apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController); apiRouter.post("/nameWeapon.php", nameWeaponController); +apiRouter.post("/playerSkills.php", playerSkillsController); apiRouter.post("/projectionManager.php", projectionManagerController); apiRouter.post("/purchase.php", purchaseController); apiRouter.post("/rerollRandomMod.php", rerollRandomModController); diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 6d6dd9bc..ae311613 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -814,13 +814,12 @@ export interface IPersonalTechProject { export interface IPlayerSkills { LPP_SPACE: number; - LPP_DRIFTER: number; - LPS_NONE: number; LPS_PILOTING: number; LPS_GUNNERY: number; LPS_TACTICAL: number; LPS_ENGINEERING: number; LPS_COMMAND: number; + LPP_DRIFTER: number; LPS_DRIFT_COMBAT: number; LPS_DRIFT_RIDING: number; LPS_DRIFT_OPPORTUNITY: number; -- 2.47.2 From d69ebf89ec362dd4d32d79b9e5ea1fae5518262e Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 13:34:41 +0100 Subject: [PATCH 03/10] feat: helminth losing apetite (#718) --- .../api/infestedFoundryController.ts | 78 ++++++++++++++++--- src/models/inventoryModels/inventoryModel.ts | 20 ++++- src/types/inventoryTypes/inventoryTypes.ts | 10 ++- 3 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index 0f0833d6..d52c7f74 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -8,6 +8,7 @@ import { ExportMisc, ExportRecipes } from "warframe-public-export-plus"; import { getRecipe } from "@/src/services/itemDataService"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import { toMongoDate } from "@/src/helpers/inventoryHelpers"; +import { logger } from "@/src/utils/logger"; export const infestedFoundryController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -67,21 +68,43 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { const miscItemChanges: IMiscItem[] = []; let totalPercentagePointsGained = 0; + const currentUnixSeconds = Math.trunc(new Date().getTime() / 1000); + for (const contribution of request.ResourceContributions) { const snack = ExportMisc.helminthSnacks[contribution.ItemType]; - // Note: Currently ignoring loss of apetite - totalPercentagePointsGained += snack.gain * 100; // 30% would be gain=0.3, so percentage points is equal to gain * 100. - const resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type); - if (resource) { - resource.Count += Math.trunc(snack.gain * 1000); - } else { - inventory.InfestedFoundry.Resources.push({ - ItemType: snack.type, - Count: Math.trunc(snack.gain * 1000) // 30% would be gain=0.3 or Count=300, so Count=gain*1000. - }); + let resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type); + if (!resource) { + resource = + inventory.InfestedFoundry.Resources[ + inventory.InfestedFoundry.Resources.push({ ItemType: snack.type, Count: 0 }) - 1 + ]; } + resource.RecentlyConvertedResources ??= []; + let record = resource.RecentlyConvertedResources.find(x => x.ItemType == contribution.ItemType); + if (!record) { + record = + resource.RecentlyConvertedResources[ + resource.RecentlyConvertedResources.push({ ItemType: contribution.ItemType, Date: 0 }) - 1 + ]; + } + + const hoursRemaining = (record.Date - currentUnixSeconds) / 3600; + const apetiteFactor = apetiteModel(hoursRemaining) / 30; + logger.debug(`helminth eating ${contribution.ItemType} (+${(snack.gain * 100).toFixed(0)}%)`, { + hoursRemaining, + apetiteFactor + }); + if (hoursRemaining >= 18) { + record.Date = currentUnixSeconds + 72 * 60 * 60; + } else { + record.Date = currentUnixSeconds + 24 * 60 * 60; + } + + totalPercentagePointsGained += snack.gain * 100 * apetiteFactor; // 30% would be gain=0.3, so percentage points is equal to gain * 100. + resource.Count += Math.trunc(snack.gain * 1000 * apetiteFactor); // 30% would be gain=0.3 or Count=300, so Count=gain*1000. + // tally items for removal const change = miscItemChanges.find(x => x.ItemType == contribution.ItemType); if (change) { @@ -387,3 +410,38 @@ interface IHelminthInvigorationRequest { ResourceTypes: string[]; ResourceCosts: number[]; } + +// Hours remaining, percentage points gained (out of 30 total) +// 0, 30 +// 5, 25.8 +// 10, 21.6 +// 12, 20 +// 16, 16.6 +// 17, 15.8 +// 18, 15 +// 20, 15 +// 24, 15 +// 36, 15 +// 40, 13.6 +// 47, 11.3 +// 48, 11 +// 50, 10.3 +// 60, 7 +// 70, 3.6 +// 71, 3.3 +// 72, 3 +const apetiteModel = (x: number): number => { + if (x <= 0) { + return 30; + } + if (x < 18) { + return -0.84 * x + 30; + } + if (x <= 36) { + return 15; + } + if (x < 71.9) { + return -0.3327892 * x + 26.94135; + } + return 3; +}; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 7c8d5b75..8202bda9 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -45,7 +45,8 @@ import { ICrewShipMembers, ICrewShip, ICrewShipPilotWeapon, - IShipExterior + IShipExterior, + IHelminthFoodRecord } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -470,7 +471,22 @@ const consumedSchuitsSchema = new Schema( { _id: false } ); -const helminthResourceSchema = new Schema({ ItemType: String, Count: Number }, { _id: false }); +const helminthFoodRecordSchema = new Schema( + { + ItemType: String, + Date: Number + }, + { _id: false } +); + +const helminthResourceSchema = new Schema( + { + ItemType: String, + Count: Number, + RecentlyConvertedResources: { type: [helminthFoodRecordSchema], default: undefined } + }, + { _id: false } +); const infestedFoundrySchema = new Schema( { diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 6d6dd9bc..1f43c918 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -513,13 +513,15 @@ export interface IFusionTreasure { Sockets: number; } +export interface IHelminthFoodRecord { + ItemType: string; + Date: number; +} + export interface IHelminthResource { ItemType: string; Count: number; - RecentlyConvertedResources?: { - ItemType: string; - Date: number; - }[]; + RecentlyConvertedResources?: IHelminthFoodRecord[]; } export interface IInfestedFoundry { -- 2.47.2 From 9d115a4d02344a60ac64b35c66b8031804d15c9b Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 13:40:19 +0100 Subject: [PATCH 04/10] feat: archon shard removal (#724) --- .../api/infestedFoundryController.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index d52c7f74..40a95d37 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -41,6 +41,25 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { break; } + case "x": { + // shard removal + const request = getJSONfromString(String(req.body)) as IShardUninstallRequest; + const inventory = await getInventory(accountId); + const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!; + suit.ArchonCrystalUpgrades![request.Slot] = {}; + const bile = inventory.InfestedFoundry!.Resources!.find( + x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile" + )!; + bile.Count -= 300; + await inventory.save(); + res.json({ + InventoryChanges: { + InfestedFoundry: inventory.toJSON().InfestedFoundry + } + }); + break; + } + case "n": { // name the beast const request = getJSONfromString(String(req.body)) as IHelminthNameRequest; @@ -274,6 +293,11 @@ interface IShardInstallRequest { Color: string; } +interface IShardUninstallRequest { + SuitId: IOid; + Slot: number; +} + interface IHelminthNameRequest { newName: string; } -- 2.47.2 From 82621ebe0f3b02391ab9a94df291b0cf2d1bc0a5 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 23:20:36 +0100 Subject: [PATCH 05/10] feat: sentient apetite (#726) --- .../api/infestedFoundryController.ts | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index 40a95d37..ea35fa4d 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -3,7 +3,13 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { getInventory, addMiscItems, updateCurrency, addRecipes } from "@/src/services/inventoryService"; import { IOid } from "@/src/types/commonTypes"; -import { IConsumedSuit, IInfestedFoundry, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes"; +import { + IConsumedSuit, + IHelminthFoodRecord, + IInfestedFoundry, + IMiscItem, + ITypeCount +} from "@/src/types/inventoryTypes/inventoryTypes"; import { ExportMisc, ExportRecipes } from "warframe-public-export-plus"; import { getRecipe } from "@/src/services/itemDataService"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; @@ -92,6 +98,34 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { for (const contribution of request.ResourceContributions) { const snack = ExportMisc.helminthSnacks[contribution.ItemType]; + // tally items for removal + const change = miscItemChanges.find(x => x.ItemType == contribution.ItemType); + if (change) { + change.ItemCount -= snack.count; + } else { + miscItemChanges.push({ ItemType: contribution.ItemType, ItemCount: snack.count * -1 }); + } + + if (snack.type == "/Lotus/Types/Items/InfestedFoundry/HelminthAppetiteCooldownReducer") { + // sentinent apetite + let mostDislikedSnackRecord: IHelminthFoodRecord = { ItemType: "", Date: 0 }; + for (const resource of inventory.InfestedFoundry.Resources) { + if (resource.RecentlyConvertedResources) { + for (const record of resource.RecentlyConvertedResources) { + if (record.Date > mostDislikedSnackRecord.Date) { + mostDislikedSnackRecord = record; + } + } + } + } + logger.debug("helminth eats sentient resource; most disliked snack:", { + type: mostDislikedSnackRecord.ItemType, + date: mostDislikedSnackRecord.Date + }); + mostDislikedSnackRecord.Date = currentUnixSeconds + 24 * 60 * 60; // Possibly unfaithful + continue; + } + let resource = inventory.InfestedFoundry.Resources.find(x => x.ItemType == snack.type); if (!resource) { resource = @@ -116,21 +150,13 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { apetiteFactor }); if (hoursRemaining >= 18) { - record.Date = currentUnixSeconds + 72 * 60 * 60; + record.Date = currentUnixSeconds + 72 * 60 * 60; // Possibly unfaithful } else { record.Date = currentUnixSeconds + 24 * 60 * 60; } totalPercentagePointsGained += snack.gain * 100 * apetiteFactor; // 30% would be gain=0.3, so percentage points is equal to gain * 100. resource.Count += Math.trunc(snack.gain * 1000 * apetiteFactor); // 30% would be gain=0.3 or Count=300, so Count=gain*1000. - - // tally items for removal - const change = miscItemChanges.find(x => x.ItemType == contribution.ItemType); - if (change) { - change.ItemCount -= snack.count; - } else { - miscItemChanges.push({ ItemType: contribution.ItemType, ItemCount: snack.count * -1 }); - } } const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry, 666 * totalPercentagePointsGained); @@ -435,6 +461,8 @@ interface IHelminthInvigorationRequest { ResourceCosts: number[]; } +// A fitted model for observed apetite values. Likely slightly inaccurate. +// // Hours remaining, percentage points gained (out of 30 total) // 0, 30 // 5, 25.8 -- 2.47.2 From b1a9b3fa431b6e39138610140e88992fd6247ddd Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 23:34:52 +0100 Subject: [PATCH 06/10] fix: incorrect skill costs for drifter --- src/controllers/api/playerSkillsController.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/controllers/api/playerSkillsController.ts b/src/controllers/api/playerSkillsController.ts index a82052d0..2610183f 100644 --- a/src/controllers/api/playerSkillsController.ts +++ b/src/controllers/api/playerSkillsController.ts @@ -10,7 +10,7 @@ export const playerSkillsController: RequestHandler = async (req, res) => { const request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest; const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]; - const cost = (1 << oldRank) * 1000; + const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000; inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost; inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++; await inventory.save(); @@ -27,3 +27,5 @@ interface IPlayerSkillsRequest { Pool: string; Skill: string; } + +const drifterCosts = [20, 25, 30, 45, 65, 90, 125, 160, 205, 255]; -- 2.47.2 From eb6baa5e1550be8e6ba3678745154afaffb568ca Mon Sep 17 00:00:00 2001 From: Sainan Date: Mon, 6 Jan 2025 01:21:02 +0100 Subject: [PATCH 07/10] fix: removing an archon shard doesn't refund it (#729) --- .../api/infestedFoundryController.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index ea35fa4d..04144475 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -52,14 +52,33 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { const request = getJSONfromString(String(req.body)) as IShardUninstallRequest; const inventory = await getInventory(accountId); const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!; + + // refund shard + const shard = Object.entries(colorToShard).find( + ([color]) => color == suit.ArchonCrystalUpgrades![request.Slot].Color + )![1]; + const miscItemChanges = [ + { + ItemType: shard, + ItemCount: 1 + } + ]; + addMiscItems(inventory, miscItemChanges); + + // remove from suit suit.ArchonCrystalUpgrades![request.Slot] = {}; + + // remove bile const bile = inventory.InfestedFoundry!.Resources!.find( x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile" )!; bile.Count -= 300; + await inventory.save(); + res.json({ InventoryChanges: { + MiscItems: miscItemChanges, InfestedFoundry: inventory.toJSON().InfestedFoundry } }); -- 2.47.2 From 709c2a401bf22d9014136771fb61e245e6192fe7 Mon Sep 17 00:00:00 2001 From: Sainan Date: Mon, 6 Jan 2025 01:21:37 +0100 Subject: [PATCH 08/10] feat: spectre loadouts (#719) --- .../api/claimCompletedRecipeController.ts | 24 +++++++++ src/controllers/api/startRecipeController.ts | 54 +++++++++++++++++++ src/models/inventoryModels/inventoryModel.ts | 21 ++++---- src/types/inventoryTypes/inventoryTypes.ts | 17 +++--- 4 files changed, 97 insertions(+), 19 deletions(-) diff --git a/src/controllers/api/claimCompletedRecipeController.ts b/src/controllers/api/claimCompletedRecipeController.ts index 5b8e048e..179327da 100644 --- a/src/controllers/api/claimCompletedRecipeController.ts +++ b/src/controllers/api/claimCompletedRecipeController.ts @@ -59,6 +59,30 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) = }); } else { logger.debug("Claiming Recipe", { recipe, pendingRecipe }); + + if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") { + const inventory = await getInventory(accountId); + inventory.PendingSpectreLoadouts ??= []; + inventory.SpectreLoadouts ??= []; + + const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex( + x => x.ItemType == recipe.resultType + ); + if (pendingLoadoutIndex != -1) { + const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType); + if (loadoutIndex != -1) { + inventory.SpectreLoadouts.splice(loadoutIndex, 1); + } + logger.debug( + "moving spectre loadout from pending to active", + inventory.toJSON().PendingSpectreLoadouts![pendingLoadoutIndex] + ); + inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]); + inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1); + await inventory.save(); + } + } + let InventoryChanges = {}; if (recipe.consumeOnUse) { const recipeChanges = [ diff --git a/src/controllers/api/startRecipeController.ts b/src/controllers/api/startRecipeController.ts index 83501874..4a511315 100644 --- a/src/controllers/api/startRecipeController.ts +++ b/src/controllers/api/startRecipeController.ts @@ -6,6 +6,7 @@ import { getRecipe } from "@/src/services/itemDataService"; import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService"; import { unixTimesInMs } from "@/src/constants/timeConstants"; import { Types } from "mongoose"; +import { ISpectreLoadout } from "@/src/types/inventoryTypes/inventoryTypes"; interface IStartRecipeRequest { RecipeName: string; @@ -43,6 +44,59 @@ export const startRecipeController: RequestHandler = async (req, res) => { _id: new Types.ObjectId() }); + if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") { + const spectreLoadout: ISpectreLoadout = { + ItemType: recipe.resultType, + Suits: "", + LongGuns: "", + Pistols: "", + Melee: "" + }; + for ( + let secretIngredientsIndex = 0; + secretIngredientsIndex != recipe.secretIngredients!.length; + ++secretIngredientsIndex + ) { + const type = recipe.secretIngredients![secretIngredientsIndex].ItemType; + const oid = startRecipeRequest.Ids[recipe.ingredients.length + secretIngredientsIndex]; + if (oid == "ffffffffffffffffffffffff") { + // user chose to preserve the active loadout + break; + } + if (type == "/Lotus/Types/Game/PowerSuits/PlayerPowerSuit") { + const item = inventory.Suits.find(x => x._id.toString() == oid)!; + spectreLoadout.Suits = item.ItemType; + } else if (type == "/Lotus/Weapons/Tenno/Pistol/LotusPistol") { + const item = inventory.Pistols.find(x => x._id.toString() == oid)!; + spectreLoadout.Pistols = item.ItemType; + spectreLoadout.PistolsModularParts = item.ModularParts; + } else if (type == "/Lotus/Weapons/Tenno/LotusLongGun") { + const item = inventory.LongGuns.find(x => x._id.toString() == oid)!; + spectreLoadout.LongGuns = item.ItemType; + spectreLoadout.LongGunsModularParts = item.ModularParts; + } else { + console.assert(type == "/Lotus/Types/Game/LotusMeleeWeapon"); + const item = inventory.Melee.find(x => x._id.toString() == oid)!; + spectreLoadout.Melee = item.ItemType; + spectreLoadout.MeleeModularParts = item.ModularParts; + } + } + if ( + spectreLoadout.Suits != "" && + spectreLoadout.LongGuns != "" && + spectreLoadout.Pistols != "" && + spectreLoadout.Melee != "" + ) { + inventory.PendingSpectreLoadouts ??= []; + const existingIndex = inventory.PendingSpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType); + if (existingIndex != -1) { + inventory.PendingSpectreLoadouts.splice(existingIndex, 1); + } + inventory.PendingSpectreLoadouts.push(spectreLoadout); + logger.debug("pending spectre loadout", spectreLoadout); + } + } + const newInventory = await inventory.save(); res.json({ diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 8202bda9..f1e3edb6 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -548,13 +548,14 @@ const fusionTreasuresSchema = new Schema().add(typeCountSchema) const spectreLoadoutsSchema = new Schema( { - LongGuns: String, - Melee: String, - Pistols: String, - PistolsFeatures: Number, - PistolsModularParts: [String], + ItemType: String, Suits: String, - ItemType: String + LongGuns: String, + LongGunsModularParts: { type: [String], default: undefined }, + Pistols: String, + PistolsModularParts: { type: [String], default: undefined }, + Melee: String, + MeleeModularParts: { type: [String], default: undefined } }, { _id: false } ); @@ -936,11 +937,9 @@ const inventorySchema = new Schema( QualifyingInvasions: [Schema.Types.Mixed], FactionScores: [Number], - //Have only Suit+Pistols+LongGuns+Melee+ItemType(BronzeSpectre,GoldSpectre,PlatinumSpectreArmy,SilverSpectreArmy) - //"/Lotus/Types/Game/SpectreArmies/BronzeSpectreArmy": "Vapor Specter Regiment", - SpectreLoadouts: [spectreLoadoutsSchema], - //If you want change Spectre Gear id - PendingSpectreLoadouts: [Schema.Types.Mixed], + // https://warframe.fandom.com/wiki/Specter_(Tenno) + PendingSpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined }, + SpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined }, //New Quest Email EmailItems: [TypeXPItemSchema], diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 1f43c918..c453206d 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -203,8 +203,8 @@ export interface IInventoryResponse { SpaceMelee: IEquipmentDatabase[]; SpaceGuns: IEquipmentDatabase[]; ArchwingEnabled: boolean; - PendingSpectreLoadouts: any[]; - SpectreLoadouts: ISpectreLoadout[]; + PendingSpectreLoadouts?: ISpectreLoadout[]; + SpectreLoadouts?: ISpectreLoadout[]; SentinelWeapons: IEquipmentDatabase[]; Sentinels: IEquipmentDatabase[]; EmailItems: ITypeCount[]; @@ -871,13 +871,14 @@ export interface IShipInventory { } export interface ISpectreLoadout { - LongGuns: string; - Melee: string; - Pistols: string; - PistolsFeatures: number; - PistolsModularParts: string[]; - Suits: string; ItemType: string; + Suits: string; + LongGuns: string; + LongGunsModularParts?: string[]; + Pistols: string; + PistolsModularParts?: string[]; + Melee: string; + MeleeModularParts?: string[]; } export interface IStepSequencer { -- 2.47.2 From 69c65f3ce2d1f47f2285dfef80a47a7b87fa7d04 Mon Sep 17 00:00:00 2001 From: Sainan Date: Mon, 6 Jan 2025 04:36:40 +0100 Subject: [PATCH 09/10] fix: missing teshin hard mode vendor manifest (#737) --- src/services/serversideVendorsService.ts | 18 +- .../TeshinHardModeVendorManifest.json | 603 ++++++++++++++++++ 2 files changed, 613 insertions(+), 8 deletions(-) create mode 100644 static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json diff --git a/src/services/serversideVendorsService.ts b/src/services/serversideVendorsService.ts index 0b61caa4..3b4c3a61 100644 --- a/src/services/serversideVendorsService.ts +++ b/src/services/serversideVendorsService.ts @@ -15,16 +15,17 @@ import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json"; import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json"; import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json"; -import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json"; 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 OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json"; -import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json"; import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json"; -import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json"; -import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json"; +import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json"; import SolarisDebtTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorManifest.json"; import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json"; +import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json"; +import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json"; +import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json"; import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json"; interface IVendorManifest { @@ -55,16 +56,17 @@ const vendorManifests: IVendorManifest[] = [ EntratiLabsEntratiLabsCommisionsManifest, EntratiLabsEntratiLabVendorManifest, HubsIronwakeDondaVendorManifest, - HubsRailjackCrewMemberVendorManifest, HubsPerrinSequenceWeaponVendorManifest, + HubsRailjackCrewMemberVendorManifest, MaskSalesmanManifest, OstronFishmongerVendorManifest, - OstronProspectorVendorManifest, OstronPetVendorManifest, - SolarisFishmongerVendorManifest, - SolarisProspectorVendorManifest, + OstronProspectorVendorManifest, SolarisDebtTokenVendorManifest, SolarisDebtTokenVendorRepossessionsManifest, + SolarisFishmongerVendorManifest, + SolarisProspectorVendorManifest, + TeshinHardModeVendorManifest, ZarimanCommisionsManifestArchimedean ]; diff --git a/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json b/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json new file mode 100644 index 00000000..abfd1cab --- /dev/null +++ b/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json @@ -0,0 +1,603 @@ +{ + "VendorInfo":{ + "_id":{ + "$oid":"63ed01efbdaa38891767bac9" + }, + "TypeName":"/Lotus/Types/Game/VendorManifests/Hubs/TeshinHardModeVendorManifest", + "ItemManifest":[ + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinArmsBlueprint", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9947" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinBodyBlueprint", + "ItemPrices":[ + { + "ItemCount":25, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9948" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinHeadBlueprint", + "ItemPrices":[ + { + "ItemCount":20, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9949" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinLegsBlueprint", + "ItemPrices":[ + { + "ItemCount":25, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994a" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994b" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994c" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/Components/FormaStanceBlueprint", + "ItemPrices":[ + { + "ItemCount":10, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994d" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Skins/Effects/OrbsEphemera", + "ItemPrices":[ + { + "ItemCount":3, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994e" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Skins/Effects/TatsuSkullEphemera", + "ItemPrices":[ + { + "ItemCount":85, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e994f" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/Randomized/RawShotgunRandomMod", + "ItemPrices":[ + { + "ItemCount":75, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9950" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Recipes/Components/UmbraFormaBlueprint", + "ItemPrices":[ + { + "ItemCount":150, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9951" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/Kuva", + "ItemPrices":[ + { + "ItemCount":55, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":50000, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9952" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/Randomized/RawModularPistolRandomMod", + "ItemPrices":[ + { + "ItemCount":75, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9953" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/Forma", + "ItemPrices":[ + { + "ItemCount":75, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":3, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9954" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/Randomized/RawModularMeleeRandomMod", + "ItemPrices":[ + { + "ItemCount":75, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9955" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/FusionBundles/EvergreenLoginRewardFusionBundle", + "ItemPrices":[ + { + "ItemCount":150, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9956" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/Randomized/RawRifleRandomMod", + "ItemPrices":[ + { + "ItemCount":75, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9957" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Upgrades/Mods/Shotgun/WeaponRecoilReductionMod", + "ItemPrices":[ + { + "ItemCount":35, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9958" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/ShipDecos/TeshinBobbleHead", + "ItemPrices":[ + { + "ItemCount":35, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e9959" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/StoreItems/AvatarImages/ImageGaussVED", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995a" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/StoreItems/AvatarImages/ImageGrendelVED", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995b" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageProteaAction", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995c" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/ShipDecos/TeaSet", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995d" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageXakuAction", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995e" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/RivenIdentifier", + "ItemPrices":[ + { + "ItemCount":20, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"2051240400000" + } + }, + "PurchaseQuantityLimit":1, + "RotatedWeekly":true, + "AllowMultipurchase":false, + "Id":{ + "$oid":"66fd60b20ba592c4c95e995f" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/BoosterPacks/RandomSyndicateProjectionPack", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":1, + "Expiry":{ + "$date":{ + "$numberLong":"1736726400000" + } + }, + "PurchaseQuantityLimit":25, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e997c" + } + }, + { + "StoreItem":"/Lotus/StoreItems/Types/Items/MiscItems/Kuva", + "ItemPrices":[ + { + "ItemCount":15, + "ItemType":"/Lotus/Types/Items/MiscItems/SteelEssence", + "ProductCategory":"MiscItems" + } + ], + "Bin":"BIN_0", + "QuantityMultiplier":10000, + "Expiry":{ + "$date":{ + "$numberLong":"1736726400000" + } + }, + "PurchaseQuantityLimit":25, + "AllowMultipurchase":true, + "Id":{ + "$oid":"66fd60b20ba592c4c95e997d" + } + } + ], + "PropertyTextHash":"0A0F20AFA748FBEE490510DBF5A33A0D", + "Expiry":{ + "$date":{ + "$numberLong":"1736726400000" + } + } + } +} \ No newline at end of file -- 2.47.2 From 05fd3c4cecf671d43938a9f5698bed072a4fc6e5 Mon Sep 17 00:00:00 2001 From: Sainan Date: Mon, 6 Jan 2025 05:26:37 +0100 Subject: [PATCH 10/10] chore: some notes in inventoryTypes --- src/types/inventoryTypes/inventoryTypes.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index c453206d..81d12bff 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -102,7 +102,8 @@ export type TSolarMapRegion = | "Uranus" | "Venus" | "Void" - | "SolarMapDeimosName"; + | "SolarMapDeimosName" + | "1999MapName"; //TODO: perhaps split response and database into their own files @@ -727,6 +728,8 @@ export interface IPendingRecipe { ItemType: string; CompletionDate: Date; ItemId: IOid; + TargetItemId?: string; // likely related to liches + TargetFingerprint?: string; // likely related to liches } export interface IPendingTrade { -- 2.47.2