diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index 26ec170d..bf3a346f 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -51,6 +51,41 @@ export const sellController: RequestHandler = async (req, res) => { inventory.Melee.pull({ _id: sellItem.String }); }); } + if (payload.Items.SpaceSuits) { + payload.Items.SpaceSuits.forEach(sellItem => { + inventory.SpaceSuits.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.SpaceGuns) { + payload.Items.SpaceGuns.forEach(sellItem => { + inventory.SpaceGuns.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.SpaceMelee) { + payload.Items.SpaceMelee.forEach(sellItem => { + inventory.SpaceMelee.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.Sentinels) { + payload.Items.Sentinels.forEach(sellItem => { + inventory.Sentinels.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.SentinelWeapons) { + payload.Items.SentinelWeapons.forEach(sellItem => { + inventory.SentinelWeapons.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.OperatorAmps) { + payload.Items.OperatorAmps.forEach(sellItem => { + inventory.OperatorAmps.pull({ _id: sellItem.String }); + }); + } + if (payload.Items.Hoverboards) { + payload.Items.Hoverboards.forEach(sellItem => { + inventory.Hoverboards.pull({ _id: sellItem.String }); + }); + } if (payload.Items.Consumables) { const consumablesChanges = []; for (const sellItem of payload.Items.Consumables) { @@ -110,6 +145,13 @@ interface ISellRequest { Recipes?: ISellItem[]; Upgrades?: ISellItem[]; MiscItems?: ISellItem[]; + SpaceSuits?: ISellItem[]; + SpaceGuns?: ISellItem[]; + SpaceMelee?: ISellItem[]; + Sentinels?: ISellItem[]; + SentinelWeapons?: ISellItem[]; + OperatorAmps?: ISellItem[]; + Hoverboards?: ISellItem[]; }; SellPrice: number; SellCurrency: diff --git a/src/controllers/custom/addItemsController.ts b/src/controllers/custom/addItemsController.ts index cce65a3c..d064a6e3 100644 --- a/src/controllers/custom/addItemsController.ts +++ b/src/controllers/custom/addItemsController.ts @@ -1,8 +1,8 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; -import { getWeaponType } from "@/src/services/itemDataService"; -import { addPowerSuit, addEquipment, getInventory, updateSlots } from "@/src/services/inventoryService"; -import { RequestHandler } from "express"; +import { addEquipment, addPowerSuit, getInventory, updateSlots } from "@/src/services/inventoryService"; +import { SlotNames } from "@/src/types/purchaseTypes"; import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes"; +import { RequestHandler } from "express"; export const addItemsController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -10,14 +10,14 @@ export const addItemsController: RequestHandler = async (req, res) => { const inventory = await getInventory(accountId); for (const request of requests) { switch (request.type) { - case ItemType.Powersuit: - updateSlots(inventory, InventorySlot.SUITS, 0, 1); + case ItemType.Suits: + updateSlots(inventory, productCategoryToSlotName[request.type], 0, 1); addPowerSuit(inventory, request.internalName); break; - case ItemType.Weapon: - updateSlots(inventory, InventorySlot.WEAPONS, 0, 1); - addEquipment(inventory, getWeaponType(request.internalName), request.internalName); + default: + updateSlots(inventory, productCategoryToSlotName[request.type], 0, 1); + addEquipment(inventory, request.type, request.internalName); break; } } @@ -25,9 +25,28 @@ export const addItemsController: RequestHandler = async (req, res) => { res.end(); }; +const productCategoryToSlotName: Record = { + Suits: InventorySlot.SUITS, + Pistols: InventorySlot.WEAPONS, + Melee: InventorySlot.WEAPONS, + LongGuns: InventorySlot.WEAPONS, + SpaceSuits: InventorySlot.SPACESUITS, + SpaceGuns: InventorySlot.SPACESUITS, + SpaceMelee: InventorySlot.SPACESUITS, + Sentinels: InventorySlot.SENTINELS, + SentinelWeapons: InventorySlot.SENTINELS +}; + enum ItemType { - Powersuit = "Powersuit", - Weapon = "Weapon" + Suits = "Suits", + SpaceSuits = "SpaceSuits", + LongGuns = "LongGuns", + Pistols = "Pistols", + Melee = "Melee", + SpaceGuns = "SpaceGuns", + SpaceMelee = "SpaceMelee", + SentinelWeapons = "SentinelWeapons", + Sentinels = "Sentinels" } interface IAddItemRequest { diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index bf531737..5033d492 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -5,6 +5,7 @@ import { ExportGear, ExportRecipes, ExportResources, + ExportSentinels, ExportUpgrades, ExportWarframes, ExportWeapons @@ -15,21 +16,66 @@ interface ListedItem { uniqueName: string; name: string; fusionLimit?: number; + exalted?: string[]; } const getItemListsController: RequestHandler = (req, response) => { const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en"); const res: Record = {}; res.LongGuns = []; - res.Pistols = []; res.Melee = []; + res.ModularParts = []; + res.Pistols = []; + res.Sentinels = []; + res.SentinelWeapons = []; + res.SpaceGuns = []; + res.SpaceMelee = []; + res.SpaceSuits = []; + res.Suits = []; res.miscitems = []; + for (const [uniqueName, item] of Object.entries(ExportWarframes)) { + if (item.productCategory == "Suits" || item.productCategory == "SpaceSuits") { + res[item.productCategory].push({ + uniqueName, + name: getString(item.name, lang), + exalted: item.exalted + }); + } + } + for (const [uniqueName, item] of Object.entries(ExportSentinels)) { + if (item.productCategory == "Sentinels") { + res[item.productCategory].push({ + uniqueName, + name: getString(item.name, lang) + }); + } + } for (const [uniqueName, item] of Object.entries(ExportWeapons)) { - if (item.totalDamage !== 0) { + if ( + uniqueName.split("/")[4] == "OperatorAmplifiers" || + uniqueName.split("/")[5] == "SUModularSecondarySet1" || + uniqueName.split("/")[5] == "SUModularPrimarySet1" || + uniqueName.split("/")[5] == "InfKitGun" || + uniqueName.split("/")[5] == "HoverboardParts" + ) { + res.ModularParts.push({ + uniqueName, + name: getString(item.name, lang) + }); + if (uniqueName.split("/")[5] != "SentTrainingAmplifier") { + res.miscitems.push({ + uniqueName: "MiscItems:" + uniqueName, + name: getString(item.name, lang) + }); + } + } else if (item.totalDamage !== 0) { if ( item.productCategory == "LongGuns" || item.productCategory == "Pistols" || - item.productCategory == "Melee" + item.productCategory == "Melee" || + item.productCategory == "SpaceGuns" || + item.productCategory == "SpaceMelee" || + item.productCategory == "SentinelWeapons" ) { res[item.productCategory].push({ uniqueName, @@ -102,15 +148,6 @@ const getItemListsController: RequestHandler = (req, response) => { } response.json({ - warframes: Object.entries(ExportWarframes) - .filter(([_uniqueName, warframe]) => warframe.productCategory == "Suits") - .map(([uniqueName, warframe]) => { - return { - uniqueName, - name: getString(warframe.name, lang), - exalted: warframe.exalted - }; - }), badItems, archonCrystalUpgrades, ...res diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index e25f9f70..794c3226 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -365,7 +365,7 @@ export const addSentinelWeapon = ( typeName: string, inventoryChanges: IInventoryChanges ): void => { - const index = inventory.SentinelWeapons.push({ ItemType: typeName }) - 1; + const index = inventory.SentinelWeapons.push({ ItemType: typeName, XP: 0 }) - 1; inventoryChanges.SentinelWeapons ??= []; (inventoryChanges.SentinelWeapons as IEquipmentClient[]).push( inventory.SentinelWeapons[index].toJSON() diff --git a/static/webui/index.html b/static/webui/index.html index d11946a4..6bbe59f4 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -99,12 +99,12 @@
Warframes
-
- + +
- +
@@ -113,7 +113,7 @@
Primary Weapons
-
+
@@ -129,7 +129,7 @@
Secondary Weapons
-
+
@@ -143,7 +143,7 @@
Melee Weapons
-
+
@@ -154,13 +154,123 @@
+
+
+
+
Archwing
+
+
+ + +
+ + +
+
+
+
+
+
+
Archwing Primary Weapons
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
Archwing Melee Weapons
+
+
+ + +
+ + +
+
+
+
+
+
+
Sentinel Weapons
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
Sentinels
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
Amps
+
+ + +
+
+
+
+
+
+
K-Drives
+
+ + +
+
+
+
+
Bulk Actions
-
- - - - +
+
+ + + + + + +
+
+ + + + + + +
@@ -384,10 +494,16 @@
- + + + + + + + diff --git a/static/webui/script.js b/static/webui/script.js index 246d17d3..ba9ffbfd 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -149,6 +149,12 @@ function fetchItemList() { "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" }, "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" }, "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" }, + "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/OperatorTrainingAmpWeapon": { + name: "Mote Amp" + }, + "/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon": { name: "Amp" }, + "/Lotus/Weapons/Operator/Pistols/DrifterPistol/DrifterPistolPlayerWeapon": { name: "Sirocco" }, + "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit": { name: "K-Drive" }, // Missing in data sources "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser": { name: "Legendary Core" }, "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" } @@ -188,84 +194,19 @@ function updateInventory() { window.didInitialInventoryUpdate = true; // Populate inventory route - document.getElementById("warframe-list").innerHTML = ""; - data.Suits.forEach(item => { - const tr = document.createElement("tr"); - tr.setAttribute("data-item-type", item.ItemType); - { - const td = document.createElement("td"); - td.textContent = itemMap[item.ItemType]?.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("Suits", item.ItemId.$oid, 1_600_000 - item.XP); - if ("exalted" in itemMap[item.ItemType]) { - for (const exaltedType of itemMap[item.ItemType].exalted) { - const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); - if (exaltedItem) { - const exaltedCap = - itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; - if (exaltedItem.XP < exaltedCap) { - addGearExp( - "SpecialItems", - exaltedItem.ItemId.$oid, - exaltedCap - exaltedItem.XP - ); - } - } - } - } - }; - a.title = "Make Rank 30"; - a.innerHTML = ``; - td.appendChild(a); - } - { - const a = document.createElement("a"); - a.href = "/webui/powersuit/" + item.ItemId.$oid; - 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("Suits", 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("Suits", item.ItemId.$oid); - }; - a.title = "Remove"; - a.innerHTML = ``; - td.appendChild(a); - } - tr.appendChild(td); - } - document.getElementById("warframe-list").appendChild(tr); - }); - ["LongGuns", "Pistols", "Melee"].forEach(category => { + [ + "Suits", + "SpaceSuits", + "Sentinels", + "LongGuns", + "Pistols", + "Melee", + "SpaceGuns", + "SpaceMelee", + "SentinelWeapons", + "Hoverboards", + "OperatorAmps" + ].forEach(category => { document.getElementById(category + "-list").innerHTML = ""; data[category].forEach(item => { const tr = document.createElement("tr"); @@ -276,22 +217,59 @@ function updateInventory() { if (item.ItemName) { td.textContent = item.ItemName + " (" + td.textContent + ")"; } + if (item.ModularParts) { + td.textContent += " ["; + item.ModularParts.forEach(part => { + td.textContent += " " + (itemMap[part]?.name ?? part) + ","; + }); + td.textContent = td.textContent.slice(0, -1) + " ]"; + } tr.appendChild(td); } { const td = document.createElement("td"); td.classList = "text-end"; - if (item.XP < 800_000) { + const maxXP = + category === "Suits" || + category === "SpaceSuits" || + category === "Sentinels" || + category === "Hoverboards" + ? 1_600_000 + : 800_000; + + if (item.XP < maxXP) { const a = document.createElement("a"); a.href = "#"; a.onclick = function (event) { event.preventDefault(); - addGearExp(category, item.ItemId.$oid, 800_000 - item.XP); + addGearExp(category, item.ItemId.$oid, maxXP - item.XP); + if ("exalted" in itemMap[item.ItemType]) { + for (const exaltedType of itemMap[item.ItemType].exalted) { + const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); + if (exaltedItem) { + const exaltedCap = + itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; + if (exaltedItem.XP < exaltedCap) { + addGearExp( + "SpecialItems", + exaltedItem.ItemId.$oid, + exaltedCap - exaltedItem.XP + ); + } + } + } + } }; a.title = "Make Rank 30"; a.innerHTML = ``; td.appendChild(a); } + if (category == "Suits") { + const a = document.createElement("a"); + a.href = "/webui/powersuit/" + item.ItemId.$oid; + a.innerHTML = ``; + td.appendChild(a); + } { const a = document.createElement("a"); a.href = "#"; @@ -524,35 +502,7 @@ function getKey(input) { ?.getAttribute("data-key"); } -function doAcquireWarframe() { - const uniqueName = getKey(document.getElementById("warframe-to-acquire")); - if (!uniqueName) { - $("#warframe-to-acquire").addClass("is-invalid").focus(); - return; - } - revalidateAuthz(() => { - const req = $.post({ - url: "/custom/addItems?" + window.authz, - contentType: "application/json", - data: JSON.stringify([ - { - type: "Powersuit", - internalName: uniqueName - } - ]) - }); - req.done(() => { - document.getElementById("warframe-to-acquire").value = ""; - updateInventory(); - }); - }); -} - -$("input[list]").on("input", function () { - $(this).removeClass("is-invalid"); -}); - -function doAcquireWeapon(category) { +function doAcquireEquipment(category) { const uniqueName = getKey(document.getElementById("acquire-type-" + category)); if (!uniqueName) { $("#acquire-type-" + category) @@ -566,7 +516,7 @@ function doAcquireWeapon(category) { contentType: "application/json", data: JSON.stringify([ { - type: "Weapon", + type: category, internalName: uniqueName } ]) @@ -578,6 +528,10 @@ function doAcquireWeapon(category) { }); } +$("input[list]").on("input", function () { + $(this).removeClass("is-invalid"); +}); + function dispatchAddItemsRequestsBatch(requests) { revalidateAuthz(() => { const req = $.post({ @@ -591,12 +545,18 @@ function dispatchAddItemsRequestsBatch(requests) { }); } -function addMissingWarframes() { +function addMissingEquipment(categories) { const requests = []; - document.querySelectorAll("#datalist-warframes option").forEach(elm => { - if (!document.querySelector("#warframe-list [data-item-type='" + elm.getAttribute("data-key") + "']")) { - requests.push({ type: "Powersuit", internalName: elm.getAttribute("data-key") }); - } + categories.forEach(category => { + document.querySelectorAll("#datalist-" + category + " option").forEach(elm => { + if ( + !document.querySelector( + "#" + category + "-list [data-item-type='" + elm.getAttribute("data-key") + "']" + ) + ) { + requests.push({ type: category, internalName: elm.getAttribute("data-key") }); + } + }); }); if ( requests.length != 0 && @@ -606,91 +566,60 @@ function addMissingWarframes() { } } -function maxRankAllWarframes() { +function maxRankAllEquipment(categories) { const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); req.done(data => { window.itemListPromise.then(itemMap => { - const batchData = { Suits: [], SpecialItems: [] }; + const batchData = {}; - data.Suits.forEach(item => { - if (item.XP < 1_600_000) { - batchData.Suits.push({ - ItemId: { $oid: item.ItemId.$oid }, - XP: 1_600_000 - item.XP - }); - } + categories.forEach(category => { + data[category].forEach(item => { + const maxXP = + category === "Suits" || + category === "SpaceSuits" || + category === "Sentinels" || + category === "Hoverboards" + ? 1_600_000 + : 800_000; - if ("exalted" in itemMap[item.ItemType]) { - for (const exaltedType of itemMap[item.ItemType].exalted) { - const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); - if (exaltedItem) { - const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; - if (exaltedItem.XP < exaltedCap) { - batchData.SpecialItems.push({ - ItemId: { $oid: exaltedItem.ItemId.$oid }, - XP: exaltedCap - }); + if (item.XP < maxXP) { + if (!batchData[category]) { + batchData[category] = []; + } + batchData[category].push({ + ItemId: { $oid: item.ItemId.$oid }, + XP: maxXP + }); + } + if (category === "Suits") { + if ("exalted" in itemMap[item.ItemType]) { + for (const exaltedType of itemMap[item.ItemType].exalted) { + const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType); + if (exaltedItem) { + const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; + if (exaltedItem.XP < exaltedCap) { + batchData["SpecialItems"].push({ + ItemId: { $oid: exaltedItem.ItemId.$oid }, + XP: exaltedCap + }); + } + } } } } - } + }); }); - if (batchData.Suits.length > 0 || batchData.SpecialItems.length > 0) { + if (Object.keys(batchData).length > 0) { return sendBatchGearExp(batchData); } - alert("No Warframes to rank up."); + alert("No equipment to rank up."); }); }); } -function addMissingWeapons() { - const requests = []; - document - .querySelectorAll("#datalist-LongGuns option, #datalist-Pistols option, #datalist-Melee option") - .forEach(elm => { - if (!document.querySelector("#weapon-list [data-item-type='" + elm.getAttribute("data-key") + "']")) { - requests.push({ type: "Weapon", internalName: elm.getAttribute("data-key") }); - } - }); - if ( - requests.length != 0 && - window.confirm("Are you sure you want to add " + requests.length + " items to your account?") - ) { - dispatchAddItemsRequestsBatch(requests); - } -} - -function maxRankAllWeapons() { - const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); - - req.done(data => { - const batchData = {}; - - ["LongGuns", "Pistols", "Melee"].forEach(category => { - data[category].forEach(item => { - if (item.XP < 800_000) { - if (!batchData[category]) { - batchData[category] = []; - } - batchData[category].push({ - ItemId: { $oid: item.ItemId.$oid }, - XP: 800_000 - item.XP - }); - } - }); - }); - - if (Object.keys(batchData).length > 0) { - return sendBatchGearExp(batchData); - } - - alert("No weapons to rank up."); - }); -} - function addGearExp(category, oid, xp) { const data = {}; data[category] = [