返回提交历史
Modified
config.json.example
+0
-2
Modified
src/controllers/api/inventoryController.ts
+1
-38
Added
src/controllers/custom/manageQuestsController.ts
+80
-0
Modified
src/routes/custom.ts
+2
-0
Modified
src/services/configService.ts
+0
-2
Modified
src/services/questService.ts
+11
-4
Modified
static/webui/index.html
+28
-8
Modified
static/webui/script.js
+9
-0
Modified
static/webui/translations/en.js
+7
-0
Modified
static/webui/translations/ru.js
+7
-0
XFEstudio/SpaceNinjaServer
feat: move quest cheats to webui (#963)
Co-authored-by: Sainan <sainan@calamity.inc> Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/963 Co-authored-by: Ordis <134585663+OrdisPrime@users.noreply.github.com> Co-committed-by: Ordis <134585663+OrdisPrime@users.noreply.github.com>
1413a6bc
代码差异
10 个文件
+145
-54
@@ -13,8 +13,6 @@
13
13
"skipAllDialogue": true,
14
14
"unlockAllScans": true,
15
15
"unlockAllMissions": true,
16
"unlockAllQuests": true,
17
"completeAllQuests": true,
18
16
"infiniteCredits": true,
19
17
"infinitePlatinum": true,
20
18
"infiniteEndo": true,
@@ -9,7 +9,6 @@ import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inve
9
9
import {
10
10
ExportCustoms,
11
11
ExportFlavour,
12
ExportKeys,
13
12
ExportRegions,
14
13
ExportResources,
15
14
ExportVirtuals
@@ -102,42 +101,6 @@ export const getInventoryResponse = async (
102
101
addString(inventoryResponse.NodeIntrosCompleted, "TeshinHardModeUnlocked");
103
102
}
104
103
105
if (config.unlockAllQuests) {
106
for (const [k, v] of Object.entries(ExportKeys)) {
107
if ("chainStages" in v) {
108
if (!inventoryResponse.QuestKeys.find(quest => quest.ItemType == k)) {
109
inventoryResponse.QuestKeys.push({ ItemType: k });
110
}
111
}
112
}
113
}
114
if (config.completeAllQuests) {
115
for (const quest of inventoryResponse.QuestKeys) {
116
quest.unlock = true;
117
quest.Completed = true;
118
119
let numStages = 1;
120
if (quest.ItemType in ExportKeys && "chainStages" in ExportKeys[quest.ItemType]) {
121
numStages = ExportKeys[quest.ItemType].chainStages!.length;
122
}
123
quest.Progress = [];
124
for (let i = 0; i != numStages; ++i) {
125
quest.Progress.push({
126
c: 0,
127
i: false,
128
m: false,
129
b: []
130
});
131
}
132
}
133
134
inventoryResponse.ArchwingEnabled = true;
135
inventoryResponse.ActiveQuest = ""; //TODO: might need to reconsider this if this does not work long term.
136
137
// Skip "Watch The Maker"
138
addString(inventoryResponse.NodeIntrosCompleted, "/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level");
139
}
140
141
104
if (config.unlockAllShipDecorations) {
142
105
inventoryResponse.ShipDecorations = [];
143
106
for (const [uniqueName, item] of Object.entries(ExportResources)) {
@@ -261,7 +224,7 @@ export const getInventoryResponse = async (
261
224
return inventoryResponse;
262
225
};
263
226
264
const addString = (arr: string[], str: string): void => {
227
export const addString = (arr: string[], str: string): void => {
265
228
if (!arr.find(x => x == str)) {
266
229
arr.push(str);
267
230
}
@@ -0,0 +1,80 @@
1
import { addString } from "@/src/controllers/api/inventoryController";
2
import { getInventory } from "@/src/services/inventoryService";
3
import { getAccountIdForRequest } from "@/src/services/loginService";
4
import { addQuestKey, IUpdateQuestRequest, updateQuestKey } from "@/src/services/questService";
5
import { IQuestStage } from "@/src/types/inventoryTypes/inventoryTypes";
6
import { logger } from "@/src/utils/logger";
7
import { RequestHandler } from "express";
8
import { ExportKeys } from "warframe-public-export-plus";
9
10
export const manageQuestsController: RequestHandler = async (req, res) => {
11
const accountId = await getAccountIdForRequest(req);
12
const operation = req.query.operation as
13
| "unlockAll"
14
| "completeAll"
15
| "ResetAll"
16
| "completeAllUnlocked"
17
| "updateKey";
18
const questKeyUpdate = req.body as IUpdateQuestRequest["QuestKeys"];
19
20
const allQuestKeys: string[] = [];
21
for (const [k, v] of Object.entries(ExportKeys)) {
22
if ("chainStages" in v) {
23
allQuestKeys.push(k);
24
}
25
}
26
const inventory = await getInventory(accountId, "QuestKeys NodeIntrosCompleted");
27
28
switch (operation) {
29
case "updateKey": {
30
//TODO: if this is intended to be used, one needs to add a updateQuestKeyMultiple, the game does never intend to do it, so it errors for multiple keys.
31
updateQuestKey(inventory, questKeyUpdate);
32
break;
33
}
34
case "unlockAll": {
35
for (const questKey of allQuestKeys) {
36
addQuestKey(inventory, { ItemType: questKey, Completed: false, unlock: true, Progress: [] });
37
}
38
break;
39
}
40
case "completeAll": {
41
logger.info("completing all quests..");
42
for (const questKey of allQuestKeys) {
43
const chainStageTotal = ExportKeys[questKey].chainStages?.length ?? 0;
44
const Progress = Array(chainStageTotal).fill({ c: 0, i: true, m: true, b: [] } satisfies IQuestStage);
45
const inventoryQuestKey = inventory.QuestKeys.find(qk => qk.ItemType === questKey);
46
if (inventoryQuestKey) {
47
inventoryQuestKey.Completed = true;
48
inventoryQuestKey.Progress = Progress;
49
continue;
50
}
51
addQuestKey(inventory, { ItemType: questKey, Completed: true, unlock: true, Progress: Progress });
52
}
53
inventory.ArchwingEnabled = true;
54
inventory.ActiveQuest = "";
55
56
// Skip "Watch The Maker"
57
addString(inventory.NodeIntrosCompleted, "/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level");
58
break;
59
}
60
case "ResetAll": {
61
logger.info("resetting all quests..");
62
for (const questKey of inventory.QuestKeys) {
63
questKey.Completed = false;
64
questKey.Progress = [];
65
}
66
break;
67
}
68
case "completeAllUnlocked": {
69
logger.info("completing all unlocked quests..");
70
for (const questKey of inventory.QuestKeys) {
71
//if (!questKey.unlock) { continue; }
72
questKey.Completed = true;
73
}
74
break;
75
}
76
}
77
78
await inventory.save();
79
res.status(200).end();
80
};
@@ -16,6 +16,7 @@ import { importController } from "@/src/controllers/custom/importController";
16
16
17
17
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
18
18
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
19
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
19
20
20
21
const customRouter = express.Router();
21
22
@@ -32,6 +33,7 @@ customRouter.post("/addCurrency", addCurrencyController);
32
33
customRouter.post("/addItems", addItemsController);
33
34
customRouter.post("/addXp", addXpController);
34
35
customRouter.post("/import", importController);
36
customRouter.post("/manageQuests", manageQuestsController);
35
37
36
38
customRouter.get("/config", getConfigDataController);
37
39
customRouter.post("/config", updateConfigDataController);
@@ -39,8 +39,6 @@ interface IConfig {
39
39
skipAllDialogue?: boolean;
40
40
unlockAllScans?: boolean;
41
41
unlockAllMissions?: boolean;
42
unlockAllQuests?: boolean;
43
completeAllQuests?: boolean;
44
42
infiniteCredits?: boolean;
45
43
infinitePlatinum?: boolean;
46
44
infiniteEndo?: boolean;
@@ -3,7 +3,6 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
3
3
import { IInventoryDatabase, IQuestKeyDatabase, IQuestStage } from "@/src/types/inventoryTypes/inventoryTypes";
4
4
import { logger } from "@/src/utils/logger";
5
5
import { HydratedDocument } from "mongoose";
6
import { config } from "@/src/services/configService";
7
6
8
7
export interface IUpdateQuestRequest {
9
8
QuestKeys: Omit<IQuestKeyDatabase, "CompletionDate">[];
@@ -23,10 +22,10 @@ export const updateQuestKey = (
23
22
throw new Error("more than 1 quest key not supported");
24
23
}
25
24
26
let questKeyIndex = inventory.QuestKeys.findIndex(questKey => questKey.ItemType === questKeyUpdate[0].ItemType);
25
const questKeyIndex = inventory.QuestKeys.findIndex(questKey => questKey.ItemType === questKeyUpdate[0].ItemType);
26
27
27
if (questKeyIndex === -1) {
28
if (!config.unlockAllQuests) throw new Error(`quest key ${questKeyUpdate[0].ItemType} not found`);
29
questKeyIndex = inventory.QuestKeys.push({ ItemType: questKeyUpdate[0].ItemType }) - 1;
28
throw new Error(`quest key ${questKeyUpdate[0].ItemType} not found`);
30
29
}
31
30
32
31
inventory.QuestKeys[questKeyIndex] = questKeyUpdate[0];
@@ -63,3 +62,11 @@ export const updateQuestStage = (
63
62
64
63
Object.assign(questStage, questStageUpdate);
65
64
};
65
66
export const addQuestKey = (inventory: TInventoryDatabaseDocument, questKey: IQuestKeyDatabase): void => {
67
if (inventory.QuestKeys.some(q => q.ItemType === questKey.ItemType)) {
68
logger.error(`quest key ${questKey.ItemType} already exists`);
69
return;
70
}
71
inventory.QuestKeys.push(questKey);
72
};
@@ -410,6 +410,27 @@
410
410
</div>
411
411
</div>
412
412
</div>
413
<div data-route="/webui/quests" data-title="Quests | OpenWF WebUI">
414
<div class="card mb-3">
415
<h5 class="card-header" data-loc="quests_list"></h5>
416
<div class="card-body">
417
<table class="table table-hover w-100">
418
<tbody id="active-quests"></tbody>
419
</table>
420
</div>
421
</div>
422
<div class="card mb-3">
423
<h5 class="card-header" data-loc="quests_Actions"></h5>
424
<div class="card-body">
425
<div class="mb-2 d-flex flex-wrap gap-2">
426
<button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="quests_UnlockAll"></button>
427
<button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="quests_CompleteAll"></button>
428
<button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="quests_CompleteAllUnlocked"></button>
429
<button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="quests_ResetAll"></button>
430
</div>
431
</div>
432
</div>
433
</div>
413
434
<div data-route="/webui/cheats, /webui/settings" data-title="Cheats | OpenWF WebUI">
414
435
<div class="row g-3">
415
436
<div class="col-md-6">
@@ -436,14 +457,6 @@
436
457
<input class="form-check-input" type="checkbox" id="unlockAllMissions" />
437
458
<label class="form-check-label" for="unlockAllMissions" data-loc="cheats_unlockAllMissions"></label>
438
459
</div>
439
<div class="form-check">
440
<input class="form-check-input" type="checkbox" id="unlockAllQuests" />
441
<label class="form-check-label" for="unlockAllQuests" data-loc="cheats_unlockAllQuests"></label>
442
</div>
443
<div class="form-check">
444
<input class="form-check-input" type="checkbox" id="completeAllQuests" />
445
<label class="form-check-label" for="completeAllQuests" data-loc="cheats_completeAllQuests"></label>
446
</div>
447
460
<div class="form-check">
448
461
<input class="form-check-input" type="checkbox" id="infiniteCredits" />
449
462
<label class="form-check-label" for="infiniteCredits" data-loc="cheats_infiniteCredits"></label>
@@ -524,6 +537,13 @@
524
537
<button class="btn btn-primary" type="submit" data-loc="cheats_changeButton"></button>
525
538
</div>
526
539
</form>
540
<h5 class="mt-3" data-loc="cheats_quests"></h6>
541
<div class="mb-2 d-flex flex-wrap gap-2">
542
<button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="cheats_quests_UnlockAll"></button>
543
<button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="cheats_quests_CompleteAll"></button>
544
<button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="cheats_quests_CompleteAllUnlocked"></button>
545
<button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="cheats_quests_ResetAll"></button>
546
</div>
527
547
</div>
528
548
</div>
529
549
</div>
@@ -1153,3 +1153,12 @@ function doAddCurrency(currency) {
1153
1153
updateInventory();
1154
1154
});
1155
1155
}
1156
1157
function doQuestUpdate(operation) {
1158
$.post({
1159
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation,
1160
contentType: "application/json"
1161
}).then(function () {
1162
updateInventory();
1163
});
1164
}
@@ -45,6 +45,7 @@ dict = {
45
45
navbar_deleteAccount: `Delete Account`,
46
46
navbar_inventory: `Inventory`,
47
47
navbar_mods: `Mods`,
48
navbar_quests: `Quests`,
48
49
navbar_cheats: `Cheats`,
49
50
navbar_import: `Import`,
50
51
inventory_addItems: `Add Items`,
@@ -72,6 +73,7 @@ dict = {
72
73
inventory_bulkRankUpSpaceWeapons: `Max Rank All Archwing Weapons`,
73
74
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
74
75
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
76
75
77
currency_RegularCredits: `Credits`,
76
78
currency_PremiumCredits: `Platinum`,
77
79
currency_FusionPoints: `Endo`,
@@ -115,6 +117,11 @@ dict = {
115
117
cheats_changeSupportedSyndicate: `Supported syndicate`,
116
118
cheats_changeButton: `Change`,
117
119
cheats_none: `None`,
120
cheats_quests: `Quests`,
121
cheats_quests_UnlockAll: `Unlock All Quests`,
122
cheats_quests_CompleteAll: `Complete All Quests`,
123
cheats_quests_CompleteAllUnlocked: `Complete All Unlocked Quests`,
124
cheats_quests_ResetAll: `Reset All Quests`,
118
125
import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
119
126
import_submit: `Submit`
120
127
};
@@ -46,6 +46,7 @@ dict = {
46
46
navbar_deleteAccount: `Удалить аккаунт`,
47
47
navbar_inventory: `Инвентарь`,
48
48
navbar_mods: `Моды`,
49
navbar_quests: `[UNTRANSLATED] Quests`,
49
50
navbar_cheats: `Читы`,
50
51
navbar_import: `Импорт`,
51
52
inventory_addItems: `Добавить предметы`,
@@ -73,6 +74,7 @@ dict = {
73
74
inventory_bulkRankUpSpaceWeapons: `Максимальный ранг всего оружия арчвингов`,
74
75
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
75
76
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
77
76
78
currency_RegularCredits: `Кредиты`,
77
79
currency_PremiumCredits: `Платина`,
78
80
currency_FusionPoints: `Эндо`,
@@ -116,6 +118,11 @@ dict = {
116
118
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
117
119
cheats_changeButton: `Изменить`,
118
120
cheats_none: `Отсутствует`,
121
cheats_quests: `[UNTRANSLATED] Quests`,
122
cheats_quests_UnlockAll: `[UNTRANSLATED] Unlock All Quests`,
123
cheats_quests_CompleteAll: `[UNTRANSLATED] Complete All Quests`,
124
cheats_quests_CompleteAllUnlocked: `[UNTRANSLATED] Complete All Unlocked Quests`,
125
cheats_quests_ResetAll: `[UNTRANSLATED] Reset All Quests`,
119
126
import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
120
127
import_submit: `Submit`
121
128
};