From 690b872b5eabf0995910aa0424d348b5725c255d Mon Sep 17 00:00:00 2001
From: Corvus
Date: Thu, 26 Jun 2025 22:26:35 -0700
Subject: [PATCH 28/43] chore(webui): update Chinese translation (#2328)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2328
Co-authored-by: Corvus
Co-committed-by: Corvus
---
static/webui/translations/zh.js | 88 ++++++++++++++++-----------------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js
index 46349a72..e6973c34 100644
--- a/static/webui/translations/zh.js
+++ b/static/webui/translations/zh.js
@@ -1,4 +1,4 @@
-// Chinese translation by meb154 & bishan178
+// Chinese translation by meb154, bishan178 & Corvus
dict = {
general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`,
general_addButton: `添加`,
@@ -187,49 +187,49 @@ dict = {
cheats_changeButton: `更改`,
cheats_none: `无`,
- worldState: `[UNTRANSLATED] World State`,
- worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
- worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`,
- worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`,
- worldState_starDays: `[UNTRANSLATED] Star Days`,
- worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`,
- disabled: `[UNTRANSLATED] Disabled`,
- worldState_we1: `[UNTRANSLATED] Weekend 1`,
- worldState_we2: `[UNTRANSLATED] Weekend 2`,
- worldState_we3: `[UNTRANSLATED] Weekend 3`,
- worldState_eidolonOverride: `[UNTRANSLATED] Eidolon Override`,
- worldState_day: `[UNTRANSLATED] Day`,
- worldState_night: `[UNTRANSLATED] Night`,
- worldState_vallisOverride: `[UNTRANSLATED] Orb Vallis Override`,
- worldState_warm: `[UNTRANSLATED] Warm`,
- worldState_cold: `[UNTRANSLATED] Cold`,
- worldState_duviriOverride: `[UNTRANSLATED] Duviri Override`,
- worldState_joy: `[UNTRANSLATED] Joy`,
- worldState_anger: `[UNTRANSLATED] Anger`,
- worldState_envy: `[UNTRANSLATED] Envy`,
- worldState_sorrow: `[UNTRANSLATED] Sorrow`,
- worldState_fear: `[UNTRANSLATED] Fear`,
- worldState_nightwaveOverride: `[UNTRANSLATED] Nightwave Override`,
- worldState_RadioLegionIntermission13Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 9`,
- worldState_RadioLegionIntermission12Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 8`,
- worldState_RadioLegionIntermission11Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 7`,
- worldState_RadioLegionIntermission10Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 6`,
- worldState_RadioLegionIntermission9Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 5`,
- worldState_RadioLegionIntermission8Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 4`,
- worldState_RadioLegionIntermission7Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 3`,
- worldState_RadioLegionIntermission6Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 2`,
- worldState_RadioLegionIntermission5Syndicate: `[UNTRANSLATED] Nora's Mix Vol. 1`,
- worldState_RadioLegionIntermission4Syndicate: `[UNTRANSLATED] Nora's Choice`,
- worldState_RadioLegionIntermission3Syndicate: `[UNTRANSLATED] Intermission III`,
- worldState_RadioLegion3Syndicate: `[UNTRANSLATED] Glassmaker`,
- worldState_RadioLegionIntermission2Syndicate: `[UNTRANSLATED] Intermission II`,
- worldState_RadioLegion2Syndicate: `[UNTRANSLATED] The Emissary`,
- worldState_RadioLegionIntermissionSyndicate: `[UNTRANSLATED] Intermission I`,
- worldState_RadioLegionSyndicate: `[UNTRANSLATED] The Wolf of Saturn Six`,
- worldState_fissures: `[UNTRANSLATED] Fissures`,
- normal: `[UNTRANSLATED] Normal`,
- worldState_allAtOnceNormal: `[UNTRANSLATED] All At Once, Normal`,
- worldState_allAtOnceSteelPath: `[UNTRANSLATED] All At Once, Steel Path`,
+ worldState: `世界状态配置`,
+ worldState_creditBoost: `现金加成`,
+ worldState_affinityBoost: `经验加成`,
+ worldState_resourceBoost: `资源加成`,
+ worldState_starDays: `活动:星日`,
+ worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
+ disabled: `关闭/取消配置`,
+ worldState_we1: `活动阶段:第一周`,
+ worldState_we2: `活动阶段:第二周`,
+ worldState_we3: `活动阶段:第三周`,
+ worldState_eidolonOverride: `夜灵平原/魔胎之境状态`,
+ worldState_day: `白昼/FASS`,
+ worldState_night: `黑夜/VOME`,
+ worldState_vallisOverride: `奥布山谷状态`,
+ worldState_warm: `温暖`,
+ worldState_cold: `寒冷`,
+ worldState_duviriOverride: `双衍王镜状态`,
+ worldState_joy: `喜悦`,
+ worldState_anger: `愤怒`,
+ worldState_envy: `嫉妒`,
+ worldState_sorrow: `悲伤`,
+ worldState_fear: `恐惧`,
+ worldState_nightwaveOverride: `午夜电波系列`,
+ worldState_RadioLegionIntermission13Syndicate: `诺拉的混选VOL.9`,
+ worldState_RadioLegionIntermission12Syndicate: `诺拉的混选VOL.8`,
+ worldState_RadioLegionIntermission11Syndicate: `诺拉的混选VOL.7`,
+ worldState_RadioLegionIntermission10Syndicate: `诺拉的混选VOL.6`,
+ worldState_RadioLegionIntermission9Syndicate: `诺拉的混选VOL.5`,
+ worldState_RadioLegionIntermission8Syndicate: `诺拉的混选VOL.4`,
+ worldState_RadioLegionIntermission7Syndicate: `诺拉的混选VOL.3`,
+ worldState_RadioLegionIntermission6Syndicate: `诺拉的混选VOL.2`,
+ worldState_RadioLegionIntermission5Syndicate: `诺拉的混选VOL.1`,
+ worldState_RadioLegionIntermission4Syndicate: `诺拉的精选`,
+ worldState_RadioLegionIntermission3Syndicate: `间歇III`,
+ worldState_RadioLegion3Syndicate: `系列3 — 玻璃匠`,
+ worldState_RadioLegionIntermission2Syndicate: `间歇II`,
+ worldState_RadioLegion2Syndicate: `系列2 — 使徒`,
+ worldState_RadioLegionIntermissionSyndicate: `间歇I`,
+ worldState_RadioLegionSyndicate: `系列1 — 土星六号之狼`,
+ worldState_fissures: `虚空裂缝难度设定`,
+ normal: `正常`,
+ worldState_allAtOnceNormal: `全部开启(普通)`,
+ worldState_allAtOnceSteelPath: `全部开启(钢铁之路)`,
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段将被覆盖到您的账户中。`,
import_submit: `提交`,
From 4895b4630b930478ebde136b3bb04a9e3c60a0b1 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 08:20:37 -0700
Subject: [PATCH 29/43] feat: credit boosters (+ daily first win) (#2324)
Daily first win is kinda weird because the client doesn't even seem to acknowledge it.
Also fixed missionCompletionCredits being added to inventory inconsistently (sometimes once, sometimes twice).
Closes #1086
Closes #2322
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2324
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
.../api/checkDailyMissionBonusController.ts | 22 +++----
.../api/missionInventoryUpdateController.ts | 2 +-
.../custom/completeAllMissionsController.ts | 2 +-
.../custom/setBoosterController.ts | 4 +-
src/models/loginModel.ts | 3 +-
src/services/missionInventoryUpdateService.ts | 65 ++++++++++++-------
src/services/questService.ts | 2 +-
src/types/loginTypes.ts | 1 +
src/types/missionTypes.ts | 6 +-
static/webui/script.js | 3 +-
10 files changed, 63 insertions(+), 47 deletions(-)
diff --git a/src/controllers/api/checkDailyMissionBonusController.ts b/src/controllers/api/checkDailyMissionBonusController.ts
index 97b838fe..8e457142 100644
--- a/src/controllers/api/checkDailyMissionBonusController.ts
+++ b/src/controllers/api/checkDailyMissionBonusController.ts
@@ -1,16 +1,12 @@
+import { getAccountForRequest } from "@/src/services/loginService";
import { RequestHandler } from "express";
-const checkDailyMissionBonusController: RequestHandler = (_req, res) => {
- const data = Buffer.from([
- 0x44, 0x61, 0x69, 0x6c, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x3a,
- 0x31, 0x2d, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x50, 0x56, 0x50, 0x57, 0x69, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73,
- 0x3a, 0x31, 0x0a
- ]);
- res.writeHead(200, {
- "Content-Type": "text/html",
- "Content-Length": data.length
- });
- res.end(data);
+export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
+ const account = await getAccountForRequest(req);
+ const today = Math.trunc(Date.now() / 86400000) * 86400;
+ if (account.DailyFirstWinDate != today) {
+ res.send("DailyMissionBonus:1-DailyPVPWinBonus:1\n");
+ } else {
+ res.send("DailyMissionBonus:0-DailyPVPWinBonus:1\n");
+ }
};
-
-export { checkDailyMissionBonusController };
diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts
index 93f8033c..e3b86b71 100644
--- a/src/controllers/api/missionInventoryUpdateController.ts
+++ b/src/controllers/api/missionInventoryUpdateController.ts
@@ -88,7 +88,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
AffiliationMods,
SyndicateXPItemReward,
ConquestCompletedMissionsCount
- } = await addMissionRewards(inventory, missionReport, firstCompletion);
+ } = await addMissionRewards(account, inventory, missionReport, firstCompletion);
if (missionReport.EndOfMatchUpload) {
inventory.RewardSeed = generateRewardSeed();
diff --git a/src/controllers/custom/completeAllMissionsController.ts b/src/controllers/custom/completeAllMissionsController.ts
index f6ab486d..66ac3c13 100644
--- a/src/controllers/custom/completeAllMissionsController.ts
+++ b/src/controllers/custom/completeAllMissionsController.ts
@@ -26,7 +26,7 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
if (mission.Completes == 0) {
mission.Completes++;
if (node.missionReward) {
- addFixedLevelRewards(node.missionReward, inventory, MissionRewards);
+ addFixedLevelRewards(node.missionReward, MissionRewards);
}
}
mission.Tier = 1;
diff --git a/src/controllers/custom/setBoosterController.ts b/src/controllers/custom/setBoosterController.ts
index 28939614..b0a1ddbf 100644
--- a/src/controllers/custom/setBoosterController.ts
+++ b/src/controllers/custom/setBoosterController.ts
@@ -23,9 +23,9 @@ export const setBoosterController: RequestHandler = async (req, res) => {
res.status(400).send("Invalid ItemType provided.");
return;
}
- const now = Math.floor(Date.now() / 1000);
+ const now = Math.trunc(Date.now() / 1000);
for (const { ItemType, ExpiryDate } of requests) {
- if (ExpiryDate < now) {
+ if (ExpiryDate <= now) {
// remove expired boosters
const index = boosters.findIndex(item => item.ItemType === ItemType);
if (index !== -1) {
diff --git a/src/models/loginModel.ts b/src/models/loginModel.ts
index 44dab113..aea5b993 100644
--- a/src/models/loginModel.ts
+++ b/src/models/loginModel.ts
@@ -25,7 +25,8 @@ const databaseAccountSchema = new Schema(
LastLogin: { type: Date, default: 0 },
LatestEventMessageDate: { type: Date, default: 0 },
LastLoginRewardDate: { type: Number, default: 0 },
- LoginDays: { type: Number, default: 1 }
+ LoginDays: { type: Number, default: 1 },
+ DailyFirstWinDate: { type: Number, default: 0 }
},
opts
);
diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts
index 09bdc1c6..af8a2e40 100644
--- a/src/services/missionInventoryUpdateService.ts
+++ b/src/services/missionInventoryUpdateService.ts
@@ -962,6 +962,7 @@ const droptableAliases: Record = {
//TODO: return type of partial missioninventoryupdate response
export const addMissionRewards = async (
+ account: TAccountDocument,
inventory: TInventoryDatabaseDocument,
{
wagerTier: wagerTier,
@@ -1009,13 +1010,17 @@ export const addMissionRewards = async (
const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
//logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
if (fixedLevelRewards.levelKeyRewards) {
- addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, MissionRewards, rewardInfo);
+ missionCompletionCredits += addFixedLevelRewards(
+ fixedLevelRewards.levelKeyRewards,
+ MissionRewards,
+ rewardInfo
+ );
}
if (fixedLevelRewards.levelKeyRewards2) {
for (const reward of fixedLevelRewards.levelKeyRewards2) {
//quest stage completion credit rewards
if (reward.rewardType == "RT_CREDITS") {
- missionCompletionCredits += reward.amount; // will be added to inventory in addCredits
+ missionCompletionCredits += reward.amount;
continue;
}
MissionRewards.push({
@@ -1044,12 +1049,11 @@ export const addMissionRewards = async (
) {
const levelCreditReward = getLevelCreditRewards(node);
missionCompletionCredits += levelCreditReward;
- inventory.RegularCredits += levelCreditReward;
logger.debug(`levelCreditReward ${levelCreditReward}`);
}
if (node.missionReward) {
- missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards, rewardInfo);
+ missionCompletionCredits += addFixedLevelRewards(node.missionReward, MissionRewards, rewardInfo);
}
if (rewardInfo.sortieTag == "Mission1") {
@@ -1159,7 +1163,9 @@ export const addMissionRewards = async (
combineInventoryChanges(inventoryChanges, inventoryChange.InventoryChanges);
}
- const credits = addCredits(inventory, {
+ inventory.RegularCredits += missionCompletionCredits;
+
+ const credits = await addCredits(account, inventory, {
missionCompletionCredits,
missionDropCredits: creditDrops ?? 0,
rngRewardCredits: inventoryChanges.RegularCredits ?? 0
@@ -1382,48 +1388,61 @@ export const addMissionRewards = async (
};
};
-//creditBonus is not entirely accurate.
-//TODO: consider ActiveBoosters
-export const addCredits = (
+export const addCredits = async (
+ account: TAccountDocument,
inventory: TInventoryDatabaseDocument,
{
missionDropCredits,
missionCompletionCredits,
rngRewardCredits
}: { missionDropCredits: number; missionCompletionCredits: number; rngRewardCredits: number }
-): IMissionCredits => {
- const hasDailyCreditBonus = true;
- const totalCredits = missionDropCredits + missionCompletionCredits + rngRewardCredits;
-
+): Promise => {
const finalCredits: IMissionCredits = {
MissionCredits: [missionDropCredits, missionDropCredits],
- CreditBonus: [missionCompletionCredits, missionCompletionCredits],
- TotalCredits: [totalCredits, totalCredits]
+ CreditsBonus: [missionCompletionCredits, missionCompletionCredits],
+ TotalCredits: [0, 0]
};
- if (hasDailyCreditBonus) {
+ const today = Math.trunc(Date.now() / 86400000) * 86400;
+ if (account.DailyFirstWinDate != today) {
+ account.DailyFirstWinDate = today;
+ await account.save();
+
+ logger.debug(`daily first win, doubling missionCompletionCredits (${missionCompletionCredits})`);
+
+ finalCredits.DailyMissionBonus = true;
inventory.RegularCredits += missionCompletionCredits;
- finalCredits.CreditBonus[1] *= 2;
- finalCredits.MissionCredits[1] *= 2;
- finalCredits.TotalCredits[1] *= 2;
+ finalCredits.CreditsBonus[1] *= 2;
}
- if (!hasDailyCreditBonus) {
- return finalCredits;
+ const totalCredits = finalCredits.MissionCredits[1] + finalCredits.CreditsBonus[1] + rngRewardCredits;
+ finalCredits.TotalCredits = [totalCredits, totalCredits];
+
+ if (config.worldState?.creditBoost) {
+ inventory.RegularCredits += finalCredits.TotalCredits[1];
+ finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
}
- return { ...finalCredits, DailyMissionBonus: true };
+ const now = Math.trunc(Date.now() / 1000); // TOVERIFY: Should we maybe subtract mission time as to apply credit boosters that expired during mission?
+ if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBooster")?.ExpiryDate ?? 0) > now) {
+ inventory.RegularCredits += finalCredits.TotalCredits[1];
+ finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
+ }
+ if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBlessing")?.ExpiryDate ?? 0) > now) {
+ inventory.RegularCredits += finalCredits.TotalCredits[1];
+ finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
+ }
+
+ return finalCredits;
};
export const addFixedLevelRewards = (
rewards: IMissionRewardExternal,
- inventory: TInventoryDatabaseDocument,
MissionRewards: IMissionReward[],
rewardInfo?: IRewardInfo
): number => {
let missionBonusCredits = 0;
if (rewards.credits) {
missionBonusCredits += rewards.credits;
- inventory.RegularCredits += rewards.credits;
}
if (rewards.items) {
for (const item of rewards.items) {
diff --git a/src/services/questService.ts b/src/services/questService.ts
index 053f6eb4..633f1022 100644
--- a/src/services/questService.ts
+++ b/src/services/questService.ts
@@ -331,7 +331,7 @@ export const giveKeyChainMissionReward = async (
const fixedLevelRewards = getLevelKeyRewards(missionName);
if (fixedLevelRewards.levelKeyRewards) {
const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
- addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards);
+ inventory.RegularCredits += addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, missionRewards);
for (const reward of missionRewards) {
await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
diff --git a/src/types/loginTypes.ts b/src/types/loginTypes.ts
index ef280188..0f5cea60 100644
--- a/src/types/loginTypes.ts
+++ b/src/types/loginTypes.ts
@@ -25,6 +25,7 @@ export interface IDatabaseAccount extends IDatabaseAccountRequiredFields {
LatestEventMessageDate: Date;
LastLoginRewardDate: number;
LoginDays: number;
+ DailyFirstWinDate: number;
}
// Includes virtual ID
diff --git a/src/types/missionTypes.ts b/src/types/missionTypes.ts
index 3de75318..bb70fc30 100644
--- a/src/types/missionTypes.ts
+++ b/src/types/missionTypes.ts
@@ -17,9 +17,9 @@ export interface IMissionReward {
}
export interface IMissionCredits {
- MissionCredits: number[];
- CreditBonus: number[];
- TotalCredits: number[];
+ MissionCredits: [number, number];
+ CreditsBonus: [number, number]; // "Credit Reward"; `CreditsBonus[1]` is `CreditsBonus[0] * 2` if DailyMissionBonus
+ TotalCredits: [number, number];
DailyMissionBonus?: boolean;
}
diff --git a/static/webui/script.js b/static/webui/script.js
index 479f0014..e90f0ed0 100644
--- a/static/webui/script.js
+++ b/static/webui/script.js
@@ -2289,14 +2289,13 @@ function doAcquireBoosters() {
const ExpiryDate = Date.now() / 1000 + 3 * 24 * 60 * 60; // default 3 days
setBooster(uniqueName, ExpiryDate, () => {
$("#acquire-type-Boosters").val("");
- updateInventory();
});
}
function doChangeBoosterExpiry(ItemType, ExpiryDateInput) {
console.log("Changing booster expiry for", ItemType, "to", ExpiryDateInput.value);
// cast local datetime string to unix timestamp
- const ExpiryDate = new Date(ExpiryDateInput.value).getTime() / 1000;
+ const ExpiryDate = Math.trunc(new Date(ExpiryDateInput.value).getTime() / 1000);
if (isNaN(ExpiryDate)) {
ExpiryDateInput.addClass("is-invalid").focus();
return false;
From abb5b8880fe268546088da87e442b0ace1887b3f Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 08:21:05 -0700
Subject: [PATCH 30/43] chore(webui): keep config in sync with multiple tabs
(#2325)
Adding "wsid" to uniquely identify a given tab (by the websocket connection) so we can avoid needless refreshing on the same tab.
Closes #2316
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2325
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
src/controllers/custom/configController.ts | 2 ++
src/services/webService.ts | 26 ++++++++++++++++++++++
static/webui/script.js | 12 ++++++----
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/src/controllers/custom/configController.ts b/src/controllers/custom/configController.ts
index 2c1e10ac..2249f48f 100644
--- a/src/controllers/custom/configController.ts
+++ b/src/controllers/custom/configController.ts
@@ -2,6 +2,7 @@ import { RequestHandler } from "express";
import { config } from "@/src/services/configService";
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
import { saveConfig } from "@/src/services/configWatcherService";
+import { sendWsBroadcastExcept } from "@/src/services/webService";
export const getConfigController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req);
@@ -24,6 +25,7 @@ export const setConfigController: RequestHandler = async (req, res) => {
const [obj, idx] = configIdToIndexable(id);
obj[idx] = value;
}
+ sendWsBroadcastExcept(parseInt(String(req.query.wsid)), { config_reloaded: true });
await saveConfig();
res.end();
} else {
diff --git a/src/services/webService.ts b/src/services/webService.ts
index ecc5a494..11ff2654 100644
--- a/src/services/webService.ts
+++ b/src/services/webService.ts
@@ -136,7 +136,10 @@ export const stopWebServer = async (): Promise => {
await Promise.all(promises);
};
+let lastWsid: number = 0;
+
interface IWsCustomData extends ws {
+ id?: number;
accountId?: string;
}
@@ -150,6 +153,7 @@ interface IWsMsgFromClient {
}
interface IWsMsgToClient {
+ //wsid?: number;
reload?: boolean;
ports?: {
http: number | undefined;
@@ -174,6 +178,10 @@ const wsOnConnect = (ws: ws, req: http.IncomingMessage): void => {
ws.close();
return;
}
+
+ (ws as IWsCustomData).id = ++lastWsid;
+ ws.send(JSON.stringify({ wsid: lastWsid }));
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
ws.on("message", async msg => {
const data = JSON.parse(String(msg)) as IWsMsgFromClient;
@@ -268,3 +276,21 @@ export const sendWsBroadcastTo = (accountId: string, data: IWsMsgToClient): void
}
}
};
+
+export const sendWsBroadcastExcept = (wsid: number | undefined, data: IWsMsgToClient): void => {
+ const msg = JSON.stringify(data);
+ if (wsServer) {
+ for (const client of wsServer.clients) {
+ if ((client as IWsCustomData).id != wsid) {
+ client.send(msg);
+ }
+ }
+ }
+ if (wssServer) {
+ for (const client of wssServer.clients) {
+ if ((client as IWsCustomData).id != wsid) {
+ client.send(msg);
+ }
+ }
+ }
+};
diff --git a/static/webui/script.js b/static/webui/script.js
index e90f0ed0..10c69dff 100644
--- a/static/webui/script.js
+++ b/static/webui/script.js
@@ -10,7 +10,8 @@
let auth_pending = false,
did_initial_auth = false,
- ws_is_open = false;
+ ws_is_open = false,
+ wsid = 0;
const sendAuth = isRegister => {
if (ws_is_open && localStorage.getItem("email") && localStorage.getItem("password")) {
auth_pending = true;
@@ -34,6 +35,9 @@ function openWebSocket() {
};
window.ws.onmessage = e => {
const msg = JSON.parse(e.data);
+ if ("wsid" in msg) {
+ wsid = msg.wsid;
+ }
if ("reload" in msg) {
setTimeout(() => {
getWebSocket().then(() => {
@@ -1858,7 +1862,7 @@ for (const id of uiConfigs) {
value = parseInt(value);
}
$.post({
- url: "/custom/setConfig?" + window.authz,
+ url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid,
contentType: "application/json",
data: JSON.stringify({ [id]: value })
});
@@ -1866,7 +1870,7 @@ for (const id of uiConfigs) {
} else if (elm.type == "checkbox") {
elm.onchange = function () {
$.post({
- url: "/custom/setConfig?" + window.authz,
+ url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid,
contentType: "application/json",
data: JSON.stringify({ [id]: this.checked })
}).then(() => {
@@ -1881,7 +1885,7 @@ for (const id of uiConfigs) {
function doSaveConfig(id) {
const elm = document.getElementById(id);
$.post({
- url: "/custom/setConfig?" + window.authz,
+ url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid,
contentType: "application/json",
data: JSON.stringify({ [id]: parseInt(elm.value) })
});
From b36d524953a4376a60e65db7a275ed3060635e75 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 08:21:27 -0700
Subject: [PATCH 31/43] feat: personal deco capacity costs (#2329)
Closes #2278
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2329
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
.../api/placeDecoInComponentController.ts | 6 ++-
src/services/guildService.ts | 3 +-
src/services/shipCustomizationsService.ts | 50 +++++++++++--------
3 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/src/controllers/api/placeDecoInComponentController.ts b/src/controllers/api/placeDecoInComponentController.ts
index a45806a8..088f1f11 100644
--- a/src/controllers/api/placeDecoInComponentController.ts
+++ b/src/controllers/api/placeDecoInComponentController.ts
@@ -57,7 +57,11 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
component.DecoCapacity -= meta.capacityCost;
}
} else {
- const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)![0];
+ const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)!;
+ if (!itemType || meta.dojoCapacityCost === undefined) {
+ throw new Error(`unknown deco type: ${deco.Type}`);
+ }
+ component.DecoCapacity -= meta.dojoCapacityCost;
if (deco.Sockets !== undefined) {
guild.VaultFusionTreasures!.find(x => x.ItemType == itemType && x.Sockets == deco.Sockets)!.ItemCount -=
1;
diff --git a/src/services/guildService.ts b/src/services/guildService.ts
index 5486c17f..edf07ce1 100644
--- a/src/services/guildService.ts
+++ b/src/services/guildService.ts
@@ -349,7 +349,8 @@ export const removeDojoDeco = (
component.DecoCapacity! += meta.capacityCost;
}
} else {
- const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)![0];
+ const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)!;
+ component.DecoCapacity! += meta.dojoCapacityCost!;
if (deco.Sockets !== undefined) {
addVaultFusionTreasures(guild, [
{
diff --git a/src/services/shipCustomizationsService.ts b/src/services/shipCustomizationsService.ts
index a01901fd..1e5dcf26 100644
--- a/src/services/shipCustomizationsService.ts
+++ b/src/services/shipCustomizationsService.ts
@@ -59,7 +59,12 @@ export const handleSetShipDecorations = async (
const roomToPlaceIn = rooms.find(room => room.Name === placedDecoration.Room);
if (!roomToPlaceIn) {
- throw new Error("room not found");
+ throw new Error(`unknown room: ${placedDecoration.Room}`);
+ }
+
+ const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)!;
+ if (!itemType || meta.capacityCost === undefined) {
+ throw new Error(`unknown deco type: ${placedDecoration.Type}`);
}
if (placedDecoration.MoveId) {
@@ -83,7 +88,7 @@ export const handleSetShipDecorations = async (
OldRoom: placedDecoration.OldRoom,
NewRoom: placedDecoration.Room,
IsApartment: placedDecoration.IsApartment,
- MaxCapacityIncrease: 0 // TODO: calculate capacity change upon removal
+ MaxCapacityIncrease: 0
};
}
@@ -96,6 +101,7 @@ export const handleSetShipDecorations = async (
}
oldRoom.PlacedDecos.pull({ _id: placedDecoration.MoveId });
+ oldRoom.MaxCapacity += meta.capacityCost;
const newDecoration = {
Type: placedDecoration.Type,
@@ -108,12 +114,14 @@ export const handleSetShipDecorations = async (
//the new room is still roomToPlaceIn
roomToPlaceIn.PlacedDecos.push(newDecoration);
+ roomToPlaceIn.MaxCapacity -= meta.capacityCost;
+
await personalRooms.save();
return {
OldRoom: placedDecoration.OldRoom,
NewRoom: placedDecoration.Room,
IsApartment: placedDecoration.IsApartment,
- MaxCapacityIncrease: 0 // TODO: calculate capacity change upon removal
+ MaxCapacityIncrease: -meta.capacityCost
};
}
@@ -121,11 +129,11 @@ export const handleSetShipDecorations = async (
const decoIndex = roomToPlaceIn.PlacedDecos.findIndex(x => x._id.equals(placedDecoration.RemoveId));
const deco = roomToPlaceIn.PlacedDecos[decoIndex];
roomToPlaceIn.PlacedDecos.splice(decoIndex, 1);
+ roomToPlaceIn.MaxCapacity += meta.capacityCost;
await personalRooms.save();
if (!config.unlockAllShipDecorations) {
const inventory = await getInventory(accountId);
- const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)![0];
if (deco.Sockets !== undefined) {
addFusionTreasures(inventory, [{ ItemType: itemType, Sockets: deco.Sockets, ItemCount: 1 }]);
} else {
@@ -138,24 +146,20 @@ export const handleSetShipDecorations = async (
DecoId: placedDecoration.RemoveId,
Room: placedDecoration.Room,
IsApartment: placedDecoration.IsApartment,
- MaxCapacityIncrease: 0
+ MaxCapacityIncrease: 0 // Client already implies the capacity being refunded.
};
- } else {
- if (!config.unlockAllShipDecorations) {
- const inventory = await getInventory(accountId);
- const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)![0];
- if (placedDecoration.Sockets !== undefined) {
- addFusionTreasures(inventory, [
- { ItemType: itemType, Sockets: placedDecoration.Sockets, ItemCount: -1 }
- ]);
- } else {
- addShipDecorations(inventory, [{ ItemType: itemType, ItemCount: -1 }]);
- }
- await inventory.save();
- }
}
- // TODO: handle capacity
+ if (!config.unlockAllShipDecorations) {
+ const inventory = await getInventory(accountId);
+ const itemType = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)![0];
+ if (placedDecoration.Sockets !== undefined) {
+ addFusionTreasures(inventory, [{ ItemType: itemType, Sockets: placedDecoration.Sockets, ItemCount: -1 }]);
+ } else {
+ addShipDecorations(inventory, [{ ItemType: itemType, ItemCount: -1 }]);
+ }
+ await inventory.save();
+ }
//place decoration
const decoId = new Types.ObjectId();
@@ -167,10 +171,16 @@ export const handleSetShipDecorations = async (
Sockets: placedDecoration.Sockets,
_id: decoId
});
+ roomToPlaceIn.MaxCapacity -= meta.capacityCost;
await personalRooms.save();
- return { DecoId: decoId.toString(), Room: placedDecoration.Room, IsApartment: placedDecoration.IsApartment };
+ return {
+ DecoId: decoId.toString(),
+ Room: placedDecoration.Room,
+ IsApartment: placedDecoration.IsApartment,
+ MaxCapacityIncrease: -meta.capacityCost
+ };
};
export const handleSetPlacedDecoInfo = async (accountId: string, req: ISetPlacedDecoInfoRequest): Promise => {
From d2cae012a7fd44f9b386e5b1d5fec3d58c7b3380 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 08:21:48 -0700
Subject: [PATCH 32/43] chore: add operation eight claw trophies to
allDecoRecipes (#2330)
Closes #2295
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2330
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
static/fixed_responses/allDecoRecipes.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/static/fixed_responses/allDecoRecipes.json b/static/fixed_responses/allDecoRecipes.json
index 4ed19d5b..efbbeed2 100644
--- a/static/fixed_responses/allDecoRecipes.json
+++ b/static/fixed_responses/allDecoRecipes.json
@@ -20,6 +20,10 @@
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/DojoRemasterTrophyGoldARecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/DojoRemasterTrophyPlatinumARecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/DojoRemasterTrophySilverARecipe",
+ "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventBronzeTrophyRecipe",
+ "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventClayTrophyRecipe",
+ "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventGoldTrophyRecipe",
+ "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventSilverTrophyRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/EntratiEventBaseTrophyRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/EntratiEventBronzeTrophyRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/EntratiEventGoldTrophyRecipe",
From 4fcac6dc378789e4d40b8ce07e2651704322a6b1 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 08:22:00 -0700
Subject: [PATCH 33/43] feat: duviri murmur reward tiers (#2331)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2331
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
package-lock.json | 8 +++----
package.json | 2 +-
src/services/missionInventoryUpdateService.ts | 21 +++++++++++++++++++
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f272a944..0ca3fde8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,7 +23,7 @@
"ncp": "^2.0.0",
"typescript": "^5.5",
"undici": "^7.10.0",
- "warframe-public-export-plus": "^0.5.72",
+ "warframe-public-export-plus": "^0.5.73",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
@@ -3386,9 +3386,9 @@
}
},
"node_modules/warframe-public-export-plus": {
- "version": "0.5.72",
- "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.72.tgz",
- "integrity": "sha512-oOZgtU6L0MGcPRKfA6+bonu+Db1kie1lVdLmA7/DbheTPweNkBEx3Hx3Seib+hEaFW+nLj3T5GtmGxGcFHCHfg=="
+ "version": "0.5.73",
+ "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.73.tgz",
+ "integrity": "sha512-v5lmaq/rNICg7WIZcosyfz92RpmrNyfW6+/Pbi9Iu8HbZH74PfaQKT6suAyC9xQn6xp8/cG3NLinqlLZovbKpw=="
},
"node_modules/warframe-riven-info": {
"version": "0.1.2",
diff --git a/package.json b/package.json
index de7411b4..a2035729 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"ncp": "^2.0.0",
"typescript": "^5.5",
"undici": "^7.10.0",
- "warframe-public-export-plus": "^0.5.72",
+ "warframe-public-export-plus": "^0.5.73",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts
index af8a2e40..340e7ba4 100644
--- a/src/services/missionInventoryUpdateService.ts
+++ b/src/services/missionInventoryUpdateService.ts
@@ -1616,6 +1616,27 @@ function getRandomMissionDrops(
? "/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriKullervoSteelPathRNGRewards"
: "/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriKullervoNormalRNGRewards"
];
+ } else if (RewardInfo.T == 17) {
+ if (mission?.Tier == 1) {
+ logger.warn(`non-steel path duviri murmur tier used on steel path?!`);
+ }
+ /*if (operation eight claw is active) {
+ drops.push({
+ StoreItem: "/Lotus/StoreItems/Types/Gameplay/DuviriMITW/Resources/DuviriMurmurItemEvent",
+ ItemCount: 10
+ });
+ }*/
+ rewardManifests = ["/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriMurmurFinalChestRewards"];
+ } else if (RewardInfo.T == 19) {
+ /*if (operation eight claw is active) {
+ drops.push({
+ StoreItem: "/Lotus/StoreItems/Types/Gameplay/DuviriMITW/Resources/DuviriMurmurItemEvent",
+ ItemCount: 15
+ });
+ }*/
+ rewardManifests = [
+ "/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriMurmurFinalSteelChestRewards"
+ ];
} else if (RewardInfo.T == 70) {
// Orowyrm chest, gives 10 Pathos Clamps, or 15 on Steel Path.
drops.push({
From 0f2b6c68cdcf117b38a0dc3745d38030d4de9015 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 19:29:55 +0200
Subject: [PATCH 34/43] chore: use some instead of find
---
src/services/worldStateService.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts
index 5aba5813..4a0cf5c3 100644
--- a/src/services/worldStateService.ts
+++ b/src/services/worldStateService.ts
@@ -372,7 +372,7 @@ const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallenge
hardWeekly: syndicate.weeklyChallenges!.filter(x =>
x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/")
),
- hasWeeklyPermanent: !!syndicate.weeklyChallenges!.find(x =>
+ hasWeeklyPermanent: syndicate.weeklyChallenges!.some(x =>
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
)
};
From 7cad8317024448b09f84f4a0d447b67a39292454 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 15:16:22 -0700
Subject: [PATCH 35/43] chore: update PE+ (#2336)
Closes #2332
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2336
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 0ca3fde8..db97566d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,7 +23,7 @@
"ncp": "^2.0.0",
"typescript": "^5.5",
"undici": "^7.10.0",
- "warframe-public-export-plus": "^0.5.73",
+ "warframe-public-export-plus": "^0.5.74",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
@@ -3386,9 +3386,9 @@
}
},
"node_modules/warframe-public-export-plus": {
- "version": "0.5.73",
- "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.73.tgz",
- "integrity": "sha512-v5lmaq/rNICg7WIZcosyfz92RpmrNyfW6+/Pbi9Iu8HbZH74PfaQKT6suAyC9xQn6xp8/cG3NLinqlLZovbKpw=="
+ "version": "0.5.74",
+ "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.74.tgz",
+ "integrity": "sha512-pA7dxA0lKn9w/2Sc97oxnn+CEzL1SrT9XriNLTDF4Xp+2SBEpGcfbqbdR9ljPQJopIbrc9Zy02R+uBQVomcwyA=="
},
"node_modules/warframe-riven-info": {
"version": "0.1.2",
diff --git a/package.json b/package.json
index a2035729..99f8c63d 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"ncp": "^2.0.0",
"typescript": "^5.5",
"undici": "^7.10.0",
- "warframe-public-export-plus": "^0.5.73",
+ "warframe-public-export-plus": "^0.5.74",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
From 3d21813a7978da594162892bf6e8675acb810968 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Sat, 28 Jun 2025 01:28:45 +0200
Subject: [PATCH 36/43] fix(vscode): update launch.json
---
.vscode/launch.json | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 26899db7..fbeaa0be 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -8,8 +8,7 @@
"type": "node",
"request": "launch",
"name": "Debug and Watch",
- "runtimeArgs": ["-r", "tsconfig-paths/register", "-r", "ts-node/register", "--watch-path", "src"],
- "args": ["${workspaceFolder}/src/index.ts"],
+ "args": ["${workspaceFolder}/scripts/dev.js"],
"console": "integratedTerminal"
}
]
From a9359bd989cfb7a25ceb5b625b45efffd08e04f8 Mon Sep 17 00:00:00 2001
From: Sainan <63328889+Sainan@users.noreply.github.com>
Date: Fri, 27 Jun 2025 20:28:44 -0700
Subject: [PATCH 37/43] feat(webui): the circuit override (#2335)
Re #2312
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2335
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
---
README.md | 2 +-
.../custom/getItemListsController.ts | 35 +++++++++++++
static/webui/index.html | 25 ++++++---
static/webui/script.js | 52 +++++++++++++++++--
static/webui/translations/de.js | 1 +
static/webui/translations/en.js | 1 +
static/webui/translations/es.js | 1 +
static/webui/translations/fr.js | 1 +
static/webui/translations/ru.js | 1 +
static/webui/translations/zh.js | 1 +
10 files changed, 109 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 5b2425ef..0985b846 100644
--- a/README.md
+++ b/README.md
@@ -35,4 +35,4 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
- `RadioLegionIntermissionSyndicate` for Intermission I
- `RadioLegionSyndicate` for The Wolf of Saturn Six
- `allTheFissures` can be set to `normal` or `hard` to enable all fissures either in normal or steel path, respectively.
-- `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`)
+- `worldState.circuitGameModes` can be set to an array of game modes which will override the otherwise-random pattern in The Circuit. Valid element values are `Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, and `Alchemy`.
diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts
index f804f81c..95f85b01 100644
--- a/src/controllers/custom/getItemListsController.ts
+++ b/src/controllers/custom/getItemListsController.ts
@@ -55,6 +55,7 @@ interface ItemLists {
EvolutionProgress: ListedItem[];
mods: ListedItem[];
Boosters: ListedItem[];
+ //circuitGameModes: ListedItem[];
}
const relicQualitySuffixes: Record = {
@@ -64,6 +65,10 @@ const relicQualitySuffixes: Record = {
VPQ_PLATINUM: " [Exceptional]"
};
+/*const toTitleCase = (str: string): string => {
+ return str.replace(/[^\s-]+/g, word => word.charAt(0).toUpperCase() + word.substr(1).toLowerCase());
+};*/
+
const getItemListsController: RequestHandler = (req, response) => {
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
const res: ItemLists = {
@@ -87,6 +92,36 @@ const getItemListsController: RequestHandler = (req, response) => {
EvolutionProgress: [],
mods: [],
Boosters: []
+ /*circuitGameModes: [
+ {
+ uniqueName: "Survival",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Survival", lang))
+ },
+ {
+ uniqueName: "VoidFlood",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Corruption", lang))
+ },
+ {
+ uniqueName: "Excavation",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Excavation", lang))
+ },
+ {
+ uniqueName: "Defense",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Defense", lang))
+ },
+ {
+ uniqueName: "Exterminate",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Exterminate", lang))
+ },
+ {
+ uniqueName: "Assassination",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Assassination", lang))
+ },
+ {
+ uniqueName: "Alchemy",
+ name: toTitleCase(getString("/Lotus/Language/Missions/MissionName_Alchemy", lang))
+ }
+ ]*/
};
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
res[item.productCategory].push({
diff --git a/static/webui/index.html b/static/webui/index.html
index 455ff556..425269b6 100644
--- a/static/webui/index.html
+++ b/static/webui/index.html
@@ -768,14 +768,14 @@
-
-