feat: exalted weapons on webui

This commit is contained in:
AMelonInsideLemon 2024-12-28 10:13:46 +01:00
parent 4d1bbff99e
commit 1184d18244
8 changed files with 182 additions and 21 deletions

View File

@ -45,6 +45,11 @@ export const sellController: RequestHandler = async (req, res) => {
inventory.Melee.pull({ _id: sellItem.String }); 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) { if (payload.Items.Consumables) {
const consumablesChanges = []; const consumablesChanges = [];
for (const sellItem of payload.Items.Consumables) { for (const sellItem of payload.Items.Consumables) {

View File

@ -1,7 +1,7 @@
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers"; import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
import { getWeaponType } from "@/src/services/itemDataService"; 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"; import { RequestHandler } from "express";
const addItemController: RequestHandler = async (req, res) => { const addItemController: RequestHandler = async (req, res) => {
@ -18,6 +18,10 @@ const addItemController: RequestHandler = async (req, res) => {
const weapon = await addEquipment(weaponType, request.InternalName, accountId); const weapon = await addEquipment(weaponType, request.InternalName, accountId);
res.json(weapon); res.json(weapon);
break; break;
case ItemType.SpecialItem:
const specialItem = await addSpecialItem(request.InternalName, accountId);
res.json(specialItem);
break;
default: default:
res.status(400).json({ error: "something went wrong" }); res.status(400).json({ error: "something went wrong" });
break; break;

View File

@ -1,10 +1,11 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { getDict, getItemName, getString } from "@/src/services/itemDataService"; import { getDict, getExalted, getItemName, getString } from "@/src/services/itemDataService";
import { import {
ExportArcanes, ExportArcanes,
ExportGear, ExportGear,
ExportRecipes, ExportRecipes,
ExportResources, ExportResources,
ExportSentinels,
ExportUpgrades, ExportUpgrades,
ExportWarframes, ExportWarframes,
ExportWeapons ExportWeapons
@ -15,12 +16,34 @@ interface ListedItem {
uniqueName: string; uniqueName: string;
name: string; name: string;
fusionLimit?: number; fusionLimit?: number;
exalted?: { uniqueName: string; name: string }[];
} }
const getItemListsController: RequestHandler = (req, res) => { const getItemListsController: RequestHandler = (req, res) => {
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en"); const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
const weapons = []; const weapons = [];
const miscitems = []; 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)) { for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
if (item.productCategory !== "OperatorAmps") { if (item.productCategory !== "OperatorAmps") {
if (item.totalDamage !== 0) { if (item.totalDamage !== 0) {
@ -84,14 +107,7 @@ const getItemListsController: RequestHandler = (req, res) => {
} }
res.json({ res.json({
warframes: Object.entries(ExportWarframes) warframes,
.filter(([_uniqueName, warframe]) => warframe.productCategory == "Suits")
.map(([uniqueName, warframe]) => {
return {
uniqueName,
name: getString(warframe.name, lang)
};
}),
weapons, weapons,
miscitems, miscitems,
mods, mods,

View File

@ -2,7 +2,8 @@ import { isString } from "@/src/helpers/general";
export enum ItemType { export enum ItemType {
Powersuit = "Powersuit", Powersuit = "Powersuit",
Weapon = "Weapon" Weapon = "Weapon",
SpecialItem = "SpecialItem"
} }
export const isItemType = (itemType: string): itemType is ItemType => { export const isItemType = (itemType: string): itemType is ItemType => {

View File

@ -29,7 +29,7 @@ import {
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { getWeaponType, getExalted } from "@/src/services/itemDataService"; import { getWeaponType, getExalted } from "@/src/services/itemDataService";
import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes"; import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes";
import { IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; import { EquipmentFeatures, IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
import { import {
ExportArcanes, ExportArcanes,
ExportCustoms, ExportCustoms,
@ -433,15 +433,19 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => {
export const addSpecialItem = async (itemName: string, accountId: string) => { export const addSpecialItem = async (itemName: string, accountId: string) => {
const inventory = await getInventory(accountId); 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)) {
const specialItemIndex = inventory.SpecialItems.push({ const specialItemIndex = inventory.SpecialItems.push({
ItemType: itemName, ItemType: itemName,
Configs: [], Configs: [],
Features: 1, Features: EquipmentFeatures.DOUBLE_CAPACITY,
UpgradeVer: 101, UpgradeVer: 101,
XP: 0 XP: 0
}); });
const changedInventory = await inventory.save(); const changedInventory = await inventory.save();
return changedInventory.SpecialItems[specialItemIndex - 1].toJSON(); return changedInventory.SpecialItems[specialItemIndex - 1].toJSON();
}
return;
}; };
export const addSpaceSuit = async (spacesuitName: string, accountId: string) => { export const addSpaceSuit = async (spacesuitName: string, accountId: string) => {

View File

@ -7,6 +7,7 @@ export interface ISellRequest {
Consumables?: ISellItem[]; Consumables?: ISellItem[];
Recipes?: ISellItem[]; Recipes?: ISellItem[];
Upgrades?: ISellItem[]; Upgrades?: ISellItem[];
SpecialItems?: ISellItem[];
}; };
SellPrice: number; SellPrice: number;
SellCurrency: SellCurrency:

View File

@ -126,6 +126,10 @@
</div> </div>
</div> </div>
<div id="powersuit-route" data-route="~ /webui/powersuit/(.+)" data-title="Inventory | OpenWF WebUI"> <div id="powersuit-route" data-route="~ /webui/powersuit/(.+)" data-title="Inventory | OpenWF WebUI">
<p class="mb-4">
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.
</p>
<h3 class="mb-0"></h3> <h3 class="mb-0"></h3>
<p class="text-body-secondary"></p> <p class="text-body-secondary"></p>
<div class="card mb-4"> <div class="card mb-4">
@ -143,6 +147,14 @@
</table> </table>
</div> </div>
</div> </div>
<div class="card mb-4">
<h5 class="card-header">Exalted Weapons</h5>
<div class="card-body">
<table class="table table-hover w-100">
<tbody id="exalted-list"></tbody>
</table>
</div>
</div>
</div> </div>
<div data-route="/webui/mods" data-title="Mods | OpenWF WebUI"> <div data-route="/webui/mods" data-title="Mods | OpenWF WebUI">
<p class="mb-4"> <p class="mb-4">

View File

@ -449,6 +449,124 @@ function updateInventory() {
$("#powersuit-route .text-body-secondary").text(""); $("#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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 80V229.5c0 17 6.7 33.3 18.7 45.3l176 176c25 25 65.5 25 90.5 0L418.7 317.3c25-25 25-65.5 0-90.5l-176-176c-12-12-28.3-18.7-45.3-18.7H48C21.5 32 0 53.5 0 80zm112 32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>`;
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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
}
document.getElementById("exalted-list").appendChild(tr);
});
}
} else {
document.getElementById("exalted-list").closest(".card").style.display = "none";
}
const uniqueUpgrades = {}; const uniqueUpgrades = {};
(item.ArchonCrystalUpgrades ?? []).forEach(upgrade => { (item.ArchonCrystalUpgrades ?? []).forEach(upgrade => {
uniqueUpgrades[upgrade.UpgradeType] ??= 0; uniqueUpgrades[upgrade.UpgradeType] ??= 0;