Compare commits

..

24 Commits
main ... main

Author SHA1 Message Date
46d37d3688 chore(webui): update Chinese translation (#2396)
Reviewed-on: OpenWF/SpaceNinjaServer#2396
Co-authored-by: Corvus <corvus@noreply.localhost>
Co-committed-by: Corvus <corvus@noreply.localhost>
2025-07-03 11:09:07 -07:00
41686aea88 fix: properly cap negative syndicate standing (#2393)
Closes #2388

Reviewed-on: OpenWF/SpaceNinjaServer#2393
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-03 11:08:57 -07:00
61ac2f8b72 chore(webui): update Chinese translation (#2394)
Reviewed-on: OpenWF/SpaceNinjaServer#2394
Co-authored-by: Corvus <corvus@noreply.localhost>
Co-committed-by: Corvus <corvus@noreply.localhost>
2025-07-02 15:04:42 -07:00
d2ab894c01 fix(webui): assign labels for appropriate inputs (#2391)
Reviewed-on: OpenWF/SpaceNinjaServer#2391
Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
2025-07-02 14:29:41 -07:00
8c85cdcd1d feat(webui): "add maxed" for mods (#2387)
Closes #2382

Reviewed-on: OpenWF/SpaceNinjaServer#2387
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-02 14:18:24 -07:00
aa6191f033 feat: relic rng cheats (#2386)
Closes #2370

Reviewed-on: OpenWF/SpaceNinjaServer#2386
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-02 14:17:14 -07:00
e26d2635fb chore(webui): fix inconsistent % chance strings (#2385)
Closes #2381

Reviewed-on: OpenWF/SpaceNinjaServer#2385
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-02 14:15:50 -07:00
dd6ae8898f chore(webui): move max rank button before detailed view link (#2384)
Reviewed-on: OpenWF/SpaceNinjaServer#2384
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-02 14:14:19 -07:00
499ca23ffb chore(webui): update inventory when equipment was forma'd (#2383)
Reviewed-on: OpenWF/SpaceNinjaServer#2383
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-02 14:14:13 -07:00
d3102acb7c chore(webui): update Chinese translation (#2380)
Reviewed-on: OpenWF/SpaceNinjaServer#2380
Co-authored-by: Corvus <corvus@noreply.localhost>
Co-committed-by: Corvus <corvus@noreply.localhost>
2025-07-01 10:58:47 -07:00
363028c9ce chore: clarify log output related to saveLoadout (#2379)
Reviewed-on: OpenWF/SpaceNinjaServer#2379
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:48:03 -07:00
1d60745f18 feat: year rollover kiss emails (#2376)
Closes #2375

Reviewed-on: OpenWF/SpaceNinjaServer#2376
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:45:41 -07:00
a9b3b16d31 feat: dojo visitors (#2374)
Closes #2373

Reviewed-on: OpenWF/SpaceNinjaServer#2374
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:45:12 -07:00
fd1d72a1cf chore(webui): add inventory update note to quests tab (#2372)
Reviewed-on: OpenWF/SpaceNinjaServer#2372
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:44:30 -07:00
75832afdbe feat: relicRewardItemCountMultiplier cheat (#2369)
Reviewed-on: OpenWF/SpaceNinjaServer#2369
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:44:13 -07:00
aa916d2820 feat: sell genetic imprints (#2368)
Reviewed-on: OpenWF/SpaceNinjaServer#2368
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-01 07:44:05 -07:00
5a5f6106a3 chore: save inventory and account in parallel when claiming login reward (#2371)
Reviewed-on: OpenWF/SpaceNinjaServer#2371
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 17:55:06 -07:00
24d9dc27e2 chore(webui): update inventory when login reward was claimed (#2367)
Closes #2360

Reviewed-on: OpenWF/SpaceNinjaServer#2367
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 13:30:09 -07:00
5e05a15743 fix: update calendar progress at daily reset (#2365)
Closes #2364

Reviewed-on: OpenWF/SpaceNinjaServer#2365
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 13:28:27 -07:00
545b949202 feat: sell crew members (#2366)
Closes #2363

Reviewed-on: OpenWF/SpaceNinjaServer#2366
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 12:58:24 -07:00
0c9b27a29b chore: optimise creditsController (#2359)
Doing both lookups in parallel saves around 1 ms in the happy case (20% of baseline time), and in case nonce does not match, the error is simply raised as per usual with the inventory request being lightweight enough to be negligible.

Noteworthy that this reasoning doesn't really work for other controllers because in the error case, the inventory request would still be quite significant, even if the HTTP request itself would still finish quickly.

Reviewed-on: OpenWF/SpaceNinjaServer#2359
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 11:05:49 -07:00
cfa750b6f7 fix: handle crafting of archwing summon for versions prior to U39 (#2358)
Closes #2356

Reviewed-on: OpenWF/SpaceNinjaServer#2358
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 11:05:16 -07:00
049baa4313 fix(webui): make sidebar sticky as intended (#2354)
also a bit of language-specific width adjustment

Reviewed-on: OpenWF/SpaceNinjaServer#2354
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-30 11:04:58 -07:00
e267ca8f55 chore(webui): update to Spanish translation (#2355)
Reviewed-on: OpenWF/SpaceNinjaServer#2355
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-06-29 19:42:24 -07:00
31 changed files with 391 additions and 105 deletions

View File

@ -60,6 +60,7 @@
"unlockAllSimarisResearchEntries": false, "unlockAllSimarisResearchEntries": false,
"disableDailyTribute": false, "disableDailyTribute": false,
"spoofMasteryRank": -1, "spoofMasteryRank": -1,
"relicRewardItemCountMultiplier": 1,
"nightwaveStandingMultiplier": 1, "nightwaveStandingMultiplier": 1,
"unfaithfulBugFixes": { "unfaithfulBugFixes": {
"ignore1999LastRegionPlayed": false, "ignore1999LastRegionPlayed": false,

8
package-lock.json generated
View File

@ -23,7 +23,7 @@
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"undici": "^7.10.0", "undici": "^7.10.0",
"warframe-public-export-plus": "^0.5.74", "warframe-public-export-plus": "^0.5.76",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0", "winston-daily-rotate-file": "^5.0.0",
@ -3386,9 +3386,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.5.74", "version": "0.5.76",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.74.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.76.tgz",
"integrity": "sha512-pA7dxA0lKn9w/2Sc97oxnn+CEzL1SrT9XriNLTDF4Xp+2SBEpGcfbqbdR9ljPQJopIbrc9Zy02R+uBQVomcwyA==" "integrity": "sha512-0gX3NTWaxFyzUmqBSUHhPY8pMRX92iXQFqoBuMQlMG1+6uC6JMKtwP5t8cuXR3pvV2vkaCi/cDWjP1JUChkZ9g=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.2", "version": "0.1.2",

View File

@ -37,7 +37,7 @@
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"undici": "^7.10.0", "undici": "^7.10.0",
"warframe-public-export-plus": "^0.5.74", "warframe-public-export-plus": "^0.5.76",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0", "winston-daily-rotate-file": "^5.0.0",

View File

@ -31,7 +31,7 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
const strings = extractStrings(line); const strings = extractStrings(line);
if (Object.keys(strings).length > 0) { if (Object.keys(strings).length > 0) {
Object.entries(strings).forEach(([key, value]) => { Object.entries(strings).forEach(([key, value]) => {
if (targetStrings.hasOwnProperty(key)) { if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED] ")) {
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`); fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
} else { } else {
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`); fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);

View File

@ -4,9 +4,15 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
export const creditsController: RequestHandler = async (req, res) => { export const creditsController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const inventory = (
await Promise.all([
const inventory = await getInventory(accountId, "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits"); getAccountIdForRequest(req),
getInventory(
req.query.accountId as string,
"RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits"
)
])
)[1];
const response = { const response = {
RegularCredits: inventory.RegularCredits, RegularCredits: inventory.RegularCredits,

View File

@ -5,6 +5,7 @@ import {
getGuildVault, getGuildVault,
hasAccessToDojo, hasAccessToDojo,
hasGuildPermission, hasGuildPermission,
processCompletedGuildTechProject,
processFundedGuildTechProject, processFundedGuildTechProject,
processGuildTechProjectContributionsUpdate, processGuildTechProjectContributionsUpdate,
removePigmentsFromGuildMembers, removePigmentsFromGuildMembers,
@ -51,8 +52,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
}; };
if (project.CompletionDate) { if (project.CompletionDate) {
techProject.CompletionDate = toMongoDate(project.CompletionDate); techProject.CompletionDate = toMongoDate(project.CompletionDate);
if (Date.now() >= project.CompletionDate.getTime()) { if (
needSave ||= setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate); Date.now() >= project.CompletionDate.getTime() &&
setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate)
) {
processCompletedGuildTechProject(guild, project.ItemType);
needSave = true;
} }
} }
techProjects.push(techProject); techProjects.push(techProject);

View File

@ -9,11 +9,13 @@ import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inve
import { ExportCustoms, ExportFlavour, ExportResources, ExportVirtuals } from "warframe-public-export-plus"; import { ExportCustoms, ExportFlavour, ExportResources, ExportVirtuals } from "warframe-public-export-plus";
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService";
import { import {
addEmailItem,
addMiscItems, addMiscItems,
allDailyAffiliationKeys, allDailyAffiliationKeys,
cleanupInventory, cleanupInventory,
createLibraryDailyTask, createLibraryDailyTask,
generateRewardSeed generateRewardSeed,
getCalendarProgress
} from "@/src/services/inventoryService"; } from "@/src/services/inventoryService";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { addString, catBreadHash } from "@/src/helpers/stringHelpers"; import { addString, catBreadHash } from "@/src/helpers/stringHelpers";
@ -108,6 +110,61 @@ export const inventoryController: RequestHandler = async (request, response) =>
} }
} }
if (inventory.CalendarProgress) {
const previousYearIteration = inventory.CalendarProgress.Iteration;
getCalendarProgress(inventory); // handle year rollover; the client expects to receive an inventory with an up-to-date CalendarProgress
// also handle sending of kiss cinematic at year rollover
if (
inventory.CalendarProgress.Iteration != previousYearIteration &&
inventory.DialogueHistory &&
inventory.DialogueHistory.Dialogues
) {
let kalymos = false;
for (const { dialogueName, kissEmail } of [
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/ArthurKissEmailItem"
},
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/EleanorKissEmailItem"
},
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/LettieKissEmailItem"
},
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/AmirKissEmailItem"
},
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/AoiKissEmailItem"
},
{
dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue",
kissEmail: "/Lotus/Types/Items/EmailItems/QuincyKissEmailItem"
}
]) {
const dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == dialogueName);
if (dialogue) {
if (dialogue.Rank == 7) {
await addEmailItem(inventory, kissEmail);
kalymos = false;
break;
}
if (dialogue.Rank == 6) {
kalymos = true;
}
}
}
if (kalymos) {
await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem");
}
}
}
cleanupInventory(inventory); cleanupInventory(inventory);
inventory.NextRefill = new Date((today + 1) * 86400000); // tomorrow at 0 UTC inventory.NextRefill = new Date((today + 1) * 86400000); // tomorrow at 0 UTC

View File

@ -9,6 +9,7 @@ import {
} from "@/src/services/loginRewardService"; } from "@/src/services/loginRewardService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { sendWsBroadcastTo } from "@/src/services/webService";
export const loginRewardsController: RequestHandler = async (req, res) => { export const loginRewardsController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req); const account = await getAccountForRequest(req);
@ -47,10 +48,10 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
response.DailyTributeInfo.HasChosenReward = true; response.DailyTributeInfo.HasChosenReward = true;
response.DailyTributeInfo.ChosenReward = randomRewards[0]; response.DailyTributeInfo.ChosenReward = randomRewards[0];
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]); response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
await inventory.save();
setAccountGotLoginRewardToday(account); setAccountGotLoginRewardToday(account);
await account.save(); await Promise.all([inventory.save(), account.save()]);
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
} }
res.json(response); res.json(response);
}; };

View File

@ -6,6 +6,7 @@ import {
} from "@/src/services/loginRewardService"; } from "@/src/services/loginRewardService";
import { getAccountForRequest } from "@/src/services/loginService"; import { getAccountForRequest } from "@/src/services/loginService";
import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
import { sendWsBroadcastTo } from "@/src/services/webService";
import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
@ -34,11 +35,10 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res)
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!; chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
inventoryChanges = await claimLoginReward(inventory, chosenReward); inventoryChanges = await claimLoginReward(inventory, chosenReward);
} }
await inventory.save();
setAccountGotLoginRewardToday(account); setAccountGotLoginRewardToday(account);
await account.save(); await Promise.all([inventory.save(), account.save()]);
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
res.json({ res.json({
DailyTributeInfo: { DailyTributeInfo: {
NewInventory: inventoryChanges, NewInventory: inventoryChanges,

View File

@ -57,8 +57,12 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
component.DecoCapacity -= meta.capacityCost; component.DecoCapacity -= meta.capacityCost;
} }
} else { } else {
const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)!; const entry = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type);
if (!itemType || meta.dojoCapacityCost === undefined) { if (!entry) {
throw new Error(`unknown deco type: ${deco.Type}`);
}
const [itemType, meta] = entry;
if (meta.dojoCapacityCost === undefined) {
throw new Error(`unknown deco type: ${deco.Type}`); throw new Error(`unknown deco type: ${deco.Type}`);
} }
component.DecoCapacity -= meta.dojoCapacityCost; component.DecoCapacity -= meta.dojoCapacityCost;
@ -75,7 +79,13 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
if (meta) { if (meta) {
processDojoBuildMaterialsGathered(guild, meta); processDojoBuildMaterialsGathered(guild, meta);
} }
} else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) { } else if (
deco.Type.startsWith("/Lotus/Objects/Tenno/Dojo/NpcPlaceables/") ||
(guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems)
) {
if (!guild.VaultRegularCredits || !guild.VaultMiscItems) {
throw new Error(`dojo visitor placed without anything in vault?!`);
}
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) { if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
let enoughMiscItems = true; let enoughMiscItems = true;
for (const ingredient of meta.ingredients) { for (const ingredient of meta.ingredients) {

View File

@ -19,6 +19,7 @@ import { sendWsBroadcastTo } from "@/src/services/webService";
export const sellController: RequestHandler = async (req, res) => { export const sellController: RequestHandler = async (req, res) => {
const payload = JSON.parse(String(req.body)) as ISellRequest; const payload = JSON.parse(String(req.body)) as ISellRequest;
//console.log(JSON.stringify(payload, null, 2));
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const requiredFields = new Set<keyof TInventoryDatabaseDocument>(); const requiredFields = new Set<keyof TInventoryDatabaseDocument>();
if (payload.SellCurrency == "SC_RegularCredits") { if (payload.SellCurrency == "SC_RegularCredits") {
@ -58,6 +59,9 @@ export const sellController: RequestHandler = async (req, res) => {
if (payload.Items.Hoverboards) { if (payload.Items.Hoverboards) {
requiredFields.add(InventorySlot.SPACESUITS); requiredFields.add(InventorySlot.SPACESUITS);
} }
if (payload.Items.CrewMembers) {
requiredFields.add(InventorySlot.CREWMEMBERS);
}
if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) { if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) {
requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS); requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
requiredFields.add("CrewShipRawSalvage"); requiredFields.add("CrewShipRawSalvage");
@ -181,6 +185,17 @@ export const sellController: RequestHandler = async (req, res) => {
inventory.Drones.pull({ _id: sellItem.String }); inventory.Drones.pull({ _id: sellItem.String });
}); });
} }
if (payload.Items.KubrowPetPrints) {
payload.Items.KubrowPetPrints.forEach(sellItem => {
inventory.KubrowPetPrints.pull({ _id: sellItem.String });
});
}
if (payload.Items.CrewMembers) {
payload.Items.CrewMembers.forEach(sellItem => {
inventory.CrewMembers.pull({ _id: sellItem.String });
freeUpSlot(inventory, InventorySlot.CREWMEMBERS);
});
}
if (payload.Items.CrewShipWeapons) { if (payload.Items.CrewShipWeapons) {
payload.Items.CrewShipWeapons.forEach(sellItem => { payload.Items.CrewShipWeapons.forEach(sellItem => {
if (sellItem.String[0] == "/") { if (sellItem.String[0] == "/") {
@ -303,6 +318,8 @@ interface ISellRequest {
OperatorAmps?: ISellItem[]; OperatorAmps?: ISellItem[];
Hoverboards?: ISellItem[]; Hoverboards?: ISellItem[];
Drones?: ISellItem[]; Drones?: ISellItem[];
KubrowPetPrints?: ISellItem[];
CrewMembers?: ISellItem[];
CrewShipWeapons?: ISellItem[]; CrewShipWeapons?: ISellItem[];
CrewShipWeaponSkins?: ISellItem[]; CrewShipWeaponSkins?: ISellItem[];
}; };

View File

@ -13,6 +13,7 @@ import { getRecipeByResult } from "@/src/services/itemDataService";
import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "@/src/services/infestedFoundryService"; import { addInfestedFoundryXP, applyCheatsToInfestedFoundry } from "@/src/services/infestedFoundryService";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { sendWsBroadcastTo } from "@/src/services/webService";
export const upgradesController: RequestHandler = async (req, res) => { export const upgradesController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -120,6 +121,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue); setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
item.Polarized ??= 0; item.Polarized ??= 0;
item.Polarized += 1; item.Polarized += 1;
sendWsBroadcastTo(accountId, { update_inventory: true }); // webui may need to to re-add "max rank" button
break; break;
} }
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": { case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker": {

View File

@ -7,7 +7,7 @@ export const addItemsController: RequestHandler = async (req, res) => {
const requests = req.body as IAddItemRequest[]; const requests = req.body as IAddItemRequest[];
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
for (const request of requests) { for (const request of requests) {
await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, undefined, true); await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, request.Fingerprint, true);
} }
await inventory.save(); await inventory.save();
res.end(); res.end();
@ -16,4 +16,5 @@ export const addItemsController: RequestHandler = async (req, res) => {
interface IAddItemRequest { interface IAddItemRequest {
ItemType: string; ItemType: string;
ItemCount: number; ItemCount: number;
Fingerprint?: string;
} }

View File

@ -6,6 +6,7 @@ import { logger } from "@/src/utils/logger";
import { addMiscItems, combineInventoryChanges } from "@/src/services/inventoryService"; import { addMiscItems, combineInventoryChanges } from "@/src/services/inventoryService";
import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
import { IInventoryChanges } from "../types/purchaseTypes"; import { IInventoryChanges } from "../types/purchaseTypes";
import { config } from "../services/configService";
export const crackRelic = async ( export const crackRelic = async (
inventory: TInventoryDatabaseDocument, inventory: TInventoryDatabaseDocument,
@ -13,7 +14,14 @@ export const crackRelic = async (
inventoryChanges: IInventoryChanges = {} inventoryChanges: IInventoryChanges = {}
): Promise<IRngResult> => { ): Promise<IRngResult> => {
const relic = ExportRelics[participant.VoidProjection]; const relic = ExportRelics[participant.VoidProjection];
const weights = refinementToWeights[relic.quality]; let weights = refinementToWeights[relic.quality];
if (relic.quality == "VPQ_SILVER" && config.exceptionalRelicsAlwaysGiveBronzeReward) {
weights = { COMMON: 1, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
} else if (relic.quality == "VPQ_GOLD" && config.flawlessRelicsAlwaysGiveSilverReward) {
weights = { COMMON: 0, UNCOMMON: 1, RARE: 0, LEGENDARY: 0 };
} else if (relic.quality == "VPQ_PLATINUM" && config.radiantRelicsAlwaysGiveGoldReward) {
weights = { COMMON: 0, UNCOMMON: 0, RARE: 1, LEGENDARY: 0 };
}
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights); logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
const reward = getRandomWeightedReward( const reward = getRandomWeightedReward(
ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
@ -35,7 +43,13 @@ export const crackRelic = async (
// Give reward // Give reward
combineInventoryChanges( combineInventoryChanges(
inventoryChanges, inventoryChanges,
(await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount)).InventoryChanges (
await handleStoreItemAcquisition(
reward.type,
inventory,
reward.itemCount * (config.relicRewardItemCountMultiplier ?? 1)
)
).InventoryChanges
); );
return reward; return reward;

View File

@ -23,7 +23,9 @@ export interface IMessageDatabase extends IMessage {
export interface IMessage { export interface IMessage {
sndr: string; sndr: string;
msg: string; msg: string;
cinematic?: string;
sub: string; sub: string;
customData?: string;
icon?: string; icon?: string;
highPriority?: boolean; highPriority?: boolean;
lowPrioNewPlayers?: boolean; lowPrioNewPlayers?: boolean;
@ -102,7 +104,9 @@ const messageSchema = new Schema<IMessageDatabase>(
ownerId: Schema.Types.ObjectId, ownerId: Schema.Types.ObjectId,
sndr: String, sndr: String,
msg: String, msg: String,
cinematic: String,
sub: String, sub: String,
customData: String,
icon: String, icon: String,
highPriority: Boolean, highPriority: Boolean,
lowPrioNewPlayers: Boolean, lowPrioNewPlayers: Boolean,

View File

@ -64,9 +64,13 @@ export interface IConfig {
noDojoResearchTime?: boolean; noDojoResearchTime?: boolean;
fastClanAscension?: boolean; fastClanAscension?: boolean;
missionsCanGiveAllRelics?: boolean; missionsCanGiveAllRelics?: boolean;
exceptionalRelicsAlwaysGiveBronzeReward?: boolean;
flawlessRelicsAlwaysGiveSilverReward?: boolean;
radiantRelicsAlwaysGiveGoldReward?: boolean;
unlockAllSimarisResearchEntries?: boolean; unlockAllSimarisResearchEntries?: boolean;
disableDailyTribute?: boolean; disableDailyTribute?: boolean;
spoofMasteryRank?: number; spoofMasteryRank?: number;
relicRewardItemCountMultiplier?: number;
nightwaveStandingMultiplier?: number; nightwaveStandingMultiplier?: number;
unfaithfulBugFixes?: { unfaithfulBugFixes?: {
ignore1999LastRegionPlayed?: boolean; ignore1999LastRegionPlayed?: boolean;

View File

@ -550,6 +550,19 @@ export const processFundedGuildTechProject = (
guild.XP += recipe.guildXpValue; guild.XP += recipe.guildXpValue;
} }
setGuildTechLogState(guild, techProject.ItemType, config.noDojoResearchTime ? 4 : 3, techProject.CompletionDate); setGuildTechLogState(guild, techProject.ItemType, config.noDojoResearchTime ? 4 : 3, techProject.CompletionDate);
if (config.noDojoResearchTime) {
processCompletedGuildTechProject(guild, techProject.ItemType);
}
};
export const processCompletedGuildTechProject = (guild: TGuildDatabaseDocument, type: string): void => {
if (type.startsWith("/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/")) {
guild.VaultDecoRecipes ??= [];
guild.VaultDecoRecipes.push({
ItemType: type,
ItemCount: 1
});
}
}; };
export const setGuildTechLogState = ( export const setGuildTechLogState = (

View File

@ -83,7 +83,7 @@ import { addQuestKey, completeQuest } from "@/src/services/questService";
import { handleBundleAcqusition } from "./purchaseService"; import { handleBundleAcqusition } from "./purchaseService";
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService"; import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
import { createMessage } from "./inboxService"; import { createMessage, IMessageCreationTemplate } from "./inboxService";
import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper"; import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper";
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService"; import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
import { ICalendarSeason } from "@/src/types/worldStateTypes"; import { ICalendarSeason } from "@/src/types/worldStateTypes";
@ -483,6 +483,16 @@ export const addItem = async (
return addCustomization(inventory, typeName); return addCustomization(inventory, typeName);
} }
if (typeName in ExportUpgrades || typeName in ExportArcanes) { if (typeName in ExportUpgrades || typeName in ExportArcanes) {
if (targetFingerprint) {
if (quantity != 1) {
logger.warn(`adding 1 of ${typeName} ${targetFingerprint} even tho quantity ${quantity} was requested`);
}
inventory.Upgrades.push({
ItemType: typeName,
UpgradeFingerprint: targetFingerprint
});
return {}; // there's not exactly a common "InventoryChanges" format for these
}
const changes = [ const changes = [
{ {
ItemType: typeName, ItemType: typeName,
@ -1256,8 +1266,8 @@ export const addStanding = (
const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0); const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing; if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing;
if (syndicate.Title == -2 && syndicate.Standing + gainedStanding < -71000) { if (syndicate.Standing + gainedStanding < -71000) {
gainedStanding = -71000 + syndicate.Standing; gainedStanding = -71000 - syndicate.Standing;
} }
if (!isMedallion || syndicateMeta.medallionsCappedByDailyLimit) { if (!isMedallion || syndicateMeta.medallionsCappedByDailyLimit) {
@ -1563,7 +1573,22 @@ export const addEmailItem = async (
const meta = ExportEmailItems[typeName]; const meta = ExportEmailItems[typeName];
const emailItem = inventory.EmailItems.find(x => x.ItemType == typeName); const emailItem = inventory.EmailItems.find(x => x.ItemType == typeName);
if (!emailItem || !meta.sendOnlyOnce) { if (!emailItem || !meta.sendOnlyOnce) {
await createMessage(inventory.accountOwnerId, [convertInboxMessage(meta.message)]); const msg: IMessageCreationTemplate = convertInboxMessage(meta.message);
if (msg.cinematic == "/Lotus/Levels/1999/PlayerHomeBalconyCinematics.level") {
msg.customData = JSON.stringify({
Tag: msg.customData + "KissCin",
CinLoadout: {
Skins: inventory.AdultOperatorLoadOuts[0].Skins,
Upgrades: inventory.AdultOperatorLoadOuts[0].Upgrades,
attcol: inventory.AdultOperatorLoadOuts[0].attcol,
cloth: inventory.AdultOperatorLoadOuts[0].cloth,
eyecol: inventory.AdultOperatorLoadOuts[0].eyecol,
pricol: inventory.AdultOperatorLoadOuts[0].pricol,
syancol: inventory.AdultOperatorLoadOuts[0].syancol
}
});
}
await createMessage(inventory.accountOwnerId, [msg]);
if (emailItem) { if (emailItem) {
emailItem.ItemCount += 1; emailItem.ItemCount += 1;

View File

@ -45,6 +45,39 @@ export type WeaponTypeInternal =
| "SpecialItems"; | "SpecialItems";
export const getRecipe = (uniqueName: string): IRecipe | undefined => { export const getRecipe = (uniqueName: string): IRecipe | undefined => {
// Handle crafting of archwing summon for versions prior to 39.0.0 as this blueprint was removed then.
if (uniqueName == "/Lotus/Types/Recipes/EidolonRecipes/OpenArchwingSummonBlueprint") {
return {
resultType: "/Lotus/Types/Restoratives/OpenArchwingSummon",
buildPrice: 7500,
buildTime: 1800,
skipBuildTimePrice: 10,
consumeOnUse: false,
num: 1,
codexSecret: false,
alwaysAvailable: true,
ingredients: [
{
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/IraditeItem",
ItemCount: 50
},
{
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/GrokdrulItem",
ItemCount: 50
},
{
ItemType: "/Lotus/Types/Items/Fish/Eidolon/FishParts/EidolonFishOilItem",
ItemCount: 30
},
{
ItemType: "/Lotus/Types/Items/MiscItems/Circuits",
ItemCount: 600
}
],
excludeFromMarket: true
};
}
return ExportRecipes[uniqueName]; return ExportRecipes[uniqueName];
}; };
@ -218,7 +251,9 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => {
return { return {
sndr: message.sender, sndr: message.sender,
msg: message.body, msg: message.body,
cinematic: message.cinematic,
sub: message.title, sub: message.title,
customData: message.customData,
att: message.attachments.length > 0 ? message.attachments : undefined, att: message.attachments.length > 0 ? message.attachments : undefined,
countedAtt: message.countedAttachments.length > 0 ? message.countedAttachments : undefined, countedAtt: message.countedAttachments.length > 0 ? message.countedAttachments : undefined,
icon: message.icon ?? "", icon: message.icon ?? "",

View File

@ -167,8 +167,13 @@ export const handleInventoryItemConfigChange = async (
inventory.LotusCustomization = equipmentChanges.LotusCustomization; inventory.LotusCustomization = equipmentChanges.LotusCustomization;
break; break;
} }
case "ValidNewLoadoutId": {
logger.debug(`ignoring ValidNewLoadoutId (${equipmentChanges.ValidNewLoadoutId})`);
// seems always equal to the id of loadout config NORMAL[0], likely has no purpose and we're free to ignore it
break;
}
default: { default: {
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") { if (equipmentKeys.includes(equipmentName as TEquipmentKey)) {
logger.debug(`general Item config saved of type ${equipmentName}`, { logger.debug(`general Item config saved of type ${equipmentName}`, {
config: equipment config: equipment
}); });
@ -216,7 +221,7 @@ export const handleInventoryItemConfigChange = async (
} }
break; break;
} else { } else {
logger.warn(`loadout category not implemented, changes may be lost: ${equipmentName}`, { logger.error(`loadout category not implemented, changes will be lost: ${equipmentName}`, {
config: equipment config: equipment
}); });
} }

View File

@ -64,8 +64,12 @@ export const handleSetShipDecorations = async (
throw new Error(`unknown room: ${placedDecoration.Room}`); throw new Error(`unknown room: ${placedDecoration.Room}`);
} }
const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)!; const entry = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type);
if (!itemType || meta.capacityCost === undefined) { if (!entry) {
throw new Error(`unknown deco type: ${placedDecoration.Type}`);
}
const [itemType, meta] = entry;
if (meta.capacityCost === undefined) {
throw new Error(`unknown deco type: ${placedDecoration.Type}`); throw new Error(`unknown deco type: ${placedDecoration.Type}`);
} }

View File

@ -92,5 +92,13 @@
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/ThumperTrophySilverRecipe", "/Lotus/Levels/ClanDojo/ComponentPropRecipes/ThumperTrophySilverRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/CorpusPlaceables/GasTurbineConeRecipe", "/Lotus/Levels/ClanDojo/ComponentPropRecipes/CorpusPlaceables/GasTurbineConeRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NaturalPlaceables/CoralChunkARecipe", "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NaturalPlaceables/CoralChunkARecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/TennoPlaceables/TnoBeaconEmitterRecipe" "/Lotus/Levels/ClanDojo/ComponentPropRecipes/TennoPlaceables/TnoBeaconEmitterRecipe",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronFemaleSitting",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronFemaleStanding",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronMaleStanding",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronMaleStandingTwo",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisForeman",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisHazard",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisStrikerOne",
"/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisStrikerThree"
] ]

View File

@ -75,7 +75,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="w-100"> <div id="main-content" class="w-100">
<div data-route="/webui/" data-title="Login | OpenWF WebUI"> <div data-route="/webui/" data-title="Login | OpenWF WebUI">
<p data-loc="login_description"></p> <p data-loc="login_description"></p>
<form onsubmit="doLogin();return false;"> <form onsubmit="doLogin();return false;">
@ -527,6 +527,7 @@
<form class="input-group mb-3" onsubmit="doAcquireMod();return false;"> <form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
<input class="form-control" id="mod-count" type="number" value="1"/> <input class="form-control" id="mod-count" type="number" value="1"/>
<input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" /> <input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" />
<button class="btn btn-success" onclick="window.maxed=true" type="submit" data-loc="mods_addMax"></button>
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button> <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
</form> </form>
<table class="table table-hover w-100"> <table class="table table-hover w-100">
@ -546,6 +547,7 @@
</div> </div>
</div> </div>
<div data-route="/webui/quests" data-title="Quests | OpenWF WebUI"> <div data-route="/webui/quests" data-title="Quests | OpenWF WebUI">
<p class="mb-3" data-loc="general_inventoryUpdateNote"></p>
<div class="row g-3"> <div class="row g-3">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
@ -777,6 +779,18 @@
<input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" /> <input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" />
<label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label> <label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="exceptionalRelicsAlwaysGiveBronzeReward" />
<label class="form-check-label" for="exceptionalRelicsAlwaysGiveBronzeReward" data-loc="cheats_exceptionalRelicsAlwaysGiveBronzeReward"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="flawlessRelicsAlwaysGiveSilverReward" />
<label class="form-check-label" for="flawlessRelicsAlwaysGiveSilverReward" data-loc="cheats_flawlessRelicsAlwaysGiveSilverReward"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="radiantRelicsAlwaysGiveGoldReward" />
<label class="form-check-label" for="radiantRelicsAlwaysGiveGoldReward" data-loc="cheats_radiantRelicsAlwaysGiveGoldReward"></label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllSimarisResearchEntries" /> <input class="form-check-input" type="checkbox" id="unlockAllSimarisResearchEntries" />
<label class="form-check-label" for="unlockAllSimarisResearchEntries" data-loc="cheats_unlockAllSimarisResearchEntries"></label> <label class="form-check-label" for="unlockAllSimarisResearchEntries" data-loc="cheats_unlockAllSimarisResearchEntries"></label>
@ -788,14 +802,21 @@
<form class="form-group mt-2" onsubmit="doSaveConfigInt('spoofMasteryRank'); return false;"> <form class="form-group mt-2" onsubmit="doSaveConfigInt('spoofMasteryRank'); return false;">
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label> <label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
<div class="input-group"> <div class="input-group">
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" /> <input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" data-default="-1" />
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</div>
</form>
<form class="form-group mt-2" onsubmit="doSaveConfigInt('relicRewardItemCountMultiplier'); return false;">
<label class="form-label" for="relicRewardItemCountMultiplier" data-loc="cheats_relicRewardItemCountMultiplier"></label>
<div class="input-group">
<input class="form-control" id="relicRewardItemCountMultiplier" type="number" min="1" max="1000000" data-default="1" />
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button> <button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</div> </div>
</form> </form>
<form class="form-group mt-2" onsubmit="doSaveConfigInt('nightwaveStandingMultiplier'); return false;"> <form class="form-group mt-2" onsubmit="doSaveConfigInt('nightwaveStandingMultiplier'); return false;">
<label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label> <label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label>
<div class="input-group"> <div class="input-group">
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" value="1" /> <input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" data-default="1" />
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button> <button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</div> </div>
</form> </form>
@ -844,7 +865,7 @@
<label class="form-check-label" for="worldState.starDays" data-loc="worldState_starDays"></label> <label class="form-check-label" for="worldState.starDays" data-loc="worldState_starDays"></label>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_galleonOfGhouls"></label> <label class="form-label" for="worldState.galleonOfGhouls" data-loc="worldState_galleonOfGhouls"></label>
<select class="form-control" id="worldState.galleonOfGhouls"> <select class="form-control" id="worldState.galleonOfGhouls">
<option value="0" data-loc="disabled"></option> <option value="0" data-loc="disabled"></option>
<option value="1" data-loc="worldState_we1"></option> <option value="1" data-loc="worldState_we1"></option>
@ -853,7 +874,7 @@
</select> </select>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_eidolonOverride"></label> <label class="form-label" for="worldState.eidolonOverride" data-loc="worldState_eidolonOverride"></label>
<select class="form-control" id="worldState.eidolonOverride"> <select class="form-control" id="worldState.eidolonOverride">
<option value="" data-loc="disabled"></option> <option value="" data-loc="disabled"></option>
<option value="day" data-loc="worldState_day"></option> <option value="day" data-loc="worldState_day"></option>
@ -861,7 +882,7 @@
</select> </select>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_vallisOverride"></label> <label class="form-label" for="worldState.vallisOverride" data-loc="worldState_vallisOverride"></label>
<select class="form-control" id="worldState.vallisOverride"> <select class="form-control" id="worldState.vallisOverride">
<option value="" data-loc="disabled"></option> <option value="" data-loc="disabled"></option>
<option value="warm" data-loc="worldState_warm"></option> <option value="warm" data-loc="worldState_warm"></option>
@ -869,7 +890,7 @@
</select> </select>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_duviriOverride"></label> <label class="form-label" for="worldState.duviriOverride" data-loc="worldState_duviriOverride"></label>
<select class="form-control" id="worldState.duviriOverride"> <select class="form-control" id="worldState.duviriOverride">
<option value="" data-loc="disabled"></option> <option value="" data-loc="disabled"></option>
<option value="joy" data-loc="worldState_joy"></option> <option value="joy" data-loc="worldState_joy"></option>
@ -880,7 +901,7 @@
</select> </select>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_nightwaveOverride"></label> <label class="form-label" for="worldState.nightwaveOverride" data-loc="worldState_nightwaveOverride"></label>
<select class="form-control" id="worldState.nightwaveOverride"> <select class="form-control" id="worldState.nightwaveOverride">
<option value="" data-loc="disabled"></option> <option value="" data-loc="disabled"></option>
<option value="RadioLegionIntermission13Syndicate" data-loc="worldState_RadioLegionIntermission13Syndicate"></option> <option value="RadioLegionIntermission13Syndicate" data-loc="worldState_RadioLegionIntermission13Syndicate"></option>
@ -902,7 +923,7 @@
</select> </select>
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">
<label class="form-label" for="changeSyndicate" data-loc="worldState_fissures"></label> <label class="form-label" for="worldState.allTheFissures" data-loc="worldState_fissures"></label>
<select class="form-control" id="worldState.allTheFissures"> <select class="form-control" id="worldState.allTheFissures">
<option value="" data-loc="normal"></option> <option value="" data-loc="normal"></option>
<option value="normal" data-loc="worldState_allAtOnceNormal"></option> <option value="normal" data-loc="worldState_allAtOnceNormal"></option>
@ -917,9 +938,9 @@
</div> </div>
</form> </form>
<form class="form-group mt-2" onsubmit="doSaveConfigFloat('worldState.darvoStockMultiplier'); return false;"> <form class="form-group mt-2" onsubmit="doSaveConfigFloat('worldState.darvoStockMultiplier'); return false;">
<label class="form-label" for="worldState.circuitGameModes" data-loc="worldState_darvoStockMultiplier"></label> <label class="form-label" for="worldState.darvoStockMultiplier" data-loc="worldState_darvoStockMultiplier"></label>
<div class="input-group"> <div class="input-group">
<input id="worldState.darvoStockMultiplier" class="form-control" type="number" step="0.01" placeholder="1" /> <input id="worldState.darvoStockMultiplier" class="form-control" type="number" step="0.01" data-default="1" />
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button> <button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</div> </div>
</form> </form>

View File

@ -651,6 +651,7 @@ function updateInventory() {
{ {
const td = document.createElement("td"); const td = document.createElement("td");
td.classList = "text-end text-nowrap"; td.classList = "text-end text-nowrap";
let maxXP = Math.pow(uniqueLevelCaps[item.ItemType] ?? 30, 2) * 1000; let maxXP = Math.pow(uniqueLevelCaps[item.ItemType] ?? 30, 2) * 1000;
if ( if (
category != "Suits" && category != "Suits" &&
@ -663,7 +664,6 @@ function updateInventory() {
) { ) {
maxXP /= 2; maxXP /= 2;
} }
let anyExaltedMissingXP = false; let anyExaltedMissingXP = false;
if (item.XP >= maxXP && item.ItemType in itemMap && "exalted" in itemMap[item.ItemType]) { if (item.XP >= maxXP && item.ItemType in itemMap && "exalted" in itemMap[item.ItemType]) {
for (const exaltedType of itemMap[item.ItemType].exalted) { for (const exaltedType of itemMap[item.ItemType].exalted) {
@ -677,13 +677,6 @@ 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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M278.5 215.6L23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41c11.1-7.2 5.5-23-7.8-23c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3l-32.2 0c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7C506.4 207.6 512 184.1 512 160c0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149C91 197 64 262.1 64 330v55.3L253.6 195.8c6.2-6.2 16.4-6.2 22.6 0c5.4 5.4 6.1 13.6 2.2 19.8z"/></svg>`;
td.appendChild(a);
}
if (item.XP < maxXP || anyExaltedMissingXP) { if (item.XP < maxXP || anyExaltedMissingXP) {
const a = document.createElement("a"); const a = document.createElement("a");
a.href = "#"; a.href = "#";
@ -721,6 +714,14 @@ function updateInventory() {
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`; a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
td.appendChild(a); td.appendChild(a);
} }
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 = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M278.5 215.6L23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41c11.1-7.2 5.5-23-7.8-23c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3l-32.2 0c-5.1 0-9.2-4.1-9.2-9.2c0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7C506.4 207.6 512 184.1 512 160c0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149C91 197 64 262.1 64 330v55.3L253.6 195.8c6.2-6.2 16.4-6.2 22.6 0c5.4 5.4 6.1 13.6 2.2 19.8z"/></svg>`;
td.appendChild(a);
}
if (!(item.Features & 8) && modularWeapons.includes(item.ItemType)) { if (!(item.Features & 8) && modularWeapons.includes(item.ItemType)) {
const a = document.createElement("a"); const a = document.createElement("a");
a.href = "#"; a.href = "#";
@ -1872,6 +1873,8 @@ function setFingerprint(ItemType, ItemId, fingerprint) {
} }
function doAcquireMod() { function doAcquireMod() {
const maxed = !!window.maxed;
window.maxed = false;
const uniqueName = getKey(document.getElementById("mod-to-acquire")); const uniqueName = getKey(document.getElementById("mod-to-acquire"));
if (!uniqueName) { if (!uniqueName) {
$("#mod-to-acquire").addClass("is-invalid").focus(); $("#mod-to-acquire").addClass("is-invalid").focus();
@ -1879,14 +1882,15 @@ function doAcquireMod() {
} }
const count = parseInt($("#mod-count").val()); const count = parseInt($("#mod-count").val());
if (count != 0) { if (count != 0) {
revalidateAuthz().then(() => { Promise.all([window.itemListPromise, revalidateAuthz()]).then(([itemList]) => {
$.post({ $.post({
url: "/custom/addItems?" + window.authz, url: "/custom/addItems?" + window.authz,
contentType: "application/json", contentType: "application/json",
data: JSON.stringify([ data: JSON.stringify([
{ {
ItemType: uniqueName, ItemType: uniqueName,
ItemCount: count ItemCount: count,
Fingerprint: maxed ? JSON.stringify({ lvl: itemList[uniqueName].fusionLimit ?? 5 }) : undefined
} }
]) ])
}).done(function () { }).done(function () {
@ -1901,6 +1905,11 @@ function doAcquireMod() {
} }
} }
function doAcquireModMax() {
const uniqueName = getKey(document.getElementById("mod-to-acquire"));
alert("doAcquireModMax: " + uniqueName);
}
const uiConfigs = [...$(".config-form input[id], .config-form select[id]")].map(x => x.id); const uiConfigs = [...$(".config-form input[id], .config-form select[id]")].map(x => x.id);
for (const id of uiConfigs) { for (const id of uiConfigs) {
@ -1984,16 +1993,14 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
$(".config-admin-show").removeClass("d-none"); $(".config-admin-show").removeClass("d-none");
Object.entries(json).forEach(entry => { Object.entries(json).forEach(entry => {
const [key, value] = entry; const [key, value] = entry;
var x = document.getElementById(`${key}`); const elm = document.getElementById(key);
if (x != null) { if (elm.type == "checkbox") {
if (x.type == "checkbox") { elm.checked = value;
x.checked = value; } else if (elm.classList.contains("tags-input")) {
} else if (x.classList.contains("tags-input")) { elm.value = value.join(", ");
x.value = value.join(", "); elm.oninput();
x.oninput();
} else { } else {
x.value = value; elm.value = value ?? elm.getAttribute("data-default");
}
} }
}); });
}) })
@ -2738,3 +2745,9 @@ function handleValenceBonusChange(event) {
}); });
}); });
} }
document.querySelectorAll("#sidebar .nav-link").forEach(function (elm) {
elm.addEventListener("click", function () {
window.scrollTo(0, 0);
});
});

View File

@ -4,9 +4,19 @@
} }
body.logged-in #sidebar { body.logged-in #sidebar {
position: sticky; position: fixed;
top: 5rem; }
margin-right: 3rem;
body.logged-in #main-content {
margin-left: 7rem;
}
body.logged-in:has([data-lang="de"].active) #main-content {
margin-left: 8rem;
}
body.logged-in:has([data-lang="zh"].active) #main-content {
margin-left: 6rem;
} }
body:not(.logged-in) #sidebar { body:not(.logged-in) #sidebar {

View File

@ -127,6 +127,7 @@ dict = {
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`, mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
mods_rivens: `Rivens`, mods_rivens: `Rivens`,
mods_mods: `Mods`, mods_mods: `Mods`,
mods_addMax: `[UNTRANSLATED] Add Maxed`,
mods_addMissingUnrankedMods: `Fehlende Mods ohne Rang hinzufügen`, mods_addMissingUnrankedMods: `Fehlende Mods ohne Rang hinzufügen`,
mods_removeUnranked: `Mods ohne Rang entfernen`, mods_removeUnranked: `Mods ohne Rang entfernen`,
mods_addMissingMaxRankMods: `Fehlende Mods mit Max. Rang hinzufügen`, mods_addMissingMaxRankMods: `Fehlende Mods mit Max. Rang hinzufügen`,
@ -182,9 +183,13 @@ dict = {
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`, cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
cheats_fastClanAscension: `Schneller Clan-Aufstieg`, cheats_fastClanAscension: `Schneller Clan-Aufstieg`,
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`, cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `[UNTRANSLATED] Exceptional Relics Always Give Bronze Reward`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `[UNTRANSLATED] Flawless Relics Always Give Silver Reward`,
cheats_radiantRelicsAlwaysGiveGoldReward: `[UNTRANSLATED] Radiant Relics Always Give Gold Reward`,
cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`, cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`,
cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`,
cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`, cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`,
cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`,
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
cheats_save: `[UNTRANSLATED] Save`, cheats_save: `[UNTRANSLATED] Save`,
cheats_account: `Account`, cheats_account: `Account`,
@ -281,19 +286,19 @@ dict = {
upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`, upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`,
upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`, upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`,
upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`, upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`,
upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`, upgrade_OnExecutionAmmo: `[UNTRANSLATED] +100% Primary and Secondary Magazine Refill on Mercy`,
upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`, upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] +100% Health Orb Chance on Mercy`,
upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`, upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] +50% Energy Orb Chance on Mercy`,
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`, upgrade_OnFailHackReset: `[UNTRANSLATED] +50% Hacking Retry Chance`,
upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`, upgrade_DamageReductionOnHack: `[UNTRANSLATED] +75% Damage Reduction while Hacking`,
upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`, upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`,
upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`, upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`,
upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`, upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`,
upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`, upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`,
upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`, upgrade_OnExecutionTerrify: `[UNTRANSLATED] +50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`, upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`,
upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`, upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`,
upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`, upgrade_OnExecutionDrainPower: `[UNTRANSLATED] +100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`, upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`,
upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`,
upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`,

View File

@ -126,6 +126,7 @@ dict = {
mods_fingerprintHelp: `Need help with the fingerprint?`, mods_fingerprintHelp: `Need help with the fingerprint?`,
mods_rivens: `Rivens`, mods_rivens: `Rivens`,
mods_mods: `Mods`, mods_mods: `Mods`,
mods_addMax: `Add Maxed`,
mods_addMissingUnrankedMods: `Add Missing Unranked Mods`, mods_addMissingUnrankedMods: `Add Missing Unranked Mods`,
mods_removeUnranked: `Remove Unranked Mods`, mods_removeUnranked: `Remove Unranked Mods`,
mods_addMissingMaxRankMods: `Add Missing Max Rank Mods`, mods_addMissingMaxRankMods: `Add Missing Max Rank Mods`,
@ -181,9 +182,13 @@ dict = {
cheats_noDojoResearchTime: `No Dojo Research Time`, cheats_noDojoResearchTime: `No Dojo Research Time`,
cheats_fastClanAscension: `Fast Clan Ascension`, cheats_fastClanAscension: `Fast Clan Ascension`,
cheats_missionsCanGiveAllRelics: `Missions Can Give All Relics`, cheats_missionsCanGiveAllRelics: `Missions Can Give All Relics`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `Exceptional Relics Always Give Bronze Reward`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `Flawless Relics Always Give Silver Reward`,
cheats_radiantRelicsAlwaysGiveGoldReward: `Radiant Relics Always Give Gold Reward`,
cheats_unlockAllSimarisResearchEntries: `Unlock All Simaris Research Entries`, cheats_unlockAllSimarisResearchEntries: `Unlock All Simaris Research Entries`,
cheats_disableDailyTribute: `Disable Daily Tribute`, cheats_disableDailyTribute: `Disable Daily Tribute`,
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
cheats_relicRewardItemCountMultiplier: `Relic Reward Item Count Multiplier`,
cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`,
cheats_save: `Save`, cheats_save: `Save`,
cheats_account: `Account`, cheats_account: `Account`,
@ -280,19 +285,19 @@ dict = {
upgrade_AvatarLootRadar: `+7m Loot Radar`, upgrade_AvatarLootRadar: `+7m Loot Radar`,
upgrade_WeaponAmmoMax: `+15% Ammo Max`, upgrade_WeaponAmmoMax: `+15% Ammo Max`,
upgrade_EnemyArmorReductionAura: `-3% Enemy Armor`, upgrade_EnemyArmorReductionAura: `-3% Enemy Armor`,
upgrade_OnExecutionAmmo: `100% Primary and Secondary Magazine Refill on Mercy`, upgrade_OnExecutionAmmo: `+100% Primary and Secondary Magazine Refill on Mercy`,
upgrade_OnExecutionHealthDrop: `100% chance to drop a Health Orb on Mercy`, upgrade_OnExecutionHealthDrop: `+100% Health Orb Chance on Mercy`,
upgrade_OnExecutionEnergyDrop: `50% chance to drop an Energy Orb on Mercy`, upgrade_OnExecutionEnergyDrop: `+50% Energy Orb Chance on Mercy`,
upgrade_OnFailHackReset: `+50% to retry on Hacking failure`, upgrade_OnFailHackReset: `+50% Hacking Retry Chance`,
upgrade_DamageReductionOnHack: `75% Damage Reduction while Hacking`, upgrade_DamageReductionOnHack: `+75% Damage Reduction while Hacking`,
upgrade_OnExecutionReviveCompanion: `Mercy Kills reduce Companion Recovery by 15s`, upgrade_OnExecutionReviveCompanion: `Mercy Kills reduce Companion Recovery by 15s`,
upgrade_OnExecutionParkourSpeed: `+60% Parkour Speed after a Mercy for 15s`, upgrade_OnExecutionParkourSpeed: `+60% Parkour Speed after a Mercy for 15s`,
upgrade_AvatarTimeLimitIncrease: `+8s to Hacking`, upgrade_AvatarTimeLimitIncrease: `+8s to Hacking`,
upgrade_ElectrifyOnHack: `Shock enemies within 20m while Hacking`, upgrade_ElectrifyOnHack: `Shock enemies within 20m while Hacking`,
upgrade_OnExecutionTerrify: `50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`, upgrade_OnExecutionTerrify: `+50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
upgrade_OnHackLockers: `Unlock 5 lockers within 20m after Hacking`, upgrade_OnHackLockers: `Unlock 5 lockers within 20m after Hacking`,
upgrade_OnExecutionBlind: `Blind enemies within 18m on Mercy`, upgrade_OnExecutionBlind: `Blind enemies within 18m on Mercy`,
upgrade_OnExecutionDrainPower: `100% chance for next ability cast to gain +50% Ability Strength on Mercy`, upgrade_OnExecutionDrainPower: `+100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
upgrade_OnHackSprintSpeed: `+75% Sprint Speed for 15s after Hacking`, upgrade_OnHackSprintSpeed: `+75% Sprint Speed for 15s after Hacking`,
upgrade_SwiftExecute: `Speed of Mercy Kills increased by 50%`, upgrade_SwiftExecute: `Speed of Mercy Kills increased by 50%`,
upgrade_OnHackInvis: `Invisible for 15 seconds after hacking`, upgrade_OnHackInvis: `Invisible for 15 seconds after hacking`,

View File

@ -2,8 +2,8 @@
dict = { dict = {
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_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_addButton: `Agregar`,
general_setButton: `[UNTRANSLATED] Set`, general_setButton: `Establecer`,
general_removeButton: `[UNTRANSLATED] Remove`, general_removeButton: `Quitar`,
general_bulkActions: `Acciones masivas`, general_bulkActions: `Acciones masivas`,
code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`, code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
@ -120,13 +120,14 @@ dict = {
detailedView_archonShardsDescription: `Puedes usar estas ranuras ilimitadas para aplicar una amplia variedad de mejoras`, 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_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_valenceBonusLabel: `Bônus de Valência`,
detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, detailedView_valenceBonusDescription: `Puedes establecer o quitar el bono de valencia de tu arma.`,
mods_addRiven: `Agregar Agrietado`, mods_addRiven: `Agregar Agrietado`,
mods_fingerprint: `Huella digital`, mods_fingerprint: `Huella digital`,
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`, mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
mods_rivens: `Agrietados`, mods_rivens: `Agrietados`,
mods_mods: `Mods`, mods_mods: `Mods`,
mods_addMax: `[UNTRANSLATED] Add Maxed`,
mods_addMissingUnrankedMods: `Agregar mods sin rango faltantes`, mods_addMissingUnrankedMods: `Agregar mods sin rango faltantes`,
mods_removeUnranked: `Quitar mods sin rango`, mods_removeUnranked: `Quitar mods sin rango`,
mods_addMissingMaxRankMods: `Agregar mods de rango máximo faltantes`, mods_addMissingMaxRankMods: `Agregar mods de rango máximo faltantes`,
@ -136,7 +137,7 @@ dict = {
cheats_skipAllDialogue: `Omitir todos los diálogos`, cheats_skipAllDialogue: `Omitir todos los diálogos`,
cheats_unlockAllScans: `Desbloquear todos los escaneos`, cheats_unlockAllScans: `Desbloquear todos los escaneos`,
cheats_unlockAllMissions: `Desbloquear todas las misiones`, 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_unlockAllMissions_ok: `Éxito. Ten en cuenta que deberás entrar a un dojo, repetidor o volver a iniciar sesión para que el cliente actualice el mapa estelar.`,
cheats_infiniteCredits: `Créditos infinitos`, cheats_infiniteCredits: `Créditos infinitos`,
cheats_infinitePlatinum: `Platino infinito`, cheats_infinitePlatinum: `Platino infinito`,
cheats_infiniteEndo: `Endo infinito`, cheats_infiniteEndo: `Endo infinito`,
@ -182,9 +183,13 @@ dict = {
cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`, cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`,
cheats_fastClanAscension: `Ascenso rápido del clan`, cheats_fastClanAscension: `Ascenso rápido del clan`,
cheats_missionsCanGiveAllRelics: `Las misiones pueden otorgar todas las reliquias`, cheats_missionsCanGiveAllRelics: `Las misiones pueden otorgar todas las reliquias`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `[UNTRANSLATED] Exceptional Relics Always Give Bronze Reward`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `[UNTRANSLATED] Flawless Relics Always Give Silver Reward`,
cheats_radiantRelicsAlwaysGiveGoldReward: `[UNTRANSLATED] Radiant Relics Always Give Gold Reward`,
cheats_unlockAllSimarisResearchEntries: `Desbloquear todas las entradas de investigación de Simaris`, cheats_unlockAllSimarisResearchEntries: `Desbloquear todas las entradas de investigación de Simaris`,
cheats_disableDailyTribute: `Desactivar tributo diario`, cheats_disableDailyTribute: `Desactivar tributo diario`,
cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`, cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`,
cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`,
cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`, cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`,
cheats_save: `Guardar`, cheats_save: `Guardar`,
cheats_account: `Cuenta`, cheats_account: `Cuenta`,
@ -306,8 +311,8 @@ dict = {
damageType_Poison: `Tóxico`, damageType_Poison: `Tóxico`,
damageType_Radiation: `Radioativo`, damageType_Radiation: `Radioativo`,
theme_dark: `[UNTRANSLATED] Dark Theme`, theme_dark: `Tema Oscuro`,
theme_light: `[UNTRANSLATED] Light Theme`, theme_light: `Tema Claro`,
prettier_sucks_ass: `` prettier_sucks_ass: ``
}; };

View File

@ -127,6 +127,7 @@ dict = {
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`, mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
mods_rivens: `Rivens`, mods_rivens: `Rivens`,
mods_mods: `Mods`, mods_mods: `Mods`,
mods_addMax: `[UNTRANSLATED] Add Maxed`,
mods_addMissingUnrankedMods: `Ajouter les mods sans rang manquants`, mods_addMissingUnrankedMods: `Ajouter les mods sans rang manquants`,
mods_removeUnranked: `Retirer les mods sans rang`, mods_removeUnranked: `Retirer les mods sans rang`,
mods_addMissingMaxRankMods: `Ajouter les mods niveau max manquants`, mods_addMissingMaxRankMods: `Ajouter les mods niveau max manquants`,
@ -182,9 +183,13 @@ dict = {
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`, cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
cheats_fastClanAscension: `Ascension de clan rapide`, cheats_fastClanAscension: `Ascension de clan rapide`,
cheats_missionsCanGiveAllRelics: `Les missions donnent toutes les reliques`, cheats_missionsCanGiveAllRelics: `Les missions donnent toutes les reliques`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `[UNTRANSLATED] Exceptional Relics Always Give Bronze Reward`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `[UNTRANSLATED] Flawless Relics Always Give Silver Reward`,
cheats_radiantRelicsAlwaysGiveGoldReward: `[UNTRANSLATED] Radiant Relics Always Give Gold Reward`,
cheats_unlockAllSimarisResearchEntries: `Débloquer toute les recherches chez Simaris`, cheats_unlockAllSimarisResearchEntries: `Débloquer toute les recherches chez Simaris`,
cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`,
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`, cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`,
cheats_nightwaveStandingMultiplier: `Multiplicateur de réputation d'Ondes Nocturnes`, cheats_nightwaveStandingMultiplier: `Multiplicateur de réputation d'Ondes Nocturnes`,
cheats_save: `Sauvegarder`, cheats_save: `Sauvegarder`,
cheats_account: `Compte`, cheats_account: `Compte`,
@ -284,7 +289,7 @@ dict = {
upgrade_OnExecutionAmmo: `100% de rechargement des armes primaires et secondaires sur une une miséricorde`, upgrade_OnExecutionAmmo: `100% de rechargement des armes primaires et secondaires sur une une miséricorde`,
upgrade_OnExecutionHealthDrop: `100% de chance de drop une orbe de santé sur une miséricorde`, upgrade_OnExecutionHealthDrop: `100% de chance de drop une orbe de santé sur une miséricorde`,
upgrade_OnExecutionEnergyDrop: `50% de chance de drop une orbe d'énergie sur une miséricorde`, upgrade_OnExecutionEnergyDrop: `50% de chance de drop une orbe d'énergie sur une miséricorde`,
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`, upgrade_OnFailHackReset: `[UNTRANSLATED] +50% Hacking Retry Chance`,
upgrade_DamageReductionOnHack: `75% de réduction de dégâts pendant un piratage`, upgrade_DamageReductionOnHack: `75% de réduction de dégâts pendant un piratage`,
upgrade_OnExecutionReviveCompanion: `Les miséricordes réduisent le temps de récupération du compagnon de 15s`, upgrade_OnExecutionReviveCompanion: `Les miséricordes réduisent le temps de récupération du compagnon de 15s`,
upgrade_OnExecutionParkourSpeed: `+60% de vitesse de parkour pendant 15s après une miséricorde`, upgrade_OnExecutionParkourSpeed: `+60% de vitesse de parkour pendant 15s après une miséricorde`,

View File

@ -127,6 +127,7 @@ dict = {
mods_fingerprintHelp: `Нужна помощь с отпечатком?`, mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
mods_rivens: `Моды Разлома`, mods_rivens: `Моды Разлома`,
mods_mods: `Моды`, mods_mods: `Моды`,
mods_addMax: `[UNTRANSLATED] Add Maxed`,
mods_addMissingUnrankedMods: `Добавить недостающие моды без ранга`, mods_addMissingUnrankedMods: `Добавить недостающие моды без ранга`,
mods_removeUnranked: `Удалить моды без ранга`, mods_removeUnranked: `Удалить моды без ранга`,
mods_addMissingMaxRankMods: `Добавить недостающие моды максимального ранга`, mods_addMissingMaxRankMods: `Добавить недостающие моды максимального ранга`,
@ -182,9 +183,13 @@ dict = {
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`, cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
cheats_fastClanAscension: `Мгновенное Вознесение Клана`, cheats_fastClanAscension: `Мгновенное Вознесение Клана`,
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`, cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `[UNTRANSLATED] Exceptional Relics Always Give Bronze Reward`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `[UNTRANSLATED] Flawless Relics Always Give Silver Reward`,
cheats_radiantRelicsAlwaysGiveGoldReward: `[UNTRANSLATED] Radiant Relics Always Give Gold Reward`,
cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`, cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`,
cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`,
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`, cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`,
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
cheats_save: `[UNTRANSLATED] Save`, cheats_save: `[UNTRANSLATED] Save`,
cheats_account: `Аккаунт`, cheats_account: `Аккаунт`,
@ -281,19 +286,19 @@ dict = {
upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`, upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`,
upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`, upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`,
upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`, upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`,
upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`, upgrade_OnExecutionAmmo: `[UNTRANSLATED] +100% Primary and Secondary Magazine Refill on Mercy`,
upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`, upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] +100% Health Orb Chance on Mercy`,
upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`, upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] +50% Energy Orb Chance on Mercy`,
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`, upgrade_OnFailHackReset: `[UNTRANSLATED] +50% Hacking Retry Chance`,
upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`, upgrade_DamageReductionOnHack: `[UNTRANSLATED] +75% Damage Reduction while Hacking`,
upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`, upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`,
upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`, upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`,
upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`, upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] +8s to Hacking`,
upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`, upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`,
upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`, upgrade_OnExecutionTerrify: `[UNTRANSLATED] +50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`, upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`,
upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`, upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`,
upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`, upgrade_OnExecutionDrainPower: `[UNTRANSLATED] +100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`, upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`,
upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`,
upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`,

View File

@ -2,8 +2,8 @@
dict = { dict = {
general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场 / 中继站或重新登录`, general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场 / 中继站或重新登录`,
general_addButton: `添加`, general_addButton: `添加`,
general_setButton: `[UNTRANSLATED] Set`, general_setButton: `设置`,
general_removeButton: `[UNTRANSLATED] Remove`, general_removeButton: `移除`,
general_bulkActions: `批量操作`, general_bulkActions: `批量操作`,
code_loginFail: `登录失败。请检查邮箱和密码。`, code_loginFail: `登录失败。请检查邮箱和密码。`,
@ -120,13 +120,14 @@ dict = {
detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`, detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`,
detailedView_archonShardsDescription2: `请注意, 在加载时, 每个执政官源力石都需要一定的时间来生效。`, detailedView_archonShardsDescription2: `请注意, 在加载时, 每个执政官源力石都需要一定的时间来生效。`,
detailedView_valenceBonusLabel: `效价加成`, detailedView_valenceBonusLabel: `效价加成`,
detailedView_valenceBonusDescription: `[UNTRANSLATED] You can set or remove the Valence Bonus from your weapon.`, detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成。`,
mods_addRiven: `添加裂罅MOD`, mods_addRiven: `添加裂罅MOD`,
mods_fingerprint: `印记`, mods_fingerprint: `印记`,
mods_fingerprintHelp: `需要印记相关的帮助?`, mods_fingerprintHelp: `需要印记相关的帮助?`,
mods_rivens: `裂罅MOD`, mods_rivens: `裂罅MOD`,
mods_mods: `Mods`, mods_mods: `Mods`,
mods_addMax: `添加(满级)`,
mods_addMissingUnrankedMods: `添加所有缺失的Mods`, mods_addMissingUnrankedMods: `添加所有缺失的Mods`,
mods_removeUnranked: `删除所有未升级的Mods`, mods_removeUnranked: `删除所有未升级的Mods`,
mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`, mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`,
@ -136,17 +137,17 @@ dict = {
cheats_skipAllDialogue: `跳过所有对话`, cheats_skipAllDialogue: `跳过所有对话`,
cheats_unlockAllScans: `解锁所有扫描`, cheats_unlockAllScans: `解锁所有扫描`,
cheats_unlockAllMissions: `解锁所有任务`, 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_unlockAllMissions_ok: `操作成功。请注意,您需要进入道场 / 中继站或重新登录客户端以刷新星图数据。`,
cheats_infiniteCredits: `无限现金`, cheats_infiniteCredits: `无限现金`,
cheats_infinitePlatinum: `无限白金`, cheats_infinitePlatinum: `无限白金`,
cheats_infiniteEndo: `无限内融核心`, cheats_infiniteEndo: `无限内融核心`,
cheats_infiniteRegalAya: `无限御品阿耶`, cheats_infiniteRegalAya: `无限御品阿耶`,
cheats_infiniteHelminthMaterials: `无限Helminth材料`, cheats_infiniteHelminthMaterials: `无限Helminth材料`,
cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`, cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`,
cheats_dontSubtractPurchaseCreditCost: `不减少现金花费`, cheats_dontSubtractPurchaseCreditCost: `购物时不减少现金花费`,
cheats_dontSubtractPurchasePlatinumCost: `不减少白金花费`, cheats_dontSubtractPurchasePlatinumCost: `购物时不减少白金花费`,
cheats_dontSubtractPurchaseItemCost: `不减少物品花费`, cheats_dontSubtractPurchaseItemCost: `购物时不减少物品花费`,
cheats_dontSubtractPurchaseStandingCost: `不减少声望花费`, cheats_dontSubtractPurchaseStandingCost: `购物时不减少声望花费`,
cheats_dontSubtractVoidTraces: `虚空光体无消耗`, cheats_dontSubtractVoidTraces: `虚空光体无消耗`,
cheats_dontSubtractConsumables: `消耗物品使用时无损耗`, cheats_dontSubtractConsumables: `消耗物品使用时无损耗`,
cheats_unlockAllShipFeatures: `解锁所有飞船功能`, cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
@ -182,9 +183,13 @@ dict = {
cheats_noDojoResearchTime: `无视道场研究时间`, cheats_noDojoResearchTime: `无视道场研究时间`,
cheats_fastClanAscension: `快速升级氏族`, cheats_fastClanAscension: `快速升级氏族`,
cheats_missionsCanGiveAllRelics: `任务可获取所有遗物`, cheats_missionsCanGiveAllRelics: `任务可获取所有遗物`,
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `卓越遗物必定掉落青铜奖励`,
cheats_flawlessRelicsAlwaysGiveSilverReward: `无瑕遗物必定掉落白银奖励`,
cheats_radiantRelicsAlwaysGiveGoldReward: `光辉遗物必定掉落黄金奖励`,
cheats_unlockAllSimarisResearchEntries: `解锁所有Simaris研究条目`, cheats_unlockAllSimarisResearchEntries: `解锁所有Simaris研究条目`,
cheats_disableDailyTribute: `禁用每日登录奖励`, cheats_disableDailyTribute: `禁用每日登录奖励`,
cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`,
cheats_relicRewardItemCountMultiplier: `虚空遗物奖励物品数量倍率`,
cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`, cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`,
cheats_save: `保存`, cheats_save: `保存`,
cheats_account: `账户`, cheats_account: `账户`,
@ -306,8 +311,8 @@ dict = {
damageType_Poison: `毒素`, damageType_Poison: `毒素`,
damageType_Radiation: `辐射`, damageType_Radiation: `辐射`,
theme_dark: `[UNTRANSLATED] Dark Theme`, theme_dark: `暗色主题`,
theme_light: `[UNTRANSLATED] Light Theme`, theme_light: `亮色主题`,
prettier_sucks_ass: `` prettier_sucks_ass: ``
}; };