2024-06-18 13:02:29 +02:00
|
|
|
import { RequestHandler } from "express";
|
|
|
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
|
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
2025-03-13 04:25:59 -07:00
|
|
|
import { getInventory, addMiscItems, updateCurrency, addRecipes, freeUpSlot } from "@/src/services/inventoryService";
|
2024-06-18 13:02:29 +02:00
|
|
|
import { IOid } from "@/src/types/commonTypes";
|
2025-01-05 23:20:36 +01:00
|
|
|
import {
|
|
|
|
IConsumedSuit,
|
|
|
|
IHelminthFoodRecord,
|
2025-02-22 11:09:17 -08:00
|
|
|
IInventoryClient,
|
2025-01-05 23:20:36 +01:00
|
|
|
IMiscItem,
|
2025-04-05 06:52:35 -07:00
|
|
|
InventorySlot
|
2025-01-05 23:20:36 +01:00
|
|
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
2025-04-05 06:52:35 -07:00
|
|
|
import { ExportMisc } from "warframe-public-export-plus";
|
2025-01-03 05:22:56 +01:00
|
|
|
import { getRecipe } from "@/src/services/itemDataService";
|
2025-01-05 06:17:42 +01:00
|
|
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
2025-01-05 13:34:41 +01:00
|
|
|
import { logger } from "@/src/utils/logger";
|
2025-01-17 05:09:25 +01:00
|
|
|
import { colorToShard } from "@/src/helpers/shardHelper";
|
2025-02-22 11:09:17 -08:00
|
|
|
import { config } from "@/src/services/configService";
|
2025-04-05 06:52:35 -07:00
|
|
|
import {
|
|
|
|
addInfestedFoundryXP,
|
|
|
|
applyCheatsToInfestedFoundry,
|
|
|
|
handleSubsumeCompletion
|
|
|
|
} from "@/src/services/infestedFoundryService";
|
2024-06-18 13:02:29 +02:00
|
|
|
|
|
|
|
export const infestedFoundryController: RequestHandler = async (req, res) => {
|
|
|
|
const accountId = await getAccountIdForRequest(req);
|
|
|
|
switch (req.query.mode) {
|
|
|
|
case "s": {
|
|
|
|
// shard installation
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IShardInstallRequest>(String(req.body));
|
2024-06-18 13:02:29 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
2025-03-31 04:15:32 -07:00
|
|
|
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
2024-06-30 13:13:26 +02:00
|
|
|
if (!suit.ArchonCrystalUpgrades || suit.ArchonCrystalUpgrades.length != 5) {
|
2024-06-18 13:02:29 +02:00
|
|
|
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}];
|
|
|
|
}
|
|
|
|
suit.ArchonCrystalUpgrades[request.Slot] = {
|
|
|
|
UpgradeType: request.UpgradeType,
|
|
|
|
Color: request.Color
|
|
|
|
};
|
|
|
|
const miscItemChanges = [
|
|
|
|
{
|
|
|
|
ItemType: colorToShard[request.Color],
|
|
|
|
ItemCount: -1
|
|
|
|
}
|
|
|
|
];
|
|
|
|
addMiscItems(inventory, miscItemChanges);
|
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
|
|
|
MiscItems: miscItemChanges
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-01-05 13:40:19 +01:00
|
|
|
case "x": {
|
|
|
|
// shard removal
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IShardUninstallRequest>(String(req.body));
|
2025-01-05 13:40:19 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
2025-03-31 04:15:32 -07:00
|
|
|
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
2025-01-06 01:21:02 +01:00
|
|
|
|
2025-03-09 03:41:12 -07:00
|
|
|
const miscItemChanges: IMiscItem[] = [];
|
|
|
|
if (suit.ArchonCrystalUpgrades![request.Slot].Color) {
|
|
|
|
// refund shard
|
|
|
|
const shard = Object.entries(colorToShard).find(
|
|
|
|
([color]) => color == suit.ArchonCrystalUpgrades![request.Slot].Color
|
|
|
|
)![1];
|
|
|
|
miscItemChanges.push({
|
2025-01-06 01:21:02 +01:00
|
|
|
ItemType: shard,
|
|
|
|
ItemCount: 1
|
2025-03-09 03:41:12 -07:00
|
|
|
});
|
|
|
|
addMiscItems(inventory, miscItemChanges);
|
|
|
|
}
|
2025-01-06 01:21:02 +01:00
|
|
|
|
|
|
|
// remove from suit
|
2025-01-05 13:40:19 +01:00
|
|
|
suit.ArchonCrystalUpgrades![request.Slot] = {};
|
2025-01-06 01:21:02 +01:00
|
|
|
|
2025-02-22 11:09:17 -08:00
|
|
|
if (!config.infiniteHelminthMaterials) {
|
|
|
|
// remove bile
|
|
|
|
const bile = inventory.InfestedFoundry!.Resources!.find(
|
|
|
|
x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile"
|
|
|
|
)!;
|
|
|
|
bile.Count -= 300;
|
|
|
|
}
|
2025-01-06 01:21:02 +01:00
|
|
|
|
2025-01-05 13:40:19 +01:00
|
|
|
await inventory.save();
|
2025-01-06 01:21:02 +01:00
|
|
|
|
2025-02-22 11:09:17 -08:00
|
|
|
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
|
|
applyCheatsToInfestedFoundry(infestedFoundry);
|
2025-01-05 13:40:19 +01:00
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
2025-01-06 01:21:02 +01:00
|
|
|
MiscItems: miscItemChanges,
|
2025-02-22 11:09:17 -08:00
|
|
|
InfestedFoundry: infestedFoundry
|
2025-01-05 13:40:19 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-06-18 13:02:29 +02:00
|
|
|
case "n": {
|
|
|
|
// name the beast
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IHelminthNameRequest>(String(req.body));
|
2024-06-18 13:02:29 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
inventory.InfestedFoundry ??= {};
|
2024-06-24 12:37:28 +02:00
|
|
|
inventory.InfestedFoundry.Name = request.newName;
|
2024-06-18 13:02:29 +02:00
|
|
|
await inventory.save();
|
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
|
|
|
InfestedFoundry: {
|
|
|
|
Name: inventory.InfestedFoundry.Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-22 07:26:14 +01:00
|
|
|
case "c": {
|
|
|
|
// consume items
|
2025-02-22 11:09:17 -08:00
|
|
|
|
|
|
|
if (config.infiniteHelminthMaterials) {
|
|
|
|
res.status(400).end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IHelminthFeedRequest>(String(req.body));
|
2024-12-22 07:26:14 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
inventory.InfestedFoundry ??= {};
|
|
|
|
inventory.InfestedFoundry.Resources ??= [];
|
|
|
|
|
|
|
|
const miscItemChanges: IMiscItem[] = [];
|
|
|
|
let totalPercentagePointsGained = 0;
|
|
|
|
|
2025-03-18 04:24:11 -07:00
|
|
|
const currentUnixSeconds = Math.trunc(Date.now() / 1000);
|
2025-01-05 13:34:41 +01:00
|
|
|
|
2024-12-22 07:26:14 +01:00
|
|
|
for (const contribution of request.ResourceContributions) {
|
|
|
|
const snack = ExportMisc.helminthSnacks[contribution.ItemType];
|
|
|
|
|
2025-01-05 23:20:36 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2025-01-05 13:34:41 +01:00
|
|
|
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) {
|
2025-01-05 23:20:36 +01:00
|
|
|
record.Date = currentUnixSeconds + 72 * 60 * 60; // Possibly unfaithful
|
2024-12-22 07:26:14 +01:00
|
|
|
} else {
|
2025-01-05 13:34:41 +01:00
|
|
|
record.Date = currentUnixSeconds + 24 * 60 * 60;
|
2024-12-22 07:26:14 +01:00
|
|
|
}
|
|
|
|
|
2025-01-05 13:34:41 +01:00
|
|
|
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.
|
2025-01-09 14:02:12 +01:00
|
|
|
if (resource.Count > 1000) resource.Count = 1000;
|
2024-12-22 07:26:14 +01:00
|
|
|
}
|
|
|
|
|
2025-01-05 07:16:48 +01:00
|
|
|
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry, 666 * totalPercentagePointsGained);
|
|
|
|
addRecipes(inventory, recipeChanges);
|
2024-12-22 07:26:14 +01:00
|
|
|
addMiscItems(inventory, miscItemChanges);
|
|
|
|
await inventory.save();
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
2025-01-05 07:16:48 +01:00
|
|
|
Recipes: recipeChanges,
|
2024-12-22 07:26:14 +01:00
|
|
|
InfestedFoundry: {
|
|
|
|
XP: inventory.InfestedFoundry.XP,
|
2024-12-31 04:46:12 +01:00
|
|
|
Resources: inventory.InfestedFoundry.Resources,
|
|
|
|
Slots: inventory.InfestedFoundry.Slots
|
2025-01-05 07:16:48 +01:00
|
|
|
},
|
|
|
|
MiscItems: miscItemChanges
|
|
|
|
}
|
2024-12-22 07:26:14 +01:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-01-05 05:17:40 +01:00
|
|
|
case "o": {
|
|
|
|
// offerings update
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IHelminthOfferingsUpdate>(String(req.body));
|
2025-01-05 05:17:40 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
inventory.InfestedFoundry ??= {};
|
|
|
|
inventory.InfestedFoundry.InvigorationIndex = request.OfferingsIndex;
|
|
|
|
inventory.InfestedFoundry.InvigorationSuitOfferings = request.SuitTypes;
|
2025-01-05 06:17:42 +01:00
|
|
|
if (request.Extra) {
|
|
|
|
inventory.InfestedFoundry.InvigorationsApplied = 0;
|
|
|
|
}
|
2025-01-05 05:17:40 +01:00
|
|
|
await inventory.save();
|
2025-02-22 11:09:17 -08:00
|
|
|
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
|
|
applyCheatsToInfestedFoundry(infestedFoundry);
|
2025-01-05 05:17:40 +01:00
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
2025-02-22 11:09:17 -08:00
|
|
|
InfestedFoundry: infestedFoundry
|
2025-01-05 05:17:40 +01:00
|
|
|
}
|
|
|
|
});
|
2024-06-18 13:02:29 +02:00
|
|
|
break;
|
2025-01-05 05:17:40 +01:00
|
|
|
}
|
2024-06-18 13:02:29 +02:00
|
|
|
|
2025-01-03 05:22:56 +01:00
|
|
|
case "a": {
|
|
|
|
// subsume warframe
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body));
|
2025-01-03 05:22:56 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const recipe = getRecipe(request.Recipe)!;
|
2025-02-22 11:09:17 -08:00
|
|
|
if (!config.infiniteHelminthMaterials) {
|
|
|
|
for (const ingredient of recipe.secretIngredients!) {
|
|
|
|
const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType);
|
|
|
|
if (resource) {
|
|
|
|
resource.Count -= ingredient.ItemCount;
|
|
|
|
}
|
2025-01-03 05:22:56 +01:00
|
|
|
}
|
|
|
|
}
|
2025-01-19 01:58:24 +01:00
|
|
|
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
2025-01-03 05:22:56 +01:00
|
|
|
inventory.Suits.pull(suit);
|
|
|
|
const consumedSuit: IConsumedSuit = { s: suit.ItemType };
|
2025-02-24 20:56:34 -08:00
|
|
|
if (suit.Configs[0] && suit.Configs[0].pricol) {
|
2025-01-03 05:22:56 +01:00
|
|
|
consumedSuit.c = suit.Configs[0].pricol;
|
|
|
|
}
|
2025-01-05 07:16:48 +01:00
|
|
|
if ((inventory.InfestedFoundry!.XP ?? 0) < 73125_00) {
|
|
|
|
inventory.InfestedFoundry!.Slots!--;
|
|
|
|
}
|
2025-01-03 05:22:56 +01:00
|
|
|
inventory.InfestedFoundry!.ConsumedSuits ??= [];
|
2025-01-20 12:21:39 +01:00
|
|
|
inventory.InfestedFoundry!.ConsumedSuits.push(consumedSuit);
|
2025-01-03 05:22:56 +01:00
|
|
|
inventory.InfestedFoundry!.LastConsumedSuit = suit;
|
2025-03-18 04:24:11 -07:00
|
|
|
inventory.InfestedFoundry!.AbilityOverrideUnlockCooldown = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
2025-01-05 07:16:48 +01:00
|
|
|
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00);
|
|
|
|
addRecipes(inventory, recipeChanges);
|
2025-03-13 04:25:59 -07:00
|
|
|
freeUpSlot(inventory, InventorySlot.SUITS);
|
2025-01-03 05:22:56 +01:00
|
|
|
await inventory.save();
|
2025-02-22 11:09:17 -08:00
|
|
|
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
|
|
applyCheatsToInfestedFoundry(infestedFoundry);
|
2025-01-03 05:22:56 +01:00
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
2025-01-05 07:16:48 +01:00
|
|
|
Recipes: recipeChanges,
|
2025-01-03 05:22:56 +01:00
|
|
|
RemovedIdItems: [
|
|
|
|
{
|
|
|
|
ItemId: request.SuitId
|
|
|
|
}
|
|
|
|
],
|
|
|
|
SuitBin: {
|
|
|
|
count: -1,
|
|
|
|
platinum: 0,
|
|
|
|
Slots: 1
|
|
|
|
},
|
2025-02-22 11:09:17 -08:00
|
|
|
InfestedFoundry: infestedFoundry
|
2025-01-03 05:22:56 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case "r": {
|
|
|
|
// rush subsume
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const currencyChanges = updateCurrency(inventory, 50, true);
|
|
|
|
const recipeChanges = handleSubsumeCompletion(inventory);
|
|
|
|
await inventory.save();
|
2025-02-22 11:09:17 -08:00
|
|
|
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
|
|
applyCheatsToInfestedFoundry(infestedFoundry);
|
2025-01-03 05:22:56 +01:00
|
|
|
res.json({
|
|
|
|
InventoryChanges: {
|
|
|
|
...currencyChanges,
|
|
|
|
Recipes: recipeChanges,
|
2025-02-22 11:09:17 -08:00
|
|
|
InfestedFoundry: infestedFoundry
|
2025-01-03 05:22:56 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-01-05 06:17:42 +01:00
|
|
|
case "u": {
|
2025-01-24 14:27:10 +01:00
|
|
|
const request = getJSONfromString<IHelminthInvigorationRequest>(String(req.body));
|
2025-01-05 06:17:42 +01:00
|
|
|
const inventory = await getInventory(accountId);
|
2025-01-19 01:58:24 +01:00
|
|
|
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
2025-03-18 04:24:11 -07:00
|
|
|
const upgradesExpiry = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
2025-01-05 06:17:42 +01:00
|
|
|
suit.OffensiveUpgrade = request.OffensiveUpgradeType;
|
|
|
|
suit.DefensiveUpgrade = request.DefensiveUpgradeType;
|
|
|
|
suit.UpgradesExpiry = upgradesExpiry;
|
2025-01-05 07:16:48 +01:00
|
|
|
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00);
|
|
|
|
addRecipes(inventory, recipeChanges);
|
2025-02-22 11:09:17 -08:00
|
|
|
if (!config.infiniteHelminthMaterials) {
|
|
|
|
for (let i = 0; i != request.ResourceTypes.length; ++i) {
|
|
|
|
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -=
|
|
|
|
request.ResourceCosts[i];
|
|
|
|
}
|
2025-01-05 06:17:42 +01:00
|
|
|
}
|
|
|
|
inventory.InfestedFoundry!.InvigorationsApplied ??= 0;
|
|
|
|
inventory.InfestedFoundry!.InvigorationsApplied += 1;
|
|
|
|
await inventory.save();
|
2025-02-22 11:09:17 -08:00
|
|
|
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
|
|
|
|
applyCheatsToInfestedFoundry(infestedFoundry);
|
2025-01-05 06:17:42 +01:00
|
|
|
res.json({
|
|
|
|
SuitId: request.SuitId,
|
|
|
|
OffensiveUpgrade: request.OffensiveUpgradeType,
|
|
|
|
DefensiveUpgrade: request.DefensiveUpgradeType,
|
|
|
|
UpgradesExpiry: toMongoDate(upgradesExpiry),
|
|
|
|
InventoryChanges: {
|
2025-01-05 07:16:48 +01:00
|
|
|
Recipes: recipeChanges,
|
2025-02-22 11:09:17 -08:00
|
|
|
InfestedFoundry: infestedFoundry
|
2025-01-05 06:17:42 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-01-05 12:26:26 +01:00
|
|
|
case "custom_unlockall": {
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
inventory.InfestedFoundry ??= {};
|
|
|
|
inventory.InfestedFoundry.XP ??= 0;
|
|
|
|
if (151875_00 > inventory.InfestedFoundry.XP) {
|
|
|
|
const recipeChanges = addInfestedFoundryXP(
|
|
|
|
inventory.InfestedFoundry,
|
|
|
|
151875_00 - inventory.InfestedFoundry.XP
|
|
|
|
);
|
|
|
|
addRecipes(inventory, recipeChanges);
|
|
|
|
await inventory.save();
|
|
|
|
}
|
|
|
|
res.end();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-06-18 13:02:29 +02:00
|
|
|
default:
|
2025-03-20 05:36:09 -07:00
|
|
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
2024-12-30 00:07:53 +01:00
|
|
|
throw new Error(`unhandled infestedFoundry mode: ${String(req.query.mode)}`);
|
2024-06-18 13:02:29 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
interface IShardInstallRequest {
|
|
|
|
SuitId: IOid;
|
|
|
|
Slot: number;
|
|
|
|
UpgradeType: string;
|
|
|
|
Color: string;
|
|
|
|
}
|
|
|
|
|
2025-01-05 13:40:19 +01:00
|
|
|
interface IShardUninstallRequest {
|
|
|
|
SuitId: IOid;
|
|
|
|
Slot: number;
|
|
|
|
}
|
|
|
|
|
2024-06-24 12:37:28 +02:00
|
|
|
interface IHelminthNameRequest {
|
|
|
|
newName: string;
|
|
|
|
}
|
|
|
|
|
2024-12-22 07:26:14 +01:00
|
|
|
interface IHelminthFeedRequest {
|
|
|
|
ResourceContributions: {
|
|
|
|
ItemType: string;
|
|
|
|
Date: number; // unix timestamp
|
|
|
|
}[];
|
|
|
|
}
|
|
|
|
|
2025-01-03 05:22:56 +01:00
|
|
|
interface IHelminthSubsumeRequest {
|
|
|
|
SuitId: IOid;
|
|
|
|
Recipe: string;
|
|
|
|
}
|
|
|
|
|
2025-01-05 05:17:40 +01:00
|
|
|
interface IHelminthOfferingsUpdate {
|
|
|
|
OfferingsIndex: number;
|
|
|
|
SuitTypes: string[];
|
|
|
|
Extra: boolean;
|
|
|
|
}
|
2025-01-05 06:17:42 +01:00
|
|
|
|
|
|
|
interface IHelminthInvigorationRequest {
|
|
|
|
SuitId: IOid;
|
|
|
|
OffensiveUpgradeType: string;
|
|
|
|
DefensiveUpgradeType: string;
|
|
|
|
ResourceTypes: string[];
|
|
|
|
ResourceCosts: number[];
|
|
|
|
}
|
2025-01-05 13:34:41 +01:00
|
|
|
|
2025-01-05 23:20:36 +01:00
|
|
|
// A fitted model for observed apetite values. Likely slightly inaccurate.
|
|
|
|
//
|
2025-01-05 13:34:41 +01:00
|
|
|
// 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;
|
|
|
|
};
|