diff --git a/src/controllers/custom/setUmbraEchoesController.ts b/src/controllers/custom/setUmbraEchoesController.ts
new file mode 100644
index 00000000..290ea764
--- /dev/null
+++ b/src/controllers/custom/setUmbraEchoesController.ts
@@ -0,0 +1,22 @@
+import { getAccountIdForRequest } from "../../services/loginService.ts";
+import { getInventory } from "../../services/inventoryService.ts";
+import type { RequestHandler } from "express";
+import { broadcastInventoryUpdate } from "../../services/wsService.ts";
+
+export const setUmbraEchoesController: RequestHandler = async (req, res) => {
+ const accountId = await getAccountIdForRequest(req);
+ const request = req.body as ISetUmbraEchoesRequest;
+ const inventory = await getInventory(accountId, "Suits");
+ const suit = inventory.Suits.id(request.oid);
+ if (suit) {
+ suit.UmbraDate = request.UmbraDate ? new Date(request.UmbraDate) : undefined;
+ await inventory.save();
+ broadcastInventoryUpdate(req);
+ }
+ res.end();
+};
+
+interface ISetUmbraEchoesRequest {
+ oid: string;
+ UmbraDate: number;
+}
diff --git a/src/controllers/stats/leaderboardController.ts b/src/controllers/stats/leaderboardController.ts
index bd269a27..d0d21138 100644
--- a/src/controllers/stats/leaderboardController.ts
+++ b/src/controllers/stats/leaderboardController.ts
@@ -1,7 +1,7 @@
import { getLeaderboard } from "../../services/leaderboardService.ts";
import type { RequestHandler } from "express";
-export const leaderboardController: RequestHandler = async (req, res) => {
+export const leaderboardPostController: RequestHandler = async (req, res) => {
const payload = JSON.parse(String(req.body)) as ILeaderboardRequest;
res.json({
results: await getLeaderboard(
@@ -15,6 +15,33 @@ export const leaderboardController: RequestHandler = async (req, res) => {
});
};
+export const leaderboardGetController: RequestHandler = async (req, res) => {
+ const payload: ILeaderboardRequest = {
+ field: "archived." + String(req.query.field),
+ before: Number(req.query.before),
+ after: Number(req.query.after),
+ pivotId: req.query.pivotAccountId ? String(req.query.pivotAccountId) : undefined,
+ guildId: undefined,
+ guildTier: undefined
+ };
+ res.json({
+ players: (
+ await getLeaderboard(
+ payload.field,
+ payload.before,
+ payload.after,
+ payload.pivotId,
+ payload.guildId,
+ payload.guildTier
+ )
+ ).map(entry => ({
+ DisplayName: entry.n,
+ score: entry.s,
+ rank: entry.r
+ }))
+ });
+};
+
interface ILeaderboardRequest {
field: string;
before: number;
diff --git a/src/routes/custom.ts b/src/routes/custom.ts
index 1a6fca1f..3978a41f 100644
--- a/src/routes/custom.ts
+++ b/src/routes/custom.ts
@@ -46,6 +46,7 @@ import { updateFingerprintController } from "../controllers/custom/updateFingerp
import { unlockLevelCapController } from "../controllers/custom/unlockLevelCapController.ts";
import { changeModularPartsController } from "../controllers/custom/changeModularPartsController.ts";
import { setInvigorationController } from "../controllers/custom/setInvigorationController.ts";
+import { setUmbraEchoesController } from "../controllers/custom/setUmbraEchoesController.ts";
import { setAccountCheatController } from "../controllers/custom/setAccountCheatController.ts";
import { setGuildCheatController } from "../controllers/custom/setGuildCheatController.ts";
@@ -97,6 +98,7 @@ customRouter.post("/updateFingerprint", updateFingerprintController);
customRouter.post("/unlockLevelCap", unlockLevelCapController);
customRouter.post("/changeModularParts", changeModularPartsController);
customRouter.post("/setInvigoration", setInvigorationController);
+customRouter.post("/setUmbraEchoes", setUmbraEchoesController);
customRouter.post("/setAccountCheat", setAccountCheatController);
customRouter.post("/setGuildCheat", setGuildCheatController);
diff --git a/src/routes/stats.ts b/src/routes/stats.ts
index 8f3dfe5b..ad8d6879 100644
--- a/src/routes/stats.ts
+++ b/src/routes/stats.ts
@@ -1,14 +1,15 @@
import express from "express";
import { viewController } from "../controllers/stats/viewController.ts";
import { uploadController } from "../controllers/stats/uploadController.ts";
-import { leaderboardController } from "../controllers/stats/leaderboardController.ts";
+import { leaderboardPostController, leaderboardGetController } from "../controllers/stats/leaderboardController.ts";
const statsRouter = express.Router();
statsRouter.get("/view.php", viewController);
statsRouter.get("/profileStats.php", viewController);
+statsRouter.get("/leaderboard.php", leaderboardGetController);
statsRouter.post("/upload.php", uploadController);
-statsRouter.post("/leaderboardWeekly.php", leaderboardController);
-statsRouter.post("/leaderboardArchived.php", leaderboardController);
+statsRouter.post("/leaderboardWeekly.php", leaderboardPostController);
+statsRouter.post("/leaderboardArchived.php", leaderboardPostController);
export { statsRouter };
diff --git a/static/webui/index.html b/static/webui/index.html
index 7c052786..6f356c97 100644
--- a/static/webui/index.html
+++ b/static/webui/index.html
@@ -822,6 +822,22 @@
+
diff --git a/static/webui/script.js b/static/webui/script.js
index ace99d86..7eabcebe 100644
--- a/static/webui/script.js
+++ b/static/webui/script.js
@@ -1652,6 +1652,12 @@ function updateInventory() {
formatDatetime("%Y-%m-%d %H:%M", Number(item.UpgradesExpiry?.$date.$numberLong)) || "";
}
+ if (item.ItemType != "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
+ document.getElementById("umbraEchoes-card").classList.remove("d-none");
+ document.getElementById("umbraEchoes-expiry").value =
+ formatDatetime("%Y-%m-%d %H:%M", Number(item.UmbraDate?.$date.$numberLong)) || "";
+ }
+
{
document.getElementById("loadout-card").classList.remove("d-none");
const maxModConfigNum = Math.min(2 + (item.ModSlotPurchases ?? 0), 5);
@@ -3519,6 +3525,7 @@ single.getRoute("#detailedView-route").on("beforeload", function () {
document.getElementById("loadout-card").classList.add("d-none");
document.getElementById("archonShards-card").classList.add("d-none");
document.getElementById("edit-suit-invigorations-card").classList.add("d-none");
+ document.getElementById("umbraEchoes-card").classList.add("d-none");
document.getElementById("modularParts-card").classList.add("d-none");
document.getElementById("modularParts-form").innerHTML = "";
document.getElementById("valenceBonus-card").classList.add("d-none");
@@ -4257,6 +4264,25 @@ function setInvigoration(data) {
});
}
+function submitUmbraEchoes(event) {
+ event.preventDefault();
+ const expiry = document.getElementById("umbraEchoes-expiry").value;
+ setUmbraEchoes({
+ UmbraDate: expiry ? new Date(expiry).getTime() : Date.now() + 1 * 24 * 60 * 60 * 1000
+ });
+}
+
+function setUmbraEchoes(data) {
+ const oid = new URLSearchParams(window.location.search).get("itemId");
+ $.post({
+ url: "/custom/setUmbraEchoes?" + window.authz,
+ contentType: "application/json",
+ data: JSON.stringify({ oid, ...data })
+ }).done(function () {
+ updateInventory();
+ });
+}
+
function handleAbilityOverride(event, configIndex) {
event.preventDefault();
const urlParams = new URLSearchParams(window.location.search);
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js
index 2ce7e4c9..37fb291c 100644
--- a/static/webui/translations/de.js
+++ b/static/webui/translations/de.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Kräftigung`,
detailedView_loadoutLabel: `Loadouts`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
+ detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Fähigkeitsstärke`,
invigorations_offensive_AbilityRange: `+100% Fähigkeitsreichweite`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Fähigkeitsüberschreibung`,
abilityOverride_onSlot: `auf Slot`,
+ detailedView_umbraEchoesDescription: `Wird ein Warframe mit dieser Flüssigkeit injiziert, kann er selbstständig an der Seite des Operators kämpfen.`,
+ detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
+
mods_addRiven: `Riven hinzufügen`,
mods_fingerprint: `Fingerabdruck`,
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js
index dcb8267a..47ef0d1d 100644
--- a/static/webui/translations/en.js
+++ b/static/webui/translations/en.js
@@ -162,6 +162,7 @@ dict = {
detailedView_invigorationLabel: `Invigoration`,
detailedView_loadoutLabel: `Loadouts`,
detailedView_equipmentFeaturesLabel: `Equipment Features`,
+ detailedView_umbraEchoesLabel: `Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Ability Strength`,
invigorations_offensive_AbilityRange: `+100% Ability Range`,
@@ -192,6 +193,9 @@ dict = {
abilityOverride_label: `Ability Override`,
abilityOverride_onSlot: `on slot`,
+ detailedView_umbraEchoesDescription: `Injecting this fluid into a Warframe will imbue it with the ability to fight autonomously alongside the Operator.`,
+ detailedView_umbraEchoesExpiryLabel: `Echo Expiry (optional)`,
+
mods_addRiven: `Add Riven`,
mods_fingerprint: `Fingerprint`,
mods_fingerprintHelp: `Need help with the fingerprint?`,
diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js
index 836b7c4c..e8109a60 100644
--- a/static/webui/translations/es.js
+++ b/static/webui/translations/es.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Fortalecimiento`,
detailedView_loadoutLabel: `Equipamientos`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
+ detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Fuerza de Habilidad`,
invigorations_offensive_AbilityRange: `+100% Alcance de Habilidad`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Intercambio de Habilidad`,
abilityOverride_onSlot: `en el espacio`,
+ detailedView_umbraEchoesDescription: `Inyectar este fluido en un warframe lo imbuirá con la capacidad para luchar autónomamente junto a su operador.`,
+ detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
+
mods_addRiven: `Agregar Agrietado`,
mods_fingerprint: `Huella digital`,
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js
index 7d0119eb..606d68f8 100644
--- a/static/webui/translations/fr.js
+++ b/static/webui/translations/fr.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Dynamisation`,
detailedView_loadoutLabel: `Équipements`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
+ detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% de puissance de pouvoir`,
invigorations_offensive_AbilityRange: `+100% de portée de pouvoir`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Remplacement de pouvoir`,
abilityOverride_onSlot: `Sur l'emplacement`,
+ detailedView_umbraEchoesDescription: `L'injection de ce fluide dans une Warframe lui donnera la possibilité de se battre de manière autonome aux côtés de l'Opérateur.`,
+ detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
+
mods_addRiven: `Ajouter un riven`,
mods_fingerprint: `Empreinte`,
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js
index 567d4736..727d8d3f 100644
--- a/static/webui/translations/ru.js
+++ b/static/webui/translations/ru.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Воодушевление`,
detailedView_loadoutLabel: `Конфигурации`,
detailedView_equipmentFeaturesLabel: `Модификаторы снаряжения`,
+ detailedView_umbraEchoesLabel: `Эхо Умбры`,
invigorations_offensive_AbilityStrength: `+200% к силе способностей.`,
invigorations_offensive_AbilityRange: `+100% к зоне поражения способностей.`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Переопределение способности`,
abilityOverride_onSlot: `в ячейке`,
+ detailedView_umbraEchoesDescription: `Введение этой жидкости в варфрейм позволит ему автономно сражаться бок о бок с оператором.`,
+ detailedView_umbraEchoesExpiryLabel: `Срок действия Эха (необязательно)`,
+
mods_addRiven: `Добавить мод Разлома`,
mods_fingerprint: `Отпечаток`,
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
diff --git a/static/webui/translations/uk.js b/static/webui/translations/uk.js
index 64e99c88..49fa93b1 100644
--- a/static/webui/translations/uk.js
+++ b/static/webui/translations/uk.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Зміцнення`,
detailedView_loadoutLabel: `Конфігурації`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
+ detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% до потужності здібностей.`,
invigorations_offensive_AbilityRange: `+100% до досяжності здібностей.`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Перевизначення здібностей`,
abilityOverride_onSlot: `у комірці`,
+ detailedView_umbraEchoesDescription: `Рідина, яка після введення дозволяє ворфрейму використовувати єдність і битися самостійно пліч-о-пліч з оператором.`,
+ detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
+
mods_addRiven: `Добавити модифікатор Розколу`,
mods_fingerprint: `Відбиток`,
mods_fingerprintHelp: `Потрібна допомога з відбитком?`,
diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js
index 8d36c529..a5df62fc 100644
--- a/static/webui/translations/zh.js
+++ b/static/webui/translations/zh.js
@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `活化`,
detailedView_loadoutLabel: `配置`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
+ detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200%技能强度`,
invigorations_offensive_AbilityRange: `+100%技能范围`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `技能替换`,
abilityOverride_onSlot: `槽位`,
+ detailedView_umbraEchoesDescription: `将这种液体注入战甲内,使其具有与指挥官并肩作战的能力。`,
+ detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
+
mods_addRiven: `添加裂罅MOD`,
mods_fingerprint: `印记`,
mods_fingerprintHelp: `需要印记相关的帮助?`,