From d69ebf89ec362dd4d32d79b9e5ea1fae5518262e Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 5 Jan 2025 13:34:41 +0100 Subject: [PATCH] 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 0f0833d62..d52c7f744 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 7c8d5b75e..8202bda9d 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 6d6dd9bc0..1f43c9182 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 {