diff --git a/src/controllers/custom/updateFingerprintController.ts b/src/controllers/custom/updateFingerprintController.ts new file mode 100644 index 00000000..df82d412 --- /dev/null +++ b/src/controllers/custom/updateFingerprintController.ts @@ -0,0 +1,39 @@ +import { getInventory } from "@/src/services/inventoryService"; +import { WeaponTypeInternal } from "@/src/services/itemDataService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { RequestHandler } from "express"; + +export const updateFingerprintController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const request = req.body as IUpdateFingerPrintRequest; + const inventory = await getInventory(accountId, request.category); + const item = inventory[request.category].id(request.oid); + if (item) { + if (request.action == "set" && request.upgradeFingerprint.buffs[0].Tag) { + const newUpgradeFingerprint = request.upgradeFingerprint; + if (!newUpgradeFingerprint.compact) newUpgradeFingerprint.compact = item.ItemType; + + item.UpgradeType = request.upgradeType; + item.UpgradeFingerprint = JSON.stringify(newUpgradeFingerprint); + } else if (request.action == "remove") { + item.UpgradeFingerprint = undefined; + item.UpgradeType = undefined; + } + await inventory.save(); + } + res.end(); +}; + +interface IUpdateFingerPrintRequest { + category: WeaponTypeInternal; + oid: string; + action: "set" | "remove"; + upgradeType: string; + upgradeFingerprint: { + compact?: string; + buffs: { + Tag: string; + Value: number; + }[]; + }; +} diff --git a/src/routes/custom.ts b/src/routes/custom.ts index e10bc721..99536459 100644 --- a/src/routes/custom.ts +++ b/src/routes/custom.ts @@ -24,6 +24,7 @@ import { importController } from "@/src/controllers/custom/importController"; import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController"; import { setEvolutionProgressController } from "@/src/controllers/custom/setEvolutionProgressController"; import { setBoosterController } from "@/src/controllers/custom/setBoosterController"; +import { updateFingerprintController } from "@/src/controllers/custom/updateFingerprintController"; import { getConfigController, setConfigController } from "@/src/controllers/custom/configController"; @@ -53,6 +54,7 @@ customRouter.post("/import", importController); customRouter.post("/manageQuests", manageQuestsController); customRouter.post("/setEvolutionProgress", setEvolutionProgressController); customRouter.post("/setBooster", setBoosterController); +customRouter.post("/updateFingerprint", updateFingerprintController); customRouter.post("/getConfig", getConfigController); customRouter.post("/setConfig", setConfigController); diff --git a/src/routes/webui.ts b/src/routes/webui.ts index 535d68b1..1e19c276 100644 --- a/src/routes/webui.ts +++ b/src/routes/webui.ts @@ -24,7 +24,7 @@ webuiRouter.use("/webui", (req, res, next) => { webuiRouter.get("/webui/inventory", (_req, res) => { res.sendFile(path.join(baseDir, "static/webui/index.html")); }); -webuiRouter.get(/webui\/powersuit\/(.+)/, (_req, res) => { +webuiRouter.get("/webui/detailedView", (_req, res) => { res.sendFile(path.join(baseDir, "static/webui/index.html")); }); webuiRouter.get("/webui/mods", (_req, res) => { diff --git a/src/services/configService.ts b/src/services/configService.ts index 67fca37e..e96ace26 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -103,11 +103,13 @@ export const config: IConfig = { }; export const loadConfig = (): void => { + const newConfig = JSON.parse(fs.readFileSync(configPath, "utf-8")) as IConfig; + // Set all values to undefined now so if the new config.json omits some fields that were previously present, it's correct in-memory. for (const key of Object.keys(config)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access (config as any)[key] = undefined; } - Object.assign(config, JSON.parse(fs.readFileSync(configPath, "utf-8"))); + Object.assign(config, newConfig); }; diff --git a/src/services/configWatcherService.ts b/src/services/configWatcherService.ts index cab235ff..4dea6eea 100644 --- a/src/services/configWatcherService.ts +++ b/src/services/configWatcherService.ts @@ -14,8 +14,8 @@ chokidar.watch(configPath).on("change", () => { try { loadConfig(); } catch (e) { - logger.error("FATAL ERROR: Config failed to be reloaded: " + (e as Error).message); - process.exit(1); + logger.error("Config changes were not applied: " + (e as Error).message); + return; } validateConfig(); syncConfigWithDatabase(); diff --git a/src/services/shipCustomizationsService.ts b/src/services/shipCustomizationsService.ts index 1e5dcf26..990fa13e 100644 --- a/src/services/shipCustomizationsService.ts +++ b/src/services/shipCustomizationsService.ts @@ -4,7 +4,8 @@ import { ISetShipCustomizationsRequest, IShipDecorationsRequest, IShipDecorationsResponse, - ISetPlacedDecoInfoRequest + ISetPlacedDecoInfoRequest, + TBootLocation } from "@/src/types/shipTypes"; import { logger } from "@/src/utils/logger"; import { Types } from "mongoose"; @@ -14,6 +15,7 @@ import { Guild } from "../models/guildModel"; import { hasGuildPermission } from "./guildService"; import { GuildPermission } from "../types/guildTypes"; import { ExportResources } from "warframe-public-export-plus"; +import { RoomsType, TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes"; export const setShipCustomizations = async ( accountId: string, @@ -183,6 +185,19 @@ export const handleSetShipDecorations = async ( }; }; +const getRoomsForBootLocation = ( + personalRooms: TPersonalRoomsDatabaseDocument, + bootLocation: TBootLocation | undefined +): RoomsType[] => { + if (bootLocation == "SHOP") { + return personalRooms.TailorShop.Rooms; + } + if (bootLocation == "APARTMENT") { + return personalRooms.Apartment.Rooms; + } + return personalRooms.Ship.Rooms; +}; + export const handleSetPlacedDecoInfo = async (accountId: string, req: ISetPlacedDecoInfoRequest): Promise => { if (req.GuildId && req.ComponentId) { const guild = (await Guild.findById(req.GuildId))!; @@ -197,14 +212,14 @@ export const handleSetPlacedDecoInfo = async (accountId: string, req: ISetPlaced const personalRooms = await getPersonalRooms(accountId); - const room = personalRooms.Ship.Rooms.find(room => room.Name === req.Room); + const room = getRoomsForBootLocation(personalRooms, req.BootLocation).find(room => room.Name === req.Room); if (!room) { - throw new Error("room not found"); + throw new Error(`unknown room: ${req.Room}`); } const placedDeco = room.PlacedDecos.id(req.DecoId); if (!placedDeco) { - throw new Error("deco not found"); + throw new Error(`unknown deco id: ${req.DecoId}`); } placedDeco.PictureFrameInfo = req.PictureFrameInfo; diff --git a/src/types/shipTypes.ts b/src/types/shipTypes.ts index 6ac738b2..25555af7 100644 --- a/src/types/shipTypes.ts +++ b/src/types/shipTypes.ts @@ -154,7 +154,7 @@ export interface ISetPlacedDecoInfoRequest { DecoId: string; Room: string; PictureFrameInfo: IPictureFrameInfo; - BootLocation?: string; + BootLocation?: TBootLocation; ComponentId?: string; GuildId?: string; } diff --git a/static/webui/index.html b/static/webui/index.html index bcca5015..6c62867e 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -13,37 +13,38 @@ OpenWF WebUI - + +
@@ -455,15 +456,15 @@
-
+

-
-
+
+

- - + +

@@ -476,6 +477,18 @@
+
+
+
+

+ + + + + + +
+

diff --git a/static/webui/script.js b/static/webui/script.js index 5a13fa4f..9948247c 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -230,6 +230,18 @@ function setLanguage(lang) { } } +function setActiveTheme(theme) { + document.documentElement.setAttribute("data-bs-theme", theme); + document.querySelector("[data-theme].active").classList.remove("active"); + document.querySelector("[data-theme=" + theme + "]").classList.add("active"); +} +setActiveTheme(localStorage.getItem("theme") ?? "dark"); + +function setTheme(theme) { + setActiveTheme(theme); + localStorage.setItem("theme", theme); +} + const webUiModularWeapons = [ "/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon", "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon", @@ -272,6 +284,8 @@ function fetchItemList() { document.getElementById("changeSyndicate").innerHTML = ""; document.getElementById("changeSyndicate").appendChild(syndicateNone); + document.getElementById("valenceBonus-innateDamage").innerHTML = ""; + // prettier-ignore data.archonCrystalUpgrades = { "/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeEquilibrium": loc("upgrade_Equilibrium").split("|VAL|").join("20"), @@ -354,6 +368,16 @@ function fetchItemList() { }; window.archonCrystalUpgrades = data.archonCrystalUpgrades; + data.innateDamages = { + InnateElectricityDamage: loc("damageType_Electricity"), + InnateFreezeDamage: loc("damageType_Freeze"), + InnateHeatDamage: loc("damageType_Fire"), + InnateImpactDamage: loc("damageType_Impact"), + InnateMagDamage: loc("damageType_Magnetic"), + InnateRadDamage: loc("damageType_Radiation"), + InnateToxinDamage: loc("damageType_Poison") + }; + // Add mods mising in data sources data.mods.push({ uniqueName: "/Lotus/Upgrades/Mods/Fusers/LegendaryModFuser", @@ -438,6 +462,13 @@ function fetchItemList() { option.value = name; document.getElementById("datalist-" + type).appendChild(option); }); + } else if (type == "innateDamages") { + Object.entries(items).forEach(([uniqueName, name]) => { + const option = document.createElement("option"); + option.value = uniqueName; + option.textContent = name; + document.getElementById("valenceBonus-innateDamage").appendChild(option); + }); } else if (type == "uniqueLevelCaps") { uniqueLevelCaps = items; } else if (type == "Syndicates") { @@ -647,6 +678,12 @@ function updateInventory() { } } + if (["Suits", "LongGuns", "Pistols", "Melee", "SpaceGuns", "SpaceMelee"].includes(category)) { + const a = document.createElement("a"); + a.href = "/webui/detailedView?productCategory=" + category + "&itemId=" + item.ItemId.$oid; + a.innerHTML = ``; + td.appendChild(a); + } if (item.XP < maxXP || anyExaltedMissingXP) { const a = document.createElement("a"); a.href = "#"; @@ -709,13 +746,6 @@ function updateInventory() { a.title = loc("code_unmature"); a.innerHTML = ``; } - - td.appendChild(a); - } - if (category == "Suits") { - const a = document.createElement("a"); - a.href = "/webui/powersuit/" + item.ItemId.$oid; - a.innerHTML = ``; td.appendChild(a); } { @@ -1114,53 +1144,73 @@ function updateInventory() { } }); - // Populate powersuit route - if (single.getCurrentPath().substr(0, 17) == "/webui/powersuit/") { - const oid = single.getCurrentPath().substr(17); - const item = data.Suits.find(x => x.ItemId.$oid == oid); + // Populate detailedView route + if (single.getCurrentPath().substr(0, 19) == "/webui/detailedView") { + const urlParams = new URLSearchParams(window.location.search); + const oid = urlParams.get("itemId"); + const category = urlParams.get("productCategory"); + const item = data[category].find(x => x.ItemId.$oid == oid); + if (item) { if (item.ItemName) { - $("#powersuit-route h3").text(item.ItemName); - $("#powersuit-route .text-body-secondary").text(itemMap[item.ItemType]?.name ?? item.ItemType); + $("#detailedView-route h3").text(item.ItemName); + $("#detailedView-route .text-body-secondary").text( + itemMap[item.ItemType]?.name ?? item.ItemType + ); } else { - $("#powersuit-route h3").text(itemMap[item.ItemType]?.name ?? item.ItemType); - $("#powersuit-route .text-body-secondary").text(""); + $("#detailedView-route h3").text(itemMap[item.ItemType]?.name ?? item.ItemType); + $("#detailedView-route .text-body-secondary").text(""); } - const uniqueUpgrades = {}; - (item.ArchonCrystalUpgrades ?? []).forEach(upgrade => { - if (upgrade && upgrade.UpgradeType) { - uniqueUpgrades[upgrade.UpgradeType] ??= 0; - uniqueUpgrades[upgrade.UpgradeType] += 1; - } - }); + if (category == "Suits") { + document.getElementById("archonShards-card").classList.remove("d-none"); - document.getElementById("crystals-list").innerHTML = ""; - Object.entries(uniqueUpgrades).forEach(([upgradeType, count]) => { - const tr = document.createElement("tr"); - { - const td = document.createElement("td"); - td.textContent = count + "x " + (archonCrystalUpgrades[upgradeType] ?? upgradeType); - tr.appendChild(td); - } - { - const td = document.createElement("td"); - td.classList = "text-end text-nowrap"; - { - const a = document.createElement("a"); - a.href = "#"; - a.onclick = function (event) { - event.preventDefault(); - doPopArchonCrystalUpgrade(upgradeType); - }; - a.title = loc("code_remove"); - a.innerHTML = ``; - td.appendChild(a); + const uniqueUpgrades = {}; + (item.ArchonCrystalUpgrades ?? []).forEach(upgrade => { + if (upgrade && upgrade.UpgradeType) { + uniqueUpgrades[upgrade.UpgradeType] ??= 0; + uniqueUpgrades[upgrade.UpgradeType] += 1; } - tr.appendChild(td); + }); + + document.getElementById("crystals-list").innerHTML = ""; + Object.entries(uniqueUpgrades).forEach(([upgradeType, count]) => { + const tr = document.createElement("tr"); + { + const td = document.createElement("td"); + td.textContent = count + "x " + (archonCrystalUpgrades[upgradeType] ?? upgradeType); + tr.appendChild(td); + } + { + const td = document.createElement("td"); + td.classList = "text-end text-nowrap"; + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + doPopArchonCrystalUpgrade(upgradeType); + }; + a.title = loc("code_remove"); + a.innerHTML = ``; + td.appendChild(a); + } + tr.appendChild(td); + } + document.getElementById("crystals-list").appendChild(tr); + }); + } else if (["LongGuns", "Pistols", "Melee", "SpaceGuns", "SpaceMelee"].includes(category)) { + document.getElementById("valenceBonus-card").classList.remove("d-none"); + document.getElementById("valenceBonus-innateDamage").value = ""; + document.getElementById("valenceBonus-procent").value = 25; + + if (item.UpgradeFingerprint) { + const buff = JSON.parse(item.UpgradeFingerprint).buffs[0]; + const buffValue = fromUpdradeFingerPrintVaule(buff.Value, 0.25); + document.getElementById("valenceBonus-innateDamage").value = buff.Tag ?? ""; + document.getElementById("valenceBonus-procent").value = Math.round(buffValue * 1000) / 10; } - document.getElementById("crystals-list").appendChild(tr); - }); + } } else { single.loadRoute("/webui/inventory"); } @@ -2098,16 +2148,19 @@ function doAddMissingMaxRankMods() { }); } -// Powersuit Route +// DetailedView Route -single.getRoute("#powersuit-route").on("beforeload", function () { +single.getRoute("#detailedView-route").on("beforeload", function () { this.element.querySelector("h3").textContent = "Loading..."; + document.getElementById("archonShards-card").classList.add("d-none"); + document.getElementById("valenceBonus-card").classList.add("d-none"); if (window.didInitialInventoryUpdate) { updateInventory(); } }); function doPushArchonCrystalUpgrade() { + const urlParams = new URLSearchParams(window.location.search); const uniqueName = getKey(document.querySelector("[list='datalist-archonCrystalUpgrades']")); if (!uniqueName) { $("[list='datalist-archonCrystalUpgrades']").addClass("is-invalid").focus(); @@ -2118,7 +2171,7 @@ function doPushArchonCrystalUpgrade() { "/custom/pushArchonCrystalUpgrade?" + window.authz + "&oid=" + - single.getCurrentPath().substr(17) + + urlParams.get("itemId") + "&type=" + uniqueName + "&count=" + @@ -2131,14 +2184,10 @@ function doPushArchonCrystalUpgrade() { } function doPopArchonCrystalUpgrade(type) { + const urlParams = new URLSearchParams(window.location.search); revalidateAuthz().then(() => { $.get( - "/custom/popArchonCrystalUpgrade?" + - window.authz + - "&oid=" + - single.getCurrentPath().substr(17) + - "&type=" + - type + "/custom/popArchonCrystalUpgrade?" + window.authz + "&oid=" + urlParams.get("itemId") + "&type=" + type ).done(function () { updateInventory(); }); @@ -2388,7 +2437,7 @@ async function doMaxPlexus() { async function doUnlockAllMissions() { await revalidateAuthz(); await fetch("/custom/completeAllMissions?" + window.authz); - updateInventory(); + toast(loc("cheats_unlockAllMissions_ok")); } const importSamples = { @@ -2617,7 +2666,7 @@ const importSamples = { }, { ItemType: "/Lotus/Upgrades/Focus/Defense/Active/CloakHealOthersFocusUpgrade", - Level: 2 + Level: 3 } ] } @@ -2649,3 +2698,43 @@ document.querySelectorAll(".tags-input").forEach(input => { }; input.oninput(); }); + +function fromUpdradeFingerPrintVaule(raw, min) { + const range = 0.6 - min; + return min + (raw * range) / 0x3fffffff; +} + +function toUpdradeFingerPrintVaule(value, min) { + const range = 0.6 - min; + return Math.trunc(((value - min) * 0x3fffffff) / range); +} + +function handleValenceBonusChange(event) { + event.preventDefault(); + const urlParams = new URLSearchParams(window.location.search); + const action = event.submitter.value; + const Tag = document.getElementById("valenceBonus-innateDamage").value; + const Value = toUpdradeFingerPrintVaule(document.getElementById("valenceBonus-procent").value / 100, 0.25); + revalidateAuthz().then(() => { + $.post({ + url: "/custom/updateFingerprint?" + window.authz, + contentType: "application/json", + data: JSON.stringify({ + category: urlParams.get("productCategory"), + oid: urlParams.get("itemId"), + action, + upgradeType: "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod", + upgradeFingerprint: { + buffs: [ + { + Tag, + Value + } + ] + } + }) + }).done(function () { + updateInventory(); + }); + }); +} diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 880b3577..e6b12f57 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -2,7 +2,10 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Hinzufügen`, + general_setButton: `[UNTRANSLATED] Set`, + general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `Massenaktionen`, + code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`, code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`, code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`, @@ -112,9 +115,13 @@ dict = { currency_FusionPoints: `Endo`, currency_PrimeTokens: `Reines Aya`, currency_owned: `Du hast |COUNT|.`, - powersuit_archonShardsLabel: `Archon-Scherben-Slots`, - powersuit_archonShardsDescription: `Du kannst diese unbegrenzten Slots nutzen, um eine Vielzahl von Verbesserungen anzuwenden.`, - powersuit_archonShardsDescription2: `Hinweis: Jede Archon-Scherbe benötigt beim Laden etwas Zeit, um angewendet zu werden.`, + + detailedView_archonShardsLabel: `Archon-Scherben-Slots`, + detailedView_archonShardsDescription: `Du kannst diese unbegrenzten Slots nutzen, um eine Vielzahl von Verbesserungen anzuwenden.`, + detailedView_archonShardsDescription2: `Hinweis: Jede Archon-Scherbe benötigt beim Laden etwas Zeit, um angewendet zu werden.`, + detailedView_valenceBonusLabel: `Valenz-Bonus`, + detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, + mods_addRiven: `Riven hinzufügen`, mods_fingerprint: `Fingerabdruck`, mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`, @@ -129,6 +136,7 @@ dict = { cheats_skipAllDialogue: `Alle Dialoge überspringen`, cheats_unlockAllScans: `Alle Scans freischalten`, cheats_unlockAllMissions: `Alle Missionen freischalten`, + cheats_unlockAllMissions_ok: `[UNTRANSLATED] Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `Unendlich Credits`, cheats_infinitePlatinum: `Unendlich Platinum`, cheats_infiniteEndo: `Unendlich Endo`, @@ -290,5 +298,16 @@ dict = { upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, + damageType_Electricity: `Elektrizität`, + damageType_Fire: `Hitze`, + damageType_Freeze: `Kälte`, + damageType_Impact: `Einschlag`, + damageType_Magnetic: `Magnetismus`, + damageType_Poison: `Gift`, + damageType_Radiation: `Strahlung`, + + theme_dark: `[UNTRANSLATED] Dark Theme`, + theme_light: `[UNTRANSLATED] Light Theme`, + prettier_sucks_ass: `` }; diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index 9144c007..c18e34d3 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -1,7 +1,10 @@ dict = { general_inventoryUpdateNote: `Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Add`, + general_setButton: `Set`, + general_removeButton: `Remove`, general_bulkActions: `Bulk Actions`, + code_loginFail: `Login failed. Double-check the email and password.`, code_regFail: `Registration failed. Account already exists?`, code_changeNameConfirm: `What would you like to change your account name to?`, @@ -111,9 +114,13 @@ dict = { currency_FusionPoints: `Endo`, currency_PrimeTokens: `Regal Aya`, currency_owned: `You have |COUNT|.`, - powersuit_archonShardsLabel: `Archon Shard Slots`, - powersuit_archonShardsDescription: `You can use these unlimited slots to apply a wide range of upgrades.`, - powersuit_archonShardsDescription2: `Note that each archon shard takes some time to be applied when loading in.`, + + detailedView_archonShardsLabel: `Archon Shard Slots`, + detailedView_archonShardsDescription: `You can use these unlimited slots to apply a wide range of upgrades.`, + detailedView_archonShardsDescription2: `Note that each archon shard takes some time to be applied when loading in.`, + detailedView_valenceBonusLabel: `Valence Bonus`, + detailedView_valenceBonusDescription: `You can set or remove the Valence Bonus from your weapon.`, + mods_addRiven: `Add Riven`, mods_fingerprint: `Fingerprint`, mods_fingerprintHelp: `Need help with the fingerprint?`, @@ -128,6 +135,7 @@ dict = { cheats_skipAllDialogue: `Skip All Dialogue`, cheats_unlockAllScans: `Unlock All Scans`, cheats_unlockAllMissions: `Unlock All Missions`, + cheats_unlockAllMissions_ok: `Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `Infinite Credits`, cheats_infinitePlatinum: `Infinite Platinum`, cheats_infiniteEndo: `Infinite Endo`, @@ -289,5 +297,16 @@ dict = { upgrade_SwiftExecute: `Speed of Mercy Kills increased by 50%`, upgrade_OnHackInvis: `Invisible for 15 seconds after hacking`, + damageType_Electricity: `Electricity`, + damageType_Fire: `Heat`, + damageType_Freeze: `Cold`, + damageType_Impact: `Impact`, + damageType_Magnetic: `Magnetic`, + damageType_Poison: `Toxin`, + damageType_Radiation: `Radiation`, + + theme_dark: `Dark Theme`, + theme_light: `Light Theme`, + prettier_sucks_ass: `` }; diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 063b8bef..fc56db1c 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -1,8 +1,11 @@ // Spanish translation by hxedcl dict = { - general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, + general_inventoryUpdateNote: `Para ver los cambios en el juego, necesitas volver a sincronizar tu inventario, por ejemplo, usando el comando /sync del bootstrapper, visitando un dojo o repetidor, o volviendo a iniciar sesión.`, general_addButton: `Agregar`, + general_setButton: `[UNTRANSLATED] Set`, + general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `Acciones masivas`, + code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`, code_regFail: `Error al registrar la cuenta. ¿Ya existe una cuenta con este correo?`, code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`, @@ -112,9 +115,13 @@ dict = { currency_FusionPoints: `Endo`, currency_PrimeTokens: `Aya Real`, currency_owned: `Tienes |COUNT|.`, - powersuit_archonShardsLabel: `Ranuras de Fragmento de Archón`, - powersuit_archonShardsDescription: `Puedes usar estas ranuras ilimitadas para aplicar una amplia variedad de mejoras`, - powersuit_archonShardsDescription2: `Ten en cuenta que cada fragmento de archón tarda un poco en aplicarse al cargar`, + + detailedView_archonShardsLabel: `Ranuras de Fragmento de Archón`, + detailedView_archonShardsDescription: `Puedes usar estas ranuras ilimitadas para aplicar una amplia variedad de mejoras`, + detailedView_archonShardsDescription2: `Ten en cuenta que cada fragmento de archón tarda un poco en aplicarse al cargar`, + detailedView_valenceBonusLabel: `Bônus de Valência`, + detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, + mods_addRiven: `Agregar Agrietado`, mods_fingerprint: `Huella digital`, mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`, @@ -129,6 +136,7 @@ dict = { cheats_skipAllDialogue: `Omitir todos los diálogos`, cheats_unlockAllScans: `Desbloquear todos los escaneos`, cheats_unlockAllMissions: `Desbloquear todas las misiones`, + cheats_unlockAllMissions_ok: `[UNTRANSLATED] Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `Créditos infinitos`, cheats_infinitePlatinum: `Platino infinito`, cheats_infiniteEndo: `Endo infinito`, @@ -175,64 +183,64 @@ dict = { cheats_fastClanAscension: `Ascenso rápido del clan`, cheats_missionsCanGiveAllRelics: `Las misiones pueden otorgar todas las reliquias`, cheats_unlockAllSimarisResearchEntries: `Desbloquear todas las entradas de investigación de Simaris`, - cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, + cheats_disableDailyTribute: `Desactivar tributo diario`, cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`, cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`, cheats_save: `Guardar`, cheats_account: `Cuenta`, cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`, cheats_helminthUnlockAll: `Subir al máximo el Helminto`, - cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`, + cheats_addMissingSubsumedAbilities: `Agregar habilidades subsumidas faltantes`, cheats_intrinsicsUnlockAll: `Maximizar todos los intrínsecos`, cheats_changeSupportedSyndicate: `Sindicatos disponibles`, cheats_changeButton: `Cambiar`, cheats_none: `Ninguno`, - 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_theCircuitOverride: `[UNTRANSLATED] The Circuit Override`, - worldState_darvoStockMultiplier: `[UNTRANSLATED] Darvo Stock Multiplier`, + worldState: `Estado del mundo`, + worldState_creditBoost: `Potenciador de Créditos`, + worldState_affinityBoost: `Potenciador de Afinidad`, + worldState_resourceBoost: `Potenciador de Recursos`, + worldState_starDays: `Días estelares`, + worldState_galleonOfGhouls: `Galeón de Gules`, + disabled: `Desactivado`, + worldState_we1: `Semana 1`, + worldState_we2: `Semana 2`, + worldState_we3: `Semana 3`, + worldState_eidolonOverride: `Tiempo de las Llanuras de Eidolon`, + worldState_day: `Dia`, + worldState_night: `Noche`, + worldState_vallisOverride: `Tiempo del Valle del Orbe`, + worldState_warm: `Cálido`, + worldState_cold: `Frío`, + worldState_duviriOverride: `Tiempo de Duviri`, + worldState_joy: `Alegría`, + worldState_anger: `Ira`, + worldState_envy: `Envidia`, + worldState_sorrow: `Tristeza`, + worldState_fear: `Miedo`, + worldState_nightwaveOverride: `Volúmen de Onda Nocturna`, + worldState_RadioLegionIntermission13Syndicate: `Mix de Nora Vol. 9`, + worldState_RadioLegionIntermission12Syndicate: `Mix de Nora Vol. 8`, + worldState_RadioLegionIntermission11Syndicate: `Mix de Nora Vol. 7`, + worldState_RadioLegionIntermission10Syndicate: `Mix de Nora Vol. 6 `, + worldState_RadioLegionIntermission9Syndicate: `Mix de Nora Vol. 5`, + worldState_RadioLegionIntermission8Syndicate: `Mix de Nora Vol. 4`, + worldState_RadioLegionIntermission7Syndicate: `Mix de Nora Vol. 3`, + worldState_RadioLegionIntermission6Syndicate: `Mix de Nora Vol. 2`, + worldState_RadioLegionIntermission5Syndicate: `Mix de Nora Vol. 1`, + worldState_RadioLegionIntermission4Syndicate: `Elección de Nora`, + worldState_RadioLegionIntermission3Syndicate: `Intermedio III`, + worldState_RadioLegion3Syndicate: `El Artesano de Cristal`, + worldState_RadioLegionIntermission2Syndicate: `Intermedio II`, + worldState_RadioLegion2Syndicate: `El Emisario`, + worldState_RadioLegionIntermissionSyndicate: `Intermedio I`, + worldState_RadioLegionSyndicate: `El lobo de Saturno Seis`, + worldState_fissures: `Fisuras`, + normal: `Normal`, + worldState_allAtOnceNormal: `Todo a la vez, normal`, + worldState_allAtOnceSteelPath: `Todo a la vez, Camino de Acero`, + worldState_theCircuitOverride: `Cambio del Circuito`, + worldState_darvoStockMultiplier: `Multiplicador de stock de Darvo`, import_importNote: `Puedes proporcionar una respuesta de inventario completa o parcial (representación del cliente) aquí. Todos los campos compatibles con el importador serán sobrescritos en tu cuenta.`, import_submit: `Enviar`, @@ -257,7 +265,7 @@ dict = { upgrade_WarframeGlobeEffectEnergy: `+|VAL|% de efectividad de orbes de energía`, upgrade_WarframeGlobeEffectHealth: `+|VAL|% de efectividad de orbes de salud`, upgrade_WarframeHealthMax: `+|VAL| de salud máxima`, - upgrade_WarframeHPBoostFromImpact: `[UNTRANSLATED] +|VAL1| Health on kill with Blast Damage (Max |VAL2| Health)`, + upgrade_WarframeHPBoostFromImpact: `+|VAL1| de salud al eliminar con daño explosivo (máx. |VAL2| de salud)`, upgrade_WarframeParkourVelocity: `+|VAL|% de velocidad de parkour`, upgrade_WarframeRadiationDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado radiactivo`, upgrade_WarframeRegen: `+|VAL| de regeneración de salud por segundo`, @@ -280,7 +288,7 @@ dict = { upgrade_DamageReductionOnHack: `75% de reducción de daño al hackear`, upgrade_OnExecutionReviveCompanion: `Las ejecuciones reducen el tiempo de recuperación del compañero en 15s`, upgrade_OnExecutionParkourSpeed: `+60% de velocidad de parkour durante 15s tras una ejecución`, - upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`, + upgrade_AvatarTimeLimitIncrease: `+8s para hackear`, upgrade_ElectrifyOnHack: `Electrocuta a los enemigos en un radio de 20m al hackear`, upgrade_OnExecutionTerrify: `50% de probabilidad de que enemigos en un radio de 15m entren en pánico por 8s tras una ejecución`, upgrade_OnHackLockers: `Desbloquea 5 casilleros en un radio de 20m tras hackear`, @@ -290,5 +298,16 @@ dict = { upgrade_SwiftExecute: `Velocidad de ejecuciones aumentada en un 50%`, upgrade_OnHackInvis: `Invisible durante 15 segundos después de hackear`, + damageType_Electricity: `Eletricidade`, + damageType_Fire: `Ígneo`, + damageType_Freeze: `Glacial`, + damageType_Impact: `Colisivo`, + damageType_Magnetic: `Magnético`, + damageType_Poison: `Tóxico`, + damageType_Radiation: `Radioativo`, + + theme_dark: `[UNTRANSLATED] Dark Theme`, + theme_light: `[UNTRANSLATED] Light Theme`, + prettier_sucks_ass: `` }; diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 7c0201d5..e35bc9ac 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -2,7 +2,10 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Ajouter`, + general_setButton: `[UNTRANSLATED] Set`, + general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `Action groupée`, + code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`, code_regFail: `Enregistrement impossible. Compte existant?`, code_changeNameConfirm: `Nouveau nom du compte :`, @@ -112,9 +115,13 @@ dict = { currency_FusionPoints: `Endo`, 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: `Un délai sera présent entre l'application des éclats et le chargement en jeu.`, + + detailedView_archonShardsLabel: `Emplacements de fragments d'Archonte`, + detailedView_archonShardsDescription: `Slots illimités pour appliquer plusieurs améliorations`, + detailedView_archonShardsDescription2: `Un délai sera présent entre l'application des éclats et le chargement en jeu.`, + detailedView_valenceBonusLabel: `Bonus de Valence`, + detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, + mods_addRiven: `Ajouter un riven`, mods_fingerprint: `Empreinte`, mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`, @@ -129,6 +136,7 @@ dict = { cheats_skipAllDialogue: `Passer les dialogues`, cheats_unlockAllScans: `Débloquer tous les scans`, cheats_unlockAllMissions: `Débloquer toutes les missions`, + cheats_unlockAllMissions_ok: `[UNTRANSLATED] Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `Crédits infinis`, cheats_infinitePlatinum: `Platinum infini`, cheats_infiniteEndo: `Endo infini`, @@ -290,5 +298,16 @@ dict = { upgrade_SwiftExecute: `Vitesse des miséricordes augmentée de 50%`, upgrade_OnHackInvis: `Invisible pendant 15 secondes après un piratage`, + damageType_Electricity: `Électrique`, + damageType_Fire: `Feu`, + damageType_Freeze: `Glace`, + damageType_Impact: `Impact`, + damageType_Magnetic: `Magnétique`, + damageType_Poison: `Poison`, + damageType_Radiation: `Radiations`, + + theme_dark: `[UNTRANSLATED] Dark Theme`, + theme_light: `[UNTRANSLATED] Light Theme`, + prettier_sucks_ass: `` }; diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index b6bba38f..0666c75c 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -2,7 +2,10 @@ dict = { general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging.`, general_addButton: `Добавить`, + general_setButton: `Установить`, + general_removeButton: `Удалить`, general_bulkActions: `Массовые действия`, + code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`, code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`, code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`, @@ -112,9 +115,13 @@ dict = { currency_FusionPoints: `Эндо`, currency_PrimeTokens: `Королевские Айя`, currency_owned: `У тебя |COUNT|.`, - powersuit_archonShardsLabel: `Ячейки осколков архонта`, - powersuit_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`, - powersuit_archonShardsDescription2: `Обратите внимание: каждый фрагмент архонта применяется с задержкой при загрузке.`, + + detailedView_archonShardsLabel: `Ячейки осколков архонта`, + detailedView_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`, + detailedView_archonShardsDescription2: `Обратите внимание: каждый фрагмент архонта применяется с задержкой при загрузке.`, + detailedView_valenceBonusLabel: `Бонус Валентности`, + detailedView_valenceBonusDescription: `Вы можете установить или убрать бонус валентности с вашего оружия.`, + mods_addRiven: `Добавить Мод Разлома`, mods_fingerprint: `Отпечаток`, mods_fingerprintHelp: `Нужна помощь с отпечатком?`, @@ -129,6 +136,7 @@ dict = { cheats_skipAllDialogue: `Пропустить все диалоги`, cheats_unlockAllScans: `Разблокировать все сканирования`, cheats_unlockAllMissions: `Разблокировать все миссии`, + cheats_unlockAllMissions_ok: `[UNTRANSLATED] Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `Бесконечные кредиты`, cheats_infinitePlatinum: `Бесконечная платина`, cheats_infiniteEndo: `Бесконечное эндо`, @@ -290,5 +298,16 @@ dict = { upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, + damageType_Electricity: `Электричество`, + damageType_Fire: `Огонь`, + damageType_Freeze: `Холод`, + damageType_Impact: `Удар`, + damageType_Magnetic: `Магнит`, + damageType_Poison: `Токсин`, + damageType_Radiation: `Радиация`, + + theme_dark: `[UNTRANSLATED] Dark Theme`, + theme_light: `[UNTRANSLATED] Light Theme`, + prettier_sucks_ass: `` }; diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index a2a39e56..a15bc3a8 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -2,7 +2,10 @@ dict = { general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场 / 中继站或重新登录`, general_addButton: `添加`, + general_setButton: `[UNTRANSLATED] Set`, + general_removeButton: `[UNTRANSLATED] Remove`, general_bulkActions: `批量操作`, + code_loginFail: `登录失败。请检查邮箱和密码。`, code_regFail: `注册失败。账号已存在。`, code_changeNameConfirm: `您想将账户名称更改为什么?`, @@ -112,9 +115,13 @@ dict = { currency_FusionPoints: `内融核心`, currency_PrimeTokens: `御品阿耶`, currency_owned: `当前拥有 |COUNT|。`, - powersuit_archonShardsLabel: `执刑官源力石槽位`, - powersuit_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`, - powersuit_archonShardsDescription2: `请注意, 在加载时, 每个执政官源力石都需要一定的时间来生效。`, + + detailedView_archonShardsLabel: `执刑官源力石槽位`, + detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`, + detailedView_archonShardsDescription2: `请注意, 在加载时, 每个执政官源力石都需要一定的时间来生效。`, + detailedView_valenceBonusLabel: `效价加成`, + detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, + mods_addRiven: `添加裂罅MOD`, mods_fingerprint: `印记`, mods_fingerprintHelp: `需要印记相关的帮助?`, @@ -129,6 +136,7 @@ dict = { cheats_skipAllDialogue: `跳过所有对话`, cheats_unlockAllScans: `解锁所有扫描`, cheats_unlockAllMissions: `解锁所有任务`, + cheats_unlockAllMissions_ok: `[UNTRANSLATED] Success. Please note that you'll need to enter a dojo/relay or relog for the client to refresh the star chart.`, cheats_infiniteCredits: `无限现金`, cheats_infinitePlatinum: `无限白金`, cheats_infiniteEndo: `无限内融核心`, @@ -290,5 +298,16 @@ dict = { upgrade_SwiftExecute: `怜悯之击速度提升50%`, upgrade_OnHackInvis: `入侵后隐身15秒`, + damageType_Electricity: `电击`, + damageType_Fire: `火焰`, + damageType_Freeze: `冰冻`, + damageType_Impact: `冲击`, + damageType_Magnetic: `磁力`, + damageType_Poison: `毒素`, + damageType_Radiation: `辐射`, + + theme_dark: `[UNTRANSLATED] Dark Theme`, + theme_light: `[UNTRANSLATED] Light Theme`, + prettier_sucks_ass: `` };