diff --git a/src/app.ts b/src/app.ts index c8b19583..291372f0 100644 --- a/src/app.ts +++ b/src/app.ts @@ -26,7 +26,7 @@ app.use((req, _res, next) => { app.use(bodyParser.raw()); app.use(express.json({ limit: "4mb" })); -app.use(bodyParser.text()); +app.use(bodyParser.text({ limit: "4mb" })); app.use(requestLogger); app.use("/api", apiRouter); diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index bede097f..ab739c4c 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -14,7 +14,12 @@ import { ExportVirtuals } from "warframe-public-export-plus"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService"; -import { addMiscItems, allDailyAffiliationKeys, createLibraryDailyTask } from "@/src/services/inventoryService"; +import { + addMiscItems, + allDailyAffiliationKeys, + cleanupInventory, + createLibraryDailyTask +} from "@/src/services/inventoryService"; import { logger } from "@/src/utils/logger"; import { catBreadHash } from "@/src/helpers/stringHelpers"; @@ -79,6 +84,8 @@ export const inventoryController: RequestHandler = async (request, response) => } } + cleanupInventory(inventory); + inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000); await inventory.save(); } diff --git a/src/controllers/api/saveDialogueController.ts b/src/controllers/api/saveDialogueController.ts index 7d7d6380..49cc605c 100644 --- a/src/controllers/api/saveDialogueController.ts +++ b/src/controllers/api/saveDialogueController.ts @@ -12,22 +12,17 @@ export const saveDialogueController: RequestHandler = async (req, res) => { const request = JSON.parse(String(req.body)) as SaveDialogueRequest; if ("YearIteration" in request) { const inventory = await getInventory(accountId, "DialogueHistory"); - if (inventory.DialogueHistory) { - inventory.DialogueHistory.YearIteration = request.YearIteration; - } else { - inventory.DialogueHistory = { YearIteration: request.YearIteration }; - } + inventory.DialogueHistory ??= {}; + inventory.DialogueHistory.YearIteration = request.YearIteration; await inventory.save(); res.end(); } else { const inventory = await getInventory(accountId); - if (!inventory.DialogueHistory) { - throw new Error("bad inventory state"); - } const inventoryChanges: IInventoryChanges = {}; const tomorrowAt0Utc = config.noKimCooldowns ? Date.now() : (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000; + inventory.DialogueHistory ??= {}; inventory.DialogueHistory.Dialogues ??= []; const dialogue = getDialogue(inventory, request.DialogueName); dialogue.Rank = request.Rank; diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index 214c51e7..1ff78b62 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -29,6 +29,7 @@ interface ListedItem { badReason?: "starter" | "frivolous" | "notraw"; partType?: string; chainLength?: number; + parazon?: boolean; } const relicQualitySuffixes: Record = { @@ -68,7 +69,8 @@ const getItemListsController: RequestHandler = (req, response) => { if (item.productCategory != "SpecialItems") { res[item.productCategory].push({ uniqueName, - name: getString(item.name, lang) + name: getString(item.name, lang), + exalted: item.exalted }); } } @@ -196,6 +198,9 @@ const getItemListsController: RequestHandler = (req, response) => { } else if (upgrade.upgradeEntries) { mod.badReason = "notraw"; } + if (upgrade.type == "PARAZON") { + mod.parazon = true; + } res.mods.push(mod); } for (const [uniqueName, upgrade] of Object.entries(ExportAvionics)) { diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 775de04a..6b73186f 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -909,7 +909,7 @@ dialogueSchema.set("toJSON", { const dialogueHistorySchema = new Schema( { - YearIteration: { type: Number, required: true }, + YearIteration: Number, Resets: Number, Dialogues: { type: [dialogueSchema], required: false } }, diff --git a/src/services/importService.ts b/src/services/importService.ts index ea03047b..cde182cc 100644 --- a/src/services/importService.ts +++ b/src/services/importService.ts @@ -37,6 +37,7 @@ import { } from "../types/inventoryTypes/inventoryTypes"; import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel"; import { ILoadoutConfigDatabase, ILoadoutDatabase } from "../types/saveLoadoutTypes"; +import { slotNames } from "../types/purchaseTypes"; const convertDate = (value: IMongoDate): Date => { return new Date(parseInt(value.$date.$numberLong)); @@ -212,20 +213,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial< replaceArray(db[key], client[key].map(convertOperatorConfig)); } } - for (const key of [ - "SuitBin", - "WeaponBin", - "SentinelBin", - "SpaceSuitBin", - "SpaceWeaponBin", - "PvpBonusLoadoutBin", - "PveBonusLoadoutBin", - "RandomModBin", - "MechBin", - "CrewMemberBin", - "OperatorAmpBin", - "CrewShipSalvageBin" - ] as const) { + for (const key of slotNames) { if (client[key] !== undefined) { replaceSlots(db[key], client[key]); } diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index fd6a597b..9e89dcfe 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -87,9 +87,7 @@ export const createInventory = async ( const inventory = new Inventory({ accountOwnerId: accountOwnerId, LoadOutPresets: defaultItemReferences.loadOutPresetId, - Ships: [defaultItemReferences.ship], - PlayedParkourTutorial: config.skipTutorial, - ReceivedStartingGear: config.skipTutorial + Ships: [defaultItemReferences.ship] }); inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask(); @@ -102,6 +100,7 @@ export const createInventory = async ( await addItem(inventory, "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords"); if (config.skipTutorial) { + inventory.PlayedParkourTutorial = true; await addStartingGear(inventory); await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain"); @@ -1769,3 +1768,23 @@ export const setupKahlSyndicate = (inventory: TInventoryDatabaseDocument): void Tag: "KahlSyndicate" }); }; + +export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void => { + let index = inventory.MiscItems.findIndex(x => x.ItemType == ""); + if (index != -1) { + inventory.MiscItems.splice(index, 1); + } + + index = inventory.Affiliations.findIndex(x => x.Tag == "KahlSyndicate"); + if (index != -1 && !inventory.Affiliations[index].WeeklyMissions) { + logger.debug(`KahlSyndicate seems broken, removing it and setting up again`); + inventory.Affiliations.splice(index, 1); + setupKahlSyndicate(inventory); + } + + const LibrarySyndicate = inventory.Affiliations.find(x => x.Tag == "LibrarySyndicate"); + if (LibrarySyndicate && LibrarySyndicate.FreeFavorsEarned) { + logger.debug(`removing FreeFavorsEarned from LibrarySyndicate`); + LibrarySyndicate.FreeFavorsEarned = undefined; + } +}; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 4dcb0fe4..46d039c1 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -55,6 +55,7 @@ import { Loadout } from "../models/inventoryModels/loadoutModel"; import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes"; import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService"; import { config } from "./configService"; +import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => { // For Spy missions, e.g. 3 vaults cracked = A, B, C @@ -331,35 +332,36 @@ export const addMissionInventoryUpdates = async ( case "LibraryScans": value.forEach(scan => { let synthesisIgnored = true; - if ( - inventory.LibraryPersonalTarget && - libraryPersonalTargetToAvatar[inventory.LibraryPersonalTarget] == scan.EnemyType - ) { - let progress = inventory.LibraryPersonalProgress.find( - x => x.TargetType == inventory.LibraryPersonalTarget - ); - if (!progress) { - progress = - inventory.LibraryPersonalProgress[ - inventory.LibraryPersonalProgress.push({ - TargetType: inventory.LibraryPersonalTarget, - Scans: 0, - Completed: false - }) - 1 - ]; + if (inventory.LibraryPersonalTarget) { + const taskAvatar = libraryPersonalTargetToAvatar[inventory.LibraryPersonalTarget]; + const taskAvatars = libraryDailyTasks.find(x => x.indexOf(taskAvatar) != -1)!; + if (taskAvatars.indexOf(scan.EnemyType) != -1) { + let progress = inventory.LibraryPersonalProgress.find( + x => x.TargetType == inventory.LibraryPersonalTarget + ); + if (!progress) { + progress = + inventory.LibraryPersonalProgress[ + inventory.LibraryPersonalProgress.push({ + TargetType: inventory.LibraryPersonalTarget, + Scans: 0, + Completed: false + }) - 1 + ]; + } + progress.Scans += scan.Count; + if ( + progress.Scans >= + (inventory.LibraryPersonalTarget == + "/Lotus/Types/Game/Library/Targets/DragonframeQuestTarget" + ? 3 + : 10) + ) { + progress.Completed = true; + } + logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`); + synthesisIgnored = false; } - progress.Scans += scan.Count; - if ( - progress.Scans >= - (inventory.LibraryPersonalTarget == - "/Lotus/Types/Game/Library/Targets/DragonframeQuestTarget" - ? 3 - : 10) - ) { - progress.Completed = true; - } - logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`); - synthesisIgnored = false; } if ( inventory.LibraryActiveDailyTaskInfo && diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index d8cd0c3c..e1946f7a 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -4,14 +4,7 @@ import { unixTimesInMs } from "@/src/constants/timeConstants"; import { config } from "@/src/services/configService"; import { CRng } from "@/src/services/rngService"; import { eMissionType, ExportNightwave, ExportRegions } from "warframe-public-export-plus"; -import { - ICalendarDay, - ICalendarSeason, - ILiteSortie, - ISeasonChallenge, - ISortie, - IWorldState -} from "../types/worldStateTypes"; +import { ICalendarDay, ICalendarSeason, ILiteSortie, ISeasonChallenge, IWorldState } from "../types/worldStateTypes"; const sortieBosses = [ "SORTIE_BOSS_HYENA", @@ -174,7 +167,47 @@ const getSortieTime = (day: number): number => { return dayStart + (isDst ? 16 : 17) * 3600000; }; -const pushSortieIfRelevant = (out: ISortie[], day: number): void => { +const pushSyndicateMissions = ( + worldState: IWorldState, + day: number, + seed: number, + idSuffix: string, + syndicateTag: string +): void => { + const nodeOptions: string[] = []; + for (const [key, value] of Object.entries(ExportRegions)) { + if ( + value.name.indexOf("Archwing") == -1 && // no archwing + value.systemIndex != 23 && // no 1999 stuff + value.missionIndex != 10 && // Exclude MT_PVP (for relays) + value.missionIndex != 23 && // no junctions + value.missionIndex <= 28 // no railjack or some such + ) { + nodeOptions.push(key); + } + } + + const rng = new CRng(seed); + const nodes: string[] = []; + for (let i = 0; i != 6; ++i) { + const index = rng.randomInt(0, nodeOptions.length - 1); + nodes.push(nodeOptions[index]); + nodeOptions.splice(index, 1); + } + + const dayStart = getSortieTime(day); + const dayEnd = getSortieTime(day + 1); + worldState.SyndicateMissions.push({ + _id: { $oid: Math.trunc(dayStart / 1000).toString(16) + idSuffix }, + Activation: { $date: { $numberLong: dayStart.toString() } }, + Expiry: { $date: { $numberLong: dayEnd.toString() } }, + Tag: syndicateTag, + Seed: seed, + Nodes: nodes + }); +}; + +const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { const dayStart = getSortieTime(day); if (!isBeforeNextExpectedWorldStateRefresh(dayStart)) { return; @@ -231,7 +264,9 @@ const pushSortieIfRelevant = (out: ISortie[], day: number): void => { value.name.indexOf("Archwing") == -1 && value.missionIndex != 0 && // Exclude MT_ASSASSINATION value.missionIndex != 5 && // Exclude MT_CAPTURE + value.missionIndex != 10 && // Exclude MT_PVP (for relays) value.missionIndex != 21 && // Exclude MT_PURIFY + value.missionIndex != 22 && // Exclude MT_ARENA value.missionIndex != 23 && // Exclude MT_JUNCTION value.missionIndex <= 28 ) { @@ -291,7 +326,7 @@ const pushSortieIfRelevant = (out: ISortie[], day: number): void => { missionTypes.add(missionType); } - out.push({ + worldState.Sorties.push({ _id: { $oid: Math.trunc(dayStart / 1000).toString(16) + "d4d932c97c0a3acd" }, Activation: { $date: { $numberLong: dayStart.toString() } }, Expiry: { $date: { $numberLong: dayEnd.toString() } }, @@ -300,6 +335,13 @@ const pushSortieIfRelevant = (out: ISortie[], day: number): void => { Boss: boss, Variants: selectedNodes }); + + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa48049", "ArbitersSyndicate"); + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa4804a", "CephalonSudaSyndicate"); + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa4804e", "NewLokaSyndicate"); + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa48050", "PerrinSyndicate"); + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa4805e", "RedVeilSyndicate"); + pushSyndicateMissions(worldState, day, rng.randomInt(0, 0xffff), "ba6f84724fa48061", "SteelMeridianSyndicate"); }; const dailyChallenges = Object.keys(ExportNightwave.challenges).filter(x => @@ -952,9 +994,9 @@ export const getWorldState = (buildLabel?: string): IWorldState => { }); } - // Sortie cycling every day - pushSortieIfRelevant(worldState.Sorties, day - 1); - pushSortieIfRelevant(worldState.Sorties, day); + // Sortie & syndicate missions cycling every day (at 16:00 or 17:00 UTC depending on if London, OT is observing DST) + pushSortieIfRelevant(worldState, day - 1); + pushSortieIfRelevant(worldState, day); // Archon Hunt cycling every week worldState.LiteSorties.push(getLiteSortie(week)); diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 219f43a5..8ddfbf42 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -1130,13 +1130,13 @@ export interface IEndlessXpProgress { } export interface IDialogueHistoryClient { - YearIteration: number; + YearIteration?: number; Resets?: number; // added in 38.5.0 Dialogues?: IDialogueClient[]; } export interface IDialogueHistoryDatabase { - YearIteration: number; + YearIteration?: number; Resets?: number; Dialogues?: IDialogueDatabase[]; } diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index 3600e6b7..8cb92ccc 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -103,6 +103,7 @@ export const slotNames = [ "WeaponBin", "MechBin", "PveBonusLoadoutBin", + "PvpBonusLoadoutBin", "SentinelBin", "SpaceSuitBin", "SpaceWeaponBin", diff --git a/static/fixed_responses/worldState/worldState.json b/static/fixed_responses/worldState/worldState.json index dd76dd56..9adb9556 100644 --- a/static/fixed_responses/worldState/worldState.json +++ b/static/fixed_responses/worldState/worldState.json @@ -63,22 +63,6 @@ } ], "SyndicateMissions": [ - { - "_id": { "$oid": "663a4fc5ba6f84724fa48049" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "ArbitersSyndicate", - "Seed": 24491, - "Nodes": ["SolNode223", "SolNode89", "SolNode146", "SolNode212", "SolNode167", "SolNode48", "SolNode78"] - }, - { - "_id": { "$oid": "663a4fc5ba6f84724fa4804a" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "CephalonSudaSyndicate", - "Seed": 12770, - "Nodes": ["SolNode36", "SolNode59", "SettlementNode12", "SolNode61", "SolNode12", "SolNode138", "SolNode72"] - }, { "_id": { "$oid": "663a4fc5ba6f84724fa4804c" }, "Activation": { "$date": { "$numberLong": "1715097541439" } }, @@ -103,14 +87,6 @@ "Seed": 50102, "Nodes": [] }, - { - "_id": { "$oid": "663a4fc5ba6f84724fa4804e" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "NewLokaSyndicate", - "Seed": 16064, - "Nodes": ["SolNode101", "SolNode224", "SolNode205", "SettlementNode2", "SolNode171", "SolNode188", "SolNode75"] - }, { "_id": { "$oid": "663a4fc5ba6f84724fa4804f" }, "Activation": { "$date": { "$numberLong": "1715097541439" } }, @@ -119,14 +95,6 @@ "Seed": 77721, "Nodes": [] }, - { - "_id": { "$oid": "663a4fc5ba6f84724fa48050" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "PerrinSyndicate", - "Seed": 9940, - "Nodes": ["SolNode39", "SolNode14", "SolNode203", "SolNode100", "SolNode130", "SolNode64", "SettlementNode15"] - }, { "_id": { "$oid": "663a4fc5ba6f84724fa48052" }, "Activation": { "$date": { "$numberLong": "1715097541439" } }, @@ -255,14 +223,6 @@ "Seed": 67257, "Nodes": [] }, - { - "_id": { "$oid": "663a4fc5ba6f84724fa4805e" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "RedVeilSyndicate", - "Seed": 46649, - "Nodes": ["SolNode226", "SolNode79", "SolNode216", "SettlementNode11", "SolNode56", "SolNode41", "SolNode23"] - }, { "_id": { "$oid": "663a4fc5ba6f84724fa48060" }, "Activation": { "$date": { "$numberLong": "1715097541439" } }, @@ -270,14 +230,6 @@ "Tag": "VoxSyndicate", "Seed": 77972, "Nodes": [] - }, - { - "_id": { "$oid": "663a4fc5ba6f84724fa48061" }, - "Activation": { "$date": { "$numberLong": "1715097541439" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Tag": "SteelMeridianSyndicate", - "Seed": 42366, - "Nodes": ["SolNode27", "SolNode107", "SolNode214", "SettlementNode1", "SolNode177", "SolNode141", "SolNode408"] } ], "ActiveMissions": [ diff --git a/static/webui/index.html b/static/webui/index.html index 5df7ba59..65a9d832 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -85,6 +85,7 @@
+
@@ -490,8 +491,9 @@
-
+
+
diff --git a/static/webui/script.js b/static/webui/script.js index 2e4477bb..7868e189 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -1,8 +1,15 @@ +let loginOrRegisterPending = false; +window.registerSubmit = false; + function doLogin() { + if (loginOrRegisterPending) { + return; + } + loginOrRegisterPending = true; localStorage.setItem("email", $("#email").val()); localStorage.setItem("password", $("#password").val()); - $("#email, #password").val(""); loginFromLocalStorage(); + registerSubmit = false; } function loginFromLocalStorage() { @@ -37,12 +44,15 @@ function doLoginRequest(succ_cb, fail_cb) { s: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==", // signature of some kind lang: "en", date: 1501230947855458660, // ??? - ClientType: "webui", + ClientType: registerSubmit ? "" : "webui", PS: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==" // anti-cheat data }) }); req.done(succ_cb); req.fail(fail_cb); + req.always(() => { + loginOrRegisterPending = false; + }); } function revalidateAuthz(succ_cb) { @@ -436,17 +446,35 @@ function updateInventory() { category != "SpaceSuits" && category != "Sentinels" && category != "Hoverboards" && - category != "MechSuits" + category != "MechSuits" && + category != "MoaPets" && + category != "KubrowPets" ) { maxXP /= 2; } - if (item.XP < maxXP) { + let anyExaltedMissingXP = false; + if (item.XP >= maxXP && "exalted" in itemMap[item.ItemType]) { + for (const exaltedType of itemMap[item.ItemType].exalted) { + const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); + if (exaltedItem) { + const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; + if (exaltedItem.XP < exaltedCap) { + anyExaltedMissingXP = true; + break; + } + } + } + } + + if (item.XP < maxXP || anyExaltedMissingXP) { const a = document.createElement("a"); a.href = "#"; a.onclick = function (event) { event.preventDefault(); - addGearExp(category, item.ItemId.$oid, maxXP - item.XP); + if (item.XP < maxXP) { + addGearExp(category, item.ItemId.$oid, maxXP - item.XP); + } if ("exalted" in itemMap[item.ItemType]) { for (const exaltedType of itemMap[item.ItemType].exalted) { const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); @@ -786,7 +814,7 @@ function updateInventory() { { const td = document.createElement("td"); td.classList = "text-end text-nowrap"; - { + if (maxRank != 0) { const a = document.createElement("a"); a.href = "#"; a.onclick = function (event) { @@ -1594,6 +1622,31 @@ function doAddAllMods() { }); } +function doRemoveUnrankedMods() { + revalidateAuthz(() => { + const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); + req.done(inventory => { + window.itemListPromise.then(itemMap => { + $.post({ + url: "/api/sell.php?" + window.authz, + contentType: "text/plain", + data: JSON.stringify({ + SellCurrency: "SC_RegularCredits", + SellPrice: 0, + Items: { + Upgrades: inventory.RawUpgrades.filter( + x => !itemMap[x.ItemType]?.parazon && x.ItemCount > 0 + ).map(x => ({ String: x.ItemType, Count: x.ItemCount })) + } + }) + }).done(function () { + updateInventory(); + }); + }); + }); + }); +} + // Powersuit Route single.getRoute("#powersuit-route").on("beforeload", function () { diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 061da9c4..b8725e00 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -54,12 +54,13 @@ dict = { code_completed: `Abgeschlossen`, code_active: `Aktiv`, code_pigment: `Pigment`, - code_mature: `[UNTRANSLATED] Mature for combat`, - code_unmature: `[UNTRANSLATED] Regress genetic aging`, + code_mature: `Für den Kampf auswachsen lassen`, + code_unmature: `Genetisches Altern zurücksetzen`, 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`, login_loginButton: `Anmelden`, + login_registerButton: `[UNTRANSLATED] Register`, navbar_logout: `Abmelden`, navbar_renameAccount: `Account umbenennen`, navbar_deleteAccount: `Account löschen`, @@ -82,7 +83,7 @@ dict = { inventory_operatorAmps: `Verstärker`, inventory_hoverboards: `K-Drives`, inventory_moaPets: `Moa`, - inventory_kubrowPets: `[UNTRANSLATED] Beasts`, + inventory_kubrowPets: `Bestien`, inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`, inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`, inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`, @@ -115,6 +116,7 @@ dict = { mods_rivens: `Rivens`, mods_mods: `Mods`, mods_bulkAddMods: `Fehlende Mods hinzufügen`, + mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`, cheats_administratorRequirement: `Du musst Administrator sein, um diese Funktion nutzen zu können. Um Administrator zu werden, füge |DISPLAYNAME| zu administratorNames in der config.json hinzu.`, cheats_server: `Server`, cheats_skipTutorial: `Tutorial überspringen`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index cd27b42d..23b8133a 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -59,6 +59,7 @@ dict = { login_emailLabel: `Email address`, login_passwordLabel: `Password`, login_loginButton: `Login`, + login_registerButton: `Register`, navbar_logout: `Logout`, navbar_renameAccount: `Rename Account`, navbar_deleteAccount: `Delete Account`, @@ -114,6 +115,7 @@ dict = { mods_rivens: `Rivens`, mods_mods: `Mods`, mods_bulkAddMods: `Add Missing Mods`, + mods_removeUnranked: `Remove Unranked Mods`, cheats_administratorRequirement: `You must be an administrator to use this feature. To become an administrator, add |DISPLAYNAME| to administratorNames in the config.json.`, cheats_server: `Server`, cheats_skipTutorial: `Skip Tutorial`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 96916759..222534cd 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -60,6 +60,7 @@ dict = { login_emailLabel: `Dirección de correo electrónico`, login_passwordLabel: `Contraseña`, login_loginButton: `Iniciar sesión`, + login_registerButton: `[UNTRANSLATED] Register`, navbar_logout: `Cerrar sesión`, navbar_renameAccount: `Renombrar cuenta`, navbar_deleteAccount: `Eliminar cuenta`, @@ -115,6 +116,7 @@ dict = { mods_rivens: `Agrietados`, mods_mods: `Mods`, mods_bulkAddMods: `Agregar mods faltantes`, + mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`, cheats_administratorRequirement: `Debes ser administrador para usar esta función. Para convertirte en administrador, agrega |DISPLAYNAME| a administratorNames en el archivo config.json.`, cheats_server: `Servidor`, cheats_skipTutorial: `Omitir tutorial`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index bf76ac9e..682086aa 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -25,10 +25,10 @@ dict = { code_renamePrompt: `Nouveau nom :`, code_remove: `Retirer`, code_addItemsConfirm: `Ajouter |COUNT| items à l'inventaire ?`, - code_succRankUp: `[UNTRANSLATED] Successfully ranked up.`, - code_noEquipmentToRankUp: `No equipment to rank up.`, + code_succRankUp: `Montée de niveau effectuée.`, + code_noEquipmentToRankUp: `Aucun équipement à monter de niveau.`, code_succAdded: `Ajouté.`, - code_succRemoved: `[UNTRANSLATED] Successfully removed.`, + code_succRemoved: `Retiré.`, code_buffsNumber: `Nombre de buffs`, code_cursesNumber: `Nombre de débuffs`, code_rerollsNumber: `Nombre de rerolls`, @@ -45,21 +45,22 @@ 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`, + code_stage: `Étape`, + code_complete: `Compléter`, + code_nextStage: `Étape suivante`, + code_prevStage: `Étape précédente`, + code_reset: `Réinitialiser`, + code_setInactive: `Rendre la quête inactive`, + code_completed: `Complétée`, + code_active: `Active`, code_pigment: `Pigment`, - code_mature: `[UNTRANSLATED] Mature for combat`, - code_unmature: `[UNTRANSLATED] Regress genetic aging`, + code_mature: `Maturer pour le combat`, + code_unmature: `Régrésser l'âge génétique`, login_description: `Connexion avec les informations de connexion OpenWF.`, login_emailLabel: `Email`, login_passwordLabel: `Mot de passe`, login_loginButton: `Connexion`, + login_registerButton: `[UNTRANSLATED] Register`, navbar_logout: `Déconnexion`, navbar_renameAccount: `Renommer le compte`, navbar_deleteAccount: `Supprimer le compte`, @@ -82,7 +83,7 @@ dict = { inventory_operatorAmps: `Amplificateurs`, inventory_hoverboards: `K-Drives`, inventory_moaPets: `Moa`, - inventory_kubrowPets: `[UNTRANSLATED] Beasts`, + inventory_kubrowPets: `Bêtes`, inventory_bulkAddSuits: `Ajouter les Warframes manquantes`, inventory_bulkAddWeapons: `Ajouter les armes manquantes`, inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`, @@ -107,14 +108,15 @@ dict = { currency_PrimeTokens: `Aya Raffiné`, currency_owned: `|COUNT| possédés.`, powersuit_archonShardsLabel: `Emplacements de fragments d'Archonte`, - powersuit_archonShardsDescription: `Slots illimités pour appliquer plusieurs améliorations.`, - powersuit_archonShardsDescription2: `[UNTRANSLATED] Note that each archon shard takes some time to be applied when loading in.`, + powersuit_archonShardsDescription: `Slots illimités pour appliquer plusieurs améliorations`, + powersuit_archonShardsDescription2: `Un délai sera présent entre l'application des éclats et le chargement en jeu.`, mods_addRiven: `Ajouter un riven`, mods_fingerprint: `Empreinte`, mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`, mods_rivens: `Rivens`, mods_mods: `Mods`, mods_bulkAddMods: `Ajouter les mods manquants`, + mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`, cheats_administratorRequirement: `Rôle d'administrateur requis pour cette fonctionnalité. Ajoutez |DISPLAYNAME| à la ligne administratorNames dans le fichier config.json.`, cheats_server: `Serveur`, cheats_skipTutorial: `Passer le tutoriel`, @@ -131,32 +133,32 @@ dict = { cheats_unlockAllFlavourItems: `Débloquer tous les Flavor Items`, cheats_unlockAllSkins: `Débloquer tous les skins`, cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`, - cheats_unlockAllDecoRecipes: `[UNTRANSLATED] Unlock All Dojo Deco Recipes`, + cheats_unlockAllDecoRecipes: `Débloquer toutes les recherches dojo`, cheats_universalPolarityEverywhere: `Polarités universelles partout`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Réacteurs et Catalyseurs partout`, cheats_unlockExilusEverywhere: `Adaptateurs Exilus partout`, cheats_unlockArcanesEverywhere: `Adaptateur d'Arcanes partout`, - cheats_noDailyStandingLimits: `Pas de limite de réputation journalière`, - cheats_noDailyFocusLimit: `[UNTRANSLATED] No Daily Focus Limits`, - cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`, - cheats_noMasteryRankUpCooldown: `[UNTRANSLATED] No Mastery Rank Up Cooldown`, - cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, - cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, - cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`, - cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`, - cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`, - cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`, - cheats_noDojoDecoBuildStage: `[UNTRANSLATED] No Dojo Deco Build Stage`, - cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`, + cheats_noDailyStandingLimits: `Aucune limite de réputation journalière`, + cheats_noDailyFocusLimit: `Aucune limite journalière de focus`, + cheats_noArgonCrystalDecay: `Aucune désintégration des Cristaux d'Argon`, + cheats_noMasteryRankUpCooldown: `Aucune attente pour la montée de rang de maîtrise`, + cheats_noVendorPurchaseLimits: `Aucune limite d'achat chez les PNJ`, + cheats_noDeathMarks: `Aucune marque d'assassin`, + cheats_noKimCooldowns: `Aucun cooldown sur le KIM`, + cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`, + cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`, + cheats_noDojoRoomBuildStage: `Aucune attente (construction des salles)`, + cheats_noDojoDecoBuildStage: `Aucune attente (construction des décorations)`, + cheats_fastDojoRoomDestruction: `Destruction de salle instantanée (Dojo)`, cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`, cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`, - cheats_fastClanAscension: `[UNTRANSLATED] Fast Clan Ascension`, - cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, + cheats_fastClanAscension: `Ascension de clan rapide`, + cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`, cheats_saveSettings: `Sauvegarder les paramètres`, cheats_account: `Compte`, cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`, cheats_helminthUnlockAll: `Helminth niveau max`, - cheats_intrinsicsUnlockAll: `[UNTRANSLATED] Max Rank All Intrinsics`, + cheats_intrinsicsUnlockAll: `Inhérences niveau max`, cheats_changeSupportedSyndicate: `Allégeance`, cheats_changeButton: `Changer`, cheats_none: `Aucun`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index b299c14c..959678f3 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -60,6 +60,7 @@ dict = { login_emailLabel: `Адрес электронной почты`, login_passwordLabel: `Пароль`, login_loginButton: `Войти`, + login_registerButton: `[UNTRANSLATED] Register`, navbar_logout: `Выйти`, navbar_renameAccount: `Переименовать аккаунт`, navbar_deleteAccount: `Удалить аккаунт`, @@ -108,13 +109,14 @@ dict = { currency_owned: `У тебя |COUNT|.`, powersuit_archonShardsLabel: `Ячейки осколков архонта`, powersuit_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`, - powersuit_archonShardsDescription2: `[UNTRANSLATED] Note that each archon shard takes some time to be applied when loading in.`, + powersuit_archonShardsDescription2: `Обратите внимание: каждый фрагмент архонта применяется с задержкой при загрузке.`, mods_addRiven: `Добавить Мод Разлома`, mods_fingerprint: `Отпечаток`, mods_fingerprintHelp: `Нужна помощь с отпечатком?`, mods_rivens: `Моды Разлома`, mods_mods: `Моды`, mods_bulkAddMods: `Добавить отсутствующие моды`, + mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`, cheats_administratorRequirement: `Вы должны быть администратором для использования этой функции. Чтобы стать администратором, добавьте \"|DISPLAYNAME|\" в administratorNames в config.json.`, cheats_server: `Сервер`, cheats_skipTutorial: `Пропустить обучение`, @@ -136,15 +138,15 @@ dict = { cheats_unlockDoubleCapacityPotatoesEverywhere: `Катализаторы везде`, cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`, cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`, - cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`, - cheats_noDailyFocusLimit: `[UNTRANSLATED] No Daily Focus Limits`, + cheats_noDailyStandingLimits: `Без ежедневных лимитов репутации`, + cheats_noDailyFocusLimit: `Без ежедневных лимитов фокуса`, cheats_noArgonCrystalDecay: `Без распада аргоновых кристаллов`, cheats_noMasteryRankUpCooldown: `Повышение ранга мастерства без кулдауна`, cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`, - cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, - cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`, + cheats_noDeathMarks: `Без меток сметри`, + cheats_noKimCooldowns: `Чаты KIM без кулдауна`, cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`, - cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`, + cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`, cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`, cheats_noDojoDecoBuildStage: `Мгновенное Строительтво Декораций Додзё`, cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index f97ec5d2..3f0e01f5 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -60,6 +60,7 @@ dict = { login_emailLabel: `电子邮箱`, login_passwordLabel: `密码`, login_loginButton: `登录`, + login_registerButton: `[UNTRANSLATED] Register`, navbar_logout: `退出登录`, navbar_renameAccount: `重命名账户`, navbar_deleteAccount: `删除账户`, @@ -115,6 +116,7 @@ dict = { mods_rivens: `裂罅MOD`, mods_mods: `Mods`, mods_bulkAddMods: `添加缺失MOD`, + mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`, cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请将 |DISPLAYNAME| 添加到 config.json 的 administratorNames 中。`, cheats_server: `服务器`, cheats_skipTutorial: `跳过教程`,