merge upstream

This commit is contained in:
Slayer55555 2025-10-05 17:16:30 -07:00
commit acde743410
12 changed files with 185 additions and 146 deletions

View File

@ -1,12 +1,13 @@
import type { RequestHandler } from "express"; import type { Request, RequestHandler } from "express";
import { Inbox } from "../../models/inboxModel.ts"; import { Inbox } from "../../models/inboxModel.ts";
import { import {
createMessage, createMessage,
createNewEventMessages,
deleteAllMessagesRead, deleteAllMessagesRead,
deleteAllMessagesReadNonCin,
deleteMessageRead, deleteMessageRead,
getAllMessagesSorted, getAllMessagesSorted,
getMessage getMessage,
type IMessageCreationTemplate
} from "../../services/inboxService.ts"; } from "../../services/inboxService.ts";
import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "../../services/loginService.ts"; import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "../../services/loginService.ts";
import { import {
@ -21,6 +22,9 @@ import { ExportFlavour } from "warframe-public-export-plus";
import { handleStoreItemAcquisition } from "../../services/purchaseService.ts"; import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
import { fromStoreItem, isStoreItem } from "../../services/itemDataService.ts"; import { fromStoreItem, isStoreItem } from "../../services/itemDataService.ts";
import type { IOid } from "../../types/commonTypes.ts"; import type { IOid } from "../../types/commonTypes.ts";
import { unixTimesInMs } from "../../constants/timeConstants.ts";
import { config } from "../../services/configService.ts";
import { Types } from "mongoose";
export const inboxController: RequestHandler = async (req, res) => { export const inboxController: RequestHandler = async (req, res) => {
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query; const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
@ -31,11 +35,11 @@ export const inboxController: RequestHandler = async (req, res) => {
if (deleteId) { if (deleteId) {
if (deleteId === "DeleteAllRead") { if (deleteId === "DeleteAllRead") {
await deleteAllMessagesRead(accountId); await deleteAllMessagesRead(accountId);
res.status(200).end(); } else if (deleteId === "DeleteAllReadNonCin") {
return; await deleteAllMessagesReadNonCin(accountId);
} else {
await deleteMessageRead(parseOid(deleteId as string));
} }
await deleteMessageRead(parseOid(deleteId as string));
res.status(200).end(); res.status(200).end();
} else if (messageId) { } else if (messageId) {
const message = await getMessage(parseOid(messageId as string)); const message = await getMessage(parseOid(messageId as string));
@ -134,6 +138,119 @@ export const inboxController: RequestHandler = async (req, res) => {
} }
}; };
const createNewEventMessages = async (req: Request): Promise<void> => {
const account = await getAccountForRequest(req);
const newEventMessages: IMessageCreationTemplate[] = [];
// Baro
const baroIndex = Math.trunc((Date.now() - 910800000) / (unixTimesInMs.day * 14));
const baroStart = baroIndex * (unixTimesInMs.day * 14) + 910800000;
const baroActualStart = baroStart + unixTimesInMs.day * (config.worldState?.baroAlwaysAvailable ? 0 : 12);
if (Date.now() >= baroActualStart && account.LatestEventMessageDate.getTime() < baroActualStart) {
newEventMessages.push({
sndr: "/Lotus/Language/G1Quests/VoidTraderName",
sub: "/Lotus/Language/CommunityMessages/VoidTraderAppearanceTitle",
msg: "/Lotus/Language/CommunityMessages/VoidTraderAppearanceMessage",
icon: "/Lotus/Interface/Icons/Npcs/BaroKiTeerPortrait.png",
startDate: new Date(baroActualStart),
endDate: new Date(baroStart + unixTimesInMs.day * 14),
CrossPlatform: true,
arg: [
{
Key: "NODE_NAME",
Tag: ["EarthHUB", "MercuryHUB", "SaturnHUB", "PlutoHUB"][baroIndex % 4]
}
],
date: new Date(baroActualStart)
});
}
// BUG: Deleting the inbox message manually means it'll just be automatically re-created. This is because we don't use startDate/endDate for these config-toggled events.
const promises = [];
if (config.worldState?.creditBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666672" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666672"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleCreditsName",
msg: "/Lotus/Language/Items/EventDoubleCreditsDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.affinityBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666673" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666673"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleAffinityName",
msg: "/Lotus/Language/Items/EventDoubleAffinityDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.resourceBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666674" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666674"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleResourceName",
msg: "/Lotus/Language/Items/EventDoubleResourceDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.galleonOfGhouls) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, goalTag: "GalleonRobbery" }))) {
newEventMessages.push({
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
sub: "/Lotus/Language/Events/GalleonRobberyIntroMsgTitle",
msg: "/Lotus/Language/Events/GalleonRobberyIntroMsgDesc",
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png",
transmission: "/Lotus/Sounds/Dialog/GalleonOfGhouls/DGhoulsWeekOneInbox0010VayHek",
att: ["/Lotus/Upgrades/Skins/Events/OgrisOldSchool"],
startDate: new Date(),
goalTag: "GalleonRobbery"
});
}
})()
);
}
await Promise.all(promises);
if (newEventMessages.length === 0) {
return;
}
await createMessage(account._id, newEventMessages);
const latestEventMessage = newEventMessages.reduce((prev, current) =>
prev.startDate! > current.startDate! ? prev : current
);
account.LatestEventMessageDate = new Date(latestEventMessage.startDate!);
await account.save();
};
// 33.6.0 has query arguments like lastMessage={"$oid":"68112baebf192e786d1502bb"} instead of lastMessage=68112baebf192e786d1502bb // 33.6.0 has query arguments like lastMessage={"$oid":"68112baebf192e786d1502bb"} instead of lastMessage=68112baebf192e786d1502bb
const parseOid = (oid: string): string => { const parseOid = (oid: string): string => {
if (oid[0] == "{") { if (oid[0] == "{") {

View File

@ -335,15 +335,16 @@ export const getInventoryResponse = async (
} }
if (config.unlockAllSkins) { if (config.unlockAllSkins) {
const missingWeaponSkins = new Set(Object.keys(ExportCustoms)); const ownedWeaponSkins = new Set<string>(inventoryResponse.WeaponSkins.map(x => x.ItemType));
inventoryResponse.WeaponSkins.forEach(x => missingWeaponSkins.delete(x.ItemType)); for (const [uniqueName, meta] of Object.entries(ExportCustoms)) {
for (const uniqueName of missingWeaponSkins) { if (!meta.alwaysAvailable && !ownedWeaponSkins.has(uniqueName)) {
inventoryResponse.WeaponSkins.push({ inventoryResponse.WeaponSkins.push({
ItemId: { ItemId: {
$oid: "ca70ca70ca70ca70" + catBreadHash(uniqueName).toString(16).padStart(8, "0") $oid: "ca70ca70ca70ca70" + catBreadHash(uniqueName).toString(16).padStart(8, "0")
}, },
ItemType: uniqueName ItemType: uniqueName
}); });
}
} }
} }

View File

@ -9,6 +9,9 @@ import type { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "../../
import { logger } from "../../utils/logger.ts"; import { logger } from "../../utils/logger.ts";
import { version_compare } from "../../helpers/inventoryHelpers.ts"; import { version_compare } from "../../helpers/inventoryHelpers.ts";
import { handleNonceInvalidation } from "../../services/wsService.ts"; import { handleNonceInvalidation } from "../../services/wsService.ts";
import { getInventory } from "../../services/inventoryService.ts";
import { createMessage } from "../../services/inboxService.ts";
import { fromStoreItem } from "../../services/itemDataService.ts";
export const loginController: RequestHandler = async (request, response) => { export const loginController: RequestHandler = async (request, response) => {
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
@ -76,6 +79,24 @@ export const loginController: RequestHandler = async (request, response) => {
handleNonceInvalidation(account._id.toString()); handleNonceInvalidation(account._id.toString());
// If the client crashed during an endless fissure mission, discharge rewards to an inbox message. (https://www.reddit.com/r/Warframe/comments/5uwwjm/til_if_you_crash_during_a_fissure_you_keep_any/)
const inventory = await getInventory(account._id.toString(), "MissionRelicRewards");
if (inventory.MissionRelicRewards) {
await createMessage(account._id, [
{
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Menu/VoidProjectionItemsMessage",
sub: "/Lotus/Language/Menu/VoidProjectionItemsSubject",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
countedAtt: inventory.MissionRelicRewards.map(x => ({ ...x, ItemType: fromStoreItem(x.ItemType) })),
attVisualOnly: true,
highPriority: true // TOVERIFY
}
]);
inventory.MissionRelicRewards = undefined;
await inventory.save();
}
response.json(createLoginResponse(myAddress, myUrlBase, account.toJSON(), buildLabel)); response.json(createLoginResponse(myAddress, myUrlBase, account.toJSON(), buildLabel));
}; };

View File

@ -115,7 +115,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
if (stage > 0) { if (stage > 0) {
await giveKeyChainStageTriggered(inventory, { await giveKeyChainStageTriggered(inventory, {
KeyChain: questKey.ItemType, KeyChain: questKey.ItemType,
ChainStage: stage ChainStage: stage - 1
}); });
} }
} }

View File

@ -6,6 +6,7 @@ import type {
} from "../types/inventoryTypes/commonInventoryTypes.ts"; } from "../types/inventoryTypes/commonInventoryTypes.ts";
import type { IMongoDate } from "../types/commonTypes.ts"; import type { IMongoDate } from "../types/commonTypes.ts";
import type { import type {
IBooster,
IDialogueClient, IDialogueClient,
IDialogueDatabase, IDialogueDatabase,
IDialogueHistoryClient, IDialogueHistoryClient,
@ -463,6 +464,9 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
if (client.Accolades !== undefined) { if (client.Accolades !== undefined) {
db.Accolades = client.Accolades; db.Accolades = client.Accolades;
} }
if (client.Boosters !== undefined) {
replaceArray<IBooster>(db.Boosters, client.Boosters);
}
}; };
export const importLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => { export const importLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {

View File

@ -1,11 +1,6 @@
import type { IMessageDatabase } from "../models/inboxModel.ts"; import type { IMessageDatabase } from "../models/inboxModel.ts";
import { Inbox } from "../models/inboxModel.ts"; import { Inbox } from "../models/inboxModel.ts";
import { getAccountForRequest } from "./loginService.ts"; import type { HydratedDocument, Types } from "mongoose";
import type { HydratedDocument } from "mongoose";
import { Types } from "mongoose";
import type { Request } from "express";
import { unixTimesInMs } from "../constants/timeConstants.ts";
import { config } from "./configService.ts";
export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => { export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => {
const inbox = await Inbox.find({ ownerId: accountId }).sort({ date: -1 }); const inbox = await Inbox.find({ ownerId: accountId }).sort({ date: -1 });
@ -29,117 +24,8 @@ export const deleteAllMessagesRead = async (accountId: string): Promise<void> =>
await Inbox.deleteMany({ ownerId: accountId, r: true }); await Inbox.deleteMany({ ownerId: accountId, r: true });
}; };
export const createNewEventMessages = async (req: Request): Promise<void> => { export const deleteAllMessagesReadNonCin = async (accountId: string): Promise<void> => {
const account = await getAccountForRequest(req); await Inbox.deleteMany({ ownerId: accountId, r: true, cinematic: null });
const newEventMessages: IMessageCreationTemplate[] = [];
// Baro
const baroIndex = Math.trunc((Date.now() - 910800000) / (unixTimesInMs.day * 14));
const baroStart = baroIndex * (unixTimesInMs.day * 14) + 910800000;
const baroActualStart = baroStart + unixTimesInMs.day * (config.worldState?.baroAlwaysAvailable ? 0 : 12);
if (Date.now() >= baroActualStart && account.LatestEventMessageDate.getTime() < baroActualStart) {
newEventMessages.push({
sndr: "/Lotus/Language/G1Quests/VoidTraderName",
sub: "/Lotus/Language/CommunityMessages/VoidTraderAppearanceTitle",
msg: "/Lotus/Language/CommunityMessages/VoidTraderAppearanceMessage",
icon: "/Lotus/Interface/Icons/Npcs/BaroKiTeerPortrait.png",
startDate: new Date(baroActualStart),
endDate: new Date(baroStart + unixTimesInMs.day * 14),
CrossPlatform: true,
arg: [
{
Key: "NODE_NAME",
Tag: ["EarthHUB", "MercuryHUB", "SaturnHUB", "PlutoHUB"][baroIndex % 4]
}
],
date: new Date(baroActualStart)
});
}
// BUG: Deleting the inbox message manually means it'll just be automatically re-created. This is because we don't use startDate/endDate for these config-toggled events.
const promises = [];
if (config.worldState?.creditBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666672" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666672"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleCreditsName",
msg: "/Lotus/Language/Items/EventDoubleCreditsDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.affinityBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666673" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666673"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleAffinityName",
msg: "/Lotus/Language/Items/EventDoubleAffinityDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.resourceBoost) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, globaUpgradeId: "5b23106f283a555109666674" }))) {
newEventMessages.push({
globaUpgradeId: new Types.ObjectId("5b23106f283a555109666674"),
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
sub: "/Lotus/Language/Items/EventDoubleResourceName",
msg: "/Lotus/Language/Items/EventDoubleResourceDesc",
icon: "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
startDate: new Date(),
CrossPlatform: true
});
}
})()
);
}
if (config.worldState?.galleonOfGhouls) {
promises.push(
(async (): Promise<void> => {
if (!(await Inbox.exists({ ownerId: account._id, goalTag: "GalleonRobbery" }))) {
newEventMessages.push({
sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
sub: "/Lotus/Language/Events/GalleonRobberyIntroMsgTitle",
msg: "/Lotus/Language/Events/GalleonRobberyIntroMsgDesc",
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png",
transmission: "/Lotus/Sounds/Dialog/GalleonOfGhouls/DGhoulsWeekOneInbox0010VayHek",
att: ["/Lotus/Upgrades/Skins/Events/OgrisOldSchool"],
startDate: new Date(),
goalTag: "GalleonRobbery"
});
}
})()
);
}
await Promise.all(promises);
if (newEventMessages.length === 0) {
return;
}
await createMessage(account._id, newEventMessages);
const latestEventMessage = newEventMessages.reduce((prev, current) =>
prev.startDate! > current.startDate! ? prev : current
);
account.LatestEventMessageDate = new Date(latestEventMessage.startDate!);
await account.save();
}; };
export const createMessage = async ( export const createMessage = async (

View File

@ -331,7 +331,7 @@ export const giveKeyChainMessage = async (
): Promise<void> => { ): Promise<void> => {
const keyChainMessage = getKeyChainMessage(keyChainInfo); const keyChainMessage = getKeyChainMessage(keyChainInfo);
if (questKey.Progress![0].c > 0) { if ((questKey.Progress?.[0]?.c ?? 0) > 0) {
keyChainMessage.att = []; keyChainMessage.att = [];
keyChainMessage.countedAtt = []; keyChainMessage.countedAtt = [];
} }

View File

@ -280,6 +280,14 @@ export const getSortie = (day: number): ISortie => {
} }
} }
const willHaveAssassination = boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2;
if (willHaveAssassination) {
const index = nodes.indexOf(sortieBossNode[boss]);
if (index != -1) {
nodes.splice(index, 1);
}
}
const selectedNodes: ISortieMission[] = []; const selectedNodes: ISortieMission[] = [];
const missionTypes = new Set(); const missionTypes = new Set();
@ -309,7 +317,7 @@ export const getSortie = (day: number): ISortie => {
"SORTIE_MODIFIER_BOW_ONLY" "SORTIE_MODIFIER_BOW_ONLY"
]; ];
if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) { if (i == 2 && willHaveAssassination) {
const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] as TSortieTileset; const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] as TSortieTileset;
pushTilesetModifiers(modifiers, tileset); pushTilesetModifiers(modifiers, tileset);
@ -361,7 +369,9 @@ export const getSortie = (day: number): ISortie => {
Activation: { $date: { $numberLong: dayStart.toString() } }, Activation: { $date: { $numberLong: dayStart.toString() } },
Expiry: { $date: { $numberLong: dayEnd.toString() } }, Expiry: { $date: { $numberLong: dayEnd.toString() } },
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards", Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
Seed: seed, Seed: selectedNodes.find(x => x.tileset == "CorpusIcePlanetTileset")
? 2081 // this seed produces 12 zeroes in a row if asked to pick (0, 1); this way the CorpusIcePlanetTileset image is always index 0, the 'correct' choice.
: seed,
Boss: boss, Boss: boss,
Variants: selectedNodes Variants: selectedNodes
}; };

