From 1184d182444329192cda6646fb9e8a84306edcc4 Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:13:46 +0100 Subject: [PATCH 1/8] feat: exalted weapons on webui --- src/controllers/api/sellController.ts | 5 + src/controllers/custom/addItemController.ts | 6 +- .../custom/getItemListsController.ts | 34 +++-- src/helpers/customHelpers/addItemHelpers.ts | 3 +- src/services/inventoryService.ts | 24 ++-- src/types/sellTypes.ts | 1 + static/webui/index.html | 12 ++ static/webui/script.js | 118 ++++++++++++++++++ 8 files changed, 182 insertions(+), 21 deletions(-) diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index 530d37cc..d2959e6d 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -45,6 +45,11 @@ export const sellController: RequestHandler = async (req, res) => { inventory.Melee.pull({ _id: sellItem.String }); }); } + if (payload.Items.SpecialItems) { + payload.Items.SpecialItems.forEach(sellItem => { + inventory.SpecialItems.pull({ _id: sellItem.String }); + }); + } if (payload.Items.Consumables) { const consumablesChanges = []; for (const sellItem of payload.Items.Consumables) { diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index ea5fd535..d9976632 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -1,7 +1,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers"; import { getWeaponType } from "@/src/services/itemDataService"; -import { addPowerSuit, addEquipment } from "@/src/services/inventoryService"; +import { addPowerSuit, addEquipment, addSpecialItem } from "@/src/services/inventoryService"; import { RequestHandler } from "express"; const addItemController: RequestHandler = async (req, res) => { @@ -18,6 +18,10 @@ const addItemController: RequestHandler = async (req, res) => { const weapon = await addEquipment(weaponType, request.InternalName, accountId); res.json(weapon); break; + case ItemType.SpecialItem: + const specialItem = await addSpecialItem(request.InternalName, accountId); + res.json(specialItem); + break; default: res.status(400).json({ error: "something went wrong" }); break; diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index e3fa95a1..5db843f2 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -1,10 +1,11 @@ import { RequestHandler } from "express"; -import { getDict, getItemName, getString } from "@/src/services/itemDataService"; +import { getDict, getExalted, getItemName, getString } from "@/src/services/itemDataService"; import { ExportArcanes, ExportGear, ExportRecipes, ExportResources, + ExportSentinels, ExportUpgrades, ExportWarframes, ExportWeapons @@ -15,12 +16,34 @@ interface ListedItem { uniqueName: string; name: string; fusionLimit?: number; + exalted?: { uniqueName: string; name: string }[]; } const getItemListsController: RequestHandler = (req, res) => { const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en"); const weapons = []; const miscitems = []; + const warframes = []; + for (const [uniqueName, item] of Object.entries(ExportWarframes)) { + if (item.productCategory == "Suits") { + const warframe: ListedItem = { + uniqueName, + name: getString(item.name, lang) + }; + const exalted = getExalted(uniqueName); + if (exalted) { + warframe.exalted = []; + exalted.forEach(element => { + const exalted = ExportWeapons[element] || ExportSentinels[element]; + warframe.exalted?.push({ + uniqueName: element, + name: getString(exalted.name, lang) + }); + }); + } + warframes.push(warframe); + } + } for (const [uniqueName, item] of Object.entries(ExportWeapons)) { if (item.productCategory !== "OperatorAmps") { if (item.totalDamage !== 0) { @@ -84,14 +107,7 @@ const getItemListsController: RequestHandler = (req, res) => { } res.json({ - warframes: Object.entries(ExportWarframes) - .filter(([_uniqueName, warframe]) => warframe.productCategory == "Suits") - .map(([uniqueName, warframe]) => { - return { - uniqueName, - name: getString(warframe.name, lang) - }; - }), + warframes, weapons, miscitems, mods, diff --git a/src/helpers/customHelpers/addItemHelpers.ts b/src/helpers/customHelpers/addItemHelpers.ts index 5ce2378f..112fd2e6 100644 --- a/src/helpers/customHelpers/addItemHelpers.ts +++ b/src/helpers/customHelpers/addItemHelpers.ts @@ -2,7 +2,8 @@ import { isString } from "@/src/helpers/general"; export enum ItemType { Powersuit = "Powersuit", - Weapon = "Weapon" + Weapon = "Weapon", + SpecialItem = "SpecialItem" } export const isItemType = (itemType: string): itemType is ItemType => { diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 73acd669..a901b5e4 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -29,7 +29,7 @@ import { import { logger } from "@/src/utils/logger"; import { getWeaponType, getExalted } from "@/src/services/itemDataService"; import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes"; -import { IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; +import { EquipmentFeatures, IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; import { ExportArcanes, ExportCustoms, @@ -433,15 +433,19 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => { export const addSpecialItem = async (itemName: string, accountId: string) => { const inventory = await getInventory(accountId); - const specialItemIndex = inventory.SpecialItems.push({ - ItemType: itemName, - Configs: [], - Features: 1, - UpgradeVer: 101, - XP: 0 - }); - const changedInventory = await inventory.save(); - return changedInventory.SpecialItems[specialItemIndex - 1].toJSON(); + // According to wiki there is one exalted item per suit type, so we check if we don't already have that item + if (!inventory.SpecialItems.length || inventory.SpecialItems.some(obj => obj.ItemType !== itemName)) { + const specialItemIndex = inventory.SpecialItems.push({ + ItemType: itemName, + Configs: [], + Features: EquipmentFeatures.DOUBLE_CAPACITY, + UpgradeVer: 101, + XP: 0 + }); + const changedInventory = await inventory.save(); + return changedInventory.SpecialItems[specialItemIndex - 1].toJSON(); + } + return; }; export const addSpaceSuit = async (spacesuitName: string, accountId: string) => { diff --git a/src/types/sellTypes.ts b/src/types/sellTypes.ts index cd9fb2dd..fe0174f5 100644 --- a/src/types/sellTypes.ts +++ b/src/types/sellTypes.ts @@ -7,6 +7,7 @@ export interface ISellRequest { Consumables?: ISellItem[]; Recipes?: ISellItem[]; Upgrades?: ISellItem[]; + SpecialItems?: ISellItem[]; }; SellPrice: number; SellCurrency: diff --git a/static/webui/index.html b/static/webui/index.html index 416d1978..b99c3aae 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -126,6 +126,10 @@
+

+ Note: Changes made here will only be reflected in-game when the game re-downloads your + inventory. Visiting the navigation should be the easiest way to trigger that. +

@@ -143,6 +147,14 @@
+
+
Exalted Weapons
+
+ + +
+
+

diff --git a/static/webui/script.js b/static/webui/script.js index 56736c38..c1e7b922 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -449,6 +449,124 @@ function updateInventory() { $("#powersuit-route .text-body-secondary").text(""); } + document.getElementById("exalted-list").innerHTML = ""; + document.getElementById("exalted-list").closest(".card").style = ""; + + const exaltedWeapons = itemMap[item.ItemType].exalted; + if (exaltedWeapons) { + const specialItems = exaltedWeapons + .map(element => { + const specialItem = data.SpecialItems.find(x => x.ItemType == element.uniqueName); + if (specialItem) { + return { + ...specialItem, + name: element.name + }; + } + return undefined; + }) + .filter(item => item !== undefined); + + specialItems.forEach(item => { + const tr = document.createElement("tr"); + { + const td = document.createElement("td"); + td.textContent = item?.name ?? item.ItemType; + if (item.ItemName) { + td.textContent = item.ItemName + " (" + td.textContent + ")"; + } + tr.appendChild(td); + } + { + const td = document.createElement("td"); + td.classList = "text-end"; + if (item.XP < 1_600_000) { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + addGearExp("SpecialItems", item.ItemId.$oid, 1_600_000 - item.XP); + }; + a.title = "Make Rank 30"; + a.innerHTML = ``; + td.appendChild(a); + } + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + const name = prompt("Enter new custom name:"); + if (name !== null) { + renameGear("SpecialItems", item.ItemId.$oid, name); + } + }; + a.title = "Rename"; + a.innerHTML = ``; + td.appendChild(a); + } + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + disposeOfGear("SpecialItems", item.ItemId.$oid); + }; + a.title = "Remove"; + a.innerHTML = ``; + td.appendChild(a); + } + tr.appendChild(td); + } + document.getElementById("exalted-list").appendChild(tr); + }); + + const missingItems = exaltedWeapons.filter( + element => !data.SpecialItems.some(x => x.ItemType === element.uniqueName) + ); + if (missingItems) { + missingItems.forEach(item => { + const tr = document.createElement("tr"); + { + const td = document.createElement("td"); + td.textContent = item?.name ?? item.uniqueName; + tr.appendChild(td); + } + { + const td = document.createElement("td"); + td.classList = "text-end"; + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + revalidateAuthz(() => { + const req = $.post({ + url: "/custom/addItem?" + window.authz, + contentType: "application/json", + data: JSON.stringify({ + type: "SpecialItem", + internalName: item.uniqueName + }) + }); + req.done(() => { + updateInventory(); + }); + }); + }; + a.title = "Add"; + a.innerHTML = ``; + td.appendChild(a); + } + tr.appendChild(td); + } + document.getElementById("exalted-list").appendChild(tr); + }); + } + } else { + document.getElementById("exalted-list").closest(".card").style.display = "none"; + } + const uniqueUpgrades = {}; (item.ArchonCrystalUpgrades ?? []).forEach(upgrade => { uniqueUpgrades[upgrade.UpgradeType] ??= 0; -- 2.47.2 From 603c98e348062b0db9b4e8dd6c2a3d153a6d63d5 Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:39:06 +0100 Subject: [PATCH 2/8] Update inventoryService.ts --- src/services/inventoryService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index a901b5e4..8ed90575 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -434,7 +434,7 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => { export const addSpecialItem = async (itemName: string, accountId: string) => { const inventory = await getInventory(accountId); // According to wiki there is one exalted item per suit type, so we check if we don't already have that item - if (!inventory.SpecialItems.length || inventory.SpecialItems.some(obj => obj.ItemType !== itemName)) { + if (inventory.SpecialItems.length && inventory.SpecialItems.some(obj => obj.ItemType !== itemName)) { const specialItemIndex = inventory.SpecialItems.push({ ItemType: itemName, Configs: [], -- 2.47.2 From c3e10a3e0e77d3178ad8a4ed413d418f1c5bf7ef Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sun, 29 Dec 2024 01:16:36 +0100 Subject: [PATCH 3/8] clarify comment --- src/services/inventoryService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 8ed90575..526f96ad 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -433,8 +433,8 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => { export const addSpecialItem = async (itemName: string, accountId: string) => { const inventory = await getInventory(accountId); - // According to wiki there is one exalted item per suit type, so we check if we don't already have that item - if (inventory.SpecialItems.length && inventory.SpecialItems.some(obj => obj.ItemType !== itemName)) { + // According to wiki exalted items unique for suit type, so we check if we don't already have that item + if (!inventory.SpecialItems.some(obj => obj.ItemType === itemName)) { const specialItemIndex = inventory.SpecialItems.push({ ItemType: itemName, Configs: [], -- 2.47.2 From b2ecd93bd697aeeac0e4f7a84d0a5d1daa01f748 Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sun, 29 Dec 2024 04:02:04 +0100 Subject: [PATCH 4/8] remove ability to sell/add missing exalted items --- src/controllers/api/sellController.ts | 5 --- src/types/sellTypes.ts | 1 - static/webui/script.js | 62 +++------------------------ 3 files changed, 6 insertions(+), 62 deletions(-) diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index d2959e6d..530d37cc 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -45,11 +45,6 @@ export const sellController: RequestHandler = async (req, res) => { inventory.Melee.pull({ _id: sellItem.String }); }); } - if (payload.Items.SpecialItems) { - payload.Items.SpecialItems.forEach(sellItem => { - inventory.SpecialItems.pull({ _id: sellItem.String }); - }); - } if (payload.Items.Consumables) { const consumablesChanges = []; for (const sellItem of payload.Items.Consumables) { diff --git a/src/types/sellTypes.ts b/src/types/sellTypes.ts index fe0174f5..cd9fb2dd 100644 --- a/src/types/sellTypes.ts +++ b/src/types/sellTypes.ts @@ -7,7 +7,6 @@ export interface ISellRequest { Consumables?: ISellItem[]; Recipes?: ISellItem[]; Upgrades?: ISellItem[]; - SpecialItems?: ISellItem[]; }; SellPrice: number; SellCurrency: diff --git a/static/webui/script.js b/static/webui/script.js index c1e7b922..68ed9724 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -480,12 +480,16 @@ function updateInventory() { { const td = document.createElement("td"); td.classList = "text-end"; - if (item.XP < 1_600_000) { + + const targetXP = item.ItemType.startsWith("/Lotus/Powersuits/Khora/Kavat/") + ? 900_000 + : 450_000; + if (item.XP < targetXP) { const a = document.createElement("a"); a.href = "#"; a.onclick = function (event) { event.preventDefault(); - addGearExp("SpecialItems", item.ItemId.$oid, 1_600_000 - item.XP); + addGearExp("SpecialItems", item.ItemId.$oid, targetXP - item.XP); }; a.title = "Make Rank 30"; a.innerHTML = ``; @@ -505,64 +509,10 @@ function updateInventory() { a.innerHTML = ``; td.appendChild(a); } - { - const a = document.createElement("a"); - a.href = "#"; - a.onclick = function (event) { - event.preventDefault(); - disposeOfGear("SpecialItems", item.ItemId.$oid); - }; - a.title = "Remove"; - a.innerHTML = ``; - td.appendChild(a); - } tr.appendChild(td); } document.getElementById("exalted-list").appendChild(tr); }); - - const missingItems = exaltedWeapons.filter( - element => !data.SpecialItems.some(x => x.ItemType === element.uniqueName) - ); - if (missingItems) { - missingItems.forEach(item => { - const tr = document.createElement("tr"); - { - const td = document.createElement("td"); - td.textContent = item?.name ?? item.uniqueName; - tr.appendChild(td); - } - { - const td = document.createElement("td"); - td.classList = "text-end"; - { - const a = document.createElement("a"); - a.href = "#"; - a.onclick = function (event) { - event.preventDefault(); - revalidateAuthz(() => { - const req = $.post({ - url: "/custom/addItem?" + window.authz, - contentType: "application/json", - data: JSON.stringify({ - type: "SpecialItem", - internalName: item.uniqueName - }) - }); - req.done(() => { - updateInventory(); - }); - }); - }; - a.title = "Add"; - a.innerHTML = ``; - td.appendChild(a); - } - tr.appendChild(td); - } - document.getElementById("exalted-list").appendChild(tr); - }); - } } else { document.getElementById("exalted-list").closest(".card").style.display = "none"; } -- 2.47.2 From d8e4b0f2f467f6b04703972690e4e680fa14ea94 Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sun, 29 Dec 2024 04:11:58 +0100 Subject: [PATCH 5/8] Update addItemController.ts --- src/controllers/custom/addItemController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index d9976632..ac9a2a92 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -19,7 +19,7 @@ const addItemController: RequestHandler = async (req, res) => { res.json(weapon); break; case ItemType.SpecialItem: - const specialItem = await addSpecialItem(request.InternalName, accountId); + const specialItem = await addSpecialItem(request.InternalName, accountId, {}); res.json(specialItem); break; default: -- 2.47.2 From 3e831aafb0f70a404778024c4191668af4d34f2b Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sun, 29 Dec 2024 04:14:09 +0100 Subject: [PATCH 6/8] Update addItemController.ts --- src/controllers/custom/addItemController.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index ac9a2a92..8a1a2d49 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -18,10 +18,6 @@ const addItemController: RequestHandler = async (req, res) => { const weapon = await addEquipment(weaponType, request.InternalName, accountId); res.json(weapon); break; - case ItemType.SpecialItem: - const specialItem = await addSpecialItem(request.InternalName, accountId, {}); - res.json(specialItem); - break; default: res.status(400).json({ error: "something went wrong" }); break; -- 2.47.2 From 9e0e84cac66e7c3279ef0144270475c6e43a9d0d Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Sun, 29 Dec 2024 04:16:19 +0100 Subject: [PATCH 7/8] lint fix --- src/controllers/custom/addItemController.ts | 2 +- src/services/inventoryService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index 8a1a2d49..ea5fd535 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -1,7 +1,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers"; import { getWeaponType } from "@/src/services/itemDataService"; -import { addPowerSuit, addEquipment, addSpecialItem } from "@/src/services/inventoryService"; +import { addPowerSuit, addEquipment } from "@/src/services/inventoryService"; import { RequestHandler } from "express"; const addItemController: RequestHandler = async (req, res) => { diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 5f18f4f2..423be170 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -29,7 +29,7 @@ import { import { logger } from "@/src/utils/logger"; import { getWeaponType, getExalted } from "@/src/services/itemDataService"; import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes"; -import { EquipmentFeatures, IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; +import { IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; import { ExportArcanes, ExportCustoms, -- 2.47.2 From b0c3e725f86b93eaeb05b64ab081c309ffa8276c Mon Sep 17 00:00:00 2001 From: Sainan Date: Sun, 29 Dec 2024 05:37:48 +0100 Subject: [PATCH 8/8] chore: fix no-case-declarations warnings --- src/controllers/custom/addItemController.ts | 6 ++++-- src/services/inventoryService.ts | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/controllers/custom/addItemController.ts b/src/controllers/custom/addItemController.ts index ea5fd535..c1045e63 100644 --- a/src/controllers/custom/addItemController.ts +++ b/src/controllers/custom/addItemController.ts @@ -9,15 +9,17 @@ const addItemController: RequestHandler = async (req, res) => { const request = toAddItemRequest(req.body); switch (request.type) { - case ItemType.Powersuit: + case ItemType.Powersuit: { const powersuit = await addPowerSuit(request.InternalName, accountId); res.json(powersuit); return; - case ItemType.Weapon: + } + case ItemType.Weapon: { const weaponType = getWeaponType(request.InternalName); const weapon = await addEquipment(weaponType, request.InternalName, accountId); res.json(weapon); break; + } default: res.status(400).json({ error: "something went wrong" }); break; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 423be170..9d51f597 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -262,7 +262,7 @@ export const addItem = async ( } } break; - case "Weapons": + case "Weapons": { const weaponType = getWeaponType(typeName); const weapon = await addEquipment(weaponType, typeName, accountId); await updateSlots(accountId, InventorySlot.WEAPONS, 0, 1); @@ -272,6 +272,7 @@ export const addItem = async ( [weaponType]: [weapon] } }; + } case "Objects": { // /Lotus/Objects/Tenno/Props/TnoLisetTextProjector (Note Beacon) const inventory = await getInventory(accountId); -- 2.47.2