feat(webui): quests support (#1411)
Reviewed-on: #1411 Reviewed-by: Sainan <sainan@calamity.inc> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
This commit is contained in:
parent
5cc991baca
commit
710470ca2d
@ -10,8 +10,6 @@ ENV APP_SKIP_TUTORIAL=true
|
||||
ENV APP_SKIP_ALL_DIALOGUE=true
|
||||
ENV APP_UNLOCK_ALL_SCANS=true
|
||||
ENV APP_UNLOCK_ALL_MISSIONS=true
|
||||
ENV APP_UNLOCK_ALL_QUESTS=true
|
||||
ENV APP_COMPLETE_ALL_QUESTS=true
|
||||
ENV APP_INFINITE_RESOURCES=true
|
||||
ENV APP_UNLOCK_ALL_SHIP_FEATURES=true
|
||||
ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=true
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
ExportAvionics,
|
||||
ExportDrones,
|
||||
ExportGear,
|
||||
ExportKeys,
|
||||
ExportMisc,
|
||||
ExportRailjackWeapons,
|
||||
ExportRecipes,
|
||||
@ -26,6 +27,7 @@ interface ListedItem {
|
||||
exalted?: string[];
|
||||
badReason?: "starter" | "frivolous" | "notraw";
|
||||
partType?: string;
|
||||
chainLength?: number;
|
||||
}
|
||||
|
||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||
@ -52,6 +54,7 @@ const getItemListsController: RequestHandler = (req, response) => {
|
||||
res.miscitems = [];
|
||||
res.Syndicates = [];
|
||||
res.OperatorAmps = [];
|
||||
res.QuestKeys = [];
|
||||
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
||||
res[item.productCategory].push({
|
||||
uniqueName,
|
||||
@ -208,6 +211,15 @@ const getItemListsController: RequestHandler = (req, response) => {
|
||||
name: getString(syndicate.name, lang)
|
||||
});
|
||||
}
|
||||
for (const [uniqueName, key] of Object.entries(ExportKeys)) {
|
||||
if (key.chainStages) {
|
||||
res.QuestKeys.push({
|
||||
uniqueName,
|
||||
name: getString(key.name || "", lang),
|
||||
chainLength: key.chainStages.length
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
response.json({
|
||||
archonCrystalUpgrades,
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { addString } from "@/src/controllers/api/inventoryController";
|
||||
import { getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { addQuestKey, completeQuest, IUpdateQuestRequest, updateQuestKey } from "@/src/services/questService";
|
||||
import {
|
||||
addQuestKey,
|
||||
completeQuest,
|
||||
giveKeyChainMissionReward,
|
||||
giveKeyChainStageTriggered
|
||||
} from "@/src/services/questService";
|
||||
import { logger } from "@/src/utils/logger";
|
||||
import { RequestHandler } from "express";
|
||||
import { ExportKeys } from "warframe-public-export-plus";
|
||||
@ -9,13 +13,17 @@ import { ExportKeys } from "warframe-public-export-plus";
|
||||
export const manageQuestsController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const operation = req.query.operation as
|
||||
| "unlockAll"
|
||||
| "completeAll"
|
||||
| "ResetAll"
|
||||
| "completeAllUnlocked"
|
||||
| "updateKey"
|
||||
| "giveAll";
|
||||
const questKeyUpdate = req.body as IUpdateQuestRequest["QuestKeys"];
|
||||
| "resetAll"
|
||||
| "giveAll"
|
||||
| "completeKey"
|
||||
| "deleteKey"
|
||||
| "resetKey"
|
||||
| "prevStage"
|
||||
| "nextStage"
|
||||
| "setInactive";
|
||||
|
||||
const questItemType = req.query.itemType as string;
|
||||
|
||||
const allQuestKeys: string[] = [];
|
||||
for (const [k, v] of Object.entries(ExportKeys)) {
|
||||
@ -26,47 +34,15 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
|
||||
const inventory = await getInventory(accountId);
|
||||
|
||||
switch (operation) {
|
||||
case "updateKey": {
|
||||
//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.
|
||||
await updateQuestKey(inventory, questKeyUpdate);
|
||||
break;
|
||||
}
|
||||
case "unlockAll": {
|
||||
for (const questKey of allQuestKeys) {
|
||||
addQuestKey(inventory, { ItemType: questKey, Completed: false, unlock: true, Progress: [] });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "completeAll": {
|
||||
logger.info("completing all quests..");
|
||||
for (const questKey of allQuestKeys) {
|
||||
try {
|
||||
await completeQuest(inventory, questKey);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
logger.error(
|
||||
`Something went wrong completing quest ${questKey}, probably could not add some item`
|
||||
);
|
||||
logger.error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
//Skip "Watch The Maker"
|
||||
if (questKey === "/Lotus/Types/Keys/NewWarIntroQuest/NewWarIntroKeyChain") {
|
||||
addString(
|
||||
inventory.NodeIntrosCompleted,
|
||||
"/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level"
|
||||
);
|
||||
}
|
||||
|
||||
if (questKey === "/Lotus/Types/Keys/ArchwingQuest/ArchwingQuestKeyChain") {
|
||||
inventory.ArchwingEnabled = true;
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
for (const questKey of inventory.QuestKeys) {
|
||||
await completeQuest(inventory, questKey.ItemType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ResetAll": {
|
||||
logger.info("resetting all quests..");
|
||||
case "resetAll": {
|
||||
for (const questKey of inventory.QuestKeys) {
|
||||
questKey.Completed = false;
|
||||
questKey.Progress = [];
|
||||
@ -75,40 +51,113 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
|
||||
inventory.ActiveQuest = "";
|
||||
break;
|
||||
}
|
||||
case "completeAllUnlocked": {
|
||||
logger.info("completing all unlocked quests..");
|
||||
for (const questKey of inventory.QuestKeys) {
|
||||
try {
|
||||
case "giveAll": {
|
||||
allQuestKeys.forEach(questKey => addQuestKey(inventory, { ItemType: questKey }));
|
||||
break;
|
||||
}
|
||||
case "deleteKey": {
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||
if (!questKey) {
|
||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||
break;
|
||||
}
|
||||
|
||||
inventory.QuestKeys.pull({ ItemType: questItemType });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "completeKey": {
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||
if (!questKey) {
|
||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||
break;
|
||||
}
|
||||
|
||||
await completeQuest(inventory, questItemType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "resetKey": {
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||
if (!questKey) {
|
||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||
break;
|
||||
}
|
||||
|
||||
questKey.Completed = false;
|
||||
questKey.Progress = [];
|
||||
questKey.CompletionDate = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "prevStage": {
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||
if (!questKey) {
|
||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||
break;
|
||||
}
|
||||
if (!questKey.Progress) break;
|
||||
|
||||
if (questKey.Completed) {
|
||||
questKey.Completed = false;
|
||||
questKey.CompletionDate = undefined;
|
||||
}
|
||||
questKey.Progress.pop();
|
||||
const stage = questKey.Progress.length - 1;
|
||||
if (stage > 0) {
|
||||
await giveKeyChainStageTriggered(inventory, {
|
||||
KeyChain: questKey.ItemType,
|
||||
ChainStage: stage
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "nextStage": {
|
||||
if (allQuestKeys.includes(questItemType)) {
|
||||
const questKey = inventory.QuestKeys.find(key => key.ItemType === questItemType);
|
||||
const questManifest = ExportKeys[questItemType];
|
||||
if (!questKey) {
|
||||
logger.error(`Quest key not found in inventory: ${questItemType}`);
|
||||
break;
|
||||
}
|
||||
if (!questKey.Progress) break;
|
||||
|
||||
const currentStage = questKey.Progress.length;
|
||||
if (currentStage + 1 == questManifest.chainStages?.length) {
|
||||
logger.debug(`Trying to complete last stage with nextStage, calling completeQuest instead`);
|
||||
await completeQuest(inventory, questKey.ItemType);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
logger.error(
|
||||
`Something went wrong completing quest ${questKey.ItemType}, probably could not add some item`
|
||||
);
|
||||
logger.error(error.message);
|
||||
} else {
|
||||
const progress = {
|
||||
c: questManifest.chainStages![currentStage].key ? -1 : 0,
|
||||
i: false,
|
||||
m: false,
|
||||
b: []
|
||||
};
|
||||
questKey.Progress.push(progress);
|
||||
|
||||
await giveKeyChainStageTriggered(inventory, {
|
||||
KeyChain: questKey.ItemType,
|
||||
ChainStage: currentStage
|
||||
});
|
||||
|
||||
if (currentStage > 0) {
|
||||
await giveKeyChainMissionReward(inventory, {
|
||||
KeyChain: questKey.ItemType,
|
||||
ChainStage: currentStage - 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Skip "Watch The Maker"
|
||||
if (questKey.ItemType === "/Lotus/Types/Keys/NewWarIntroQuest/NewWarIntroKeyChain") {
|
||||
addString(
|
||||
inventory.NodeIntrosCompleted,
|
||||
"/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level"
|
||||
);
|
||||
}
|
||||
|
||||
if (questKey.ItemType === "/Lotus/Types/Keys/ArchwingQuest/ArchwingQuestKeyChain") {
|
||||
inventory.ArchwingEnabled = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "giveAll": {
|
||||
for (const questKey of allQuestKeys) {
|
||||
addQuestKey(inventory, { ItemType: questKey });
|
||||
}
|
||||
case "setInactive":
|
||||
inventory.ActiveQuest = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
|
@ -30,6 +30,9 @@ webuiRouter.get("/webui/mods", (_req, res) => {
|
||||
webuiRouter.get("/webui/settings", (_req, res) => {
|
||||
res.sendFile(path.join(rootDir, "static/webui/index.html"));
|
||||
});
|
||||
webuiRouter.get("/webui/quests", (_req, res) => {
|
||||
res.sendFile(path.join(rootDir, "static/webui/index.html"));
|
||||
});
|
||||
webuiRouter.get("/webui/cheats", (_req, res) => {
|
||||
res.sendFile(path.join(rootDir, "static/webui/index.html"));
|
||||
});
|
||||
|
@ -130,73 +130,56 @@ export const completeQuest = async (inventory: TInventoryDatabaseDocument, quest
|
||||
throw new Error(`Quest ${questKey} does not contain chain stages`);
|
||||
}
|
||||
|
||||
const chainStageTotal = ExportKeys[questKey].chainStages?.length ?? 0;
|
||||
const chainStageTotal = chainStages.length;
|
||||
|
||||
const existingQuestKey = inventory.QuestKeys.find(qk => qk.ItemType === questKey);
|
||||
|
||||
const startingStage = Math.max((existingQuestKey?.Progress?.length ?? 0) - 1, 0);
|
||||
|
||||
if (existingQuestKey?.Completed) {
|
||||
return;
|
||||
}
|
||||
const Progress = Array(chainStageTotal).fill({
|
||||
c: 0,
|
||||
i: false,
|
||||
m: false,
|
||||
b: []
|
||||
} satisfies IQuestStage);
|
||||
|
||||
const completedQuestKey: IQuestKeyDatabase = {
|
||||
ItemType: questKey,
|
||||
Completed: true,
|
||||
unlock: true,
|
||||
Progress: Progress,
|
||||
CompletionDate: new Date()
|
||||
};
|
||||
|
||||
//overwrite current quest progress, might lead to multiple quest item rewards
|
||||
if (existingQuestKey) {
|
||||
existingQuestKey.overwrite(completedQuestKey);
|
||||
//Object.assign(existingQuestKey, completedQuestKey);
|
||||
existingQuestKey.Progress = existingQuestKey.Progress ?? [];
|
||||
|
||||
const existingProgressLength = existingQuestKey.Progress.length;
|
||||
|
||||
if (existingProgressLength < chainStageTotal) {
|
||||
const missingProgress: IQuestStage[] = Array.from(
|
||||
{ length: chainStageTotal - existingProgressLength },
|
||||
() =>
|
||||
({
|
||||
c: 0,
|
||||
i: false,
|
||||
m: false,
|
||||
b: []
|
||||
}) as IQuestStage
|
||||
);
|
||||
|
||||
existingQuestKey.Progress.push(...missingProgress);
|
||||
existingQuestKey.CompletionDate = new Date();
|
||||
existingQuestKey.Completed = true;
|
||||
}
|
||||
} else {
|
||||
const completedQuestKey: IQuestKeyDatabase = {
|
||||
ItemType: questKey,
|
||||
Completed: true,
|
||||
unlock: true,
|
||||
Progress: Array(chainStageTotal).fill({
|
||||
c: 0,
|
||||
i: false,
|
||||
m: false,
|
||||
b: []
|
||||
} satisfies IQuestStage),
|
||||
CompletionDate: new Date()
|
||||
};
|
||||
addQuestKey(inventory, completedQuestKey);
|
||||
}
|
||||
|
||||
for (let i = 0; i < chainStageTotal; i++) {
|
||||
if (chainStages[i].itemsToGiveWhenTriggered.length > 0) {
|
||||
await giveKeyChainItem(inventory, { KeyChain: questKey, ChainStage: i });
|
||||
}
|
||||
for (let i = startingStage; i < chainStageTotal; i++) {
|
||||
await giveKeyChainStageTriggered(inventory, { KeyChain: questKey, ChainStage: i });
|
||||
|
||||
if (chainStages[i].messageToSendWhenTriggered) {
|
||||
await giveKeyChainMessage(inventory, inventory.accountOwnerId, {
|
||||
KeyChain: questKey,
|
||||
ChainStage: i
|
||||
});
|
||||
}
|
||||
|
||||
const missionName = chainStages[i].key;
|
||||
if (missionName) {
|
||||
const fixedLevelRewards = getLevelKeyRewards(missionName);
|
||||
//logger.debug(`fixedLevelRewards`, fixedLevelRewards);
|
||||
if (fixedLevelRewards.levelKeyRewards) {
|
||||
const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
|
||||
addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards);
|
||||
|
||||
for (const reward of missionRewards) {
|
||||
await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
|
||||
}
|
||||
} else if (fixedLevelRewards.levelKeyRewards2) {
|
||||
for (const reward of fixedLevelRewards.levelKeyRewards2) {
|
||||
if (reward.rewardType == "RT_CREDITS") {
|
||||
inventory.RegularCredits += reward.amount;
|
||||
continue;
|
||||
}
|
||||
if (reward.rewardType == "RT_RESOURCE") {
|
||||
await addItem(inventory, fromStoreItem(reward.itemType), reward.amount);
|
||||
} else {
|
||||
await addItem(inventory, fromStoreItem(reward.itemType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await giveKeyChainMissionReward(inventory, { KeyChain: questKey, ChainStage: i });
|
||||
}
|
||||
|
||||
const questCompletionItems = getQuestCompletionItems(questKey);
|
||||
@ -205,7 +188,7 @@ export const completeQuest = async (inventory: TInventoryDatabaseDocument, quest
|
||||
await addItems(inventory, questCompletionItems);
|
||||
}
|
||||
|
||||
inventory.ActiveQuest = "";
|
||||
if (inventory.ActiveQuest == questKey) inventory.ActiveQuest = "";
|
||||
|
||||
if (questKey == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain") {
|
||||
setupKahlSyndicate(inventory);
|
||||
@ -247,3 +230,60 @@ export const giveKeyChainMessage = async (
|
||||
|
||||
updateQuestStage(inventory, keyChainInfo, { m: true });
|
||||
};
|
||||
|
||||
export const giveKeyChainMissionReward = async (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
keyChainInfo: IKeyChainRequest
|
||||
): Promise<void> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const chainStages = ExportKeys[keyChainInfo.KeyChain]?.chainStages;
|
||||
|
||||
if (chainStages) {
|
||||
const missionName = chainStages[keyChainInfo.ChainStage].key;
|
||||
if (missionName) {
|
||||
const fixedLevelRewards = getLevelKeyRewards(missionName);
|
||||
if (fixedLevelRewards.levelKeyRewards) {
|
||||
const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
|
||||
addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards);
|
||||
|
||||
for (const reward of missionRewards) {
|
||||
await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
|
||||
}
|
||||
|
||||
updateQuestStage(inventory, keyChainInfo, { c: 0 });
|
||||
} else if (fixedLevelRewards.levelKeyRewards2) {
|
||||
for (const reward of fixedLevelRewards.levelKeyRewards2) {
|
||||
if (reward.rewardType == "RT_CREDITS") {
|
||||
inventory.RegularCredits += reward.amount;
|
||||
continue;
|
||||
}
|
||||
if (reward.rewardType == "RT_RESOURCE") {
|
||||
await addItem(inventory, fromStoreItem(reward.itemType), reward.amount);
|
||||
} else {
|
||||
await addItem(inventory, fromStoreItem(reward.itemType));
|
||||
}
|
||||
}
|
||||
|
||||
updateQuestStage(inventory, keyChainInfo, { c: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const giveKeyChainStageTriggered = async (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
keyChainInfo: IKeyChainRequest
|
||||
): Promise<void> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const chainStages = ExportKeys[keyChainInfo.KeyChain]?.chainStages;
|
||||
|
||||
if (chainStages) {
|
||||
if (chainStages[keyChainInfo.ChainStage].itemsToGiveWhenTriggered.length > 0) {
|
||||
await giveKeyChainItem(inventory, keyChainInfo);
|
||||
}
|
||||
|
||||
if (chainStages[keyChainInfo.ChainStage].messageToSendWhenTriggered) {
|
||||
await giveKeyChainMessage(inventory, inventory.accountOwnerId, keyChainInfo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -61,6 +61,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/webui/mods" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_mods"></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/webui/quests" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_quests"></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/webui/cheats" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" data-loc="navbar_cheats"></a>
|
||||
</li>
|
||||
@ -470,22 +473,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<div data-route="/webui/quests" data-title="Quests | OpenWF WebUI">
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header" data-loc="quests_list"></h5>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover w-100">
|
||||
<tbody id="active-quests"></tbody>
|
||||
</table>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header" data-loc="quests_list"></h5>
|
||||
<div class="card-body">
|
||||
<form class="input-group mb-3" onsubmit="doAcquireEquipment('QuestKeys');return false;">
|
||||
<input class="form-control" id="acquire-type-QuestKeys" list="datalist-QuestKeys" />
|
||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||
</form>
|
||||
<table class="table table-hover w-100">
|
||||
<tbody id="QuestKeys-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header" data-loc="quests_Actions"></h5>
|
||||
<div class="card-body">
|
||||
<div class="mb-2 d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="quests_UnlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="quests_CompleteAll"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="quests_CompleteAllUnlocked"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="quests_ResetAll"></button>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-primary" onclick="doBulkQuestUpdate('giveAll');" data-loc="quests_giveAll"></button>
|
||||
<button class="btn btn-primary" onclick="doBulkQuestUpdate('completeAll');" data-loc="quests_completeAll"></button>
|
||||
<button class="btn btn-primary" onclick="doBulkQuestUpdate('resetAll');" data-loc="quests_resetAll"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -633,14 +645,6 @@
|
||||
<button class="btn btn-primary" type="submit" data-loc="cheats_changeButton"></button>
|
||||
</div>
|
||||
</form>
|
||||
<h5 class="mt-3" data-loc="cheats_quests"></h6>
|
||||
<div class="mb-2 d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="cheats_quests_unlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="cheats_quests_completeAll"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="cheats_quests_completeAllUnlocked"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="cheats_quests_resetAll"></button>
|
||||
<button class="btn btn-primary" onclick="doQuestUpdate('giveAll');" data-loc="cheats_quests_giveAll"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -666,6 +670,7 @@
|
||||
<datalist id="datalist-MechSuits"></datalist>
|
||||
<datalist id="datalist-Syndicates"></datalist>
|
||||
<datalist id="datalist-MoaPets"></datalist>
|
||||
<datalist id="datalist-QuestKeys"></datalist>
|
||||
<datalist id="datalist-miscitems"></datalist>
|
||||
<datalist id="datalist-mods">
|
||||
<option data-key="/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser" value="Legendary Core"></option>
|
||||
|
@ -489,6 +489,132 @@ function updateInventory() {
|
||||
});
|
||||
});
|
||||
|
||||
// Populate quests route
|
||||
document.getElementById("QuestKeys-list").innerHTML = "";
|
||||
data.QuestKeys.forEach(item => {
|
||||
const tr = document.createElement("tr");
|
||||
tr.setAttribute("data-item-type", item.ItemType);
|
||||
const stage = item.Progress?.length ?? 0;
|
||||
|
||||
const datalist = document.getElementById("datalist-QuestKeys");
|
||||
const optionToRemove = datalist.querySelector(`option[data-key="${item.ItemType}"]`);
|
||||
if (optionToRemove) {
|
||||
datalist.removeChild(optionToRemove);
|
||||
}
|
||||
|
||||
{
|
||||
const td = document.createElement("td");
|
||||
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||
if (!item.Completed) {
|
||||
td.textContent +=
|
||||
" | " + loc("code_stage") + ": [" + stage + "/" + itemMap[item.ItemType].chainLength + "]";
|
||||
} else {
|
||||
td.textContent += " | " + loc("code_completed");
|
||||
}
|
||||
|
||||
if (data.ActiveQuest == item.ItemType) td.textContent += " | " + loc("code_active");
|
||||
tr.appendChild(td);
|
||||
}
|
||||
{
|
||||
const td = document.createElement("td");
|
||||
td.classList = "text-end text-nowrap";
|
||||
if (data.ActiveQuest == item.ItemType && !item.Completed) {
|
||||
console.log(data.ActiveQuest);
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
doQuestUpdate("setInactive", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_setInactive");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm192-96l128 0c17.7 0 32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
if (stage > 0) {
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
doQuestUpdate("resetKey", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_reset");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M463.5 224l8.5 0c13.3 0 24-10.7 24-24l0-128c0-9.7-5.8-18.5-14.8-22.2s-19.3-1.7-26.2 5.2L413.4 96.6c-87.6-86.5-228.7-86.2-315.8 1c-87.5 87.5-87.5 229.3 0 316.8s229.3 87.5 316.8 0c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0c-62.5 62.5-163.8 62.5-226.3 0s-62.5-163.8 0-226.3c62.2-62.2 162.7-62.5 225.3-1L327 183c-6.9 6.9-8.9 17.2-5.2 26.2s12.5 14.8 22.2 14.8l119.5 0z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
if (itemMap[item.ItemType].chainLength > stage && !item.Completed) {
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
doQuestUpdate("completeKey", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_complete");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
if (stage > 0 && itemMap[item.ItemType].chainLength > 1) {
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
doQuestUpdate("prevStage", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_prevStage");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
if (
|
||||
itemMap[item.ItemType].chainLength > stage &&
|
||||
!item.Completed &&
|
||||
itemMap[item.ItemType].chainLength > 1
|
||||
) {
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
doQuestUpdate("nextStage", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_nextStage");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
{
|
||||
const a = document.createElement("a");
|
||||
a.href = "#";
|
||||
a.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
const option = document.createElement("option");
|
||||
option.setAttribute("data-key", item.ItemType);
|
||||
option.value = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||
document.getElementById("datalist-QuestKeys").appendChild(option);
|
||||
doQuestUpdate("deleteKey", item.ItemType);
|
||||
};
|
||||
a.title = loc("code_remove");
|
||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
|
||||
td.appendChild(a);
|
||||
}
|
||||
tr.appendChild(td);
|
||||
}
|
||||
document.getElementById("QuestKeys-list").appendChild(tr);
|
||||
});
|
||||
|
||||
const datalistQuestKeys = document.querySelectorAll("#datalist-QuestKeys option");
|
||||
const form = document.querySelector("form[onsubmit*=\"doAcquireEquipment('QuestKeys')\"]");
|
||||
const giveAllQuestButton = document.querySelector("button[onclick*=\"doBulkQuestUpdate('giveAll')\"]");
|
||||
|
||||
if (datalistQuestKeys.length === 0) {
|
||||
form.classList.add("disabled");
|
||||
form.querySelector("input").disabled = true;
|
||||
form.querySelector("button").disabled = true;
|
||||
giveAllQuestButton.disabled = true;
|
||||
} else {
|
||||
form.classList.remove("disabled");
|
||||
form.querySelector("input").disabled = false;
|
||||
form.querySelector("button").disabled = false;
|
||||
giveAllQuestButton.disabled = false;
|
||||
}
|
||||
|
||||
// Populate mods route
|
||||
document.getElementById("riven-list").innerHTML = "";
|
||||
document.getElementById("mods-list").innerHTML = "";
|
||||
@ -1397,7 +1523,16 @@ function doAddCurrency(currency) {
|
||||
});
|
||||
}
|
||||
|
||||
function doQuestUpdate(operation) {
|
||||
function doQuestUpdate(operation, itemType) {
|
||||
$.post({
|
||||
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType,
|
||||
contentType: "application/json"
|
||||
}).then(function () {
|
||||
updateInventory();
|
||||
});
|
||||
}
|
||||
|
||||
function doBulkQuestUpdate(operation) {
|
||||
$.post({
|
||||
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation,
|
||||
contentType: "application/json"
|
||||
|
@ -45,6 +45,14 @@ dict = {
|
||||
code_zanukaA: `Jagdhund: Dorma`,
|
||||
code_zanukaB: `Jagdhund: Bhaira`,
|
||||
code_zanukaC: `Jagdhund: Hec`,
|
||||
code_stage: `[UNTRANSLATED] Stage`,
|
||||
code_complete: `[UNTRANSLATED] Complete`,
|
||||
code_nextStage: `[UNTRANSLATED] Next stage`,
|
||||
code_prevStage: `[UNTRANSLATED] Previous stage`,
|
||||
code_reset: `[UNTRANSLATED] Reset`,
|
||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
||||
code_completed: `[UNTRANSLATED] Completed`,
|
||||
code_active: `[UNTRANSLATED] Active`,
|
||||
login_description: `Melde dich mit deinem OpenWF-Account an (denselben Angaben wie im Spiel, wenn du dich mit diesem Server verbindest).`,
|
||||
login_emailLabel: `E-Mail-Adresse`,
|
||||
login_passwordLabel: `Passwort`,
|
||||
@ -84,6 +92,11 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
||||
|
||||
quests_list: `Quests`,
|
||||
quests_completeAll: `Alle Quests abschließen`,
|
||||
quests_resetAll: `Alle Quests zurücksetzen`,
|
||||
quests_giveAll: `Alle Quests erhalten`,
|
||||
|
||||
currency_RegularCredits: `Credits`,
|
||||
currency_PremiumCredits: `Platinum`,
|
||||
currency_FusionPoints: `Endo`,
|
||||
@ -135,12 +148,6 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
||||
cheats_changeButton: `Ändern`,
|
||||
cheats_none: `Keines`,
|
||||
cheats_quests: `Quests`,
|
||||
cheats_quests_unlockAll: `Alle Quests freischalten`,
|
||||
cheats_quests_completeAll: `Alle Quests abschließen`,
|
||||
cheats_quests_completeAllUnlocked: `Alle freigeschalteten Quests abschließen`,
|
||||
cheats_quests_resetAll: `Alle Quests zurücksetzen`,
|
||||
cheats_quests_giveAll: `Alle Quests erhalten`,
|
||||
import_importNote: `Du kannst hier eine vollständige oder teilweise Inventarantwort (Client-Darstellung) einfügen. Alle Felder, die vom Importer unterstützt werden, <b>werden in deinem Account überschrieben</b>.`,
|
||||
import_submit: `Absenden`,
|
||||
prettier_sucks_ass: ``
|
||||
|
@ -44,6 +44,14 @@ dict = {
|
||||
code_zanukaA: `Dorma Hound`,
|
||||
code_zanukaB: `Bhaira Hound`,
|
||||
code_zanukaC: `Hec Hound`,
|
||||
code_stage: `Stage`,
|
||||
code_complete: `Complete`,
|
||||
code_nextStage: `Next stage`,
|
||||
code_prevStage: `Previous stage`,
|
||||
code_reset: `Reset`,
|
||||
code_setInactive: `Make the quest inactive`,
|
||||
code_completed: `Completed`,
|
||||
code_active: `Active`,
|
||||
login_description: `Login using your OpenWF account credentials (same as in-game when connecting to this server).`,
|
||||
login_emailLabel: `Email address`,
|
||||
login_passwordLabel: `Password`,
|
||||
@ -83,6 +91,11 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
||||
|
||||
quests_list: `Quests`,
|
||||
quests_completeAll: `Complete All Quests`,
|
||||
quests_resetAll: `Reset All Quests`,
|
||||
quests_giveAll: `Give All Quests`,
|
||||
|
||||
currency_RegularCredits: `Credits`,
|
||||
currency_PremiumCredits: `Platinum`,
|
||||
currency_FusionPoints: `Endo`,
|
||||
@ -134,12 +147,6 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
||||
cheats_changeButton: `Change`,
|
||||
cheats_none: `None`,
|
||||
cheats_quests: `Quests`,
|
||||
cheats_quests_unlockAll: `Unlock All Quests`,
|
||||
cheats_quests_completeAll: `Complete All Quests`,
|
||||
cheats_quests_completeAllUnlocked: `Complete All Unlocked Quests`,
|
||||
cheats_quests_resetAll: `Reset All Quests`,
|
||||
cheats_quests_giveAll: `Give All Quests`,
|
||||
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.`,
|
||||
import_submit: `Submit`,
|
||||
prettier_sucks_ass: ``
|
||||
|
@ -45,6 +45,14 @@ dict = {
|
||||
code_zanukaA: `Molosse Dorma`,
|
||||
code_zanukaB: `Molosse Bhaira`,
|
||||
code_zanukaC: `Molosse Hec`,
|
||||
code_stage: `[UNTRANSLATED] Stage`,
|
||||
code_complete: `[UNTRANSLATED] Complete`,
|
||||
code_nextStage: `[UNTRANSLATED] Next stage`,
|
||||
code_prevStage: `[UNTRANSLATED] Previous stage`,
|
||||
code_reset: `[UNTRANSLATED] Reset`,
|
||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
||||
code_completed: `[UNTRANSLATED] Completed`,
|
||||
code_active: `[UNTRANSLATED] Active`,
|
||||
login_description: `Connexion avec les informations de connexion OpenWF.`,
|
||||
login_emailLabel: `Email`,
|
||||
login_passwordLabel: `Mot de passe`,
|
||||
@ -84,6 +92,11 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Toutes les Sentinelles rang max`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles rang max`,
|
||||
|
||||
quests_list: `Quêtes`,
|
||||
quests_completeAll: `Compléter toutes les quêtes`,
|
||||
quests_resetAll: `Réinitialiser toutes les quêtes`,
|
||||
quests_giveAll: `Obtenir toutes les quêtes`,
|
||||
|
||||
currency_RegularCredits: `Crédits`,
|
||||
currency_PremiumCredits: `Platinum`,
|
||||
currency_FusionPoints: `Endo`,
|
||||
@ -135,12 +148,6 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Allégeance`,
|
||||
cheats_changeButton: `Changer`,
|
||||
cheats_none: `Aucun`,
|
||||
cheats_quests: `Quêtes`,
|
||||
cheats_quests_unlockAll: `Débloquer toutes les quêtes`,
|
||||
cheats_quests_completeAll: `Compléter toutes les quêtes`,
|
||||
cheats_quests_completeAllUnlocked: `Compléter toutes les quêtes déverrouillées`,
|
||||
cheats_quests_resetAll: `Réinitialiser toutes les quêtes`,
|
||||
cheats_quests_giveAll: `Obtenir toutes les quêtes`,
|
||||
import_importNote: `Import manuel. Toutes les modifcations supportées par l'inventaire <b>écraseront celles présentes dans la base de données</b>.`,
|
||||
import_submit: `Soumettre`,
|
||||
prettier_sucks_ass: ``
|
||||
|
@ -45,6 +45,14 @@ dict = {
|
||||
code_zanukaA: `Гончая: Дорма`,
|
||||
code_zanukaB: `Гончая: Бхайра`,
|
||||
code_zanukaC: `Гончая: Хек`,
|
||||
code_stage: `Этап`,
|
||||
code_complete: `Завершить`,
|
||||
code_nextStage: `Cледующий этап`,
|
||||
code_prevStage: `Предыдущий этап`,
|
||||
code_reset: `Сбросить`,
|
||||
code_setInactive: `Сделать квест неактивным`,
|
||||
code_completed: `Завершено`,
|
||||
code_active: `Активный`,
|
||||
login_description: `Войдите, используя учетные данные OpenWF (те же, что и в игре при подключении к этому серверу).`,
|
||||
login_emailLabel: `Адрес электронной почты`,
|
||||
login_passwordLabel: `Пароль`,
|
||||
@ -84,6 +92,11 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
|
||||
|
||||
quests_list: `Квесты`,
|
||||
quests_completeAll: `Завершить все квесты`,
|
||||
quests_resetAll: `Сбросить прогресс всех квестов`,
|
||||
quests_giveAll: `Выдать все квесты`,
|
||||
|
||||
currency_RegularCredits: `Кредиты`,
|
||||
currency_PremiumCredits: `Платина`,
|
||||
currency_FusionPoints: `Эндо`,
|
||||
@ -135,12 +148,6 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
||||
cheats_changeButton: `Изменить`,
|
||||
cheats_none: `Отсутствует`,
|
||||
cheats_quests: `Квесты`,
|
||||
cheats_quests_unlockAll: `Разблокировать все квесты`,
|
||||
cheats_quests_completeAll: `Завершить все квесты`,
|
||||
cheats_quests_completeAllUnlocked: `Завершить все разблокированые квесты`,
|
||||
cheats_quests_resetAll: `Сбросить прогресс всех квестов`,
|
||||
cheats_quests_giveAll: `Выдать все квесты`,
|
||||
import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
|
||||
import_submit: `Отправить`,
|
||||
prettier_sucks_ass: ``
|
||||
|
@ -45,6 +45,14 @@ dict = {
|
||||
code_zanukaA: `铎玛猎犬`,
|
||||
code_zanukaB: `拜拉猎犬`,
|
||||
code_zanukaC: `骸克猎犬`,
|
||||
code_stage: `[UNTRANSLATED] Stage`,
|
||||
code_complete: `[UNTRANSLATED] Complete`,
|
||||
code_nextStage: `[UNTRANSLATED] Next stage`,
|
||||
code_prevStage: `[UNTRANSLATED] Previous stage`,
|
||||
code_reset: `[UNTRANSLATED] Reset`,
|
||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
||||
code_completed: `[UNTRANSLATED] Completed`,
|
||||
code_active: `[UNTRANSLATED] Active`,
|
||||
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`,
|
||||
login_emailLabel: `电子邮箱`,
|
||||
login_passwordLabel: `密码`,
|
||||
@ -84,6 +92,11 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
||||
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
||||
|
||||
quests_list: `任务`,
|
||||
quests_completeAll: `完成所有任务`,
|
||||
quests_resetAll: `重置所有任务`,
|
||||
quests_giveAll: `授予所有任务`,
|
||||
|
||||
currency_RegularCredits: `现金`,
|
||||
currency_PremiumCredits: `白金`,
|
||||
currency_FusionPoints: `内融核心`,
|
||||
@ -135,12 +148,6 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||
cheats_changeButton: `更改`,
|
||||
cheats_none: `无`,
|
||||
cheats_quests: `任务`,
|
||||
cheats_quests_unlockAll: `解锁所有任务`,
|
||||
cheats_quests_completeAll: `完成所有任务`,
|
||||
cheats_quests_completeAllUnlocked: `完成所有已解锁任务`,
|
||||
cheats_quests_resetAll: `重置所有任务`,
|
||||
cheats_quests_giveAll: `授予所有任务`,
|
||||
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
|
||||
import_submit: `提交`,
|
||||
prettier_sucks_ass: ``
|
||||
|
Loading…
x
Reference in New Issue
Block a user