View File

@ -193,7 +193,7 @@ dict = {
cheats_skipTutorial: `Tutorial überspringen`, cheats_skipTutorial: `Tutorial überspringen`,
cheats_skipAllDialogue: `Alle Dialoge überspringen`, cheats_skipAllDialogue: `Alle Dialoge überspringen`,
cheats_unlockAllScans: `Alle Scans freischalten`, cheats_unlockAllScans: `Alle Scans freischalten`,
cheats_unlockSuccRelog: `[UNTRANSLATED] Success. Please that you'll need to relog for the client to refresh this.`, cheats_unlockSuccRelog: `[UNTRANSLATED] Success. Please note that you'll need to relog for the client to refresh this.`,
cheats_unlockAllMissions: `Alle Missionen freischalten`, cheats_unlockAllMissions: `Alle Missionen freischalten`,
cheats_unlockAllMissions_ok: `Erfolgreich. Bitte beachte, dass du ein Dojo/Relais besuchen oder dich neu einloggen musst, damit die Sternenkarte aktualisiert wird.`, cheats_unlockAllMissions_ok: `Erfolgreich. Bitte beachte, dass du ein Dojo/Relais besuchen oder dich neu einloggen musst, damit die Sternenkarte aktualisiert wird.`,
cheats_infiniteCredits: `Unendlich Credits`, cheats_infiniteCredits: `Unendlich Credits`,
@ -227,7 +227,7 @@ dict = {
cheats_baroFullyStocked: `Baro hat volles Inventar`, cheats_baroFullyStocked: `Baro hat volles Inventar`,
cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`, cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`,
cheats_unlockAllProfitTakerStages: `Alle Profiteintreiber-Phasen freischalten`, cheats_unlockAllProfitTakerStages: `Alle Profiteintreiber-Phasen freischalten`,
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging..`, cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command in game chat, visiting a dojo/relay, or relogging.`,
cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`, cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`,
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`, cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`, cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,

View File

@ -1,5 +1,5 @@
dict = { 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_inventoryUpdateNote: `Note: To see changes in-game, you need to resync your inventory, e.g. using the bootstrapper's /sync command in game chat, visiting a dojo/relay, or relogging.`,
general_inventoryUpdateNoteGameWs: `Note: You may need to reopen any menu you are on for changes to be reflected.`, general_inventoryUpdateNoteGameWs: `Note: You may need to reopen any menu you are on for changes to be reflected.`,
general_addButton: `Add`, general_addButton: `Add`,
general_setButton: `Set`, general_setButton: `Set`,
@ -192,7 +192,7 @@ dict = {
cheats_skipTutorial: `Skip Tutorial`, cheats_skipTutorial: `Skip Tutorial`,
cheats_skipAllDialogue: `Skip All Dialogue`, cheats_skipAllDialogue: `Skip All Dialogue`,
cheats_unlockAllScans: `Unlock All Scans`, cheats_unlockAllScans: `Unlock All Scans`,
cheats_unlockSuccRelog: `Success. Please that you'll need to relog for the client to refresh this.`, cheats_unlockSuccRelog: `Success. Please note that you'll need to relog for the client to refresh this.`,
cheats_unlockAllMissions: `Unlock All Missions`, 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_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_infiniteCredits: `Infinite Credits`,
@ -226,7 +226,7 @@ dict = {
cheats_baroFullyStocked: `Baro Fully Stocked`, cheats_baroFullyStocked: `Baro Fully Stocked`,
cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`, cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`,
cheats_unlockAllProfitTakerStages: `Unlock All Profit Taker Stages`, cheats_unlockAllProfitTakerStages: `Unlock All Profit Taker Stages`,
cheats_unlockSuccInventory: `Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging..`, cheats_unlockSuccInventory: `Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command in game chat, visiting a dojo/relay, or relogging.`,
cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`, cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`,
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`, cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`, cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,

View File

@ -1,4 +1,4 @@
// Spanish translation by hxedcl // Spanish translation by hxedcl, Slayer55555
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_inventoryUpdateNoteGameWs: `Nota: Puede que necesites reabrir cualquier menú en el que te encuentres para que los cambios se reflejen.`, general_inventoryUpdateNoteGameWs: `Nota: Puede que necesites reabrir cualquier menú en el que te encuentres para que los cambios se reflejen.`,

View File

@ -1,4 +1,4 @@
// Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang, Corvus, & qingchun // Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang, Corvus, qingchun
dict = { dict = {
general_inventoryUpdateNote: `注意: 要在游戏中查看更改,您需要重新同步库存,例如使用客户端的 /sync 命令,访问道场/中继站或重新登录.`, general_inventoryUpdateNote: `注意: 要在游戏中查看更改,您需要重新同步库存,例如使用客户端的 /sync 命令,访问道场/中继站或重新登录.`,
general_inventoryUpdateNoteGameWs: `[UNTRANSLATED] Note: You may need to reopen any menu you are on for changes to be reflected.`, general_inventoryUpdateNoteGameWs: `[UNTRANSLATED] Note: You may need to reopen any menu you are on for changes to be reflected.`,
@ -193,7 +193,7 @@ dict = {
cheats_skipTutorial: `跳过教程`, cheats_skipTutorial: `跳过教程`,
cheats_skipAllDialogue: `跳过所有对话`, cheats_skipAllDialogue: `跳过所有对话`,
cheats_unlockAllScans: `解锁所有扫描`, cheats_unlockAllScans: `解锁所有扫描`,
cheats_unlockSuccRelog: `[UNTRANSLATED] Success. Please that you'll need to relog for the client to refresh this.`, cheats_unlockSuccRelog: `[UNTRANSLATED] Success. Please note that you'll need to relog for the client to refresh this.`,
cheats_unlockAllMissions: `解锁所有星图`, cheats_unlockAllMissions: `解锁所有星图`,
cheats_unlockAllMissions_ok: `操作成功.请注意,您需要进入道场/中继站或重新登录以刷新星图数据.`, cheats_unlockAllMissions_ok: `操作成功.请注意,您需要进入道场/中继站或重新登录以刷新星图数据.`,
cheats_infiniteCredits: `无限现金`, cheats_infiniteCredits: `无限现金`,
@ -227,7 +227,7 @@ dict = {
cheats_baroFullyStocked: `虚空商人贩卖所有商品`, cheats_baroFullyStocked: `虚空商人贩卖所有商品`,
cheats_syndicateMissionsRepeatable: `集团任务可重复完成`, cheats_syndicateMissionsRepeatable: `集团任务可重复完成`,
cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`, cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`,
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command, visiting a dojo/relay, or relogging..`, cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. using the bootstrapper's /sync command in game chat, visiting a dojo/relay, or relogging.`,
cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`, cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`,
cheats_instantResourceExtractorDrones: `资源无人机即时完成`, cheats_instantResourceExtractorDrones: `资源无人机即时完成`,
cheats_noResourceExtractorDronesDamage: `资源无人机不会损毁`, cheats_noResourceExtractorDronesDamage: `资源无人机不会损毁`,