From b62e326920b335a892da8548e1f6a58180ec4f2d Mon Sep 17 00:00:00 2001
From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Date: Tue, 29 Jul 2025 00:31:29 -0700
Subject: [PATCH] feat(webui): ability overrides (#2558)
Closes #851
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2558
Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com>
Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
---
 .../custom/abilityOverrideController.ts       |  33 +++++
 .../custom/getItemListsController.ts          |  18 ++-
 src/routes/custom.ts                          |   2 +
 static/webui/index.html                       |   8 +
 static/webui/script.js                        | 138 ++++++++++++++++++
 static/webui/translations/de.js               |   4 +
 static/webui/translations/en.js               |   4 +
 static/webui/translations/es.js               |   4 +
 static/webui/translations/fr.js               |   4 +
 static/webui/translations/ru.js               |   4 +
 static/webui/translations/zh.js               |   4 +
 11 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 src/controllers/custom/abilityOverrideController.ts
diff --git a/src/controllers/custom/abilityOverrideController.ts b/src/controllers/custom/abilityOverrideController.ts
new file mode 100644
index 000000000..e67afb1e6
--- /dev/null
+++ b/src/controllers/custom/abilityOverrideController.ts
@@ -0,0 +1,33 @@
+import { getInventory } from "@/src/services/inventoryService";
+import { getAccountIdForRequest } from "@/src/services/loginService";
+import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
+import { RequestHandler } from "express";
+
+export const abilityOverrideController: RequestHandler = async (req, res) => {
+    const accountId = await getAccountIdForRequest(req);
+    const request = req.body as IAbilityOverrideRequest;
+    if (request.category === "Suits") {
+        const inventory = await getInventory(accountId, request.category);
+        const item = inventory[request.category].id(request.oid);
+        if (item) {
+            if (request.action == "set") {
+                item.Configs[request.configIndex].AbilityOverride = request.AbilityOverride;
+            } else {
+                item.Configs[request.configIndex].AbilityOverride = undefined;
+            }
+            await inventory.save();
+        }
+    }
+    res.end();
+};
+
+interface IAbilityOverrideRequest {
+    category: TEquipmentKey;
+    oid: string;
+    action: "set" | "remove";
+    configIndex: number;
+    AbilityOverride: {
+        Ability: string;
+        Index: number;
+    };
+}
diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts
index d065d2e28..6fe5b0dbf 100644
--- a/src/controllers/custom/getItemListsController.ts
+++ b/src/controllers/custom/getItemListsController.ts
@@ -1,6 +1,7 @@
 import { RequestHandler } from "express";
 import { getDict, getItemName, getString } from "@/src/services/itemDataService";
 import {
+    ExportAbilities,
     ExportArcanes,
     ExportAvionics,
     ExportBoosters,
@@ -57,6 +58,7 @@ interface ItemLists {
     mods: ListedItem[];
     Boosters: ListedItem[];
     VarziaOffers: ListedItem[];
+    Abilities: ListedItem[];
     //circuitGameModes: ListedItem[];
 }
 
@@ -94,7 +96,8 @@ const getItemListsController: RequestHandler = (req, response) => {
         EvolutionProgress: [],
         mods: [],
         Boosters: [],
-        VarziaOffers: []
+        VarziaOffers: [],
+        Abilities: []
         /*circuitGameModes: [
             {
                 uniqueName: "Survival",
@@ -132,6 +135,12 @@ const getItemListsController: RequestHandler = (req, response) => {
             name: getString(item.name, lang),
             exalted: item.exalted
         });
+        item.abilities.forEach(ability => {
+            res.Abilities.push({
+                uniqueName: ability.uniqueName,
+                name: getString(ability.name || uniqueName, lang)
+            });
+        });
     }
     for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
         if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
@@ -348,6 +357,13 @@ const getItemListsController: RequestHandler = (req, response) => {
         });
     }
 
+    for (const [uniqueName, ability] of Object.entries(ExportAbilities)) {
+        res.Abilities.push({
+            uniqueName,
+            name: getString(ability.name || uniqueName, lang)
+        });
+    }
+
     response.json(res);
 };
 
diff --git a/src/routes/custom.ts b/src/routes/custom.ts
index 9eb3d9e45..acd5c834a 100644
--- a/src/routes/custom.ts
+++ b/src/routes/custom.ts
@@ -15,6 +15,7 @@ import { webuiFileChangeDetectedController } from "@/src/controllers/custom/webu
 import { completeAllMissionsController } from "@/src/controllers/custom/completeAllMissionsController";
 import { addMissingHelminthBlueprintsController } from "@/src/controllers/custom/addMissingHelminthBlueprintsController";
 
+import { abilityOverrideController } from "@/src/controllers/custom/abilityOverrideController";
 import { createAccountController } from "@/src/controllers/custom/createAccountController";
 import { createMessageController } from "@/src/controllers/custom/createMessageController";
 import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
@@ -47,6 +48,7 @@ customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController);
 customRouter.get("/completeAllMissions", completeAllMissionsController);
 customRouter.get("/addMissingHelminthBlueprints", addMissingHelminthBlueprintsController);
 
+customRouter.post("/abilityOverride", abilityOverrideController);
 customRouter.post("/createAccount", createAccountController);
 customRouter.post("/createMessage", createMessageController);
 customRouter.post("/addCurrency", addCurrencyController);
diff --git a/static/webui/index.html b/static/webui/index.html
index ba2c4b935..0e0a69417 100644
--- a/static/webui/index.html
+++ b/static/webui/index.html
@@ -460,6 +460,13 @@
                 
                     
                     
@@ -1073,6 +1080,7 @@
     
     
     
+