feat: exalted weapons on webui
This commit is contained in:
parent
4d1bbff99e
commit
1184d18244
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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 => {
|
||||||
|
@ -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);
|
||||||
const specialItemIndex = inventory.SpecialItems.push({
|
// According to wiki there is one exalted item per suit type, so we check if we don't already have that item
|
||||||
ItemType: itemName,
|
if (!inventory.SpecialItems.length || inventory.SpecialItems.some(obj => obj.ItemType !== itemName)) {
|
||||||
Configs: [],
|
const specialItemIndex = inventory.SpecialItems.push({
|
||||||
Features: 1,
|
ItemType: itemName,
|
||||||
UpgradeVer: 101,
|
Configs: [],
|
||||||
XP: 0
|
Features: EquipmentFeatures.DOUBLE_CAPACITY,
|
||||||
});
|
UpgradeVer: 101,
|
||||||
const changedInventory = await inventory.save();
|
XP: 0
|
||||||
return changedInventory.SpecialItems[specialItemIndex - 1].toJSON();
|
});
|
||||||
|
const changedInventory = await inventory.save();
|
||||||
|
return changedInventory.SpecialItems[specialItemIndex - 1].toJSON();
|
||||||
|
}
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addSpaceSuit = async (spacesuitName: string, accountId: string) => {
|
export const addSpaceSuit = async (spacesuitName: string, accountId: string) => {
|
||||||
|
@ -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:
|
||||||
|
@ -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">
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user