返回提交历史
Modified
src/controllers/api/sellController.ts
+42
-0
Modified
src/controllers/custom/addItemsController.ts
+29
-10
Modified
src/controllers/custom/getItemListsController.ts
+49
-12
Modified
src/services/inventoryService.ts
+1
-1
Modified
static/webui/index.html
+128
-12
Modified
static/webui/script.js
+112
-183
XFEstudio/SpaceNinjaServer
feat(webui): more equipment (#826)
86a2b57e
代码差异
6 个文件
+361
-218
@@ -51,6 +51,41 @@ export const sellController: RequestHandler = async (req, res) => {
51
51
inventory.Melee.pull({ _id: sellItem.String });
52
52
});
53
53
}
54
if (payload.Items.SpaceSuits) {
55
payload.Items.SpaceSuits.forEach(sellItem => {
56
inventory.SpaceSuits.pull({ _id: sellItem.String });
57
});
58
}
59
if (payload.Items.SpaceGuns) {
60
payload.Items.SpaceGuns.forEach(sellItem => {
61
inventory.SpaceGuns.pull({ _id: sellItem.String });
62
});
63
}
64
if (payload.Items.SpaceMelee) {
65
payload.Items.SpaceMelee.forEach(sellItem => {
66
inventory.SpaceMelee.pull({ _id: sellItem.String });
67
});
68
}
69
if (payload.Items.Sentinels) {
70
payload.Items.Sentinels.forEach(sellItem => {
71
inventory.Sentinels.pull({ _id: sellItem.String });
72
});
73
}
74
if (payload.Items.SentinelWeapons) {
75
payload.Items.SentinelWeapons.forEach(sellItem => {
76
inventory.SentinelWeapons.pull({ _id: sellItem.String });
77
});
78
}
79
if (payload.Items.OperatorAmps) {
80
payload.Items.OperatorAmps.forEach(sellItem => {
81
inventory.OperatorAmps.pull({ _id: sellItem.String });
82
});
83
}
84
if (payload.Items.Hoverboards) {
85
payload.Items.Hoverboards.forEach(sellItem => {
86
inventory.Hoverboards.pull({ _id: sellItem.String });
87
});
88
}
54
89
if (payload.Items.Consumables) {
55
90
const consumablesChanges = [];
56
91
for (const sellItem of payload.Items.Consumables) {
@@ -110,6 +145,13 @@ interface ISellRequest {
110
145
Recipes?: ISellItem[];
111
146
Upgrades?: ISellItem[];
112
147
MiscItems?: ISellItem[];
148
SpaceSuits?: ISellItem[];
149
SpaceGuns?: ISellItem[];
150
SpaceMelee?: ISellItem[];
151
Sentinels?: ISellItem[];
152
SentinelWeapons?: ISellItem[];
153
OperatorAmps?: ISellItem[];
154
Hoverboards?: ISellItem[];
113
155
};
114
156
SellPrice: number;
115
157
SellCurrency:
@@ -1,8 +1,8 @@
1
1
import { getAccountIdForRequest } from "@/src/services/loginService";
2
import { getWeaponType } from "@/src/services/itemDataService";
3
import { addPowerSuit, addEquipment, getInventory, updateSlots } from "@/src/services/inventoryService";
4
import { RequestHandler } from "express";
2
import { addEquipment, addPowerSuit, getInventory, updateSlots } from "@/src/services/inventoryService";
3
import { SlotNames } from "@/src/types/purchaseTypes";
5
4
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
5
import { RequestHandler } from "express";
6
6
7
7
export const addItemsController: RequestHandler = async (req, res) => {
8
8
const accountId = await getAccountIdForRequest(req);
@@ -10,14 +10,14 @@ export const addItemsController: RequestHandler = async (req, res) => {
10
10
const inventory = await getInventory(accountId);
11
11
for (const request of requests) {
12
12
switch (request.type) {
13
case ItemType.Powersuit:
14
updateSlots(inventory, InventorySlot.SUITS, 0, 1);
13
case ItemType.Suits:
14
updateSlots(inventory, productCategoryToSlotName[request.type], 0, 1);
15
15
addPowerSuit(inventory, request.internalName);
16
16
break;
17
17
18
case ItemType.Weapon:
19
updateSlots(inventory, InventorySlot.WEAPONS, 0, 1);
20
addEquipment(inventory, getWeaponType(request.internalName), request.internalName);
18
default:
19
updateSlots(inventory, productCategoryToSlotName[request.type], 0, 1);
20
addEquipment(inventory, request.type, request.internalName);
21
21
break;
22
22
}
23
23
}
@@ -25,9 +25,28 @@ export const addItemsController: RequestHandler = async (req, res) => {
25
25
res.end();
26
26
};
27
27
28
const productCategoryToSlotName: Record<ItemType, SlotNames> = {
29
Suits: InventorySlot.SUITS,
30
Pistols: InventorySlot.WEAPONS,
31
Melee: InventorySlot.WEAPONS,
32
LongGuns: InventorySlot.WEAPONS,
33
SpaceSuits: InventorySlot.SPACESUITS,
34
SpaceGuns: InventorySlot.SPACESUITS,
35
SpaceMelee: InventorySlot.SPACESUITS,
36
Sentinels: InventorySlot.SENTINELS,
37
SentinelWeapons: InventorySlot.SENTINELS
38
};
39
28
40
enum ItemType {
29
Powersuit = "Powersuit",
30
Weapon = "Weapon"
41
Suits = "Suits",
42
SpaceSuits = "SpaceSuits",
43
LongGuns = "LongGuns",
44
Pistols = "Pistols",
45
Melee = "Melee",
46
SpaceGuns = "SpaceGuns",
47
SpaceMelee = "SpaceMelee",
48
SentinelWeapons = "SentinelWeapons",
49
Sentinels = "Sentinels"
31
50
}
32
51
33
52
interface IAddItemRequest {
@@ -5,6 +5,7 @@ import {
5
5
ExportGear,
6
6
ExportRecipes,
7
7
ExportResources,
8
ExportSentinels,
8
9
ExportUpgrades,
9
10
ExportWarframes,
10
11
ExportWeapons
@@ -15,21 +16,66 @@ interface ListedItem {
15
16
uniqueName: string;
16
17
name: string;
17
18
fusionLimit?: number;
19
exalted?: string[];
18
20
}
19
21
20
22
const getItemListsController: RequestHandler = (req, response) => {
21
23
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
22
24
const res: Record<string, ListedItem[]> = {};
23
25
res.LongGuns = [];
24
res.Pistols = [];
25
26
res.Melee = [];
27
res.ModularParts = [];
28
res.Pistols = [];
29
res.Sentinels = [];
30
res.SentinelWeapons = [];
31
res.SpaceGuns = [];
32
res.SpaceMelee = [];
33
res.SpaceSuits = [];
34
res.Suits = [];
26
35
res.miscitems = [];
36
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
37
if (item.productCategory == "Suits" || item.productCategory == "SpaceSuits") {
38
res[item.productCategory].push({
39
uniqueName,
40
name: getString(item.name, lang),
41
exalted: item.exalted
42
});
43
}
44
}
45
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
46
if (item.productCategory == "Sentinels") {
47
res[item.productCategory].push({
48
uniqueName,
49
name: getString(item.name, lang)
50
});
51
}
52
}
27
53
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
28
if (item.totalDamage !== 0) {
54
if (
55
uniqueName.split("/")[4] == "OperatorAmplifiers" ||
56
uniqueName.split("/")[5] == "SUModularSecondarySet1" ||
57
uniqueName.split("/")[5] == "SUModularPrimarySet1" ||
58
uniqueName.split("/")[5] == "InfKitGun" ||
59
uniqueName.split("/")[5] == "HoverboardParts"
60
) {
61
res.ModularParts.push({
62
uniqueName,
63
name: getString(item.name, lang)
64
});
65
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
66
res.miscitems.push({
67
uniqueName: "MiscItems:" + uniqueName,
68
name: getString(item.name, lang)
69
});
70
}
71
} else if (item.totalDamage !== 0) {
29
72
if (
30
73
item.productCategory == "LongGuns" ||
31
74
item.productCategory == "Pistols" ||
32
item.productCategory == "Melee"
75
item.productCategory == "Melee" ||
76
item.productCategory == "SpaceGuns" ||
77
item.productCategory == "SpaceMelee" ||
78
item.productCategory == "SentinelWeapons"
33
79
) {
34
80
res[item.productCategory].push({
35
81
uniqueName,
@@ -102,15 +148,6 @@ const getItemListsController: RequestHandler = (req, response) => {
102
148
}
103
149
104
150
response.json({
105
warframes: Object.entries(ExportWarframes)
106
.filter(([_uniqueName, warframe]) => warframe.productCategory == "Suits")
107
.map(([uniqueName, warframe]) => {
108
return {
109
uniqueName,
110
name: getString(warframe.name, lang),
111
exalted: warframe.exalted
112
};
113
}),
114
151
badItems,
115
152
archonCrystalUpgrades,
116
153
...res
@@ -365,7 +365,7 @@ export const addSentinelWeapon = (
365
365
typeName: string,
366
366
inventoryChanges: IInventoryChanges
367
367
): void => {
368
const index = inventory.SentinelWeapons.push({ ItemType: typeName }) - 1;
368
const index = inventory.SentinelWeapons.push({ ItemType: typeName, XP: 0 }) - 1;
369
369
inventoryChanges.SentinelWeapons ??= [];
370
370
(inventoryChanges.SentinelWeapons as IEquipmentClient[]).push(
371
371
inventory.SentinelWeapons[index].toJSON<IEquipmentClient>()
@@ -99,12 +99,12 @@
99
99
<div class="card mb-3" style="height: 400px;">
100
100
<h5 class="card-header">Warframes</h5>
101
101
<div class="card-body overflow-auto">
102
<form class="input-group mb-3" onsubmit="doAcquireWarframe();return false;">
103
<input class="form-control" id="warframe-to-acquire" list="datalist-warframes" />
102
<form class="input-group mb-3" onsubmit="doAcquireEquipment('Suits');return false;">
103
<input class="form-control" id="acquire-type-Suits" list="datalist-Suits" />
104
104
<button class="btn btn-primary" type="submit">Add</button>
105
105
</form>
106
106
<table class="table table-hover w-100">
107
<tbody id="warframe-list"></tbody>
107
<tbody id="Suits-list"></tbody>
108
108
</table>
109
109
</div>
110
110
</div>
@@ -113,7 +113,7 @@
113
113
<div class="card mb-3" style="height: 400px;">
114
114
<h5 class="card-header">Primary Weapons</h5>
115
115
<div class="card-body overflow-auto">
116
<form class="input-group mb-3" onsubmit="doAcquireWeapon('LongGuns');return false;">
116
<form class="input-group mb-3" onsubmit="doAcquireEquipment('LongGuns');return false;">
117
117
<input class="form-control" id="acquire-type-LongGuns" list="datalist-LongGuns" />
118
118
<button class="btn btn-primary" type="submit">Add</button>
119
119
</form>
@@ -129,7 +129,7 @@
129
129
<div class="card mb-3" style="height: 400px;">
130
130
<h5 class="card-header">Secondary Weapons</h5>
131
131
<div class="card-body overflow-auto">
132
<form class="input-group mb-3" onsubmit="doAcquireWeapon('Pistols');return false;">
132
<form class="input-group mb-3" onsubmit="doAcquireEquipment('Pistols');return false;">
133
133
<input class="form-control" id="acquire-type-Pistols" list="datalist-Pistols" />
134
134
<button class="btn btn-primary" type="submit">Add</button>
135
135
</form>
@@ -143,7 +143,7 @@
143
143
<div class="card mb-3" style="height: 400px;">
144
144
<h5 class="card-header">Melee Weapons</h5>
145
145
<div class="card-body overflow-auto">
146
<form class="input-group mb-3" onsubmit="doAcquireWeapon('Melee');return false;">
146
<form class="input-group mb-3" onsubmit="doAcquireEquipment('Melee');return false;">
147
147
<input class="form-control" id="acquire-type-Melee" list="datalist-Melee" />
148
148
<button class="btn btn-primary" type="submit">Add</button>
149
149
</form>
@@ -154,13 +154,123 @@
154
154
</div>
155
155
</div>
156
156
</div>
157
<div class="row g-3">
158
<div class="col-lg-6">
159
<div class="card mb-3" style="height: 400px;">
160
<h5 class="card-header">Archwing</h5>
161
<div class="card-body overflow-auto">
162
<form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceSuits');return false;">
163
<input class="form-control" id="acquire-type-SpaceSuits" list="datalist-SpaceSuits" />
164
<button class="btn btn-primary" type="submit">Add</button>
165
</form>
166
<table class="table table-hover w-100">
167
<tbody id="SpaceSuits-list"></tbody>
168
</table>
169
</div>
170
</div>
171
</div>
172
<div class="col-lg-6">
173
<div class="card mb-3" style="height: 400px;">
174
<h5 class="card-header">Archwing Primary Weapons</h5>
175
<div class="card-body overflow-auto">
176
<form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceGuns');return false;">
177
<input class="form-control" id="acquire-type-SpaceGuns" list="datalist-SpaceGuns" />
178
<button class="btn btn-primary" type="submit">Add</button>
179
</form>
180
<table class="table table-hover w-100">
181
<tbody id="SpaceGuns-list"></tbody>
182
</table>
183
</div>
184
</div>
185
</div>
186
</div>
187
<div class="row g-3">
188
<div class="col-lg-6">
189
<div class="card mb-3" style="height: 400px;">
190
<h5 class="card-header">Archwing Melee Weapons</h5>
191
<div class="card-body overflow-auto">
192
<form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceMelee');return false;">
193
<input class="form-control" id="acquire-type-SpaceMelee" list="datalist-SpaceMelee" />
194
<button class="btn btn-primary" type="submit">Add</button>
195
</form>
196
<table class="table table-hover w-100">
197
<tbody id="SpaceMelee-list"></tbody>
198
</table>
199
</div>
200
</div>
201
</div>
202
<div class="col-lg-6">
203
<div class="card mb-3" style="height: 400px;">
204
<h5 class="card-header">Sentinel Weapons</h5>
205
<div class="card-body overflow-auto">
206
<form class="input-group mb-3" onsubmit="doAcquireEquipment('SentinelWeapons');return false;">
207
<input class="form-control" id="acquire-type-SentinelWeapons" list="datalist-SentinelWeapons" />
208
<button class="btn btn-primary" type="submit">Add</button>
209
</form>
210
<table class="table table-hover w-100">
211
<tbody id="SentinelWeapons-list"></tbody>
212
</table>
213
</div>
214
</div>
215
</div>
216
</div>
217
<div class="row g-3">
218
<div class="col-lg-6">
219
<div class="card mb-3" style="height: 400px;">
220
<h5 class="card-header">Sentinels</h5>
221
<div class="card-body overflow-auto">
222
<form class="input-group mb-3" onsubmit="doAcquireEquipment('Sentinels');return false;">
223
<input class="form-control" id="acquire-type-Sentinels" list="datalist-Sentinels" />
224
<button class="btn btn-primary" type="submit">Add</button>
225
</form>
226
<table class="table table-hover w-100">
227
<tbody id="Sentinels-list"></tbody>
228
</table>
229
</div>
230
</div>
231
</div>
232
</div>
233
<div class="row g-3">
234
<div class="col-lg-6">
235
<div class="card mb-3" style="height: 400px;">
236
<h5 class="card-header">Amps</h5>
237
<div class="card-body overflow-auto">
238
<table class="table table-hover w-100">
239
<tbody id="OperatorAmps-list"></tbody>
240
</table>
241
</div>
242
</div>
243
</div>
244
<div class="col-lg-6">
245
<div class="card mb-3" style="height: 400px;">
246
<h5 class="card-header">K-Drives</h5>
247
<div class="card-body overflow-auto">
248
<table class="table table-hover w-100">
249
<tbody id="Hoverboards-list"></tbody>
250
</table>
251
</div>
252
</div>
253
</div>
254
</div>
157
255
<div class="card mb-3">
158
256
<h5 class="card-header">Bulk Actions</h5>
159
<div class="card-body d-flex flex-wrap gap-2">
160
<button class="btn btn-primary" onclick="addMissingWarframes();">Add Missing Warframes</button>
161
<button class="btn btn-primary" onclick="addMissingWeapons();">Add Missing Weapons</button>
162
<button class="btn btn-success" onclick="maxRankAllWarframes()">Max Rank All Warframes</button>
163
<button class="btn btn-success" onclick="maxRankAllWeapons()">Max Rank All Weapons</button>
257
<div class="card-body">
258
<div class="mb-2 d-flex flex-wrap gap-2">
259
<button class="btn btn-primary" onclick="addMissingEquipment(['Suits']);">Add Missing Warframes</button>
260
<button class="btn btn-primary" onclick="addMissingEquipment(['Melee', 'LongGuns', 'Pistols']);">Add Missing Weapons</button>
261
<button class="btn btn-primary" onclick="addMissingEquipment(['SpaceSuits']);">Add Missing Archwings</button>
262
<button class="btn btn-primary" onclick="addMissingEquipment(['SpaceGuns', 'SpaceMelee']);">Add Missing Archwing Weapons</button>
263
<button class="btn btn-primary" onclick="addMissingEquipment(['Sentinels']);">Add Missing Sentinels</button>
264
<button class="btn btn-primary" onclick="addMissingEquipment(['SentinelWeapons']);">Add Missing Sentinel Weapons</button>
265
</div>
266
<div class="mb-2 d-flex flex-wrap gap-2">
267
<button class="btn btn-success" onclick="maxRankAllEquipment(['Suits']);">Max Rank All Warframes</button>
268
<button class="btn btn-success" onclick="maxRankAllEquipment(['Melee', 'LongGuns', 'Pistols']);">Max Rank All Weapons</button>
269
<button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceSuits']);">Max Rank All Archwings</button>
270
<button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceGuns', 'SpaceMelee']);">Max Rank All Archwing Weapons</button>
271
<button class="btn btn-success" onclick="maxRankAllEquipment(['Sentinels']);">Max Rank All Sentinels</button>
272
<button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);">Max Rank All Sentinel Weapons</button>
273
</div>
164
274
</div>
165
275
</div>
166
276
</div>
@@ -384,10 +494,16 @@
384
494
</div>
385
495
</div>
386
496
</div>
387
<datalist id="datalist-warframes"></datalist>
497
<datalist id="datalist-Suits"></datalist>
498
<datalist id="datalist-SpaceSuits"></datalist>
388
499
<datalist id="datalist-LongGuns"></datalist>
389
500
<datalist id="datalist-Pistols"></datalist>
390
501
<datalist id="datalist-Melee"></datalist>
502
<datalist id="datalist-SpaceGuns"></datalist>
503
<datalist id="datalist-SpaceMelee"></datalist>
504
<datalist id="datalist-SentinelWeapons"></datalist>
505
<datalist id="datalist-Sentinels"></datalist>
506
<datalist id="datalist-ModularParts"></datalist>
391
507
<datalist id="datalist-miscitems"></datalist>
392
508
<datalist id="datalist-mods">
393
509
<option data-key="/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser" value="Legendary Core"></option>
@@ -149,6 +149,12 @@ function fetchItemList() {
149
149
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" },
150
150
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" },
151
151
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" },
152
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/OperatorTrainingAmpWeapon": {
153
name: "Mote Amp"
154
},
155
"/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon": { name: "Amp" },
156
"/Lotus/Weapons/Operator/Pistols/DrifterPistol/DrifterPistolPlayerWeapon": { name: "Sirocco" },
157
"/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit": { name: "K-Drive" },
152
158
// Missing in data sources
153
159
"/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser": { name: "Legendary Core" },
154
160
"/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }
@@ -188,84 +194,19 @@ function updateInventory() {
188
194
window.didInitialInventoryUpdate = true;
189
195
190
196
// Populate inventory route
191
document.getElementById("warframe-list").innerHTML = "";
192
data.Suits.forEach(item => {
193
const tr = document.createElement("tr");
194
tr.setAttribute("data-item-type", item.ItemType);
195
{
196
const td = document.createElement("td");
197
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
198
if (item.ItemName) {
199
td.textContent = item.ItemName + " (" + td.textContent + ")";
200
}
201
tr.appendChild(td);
202
}
203
{
204
const td = document.createElement("td");
205
td.classList = "text-end";
206
if (item.XP < 1_600_000) {
207
const a = document.createElement("a");
208
a.href = "#";
209
a.onclick = function (event) {
210
event.preventDefault();
211
addGearExp("Suits", item.ItemId.$oid, 1_600_000 - item.XP);
212
if ("exalted" in itemMap[item.ItemType]) {
213
for (const exaltedType of itemMap[item.ItemType].exalted) {
214
const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType);
215
if (exaltedItem) {
216
const exaltedCap =
217
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
218
if (exaltedItem.XP < exaltedCap) {
219
addGearExp(
220
"SpecialItems",
221
exaltedItem.ItemId.$oid,
222
exaltedCap - exaltedItem.XP
223
);
224
}
225
}
226
}
227
}
228
};
229
a.title = "Make Rank 30";
230
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>`;
231
td.appendChild(a);
232
}
233
{
234
const a = document.createElement("a");
235
a.href = "/webui/powersuit/" + item.ItemId.$oid;
236
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M278.5 215.6L23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41c11.1-7.2 5.5-23-7.8-23c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3l-32.2 0c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7C506.4 207.6 512 184.1 512 160c0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149C91 197 64 262.1 64 330v55.3L253.6 195.8c6.2-6.2 16.4-6.2 22.6 0c5.4 5.4 6.1 13.6 2.2 19.8z"/></svg>`;
237
td.appendChild(a);
238
}
239
{
240
const a = document.createElement("a");
241
a.href = "#";
242
a.onclick = function (event) {
243
event.preventDefault();
244
const name = prompt("Enter new custom name:");
245
if (name !== null) {
246
renameGear("Suits", item.ItemId.$oid, name);
247
}
248
};
249
a.title = "Rename";
250
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>`;
251
td.appendChild(a);
252
}
253
{
254
const a = document.createElement("a");
255
a.href = "#";
256
a.onclick = function (event) {
257
event.preventDefault();
258
disposeOfGear("Suits", item.ItemId.$oid);
259
};
260
a.title = "Remove";
261
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>`;
262
td.appendChild(a);
263
}
264
tr.appendChild(td);
265
}
266
document.getElementById("warframe-list").appendChild(tr);
267
});
268
["LongGuns", "Pistols", "Melee"].forEach(category => {
197
[
198
"Suits",
199
"SpaceSuits",
200
"Sentinels",
201
"LongGuns",
202
"Pistols",
203
"Melee",
204
"SpaceGuns",
205
"SpaceMelee",
206
"SentinelWeapons",
207
"Hoverboards",
208
"OperatorAmps"
209
].forEach(category => {
269
210
document.getElementById(category + "-list").innerHTML = "";
270
211
data[category].forEach(item => {
271
212
const tr = document.createElement("tr");
@@ -276,22 +217,59 @@ function updateInventory() {
276
217
if (item.ItemName) {
277
218
td.textContent = item.ItemName + " (" + td.textContent + ")";
278
219
}
220
if (item.ModularParts) {
221
td.textContent += " [";
222
item.ModularParts.forEach(part => {
223
td.textContent += " " + (itemMap[part]?.name ?? part) + ",";
224
});
225
td.textContent = td.textContent.slice(0, -1) + " ]";
226
}
279
227
tr.appendChild(td);
280
228
}
281
229
{
282
230
const td = document.createElement("td");
283
231
td.classList = "text-end";
284
if (item.XP < 800_000) {
232
const maxXP =
233
category === "Suits" ||
234
category === "SpaceSuits" ||
235
category === "Sentinels" ||
236
category === "Hoverboards"
237
? 1_600_000
238
: 800_000;
239
240
if (item.XP < maxXP) {
285
241
const a = document.createElement("a");
286
242
a.href = "#";
287
243
a.onclick = function (event) {
288
244
event.preventDefault();
289
addGearExp(category, item.ItemId.$oid, 800_000 - item.XP);
245
addGearExp(category, item.ItemId.$oid, maxXP - item.XP);
246
if ("exalted" in itemMap[item.ItemType]) {
247
for (const exaltedType of itemMap[item.ItemType].exalted) {
248
const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType);
249
if (exaltedItem) {
250
const exaltedCap =
251
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
252
if (exaltedItem.XP < exaltedCap) {
253
addGearExp(
254
"SpecialItems",
255
exaltedItem.ItemId.$oid,
256
exaltedCap - exaltedItem.XP
257
);
258
}
259
}
260
}
261
}
290
262
};
291
263
a.title = "Make Rank 30";
292
264
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>`;
293
265
td.appendChild(a);
294
266
}
267
if (category == "Suits") {
268
const a = document.createElement("a");
269
a.href = "/webui/powersuit/" + item.ItemId.$oid;
270
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M278.5 215.6L23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41c11.1-7.2 5.5-23-7.8-23c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3l-32.2 0c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7C506.4 207.6 512 184.1 512 160c0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149C91 197 64 262.1 64 330v55.3L253.6 195.8c6.2-6.2 16.4-6.2 22.6 0c5.4 5.4 6.1 13.6 2.2 19.8z"/></svg>`;
271
td.appendChild(a);
272
}
295
273
{
296
274
const a = document.createElement("a");
297
275
a.href = "#";
@@ -524,35 +502,7 @@ function getKey(input) {
524
502
?.getAttribute("data-key");
525
503
}
526
504
527
function doAcquireWarframe() {
528
const uniqueName = getKey(document.getElementById("warframe-to-acquire"));
529
if (!uniqueName) {
530
$("#warframe-to-acquire").addClass("is-invalid").focus();
531
return;
532
}
533
revalidateAuthz(() => {
534
const req = $.post({
535
url: "/custom/addItems?" + window.authz,
536
contentType: "application/json",
537
data: JSON.stringify([
538
{
539
type: "Powersuit",
540
internalName: uniqueName
541
}
542
])
543
});
544
req.done(() => {
545
document.getElementById("warframe-to-acquire").value = "";
546
updateInventory();
547
});
548
});
549
}
550
551
$("input[list]").on("input", function () {
552
$(this).removeClass("is-invalid");
553
});
554
555
function doAcquireWeapon(category) {
505
function doAcquireEquipment(category) {
556
506
const uniqueName = getKey(document.getElementById("acquire-type-" + category));
557
507
if (!uniqueName) {
558
508
$("#acquire-type-" + category)
@@ -566,7 +516,7 @@ function doAcquireWeapon(category) {
566
516
contentType: "application/json",
567
517
data: JSON.stringify([
568
518
{
569
type: "Weapon",
519
type: category,
570
520
internalName: uniqueName
571
521
}
572
522
])
@@ -578,6 +528,10 @@ function doAcquireWeapon(category) {
578
528
});
579
529
}
580
530
531
$("input[list]").on("input", function () {
532
$(this).removeClass("is-invalid");
533
});
534
581
535
function dispatchAddItemsRequestsBatch(requests) {
582
536
revalidateAuthz(() => {
583
537
const req = $.post({
@@ -591,12 +545,18 @@ function dispatchAddItemsRequestsBatch(requests) {
591
545
});
592
546
}
593
547
594
function addMissingWarframes() {
548
function addMissingEquipment(categories) {
595
549
const requests = [];
596
document.querySelectorAll("#datalist-warframes option").forEach(elm => {
597
if (!document.querySelector("#warframe-list [data-item-type='" + elm.getAttribute("data-key") + "']")) {
598
requests.push({ type: "Powersuit", internalName: elm.getAttribute("data-key") });
599
}
550
categories.forEach(category => {
551
document.querySelectorAll("#datalist-" + category + " option").forEach(elm => {
552
if (
553
!document.querySelector(
554
"#" + category + "-list [data-item-type='" + elm.getAttribute("data-key") + "']"
555
)
556
) {
557
requests.push({ type: category, internalName: elm.getAttribute("data-key") });
558
}
559
});
600
560
});
601
561
if (
602
562
requests.length != 0 &&
@@ -606,88 +566,57 @@ function addMissingWarframes() {
606
566
}
607
567
}
608
568
609
function maxRankAllWarframes() {
569
function maxRankAllEquipment(categories) {
610
570
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
611
571
612
572
req.done(data => {
613
573
window.itemListPromise.then(itemMap => {
614
const batchData = { Suits: [], SpecialItems: [] };
615
616
data.Suits.forEach(item => {
617
if (item.XP < 1_600_000) {
618
batchData.Suits.push({
619
ItemId: { $oid: item.ItemId.$oid },
620
XP: 1_600_000 - item.XP
621
});
622
}
574
const batchData = {};
623
575
624
if ("exalted" in itemMap[item.ItemType]) {
625
for (const exaltedType of itemMap[item.ItemType].exalted) {
626
const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType);
627
if (exaltedItem) {
628
const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
629
if (exaltedItem.XP < exaltedCap) {
630
batchData.SpecialItems.push({
631
ItemId: { $oid: exaltedItem.ItemId.$oid },
632
XP: exaltedCap
633
});
576
categories.forEach(category => {
577
data[category].forEach(item => {
578
const maxXP =
579
category === "Suits" ||
580
category === "SpaceSuits" ||
581
category === "Sentinels" ||
582
category === "Hoverboards"
583
? 1_600_000
584
: 800_000;
585
586
if (item.XP < maxXP) {
587
if (!batchData[category]) {
588
batchData[category] = [];
589
}
590
batchData[category].push({
591
ItemId: { $oid: item.ItemId.$oid },
592
XP: maxXP
593
});
594
}
595
if (category === "Suits") {
596
if ("exalted" in itemMap[item.ItemType]) {
597
for (const exaltedType of itemMap[item.ItemType].exalted) {
598
const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType);
599
if (exaltedItem) {
600
const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
601
if (exaltedItem.XP < exaltedCap) {
602
batchData["SpecialItems"].push({
603
ItemId: { $oid: exaltedItem.ItemId.$oid },
604
XP: exaltedCap
605
});
606
}
607
}
634
608
}
635
609
}
636
610
}
637
}
611
});
638
612
});
639
613
640
if (batchData.Suits.length > 0 || batchData.SpecialItems.length > 0) {
614
if (Object.keys(batchData).length > 0) {
641
615
return sendBatchGearExp(batchData);
642
616
}
643
617
644
alert("No Warframes to rank up.");
645
});
646
});
647
}
648
649
function addMissingWeapons() {
650
const requests = [];
651
document
652
.querySelectorAll("#datalist-LongGuns option, #datalist-Pistols option, #datalist-Melee option")
653
.forEach(elm => {
654
if (!document.querySelector("#weapon-list [data-item-type='" + elm.getAttribute("data-key") + "']")) {
655
requests.push({ type: "Weapon", internalName: elm.getAttribute("data-key") });
656
}
618
alert("No equipment to rank up.");
657
619
});
658
if (
659
requests.length != 0 &&
660
window.confirm("Are you sure you want to add " + requests.length + " items to your account?")
661
) {
662
dispatchAddItemsRequestsBatch(requests);
663
}
664
}
665
666
function maxRankAllWeapons() {
667
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
668
669
req.done(data => {
670
const batchData = {};
671
672
["LongGuns", "Pistols", "Melee"].forEach(category => {
673
data[category].forEach(item => {
674
if (item.XP < 800_000) {
675
if (!batchData[category]) {
676
batchData[category] = [];
677
}
678
batchData[category].push({
679
ItemId: { $oid: item.ItemId.$oid },
680
XP: 800_000 - item.XP
681
});
682
}
683
});
684
});
685
686
if (Object.keys(batchData).length > 0) {
687
return sendBatchGearExp(batchData);
688
}
689
690
alert("No weapons to rank up.");
691
620
});
692
621
}
693
622