From ec5eba3e909d6dbe5c9b6c5632d570e74cd0beec Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 13 Aug 2025 23:09:27 +0200 Subject: [PATCH] chore: make 'infinite' cheats per-account toggles --- config-vanilla.json | 5 --- src/controllers/api/artifactsController.ts | 5 +-- src/controllers/api/creditsController.ts | 7 ++- .../api/infestedFoundryController.ts | 22 +++++----- src/controllers/api/inventoryController.ts | 10 ++--- src/controllers/api/upgradesController.ts | 5 +-- .../custom/setAccountCheatController.ts | 18 ++++++++ src/models/inventoryModels/inventoryModel.ts | 8 ++++ src/routes/custom.ts | 2 + src/services/configService.ts | 5 --- src/services/infestedFoundryService.ts | 11 +++-- src/services/inventoryService.ts | 6 +-- src/services/purchaseService.ts | 2 +- src/types/inventoryTypes/inventoryTypes.ts | 12 ++++- static/webui/index.html | 44 +++++++++---------- static/webui/script.js | 27 +++++++++++- 16 files changed, 120 insertions(+), 69 deletions(-) create mode 100644 src/controllers/custom/setAccountCheatController.ts diff --git a/config-vanilla.json b/config-vanilla.json index d285922c..4d18edcc 100644 --- a/config-vanilla.json +++ b/config-vanilla.json @@ -13,11 +13,6 @@ "skipTutorial": false, "skipAllDialogue": false, "unlockAllScans": false, - "infiniteCredits": false, - "infinitePlatinum": false, - "infiniteEndo": false, - "infiniteRegalAya": false, - "infiniteHelminthMaterials": false, "claimingBlueprintRefundsIngredients": false, "dontSubtractPurchaseCreditCost": false, "dontSubtractPurchasePlatinumCost": false, diff --git a/src/controllers/api/artifactsController.ts b/src/controllers/api/artifactsController.ts index 85c92592..7bbb68a7 100644 --- a/src/controllers/api/artifactsController.ts +++ b/src/controllers/api/artifactsController.ts @@ -3,7 +3,6 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { RequestHandler } from "express"; import { IInventoryClient, IUpgradeClient } from "@/src/types/inventoryTypes/inventoryTypes"; import { addMods, getInventory } from "@/src/services/inventoryService"; -import { config } from "@/src/services/configService"; export const artifactsController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -34,10 +33,10 @@ export const artifactsController: RequestHandler = async (req, res) => { addMods(inventory, [{ ItemType, ItemCount: -1 }]); } - if (!config.infiniteCredits) { + if (!inventory.infiniteCredits) { inventory.RegularCredits -= Cost; } - if (!config.infiniteEndo) { + if (!inventory.infiniteEndo) { inventory.FusionPoints -= FusionPointCost; } diff --git a/src/controllers/api/creditsController.ts b/src/controllers/api/creditsController.ts index d7b91d24..ecd37fa1 100644 --- a/src/controllers/api/creditsController.ts +++ b/src/controllers/api/creditsController.ts @@ -1,5 +1,4 @@ import { RequestHandler } from "express"; -import { config } from "@/src/services/configService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { getInventory } from "@/src/services/inventoryService"; @@ -9,7 +8,7 @@ export const creditsController: RequestHandler = async (req, res) => { getAccountIdForRequest(req), getInventory( req.query.accountId as string, - "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits" + "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits infiniteCredits infinitePlatinum" ) ]) )[1]; @@ -21,10 +20,10 @@ export const creditsController: RequestHandler = async (req, res) => { PremiumCredits: inventory.PremiumCredits }; - if (config.infiniteCredits) { + if (inventory.infiniteCredits) { response.RegularCredits = 999999999; } - if (config.infinitePlatinum) { + if (inventory.infinitePlatinum) { response.PremiumCreditsFree = 0; response.PremiumCredits = 999999999; } diff --git a/src/controllers/api/infestedFoundryController.ts b/src/controllers/api/infestedFoundryController.ts index 495b4d8b..a962d7a8 100644 --- a/src/controllers/api/infestedFoundryController.ts +++ b/src/controllers/api/infestedFoundryController.ts @@ -15,7 +15,6 @@ import { getRecipe } from "@/src/services/itemDataService"; import { toMongoDate, version_compare } from "@/src/helpers/inventoryHelpers"; import { logger } from "@/src/utils/logger"; import { colorToShard } from "@/src/helpers/shardHelper"; -import { config } from "@/src/services/configService"; import { addInfestedFoundryXP, applyCheatsToInfestedFoundry, @@ -73,7 +72,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { addMiscItems(inventory, miscItemChanges); // consume resources - if (!config.infiniteHelminthMaterials) { + if (!inventory.infiniteHelminthMaterials) { let type: string; let count: number; if (account.BuildLabel && version_compare(account.BuildLabel, "2025.05.20.10.18") < 0) { @@ -99,7 +98,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { await inventory.save(); const infestedFoundry = inventory.toJSON().InfestedFoundry!; - applyCheatsToInfestedFoundry(infestedFoundry); + applyCheatsToInfestedFoundry(inventory, infestedFoundry); res.json({ InventoryChanges: { MiscItems: miscItemChanges, @@ -129,13 +128,14 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { case "c": { // consume items - if (config.infiniteHelminthMaterials) { + const inventory = await getInventory(account._id.toString()); + + if (inventory.infiniteHelminthMaterials) { res.status(400).end(); return; } const request = getJSONfromString(String(req.body)); - const inventory = await getInventory(account._id.toString()); inventory.InfestedFoundry ??= {}; inventory.InfestedFoundry.Resources ??= []; @@ -240,7 +240,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { } await inventory.save(); const infestedFoundry = inventory.toJSON().InfestedFoundry!; - applyCheatsToInfestedFoundry(infestedFoundry); + applyCheatsToInfestedFoundry(inventory, infestedFoundry); res.json({ InventoryChanges: { InfestedFoundry: infestedFoundry @@ -254,7 +254,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { const request = getJSONfromString(String(req.body)); const inventory = await getInventory(account._id.toString()); const recipe = getRecipe(request.Recipe)!; - if (!config.infiniteHelminthMaterials) { + if (!inventory.infiniteHelminthMaterials) { for (const ingredient of recipe.secretIngredients!) { const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType); if (resource) { @@ -280,7 +280,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { freeUpSlot(inventory, InventorySlot.SUITS); await inventory.save(); const infestedFoundry = inventory.toJSON().InfestedFoundry!; - applyCheatsToInfestedFoundry(infestedFoundry); + applyCheatsToInfestedFoundry(inventory, infestedFoundry); res.json({ InventoryChanges: { Recipes: recipeChanges, @@ -307,7 +307,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { const recipeChanges = handleSubsumeCompletion(inventory); await inventory.save(); const infestedFoundry = inventory.toJSON().InfestedFoundry!; - applyCheatsToInfestedFoundry(infestedFoundry); + applyCheatsToInfestedFoundry(inventory, infestedFoundry); res.json({ InventoryChanges: { ...currencyChanges, @@ -328,7 +328,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { suit.UpgradesExpiry = upgradesExpiry; const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00); addRecipes(inventory, recipeChanges); - if (!config.infiniteHelminthMaterials) { + if (!inventory.infiniteHelminthMaterials) { for (let i = 0; i != request.ResourceTypes.length; ++i) { inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -= request.ResourceCosts[i]; @@ -338,7 +338,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => { inventory.InfestedFoundry!.InvigorationsApplied += 1; await inventory.save(); const infestedFoundry = inventory.toJSON().InfestedFoundry!; - applyCheatsToInfestedFoundry(infestedFoundry); + applyCheatsToInfestedFoundry(inventory, infestedFoundry); res.json({ SuitId: request.SuitId, OffensiveUpgrade: request.OffensiveUpgradeType, diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 53c82da5..d5df7619 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -295,17 +295,17 @@ export const getInventoryResponse = async ( }; } - if (config.infiniteCredits) { + if (inventory.infiniteCredits) { inventoryResponse.RegularCredits = 999999999; } - if (config.infinitePlatinum) { + if (inventory.infinitePlatinum) { inventoryResponse.PremiumCreditsFree = 0; inventoryResponse.PremiumCredits = 999999999; } - if (config.infiniteEndo) { + if (inventory.infiniteEndo) { inventoryResponse.FusionPoints = 999999999; } - if (config.infiniteRegalAya) { + if (inventory.infiniteRegalAya) { inventoryResponse.PrimeTokens = 999999999; } @@ -450,7 +450,7 @@ export const getInventoryResponse = async ( } if (inventoryResponse.InfestedFoundry) { - applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry); + applyCheatsToInfestedFoundry(inventory, inventoryResponse.InfestedFoundry); } // Set 2FA enabled so trading post can be used diff --git a/src/controllers/api/upgradesController.ts b/src/controllers/api/upgradesController.ts index 545e0038..54aab912 100644 --- a/src/controllers/api/upgradesController.ts +++ b/src/controllers/api/upgradesController.ts @@ -7,7 +7,6 @@ import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/se import { getRecipeByResult } from "@/src/services/itemDataService"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "@/src/services/infestedFoundryService"; -import { config } from "@/src/services/configService"; import { sendWsBroadcastTo } from "@/src/services/wsService"; import { EquipmentFeatures, IEquipmentDatabase } from "@/src/types/equipmentTypes"; @@ -52,7 +51,7 @@ export const upgradesController: RequestHandler = async (req, res) => { const recipe = getRecipeByResult(operation.UpgradeRequirement)!; for (const ingredient of recipe.ingredients) { totalPercentagePointsConsumed += ingredient.ItemCount / 10; - if (!config.infiniteHelminthMaterials) { + if (!inventory.infiniteHelminthMaterials) { inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -= ingredient.ItemCount; } @@ -69,7 +68,7 @@ export const upgradesController: RequestHandler = async (req, res) => { inventoryChanges.Recipes = recipeChanges; inventoryChanges.InfestedFoundry = inventory.toJSON().InfestedFoundry; - applyCheatsToInfestedFoundry(inventoryChanges.InfestedFoundry!); + applyCheatsToInfestedFoundry(inventory, inventoryChanges.InfestedFoundry!); } else switch (operation.UpgradeRequirement) { case "/Lotus/Types/Items/MiscItems/OrokinReactor": diff --git a/src/controllers/custom/setAccountCheatController.ts b/src/controllers/custom/setAccountCheatController.ts new file mode 100644 index 00000000..9647d2ad --- /dev/null +++ b/src/controllers/custom/setAccountCheatController.ts @@ -0,0 +1,18 @@ +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { IAccountCheats } from "@/src/types/inventoryTypes/inventoryTypes"; +import { RequestHandler } from "express"; + +export const setAccountCheatController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const payload = req.body as ISetAccountCheatRequest; + const inventory = await getInventory(accountId, payload.key); + inventory[payload.key] = payload.value; + await inventory.save(); + res.end(); +}; + +interface ISetAccountCheatRequest { + key: keyof IAccountCheats; + value: boolean; +} diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index fcd7f08e..b11135a0 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -1425,6 +1425,14 @@ const hubNpcCustomizationSchema = new Schema( const inventorySchema = new Schema( { accountOwnerId: Schema.Types.ObjectId, + + // SNS account cheats + infiniteCredits: Boolean, + infinitePlatinum: Boolean, + infiniteEndo: Boolean, + infiniteRegalAya: Boolean, + infiniteHelminthMaterials: Boolean, + SubscribedToEmails: { type: Number, default: 0 }, SubscribedToEmailsPersonalized: { type: Number, default: 0 }, RewardSeed: BigInt, diff --git a/src/routes/custom.ts b/src/routes/custom.ts index acd5c834..262fdaa7 100644 --- a/src/routes/custom.ts +++ b/src/routes/custom.ts @@ -28,6 +28,7 @@ import { setBoosterController } from "@/src/controllers/custom/setBoosterControl import { updateFingerprintController } from "@/src/controllers/custom/updateFingerprintController"; import { changeModularPartsController } from "@/src/controllers/custom/changeModularPartsController"; import { editSuitInvigorationUpgradeController } from "@/src/controllers/custom/editSuitInvigorationUpgradeController"; +import { setAccountCheatController } from "@/src/controllers/custom/setAccountCheatController"; import { getConfigController, setConfigController } from "@/src/controllers/custom/configController"; @@ -61,6 +62,7 @@ customRouter.post("/setBooster", setBoosterController); customRouter.post("/updateFingerprint", updateFingerprintController); customRouter.post("/changeModularParts", changeModularPartsController); customRouter.post("/editSuitInvigorationUpgrade", editSuitInvigorationUpgradeController); +customRouter.post("/setAccountCheat", setAccountCheatController); customRouter.post("/getConfig", getConfigController); customRouter.post("/setConfig", setConfigController); diff --git a/src/services/configService.ts b/src/services/configService.ts index 0d800477..b84975f3 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -20,11 +20,6 @@ export interface IConfig { skipTutorial?: boolean; skipAllDialogue?: boolean; unlockAllScans?: boolean; - infiniteCredits?: boolean; - infinitePlatinum?: boolean; - infiniteEndo?: boolean; - infiniteRegalAya?: boolean; - infiniteHelminthMaterials?: boolean; claimingBlueprintRefundsIngredients?: boolean; dontSubtractPurchaseCreditCost?: boolean; dontSubtractPurchasePlatinumCost?: boolean; diff --git a/src/services/infestedFoundryService.ts b/src/services/infestedFoundryService.ts index 3349047b..bfef29ab 100644 --- a/src/services/infestedFoundryService.ts +++ b/src/services/infestedFoundryService.ts @@ -1,8 +1,11 @@ import { ExportRecipes } from "warframe-public-export-plus"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; -import { IInfestedFoundryClient, IInfestedFoundryDatabase } from "@/src/types/inventoryTypes/inventoryTypes"; +import { + IAccountCheats, + IInfestedFoundryClient, + IInfestedFoundryDatabase +} from "@/src/types/inventoryTypes/inventoryTypes"; import { addRecipes } from "@/src/services/inventoryService"; -import { config } from "@/src/services/configService"; import { ITypeCount } from "@/src/types/commonTypes"; export const addInfestedFoundryXP = (infestedFoundry: IInfestedFoundryDatabase, delta: number): ITypeCount[] => { @@ -97,8 +100,8 @@ export const handleSubsumeCompletion = (inventory: TInventoryDatabaseDocument): return recipeChanges; }; -export const applyCheatsToInfestedFoundry = (infestedFoundry: IInfestedFoundryClient): void => { - if (config.infiniteHelminthMaterials) { +export const applyCheatsToInfestedFoundry = (cheats: IAccountCheats, infestedFoundry: IInfestedFoundryClient): void => { + if (cheats.infiniteHelminthMaterials) { infestedFoundry.Resources = [ { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthCalx", Count: 1000 }, { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBiotics", Count: 1000 }, diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index c6c9d73b..772ba929 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1201,8 +1201,8 @@ export const updateSlots = ( } }; -const isCurrencyTracked = (usePremium: boolean): boolean => { - return usePremium ? !config.infinitePlatinum : !config.infiniteCredits; +const isCurrencyTracked = (inventory: TInventoryDatabaseDocument, usePremium: boolean): boolean => { + return usePremium ? !inventory.infinitePlatinum : !inventory.infiniteCredits; }; export const updateCurrency = ( @@ -1211,7 +1211,7 @@ export const updateCurrency = ( usePremium: boolean, inventoryChanges: IInventoryChanges = {} ): IInventoryChanges => { - if (price != 0 && isCurrencyTracked(usePremium)) { + if (price != 0 && isCurrencyTracked(inventory, usePremium)) { if (usePremium) { if (inventory.PremiumCreditsFree > 0) { const premiumCreditsFreeDelta = Math.min(price, inventory.PremiumCreditsFree) * -1; diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 8f9d8f3f..eb8bad1d 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -328,7 +328,7 @@ export const handlePurchase = async ( purchaseResponse.InventoryChanges.MiscItems ??= []; purchaseResponse.InventoryChanges.MiscItems.push(invItem); } - } else if (!config.infiniteRegalAya) { + } else if (!inventory.infiniteRegalAya) { inventory.PrimeTokens -= offer.PrimePrice! * purchaseRequest.PurchaseParams.Quantity; purchaseResponse.InventoryChanges.PrimeTokens ??= 0; diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 1da1eaff..f08e0728 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -19,6 +19,15 @@ export type InventoryDatabaseEquipment = { [_ in TEquipmentKey]: IEquipmentDatabase[]; }; +// Fields specific to SNS +export interface IAccountCheats { + infiniteCredits?: boolean; + infinitePlatinum?: boolean; + infiniteEndo?: boolean; + infiniteRegalAya?: boolean; + infiniteHelminthMaterials?: boolean; +} + export interface IInventoryDatabase extends Omit< IInventoryClient, @@ -61,7 +70,8 @@ export interface IInventoryDatabase | "PersonalGoalProgress" | TEquipmentKey >, - InventoryDatabaseEquipment { + InventoryDatabaseEquipment, + IAccountCheats { accountOwnerId: Types.ObjectId; Created: Date; TrainingDate: Date; diff --git a/static/webui/index.html b/static/webui/index.html index e9a5e2a2..5a9707be 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -663,26 +663,6 @@ -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
@@ -891,8 +871,28 @@
-
-
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
diff --git a/static/webui/script.js b/static/webui/script.js index 4f995de8..50aaf932 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -605,6 +605,8 @@ function fetchItemList() { } fetchItemList(); +const accountCheats = document.querySelectorAll("#account-cheats input[id]"); + // Assumes that caller revalidates authz function updateInventory() { const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); @@ -1473,6 +1475,10 @@ function updateInventory() { } document.getElementById("Boosters-list").appendChild(tr); }); + + for (const elm of accountCheats) { + elm.checked = !!data[elm.id]; + } }); }); } @@ -2109,6 +2115,8 @@ function doAcquireModMax() { alert("doAcquireModMax: " + uniqueName); } +// Cheats route + const uiConfigs = [...$(".config-form input[id], .config-form select[id]")].map(x => x.id); for (const id of uiConfigs) { @@ -2193,8 +2201,6 @@ function doSaveConfigStringArray(id) { }); } -// Cheats route - single.getRoute("/webui/cheats").on("beforeload", function () { let interval; interval = setInterval(() => { @@ -2306,6 +2312,23 @@ function doIntrinsicsUnlockAll() { }); } +document.querySelectorAll("#account-cheats input[type=checkbox]").forEach(elm => { + elm.onchange = function () { + revalidateAuthz().then(() => { + $.post({ + url: "/custom/setAccountCheat?" + window.authz /*+ "&wsid=" + wsid*/, + contentType: "application/json", + data: JSON.stringify({ + key: elm.id, + value: elm.checked + }) + }); + }); + }; +}); + +// Mods route + function doAddAllMods() { let modsAll = new Set(); for (const child of document.getElementById("datalist-mods").children) {