forked from OpenWF/SpaceNinjaServer
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bce83d14c | |||
| cc5682760d | |||
| 00acaed62a | |||
| d794bd94ce | |||
| cecc65197b | |||
| b1c1b56de3 | |||
| 167da9c573 | |||
| 5e6955ae32 | |||
| f2145ed91b | |||
| 20d9a699b4 | |||
| 2b054d1728 | |||
| 5ac73528a0 | |||
| 678ad0c4a1 | |||
| 4bdb759463 | |||
| 71be8a2868 | |||
| f3072e84c9 | |||
| b2749765a3 |
@ -20,6 +20,7 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
|
||||
- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis.
|
||||
- `worldState.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
|
||||
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
|
||||
- `RadioLegionIntermission14Syndicate` for Nora's Mix: Dreams of the Dead
|
||||
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
|
||||
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
|
||||
- `RadioLegionIntermission11Syndicate` for Nora's Mix Vol. 7
|
||||
|
||||
@ -41,8 +41,7 @@ function run(changedFile) {
|
||||
}
|
||||
|
||||
const thisbuildproc = spawn(
|
||||
process.versions.bun ? "bun" : "npm",
|
||||
["run", cangoraw ? "verify" : "build:dev"],
|
||||
[process.versions.bun ? "bun" : "npm", "run", cangoraw ? "verify" : "build:dev"].join(" "),
|
||||
spawnopts
|
||||
);
|
||||
const thisbuildstart = Date.now();
|
||||
@ -55,8 +54,13 @@ function run(changedFile) {
|
||||
if (code === 0) {
|
||||
console.log(`${cangoraw ? "Verified" : "Built"} in ${Date.now() - thisbuildstart} ms`);
|
||||
runproc = spawn(
|
||||
process.versions.bun ? "bun" : "npm",
|
||||
["run", cangoraw ? (process.versions.bun ? "raw:bun" : "raw") : "start", "--", ...args],
|
||||
[
|
||||
process.versions.bun ? "bun" : "npm",
|
||||
"run",
|
||||
cangoraw ? (process.versions.bun ? "raw:bun" : "raw") : "start",
|
||||
"--",
|
||||
...args
|
||||
].join(" "),
|
||||
spawnopts
|
||||
);
|
||||
runproc.on("exit", () => {
|
||||
|
||||
@ -17,7 +17,7 @@ const app = express();
|
||||
|
||||
app.use((req, _res, next) => {
|
||||
// 38.5.0 introduced "ezip" for encrypted body blobs and "e" for request verification only (encrypted body blobs with no application data).
|
||||
// The bootstrapper decrypts it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
|
||||
// The client patch is expected to decrypt it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
|
||||
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
||||
req.headers["content-encoding"] = undefined;
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
export const EPOCH = 1734307200_000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be the start of winter in 1999 iteration 0
|
||||
|
||||
const millisecondsPerSecond = 1000;
|
||||
const secondsPerMinute = 60;
|
||||
const minutesPerHour = 60;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
import { EPOCH, getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
|
||||
import { unixTimesInMs } from "../../constants/timeConstants.ts";
|
||||
import { getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
|
||||
import { EPOCH, unixTimesInMs } from "../../constants/timeConstants.ts";
|
||||
import type { ISeasonChallenge } from "../../types/worldStateTypes.ts";
|
||||
import { ExportChallenges } from "warframe-public-export-plus";
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { parseString } from "../../helpers/general.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
import { giveKeyChainItem } from "../../services/questService.ts";
|
||||
import type { IKeyChainRequest } from "../../types/requestTypes.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
|
||||
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
|
||||
const accountId = parseString(req.query.accountId);
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
|
||||
|
||||
const inventory = await getInventory(accountId);
|
||||
|
||||
@ -353,11 +353,11 @@ export const getInventoryResponse = async (
|
||||
if (!xpBasedLevelCapDisabled) {
|
||||
// This client has not been patched to accept any mastery rank, need to fake the XP.
|
||||
inventoryResponse.XPInfo = [];
|
||||
let numFrames = getExpRequiredForMr(Math.min(inventory.spoofMasteryRank, 5030)) / 6000;
|
||||
let numFrames = getExpRequiredForMr(Math.min(inventory.spoofMasteryRank, 5030)) / (30 * 200);
|
||||
while (numFrames-- > 0) {
|
||||
inventoryResponse.XPInfo.push({
|
||||
ItemType: "/Lotus/Powersuits/Mag/Mag",
|
||||
XP: 1_600_000
|
||||
XP: 900_000 // Enough for rank 30 as per https://wiki.warframe.com/w/Affinity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
17
src/controllers/api/reverseQuestProgressController.ts
Normal file
17
src/controllers/api/reverseQuestProgressController.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { resetQuestKeyToStage } from "../../services/questService.ts";
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import type { IKeyChainRequest } from "../../types/requestTypes.ts";
|
||||
|
||||
export const reverseQuestProgressController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
|
||||
|
||||
const inventory = await getInventory(accountId);
|
||||
resetQuestKeyToStage(inventory, keyChainInfo);
|
||||
await inventory.save();
|
||||
|
||||
res.end();
|
||||
};
|
||||
@ -36,6 +36,11 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
|
||||
}
|
||||
addString(inventory.NodeIntrosCompleted, "TeshinHardModeUnlocked");
|
||||
addString(inventory.NodeIntrosCompleted, "CetusSyndicate_IntroJob");
|
||||
let syndicate = inventory.Affiliations.find(x => x.Tag == "CetusSyndicate");
|
||||
if (!syndicate) {
|
||||
syndicate =
|
||||
inventory.Affiliations[inventory.Affiliations.push({ Tag: "CetusSyndicate", Standing: 250, Title: 0 })]; // Non-zero standing avoids Konzu's "prove yourself" text. 250 is identical to newbie bounty + bonus
|
||||
}
|
||||
await inventory.save();
|
||||
res.end();
|
||||
};
|
||||
|
||||
@ -61,6 +61,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
|
||||
break;
|
||||
}
|
||||
inventory.QuestKeys.pull({ ItemType: questItemType });
|
||||
if (inventory.ActiveQuest == questItemType) inventory.ActiveQuest = "";
|
||||
break;
|
||||
}
|
||||
case "completeKey": {
|
||||
|
||||
@ -120,6 +120,7 @@ import { rerollRandomModController } from "../controllers/api/rerollRandomModCon
|
||||
import { researchMushroomController } from "../controllers/api/researchMushroomController.ts";
|
||||
import { resetQuestProgressController } from "../controllers/api/resetQuestProgressController.ts";
|
||||
import { retrievePetFromStasisController } from "../controllers/api/retrievePetFromStasisController.ts";
|
||||
import { reverseQuestProgressController } from "../controllers/api/reverseQuestProgressController.ts";
|
||||
import { saveDialogueController } from "../controllers/api/saveDialogueController.ts";
|
||||
import { saveLoadoutController } from "../controllers/api/saveLoadoutController.ts";
|
||||
import { saveSettingsController } from "../controllers/api/saveSettingsController.ts";
|
||||
@ -323,6 +324,7 @@ apiRouter.post("/renamePet.php", renamePetController);
|
||||
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
||||
apiRouter.post("/researchMushroom.php", researchMushroomController);
|
||||
apiRouter.post("/retrievePetFromStasis.php", retrievePetFromStasisController);
|
||||
apiRouter.post("/reverseQuestProgress.php", reverseQuestProgressController);
|
||||
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
||||
apiRouter.post("/saveLoadout.php", saveLoadoutController);
|
||||
apiRouter.post("/saveSettings.php", saveSettingsController);
|
||||
|
||||
425
src/services/conquestService.ts
Normal file
425
src/services/conquestService.ts
Normal file
@ -0,0 +1,425 @@
|
||||
import type { TFaction, TMissionType } from "warframe-public-export-plus";
|
||||
import type { CalendarSeasonType, IConquest, IConquestMission, TConquestType } from "../types/worldStateTypes.ts";
|
||||
import { mixSeeds, SRng } from "./rngService.ts";
|
||||
import { EPOCH } from "../constants/timeConstants.ts";
|
||||
|
||||
const missionAndFactionTypes: Record<TConquestType, Partial<Record<TMissionType, TFaction[]>>> = {
|
||||
CT_LAB: {
|
||||
MT_EXTERMINATION: ["FC_MITW"],
|
||||
MT_SURVIVAL: ["FC_MITW"],
|
||||
MT_ALCHEMY: ["FC_MITW"],
|
||||
MT_DEFENSE: ["FC_MITW"],
|
||||
MT_ARTIFACT: ["FC_MITW"]
|
||||
},
|
||||
CT_HEX: {
|
||||
MT_EXTERMINATION: ["FC_SCALDRA", "FC_TECHROT"],
|
||||
MT_SURVIVAL: ["FC_SCALDRA", "FC_TECHROT"],
|
||||
MT_DEFENSE: ["FC_SCALDRA"],
|
||||
MT_ENDLESS_CAPTURE: ["FC_TECHROT"]
|
||||
}
|
||||
};
|
||||
|
||||
const assassinationFactionOptions: Record<TConquestType, TFaction[]> = {
|
||||
CT_LAB: ["FC_MITW"],
|
||||
CT_HEX: ["FC_SCALDRA"]
|
||||
};
|
||||
|
||||
type TConquestDifficulty = "CD_NORMAL" | "CD_HARD";
|
||||
|
||||
interface IConquestConditional {
|
||||
tag: string;
|
||||
missionType?: TMissionType;
|
||||
conquest?: TConquestType;
|
||||
difficulty?: TConquestDifficulty;
|
||||
season?: CalendarSeasonType;
|
||||
}
|
||||
|
||||
const deviations: readonly IConquestConditional[] = [
|
||||
{
|
||||
tag: "AlchemicalShields",
|
||||
missionType: "MT_ALCHEMY"
|
||||
},
|
||||
{
|
||||
tag: "ContaminationZone",
|
||||
missionType: "MT_SURVIVAL",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "DoubleTrouble",
|
||||
missionType: "MT_ARTIFACT"
|
||||
},
|
||||
{
|
||||
tag: "EscalateImmediately",
|
||||
missionType: "MT_EXTERMINATION",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "EximusGrenadiers",
|
||||
missionType: "MT_ALCHEMY"
|
||||
},
|
||||
{
|
||||
tag: "FortifiedFoes",
|
||||
missionType: "MT_EXTERMINATION"
|
||||
},
|
||||
{
|
||||
tag: "FragileNodes",
|
||||
missionType: "MT_ARTIFACT"
|
||||
},
|
||||
{
|
||||
tag: "GrowingIncursion",
|
||||
missionType: "MT_EXTERMINATION",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "HarshWords",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "HighScalingLegacyte",
|
||||
missionType: "MT_ENDLESS_CAPTURE",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "DoubleTroubleLegacyte",
|
||||
missionType: "MT_ENDLESS_CAPTURE",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "HostileSecurity",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "InfiniteTide",
|
||||
missionType: "MT_ASSASSINATION",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "LostInTranslation",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "MutatedEnemies",
|
||||
missionType: "MT_ENDLESS_CAPTURE",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "NecramechActivation",
|
||||
missionType: "MT_SURVIVAL",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "Reinforcements",
|
||||
missionType: "MT_ASSASSINATION",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "StickyFingers",
|
||||
missionType: "MT_ARTIFACT",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "TankStrongArmor",
|
||||
missionType: "MT_ASSASSINATION",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "TankReinforcements",
|
||||
missionType: "MT_ASSASSINATION",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "TankSuperToxic",
|
||||
missionType: "MT_ASSASSINATION",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "TechrotConjunction",
|
||||
missionType: "MT_SURVIVAL",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "UnpoweredCapsules",
|
||||
missionType: "MT_SURVIVAL",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "VolatileGrenades",
|
||||
missionType: "MT_ALCHEMY"
|
||||
},
|
||||
{
|
||||
tag: "GestatingTumors",
|
||||
missionType: "MT_SURVIVAL",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "ChemicalNoise",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "ExplosiveEnergy",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "DisruptiveSounds",
|
||||
missionType: "MT_DEFENSE",
|
||||
conquest: "CT_HEX"
|
||||
}
|
||||
];
|
||||
|
||||
const risks: readonly IConquestConditional[] = [
|
||||
{
|
||||
tag: "Voidburst"
|
||||
},
|
||||
{
|
||||
tag: "RegeneratingEnemies"
|
||||
},
|
||||
{
|
||||
tag: "VoidAberration"
|
||||
},
|
||||
{
|
||||
tag: "ShieldedFoes"
|
||||
},
|
||||
{
|
||||
tag: "PointBlank"
|
||||
},
|
||||
{
|
||||
tag: "Deflectors",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "AcceleratedEnemies"
|
||||
},
|
||||
{
|
||||
tag: "DrainingResiduals"
|
||||
},
|
||||
{
|
||||
tag: "Quicksand"
|
||||
},
|
||||
{
|
||||
tag: "AntiMaterialWeapons",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "ExplosiveCrawlers",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "EMPBlackHole",
|
||||
conquest: "CT_LAB"
|
||||
},
|
||||
{
|
||||
tag: "ArtilleryBeacons",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "InfectedTechrot",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "BalloonFest",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "MiasmiteHive",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "CompetitionSpillover",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "HostileOvergrowth",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "MurmurIncursion",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "FactionSwarm_Techrot",
|
||||
conquest: "CT_HEX",
|
||||
difficulty: "CD_NORMAL"
|
||||
},
|
||||
{
|
||||
tag: "FactionSwarm_Scaldra",
|
||||
conquest: "CT_HEX",
|
||||
difficulty: "CD_NORMAL"
|
||||
},
|
||||
{
|
||||
tag: "HeavyWarfare",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "ArcadeAutomata",
|
||||
conquest: "CT_HEX",
|
||||
difficulty: "CD_NORMAL"
|
||||
},
|
||||
{
|
||||
tag: "EfervonFog",
|
||||
conquest: "CT_HEX"
|
||||
},
|
||||
{
|
||||
tag: "WinterFrost",
|
||||
conquest: "CT_HEX",
|
||||
season: "CST_WINTER"
|
||||
},
|
||||
{
|
||||
tag: "JadeSpring",
|
||||
conquest: "CT_HEX",
|
||||
season: "CST_SPRING"
|
||||
},
|
||||
{
|
||||
tag: "ExplosiveSummer",
|
||||
conquest: "CT_HEX",
|
||||
season: "CST_SUMMER"
|
||||
},
|
||||
{
|
||||
tag: "FallFog",
|
||||
conquest: "CT_HEX",
|
||||
season: "CST_FALL"
|
||||
}
|
||||
];
|
||||
|
||||
const filterConditionals = (
|
||||
arr: readonly IConquestConditional[],
|
||||
missionType: TMissionType | null,
|
||||
conquest: TConquestType | null,
|
||||
difficulty: TConquestDifficulty | null,
|
||||
season: CalendarSeasonType | null
|
||||
): string[] => {
|
||||
const applicable = [];
|
||||
for (const cond of arr) {
|
||||
if (
|
||||
(!cond.missionType || cond.missionType == missionType) &&
|
||||
(!cond.conquest || cond.conquest == conquest) &&
|
||||
(!cond.difficulty || cond.difficulty == difficulty) &&
|
||||
(!cond.season || cond.season == season)
|
||||
) {
|
||||
applicable.push(cond.tag);
|
||||
}
|
||||
}
|
||||
return applicable;
|
||||
};
|
||||
|
||||
const buildMission = (
|
||||
rng: SRng,
|
||||
conquest: TConquestType,
|
||||
missionType: TMissionType,
|
||||
faction: TFaction,
|
||||
season: CalendarSeasonType | null
|
||||
): IConquestMission => {
|
||||
const deviation = rng.randomElement(filterConditionals(deviations, missionType, conquest, null, season))!;
|
||||
const easyRisk = rng.randomElement(filterConditionals(risks, missionType, conquest, "CD_NORMAL", season))!;
|
||||
const hardRiskOptions = filterConditionals(risks, missionType, conquest, "CD_HARD", season);
|
||||
{
|
||||
const i = hardRiskOptions.indexOf(easyRisk);
|
||||
if (i != -1) {
|
||||
hardRiskOptions.splice(i, 1);
|
||||
}
|
||||
}
|
||||
const hardRisk = rng.randomElement(hardRiskOptions)!;
|
||||
return {
|
||||
faction,
|
||||
missionType,
|
||||
difficulties: [
|
||||
{
|
||||
type: "CD_NORMAL",
|
||||
deviation,
|
||||
risks: [easyRisk]
|
||||
},
|
||||
{
|
||||
type: "CD_HARD",
|
||||
deviation,
|
||||
risks: [easyRisk, hardRisk]
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
const conquestStartingDay: Record<TConquestType, number> = {
|
||||
CT_LAB: 3703,
|
||||
CT_HEX: 4053
|
||||
};
|
||||
|
||||
// This function produces identical results to clients pre-40.0.0.
|
||||
const getFrameVariables = (conquestType: TConquestType, time: number): [string, string, string, string] => {
|
||||
const day = Math.floor((time - 1391990400_000) / 86400_000) - conquestStartingDay[conquestType];
|
||||
const week = Math.floor(day / 7) + 1;
|
||||
const frameVariables = [
|
||||
"Framecurse",
|
||||
"Knifestep",
|
||||
"Exhaustion",
|
||||
"Gearless",
|
||||
"TimeDilation",
|
||||
"Armorless",
|
||||
"Starvation",
|
||||
"ShieldDelay",
|
||||
"Withering",
|
||||
"ContactDamage",
|
||||
"AbilityLockout",
|
||||
"OperatorLockout",
|
||||
"EnergyStarved",
|
||||
"OverSensitive",
|
||||
"AntiGuard",
|
||||
"DecayingFlesh",
|
||||
"VoidEnergyOverload",
|
||||
"DullBlades",
|
||||
"Undersupplied"
|
||||
];
|
||||
const mag = Math.floor(frameVariables.length / 4);
|
||||
const rng = new SRng(conquestStartingDay[conquestType] + Math.floor(week / mag));
|
||||
rng.shuffleArray(frameVariables);
|
||||
const i = week % mag;
|
||||
return [frameVariables[i], frameVariables[i + 1], frameVariables[i + 2], frameVariables[i + 3]];
|
||||
};
|
||||
|
||||
export const getConquest = (
|
||||
conquestType: TConquestType,
|
||||
week: number,
|
||||
season: CalendarSeasonType | null
|
||||
): IConquest => {
|
||||
const rng = new SRng(mixSeeds(conquestStartingDay[conquestType], week));
|
||||
|
||||
const missions: IConquestMission[] = [];
|
||||
{
|
||||
const missionOptions = Object.entries(missionAndFactionTypes[conquestType]);
|
||||
{
|
||||
const i = rng.randomInt(0, missionOptions.length - 1);
|
||||
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
|
||||
missions.push(
|
||||
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
|
||||
);
|
||||
}
|
||||
{
|
||||
const i = rng.randomInt(0, missionOptions.length - 1);
|
||||
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
|
||||
missions.push(
|
||||
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
|
||||
);
|
||||
}
|
||||
missionOptions.push(["MT_ASSASSINATION", assassinationFactionOptions[conquestType]]);
|
||||
{
|
||||
const i = rng.randomInt(0, missionOptions.length - 1);
|
||||
const [missionType, factionOptions] = missionOptions.splice(i, 1)[0];
|
||||
missions.push(
|
||||
buildMission(rng, conquestType, missionType as TMissionType, rng.randomElement(factionOptions)!, season)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const weekStart = EPOCH + week * 604800000;
|
||||
const weekEnd = weekStart + 604800000;
|
||||
return {
|
||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||
Type: conquestType,
|
||||
Missions: missions,
|
||||
Variables: getFrameVariables(conquestType, weekStart),
|
||||
RandomSeed: rng.randomInt(0, 1_000_000)
|
||||
};
|
||||
};
|
||||
@ -41,8 +41,8 @@ export const createAccount = async (accountData: IDatabaseAccountRequiredFields)
|
||||
await account.save();
|
||||
const loadoutId = await createLoadout(account._id);
|
||||
const shipId = await createShip(account._id);
|
||||
await createInventory(account._id, { loadOutPresetId: loadoutId, ship: shipId });
|
||||
await createPersonalRooms(account._id, shipId);
|
||||
await createInventory(account._id, { loadOutPresetId: loadoutId, ship: shipId });
|
||||
await createStats(account._id.toString());
|
||||
return account.toJSON();
|
||||
} catch (error) {
|
||||
@ -64,17 +64,6 @@ export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Typ
|
||||
personalRoomsOwnerId: accountId,
|
||||
activeShipId: shipId
|
||||
});
|
||||
if (config.skipTutorial) {
|
||||
// unlocked during Vor's Prize and The Teacher quests
|
||||
const defaultFeatures = [
|
||||
"/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem",
|
||||
"/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem",
|
||||
"/Lotus/Types/Items/ShipFeatureItems/SocialMenuFeatureItem",
|
||||
"/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem",
|
||||
"/Lotus/Types/Items/ShipFeatureItems/ModsFeatureItem"
|
||||
];
|
||||
personalRooms.Ship.Features.push(...defaultFeatures);
|
||||
}
|
||||
await personalRooms.save();
|
||||
};
|
||||
|
||||
|
||||
@ -2031,7 +2031,7 @@ function getRandomMissionDrops(
|
||||
.replace("SteelPath", "Steel")
|
||||
.replace(
|
||||
"/Lotus/Types/Gameplay/NokkoColony/Jobs/NokkoJob",
|
||||
"Lotus/Types/Game/MissionDecks/NokkoColonyRewards/NokkoColonyRewards"
|
||||
"/Lotus/Types/Game/MissionDecks/NokkoColonyRewards/NokkoColonyRewards"
|
||||
),
|
||||
masteryReq: 0,
|
||||
minEnemyLevel: 30,
|
||||
|
||||
@ -2,16 +2,25 @@ import type { IKeyChainRequest } from "../types/requestTypes.ts";
|
||||
import { isEmptyObject } from "../helpers/general.ts";
|
||||
import type { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel.ts";
|
||||
import { createMessage } from "./inboxService.ts";
|
||||
import { addItem, addItems, addKeyChainItems, setupKahlSyndicate } from "./inventoryService.ts";
|
||||
import {
|
||||
addEquipment,
|
||||
addItem,
|
||||
addItems,
|
||||
addKeyChainItems,
|
||||
addPowerSuit,
|
||||
setupKahlSyndicate
|
||||
} from "./inventoryService.ts";
|
||||
import { fromStoreItem, getKeyChainMessage, getLevelKeyRewards } from "./itemDataService.ts";
|
||||
import type { IQuestKeyClient, IQuestKeyDatabase, IQuestStage } from "../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import { ExportKeys } from "warframe-public-export-plus";
|
||||
import { ExportKeys, ExportRecipes } from "warframe-public-export-plus";
|
||||
import { addFixedLevelRewards } from "./missionInventoryUpdateService.ts";
|
||||
import type { IInventoryChanges } from "../types/purchaseTypes.ts";
|
||||
import questCompletionItems from "../../static/fixed_responses/questCompletionRewards.json" with { type: "json" };
|
||||
import type { ITypeCount } from "../types/commonTypes.ts";
|
||||
import { addString } from "../helpers/stringHelpers.ts";
|
||||
import { unlockShipFeature } from "./personalRoomsService.ts";
|
||||
import { EquipmentFeatures } from "../types/equipmentTypes.ts";
|
||||
|
||||
export interface IUpdateQuestRequest {
|
||||
QuestKeys: IQuestKeyClient[];
|
||||
@ -92,6 +101,26 @@ export const updateQuestStage = (
|
||||
}
|
||||
};
|
||||
|
||||
export const resetQuestKeyToStage = (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
{ KeyChain, ChainStage }: IKeyChainRequest
|
||||
): void => {
|
||||
const quest = inventory.QuestKeys.find(quest => quest.ItemType === KeyChain);
|
||||
|
||||
if (!quest) {
|
||||
throw new Error(`Quest ${KeyChain} not found in QuestKeys`);
|
||||
}
|
||||
|
||||
quest.Progress ??= [];
|
||||
|
||||
const run = quest.Progress[0]?.c ?? 0;
|
||||
if (run >= 0) {
|
||||
for (let i = ChainStage; i < quest.Progress.length; ++i) {
|
||||
quest.Progress[i].c = run - 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const addQuestKey = (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
questKey: IQuestKeyDatabase
|
||||
@ -169,6 +198,7 @@ export const completeQuest = async (
|
||||
stage.c = run;
|
||||
await giveKeyChainStageTriggered(inventory, { KeyChain: questKey, ChainStage: i }, sendMessages);
|
||||
await giveKeyChainMissionReward(inventory, { KeyChain: questKey, ChainStage: i });
|
||||
await installShipFeatures(inventory, { KeyChain: questKey, ChainStage: i });
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,6 +335,9 @@ const handleQuestCompletion = async (
|
||||
logger.debug(`quest completion items`, questCompletionItems);
|
||||
if (questCompletionItems) {
|
||||
await addItems(inventory, questCompletionItems, inventoryChanges);
|
||||
for (const item of questCompletionItems) {
|
||||
await removeRequiredItems(inventory, item.ItemType);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -354,7 +387,12 @@ export const giveKeyChainMessage = async (
|
||||
await createMessage(inventory.accountOwnerId, [keyChainMessage]);
|
||||
} else {
|
||||
if (keyChainMessage.countedAtt?.length) await addItems(inventory, keyChainMessage.countedAtt);
|
||||
if (keyChainMessage.att?.length) await addItems(inventory, keyChainMessage.att);
|
||||
if (keyChainMessage.att?.length) {
|
||||
await addItems(inventory, keyChainMessage.att);
|
||||
for (const reward of keyChainMessage.att) {
|
||||
await removeRequiredItems(inventory, reward);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateQuestStage(inventory, keyChainInfo, { m: true });
|
||||
@ -379,6 +417,7 @@ export const giveKeyChainMissionReward = async (
|
||||
|
||||
for (const reward of missionRewards) {
|
||||
await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
|
||||
await removeRequiredItems(inventory, fromStoreItem(reward.StoreItem));
|
||||
}
|
||||
|
||||
updateQuestStage(inventory, keyChainInfo, { c: run });
|
||||
@ -392,6 +431,7 @@ export const giveKeyChainMissionReward = async (
|
||||
await addItem(inventory, fromStoreItem(reward.itemType), reward.amount);
|
||||
} else {
|
||||
await addItem(inventory, fromStoreItem(reward.itemType));
|
||||
await removeRequiredItems(inventory, fromStoreItem(reward.itemType));
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,3 +460,337 @@ export const giveKeyChainStageTriggered = async (
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const installShipFeatures = async (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
keyChainInfo: IKeyChainRequest
|
||||
): Promise<void> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const chainStages = ExportKeys[keyChainInfo.KeyChain]?.chainStages;
|
||||
const questKey = inventory.QuestKeys.find(qk => qk.ItemType === keyChainInfo.KeyChain);
|
||||
if (chainStages && questKey) {
|
||||
if (keyChainInfo.ChainStage - 1 >= 0) {
|
||||
const prevStage = chainStages[keyChainInfo.ChainStage - 1];
|
||||
for (const item of prevStage.itemsToGiveWhenTriggered) {
|
||||
if (item.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")) {
|
||||
logger.debug(`installing ship feature ${fromStoreItem(item)}`);
|
||||
await unlockShipFeature(inventory, fromStoreItem(item));
|
||||
}
|
||||
}
|
||||
if (prevStage.key) {
|
||||
const fixedLevelRewards = getLevelKeyRewards(prevStage.key);
|
||||
if (fixedLevelRewards.levelKeyRewards?.items) {
|
||||
for (const item of fixedLevelRewards.levelKeyRewards.items) {
|
||||
if (item.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")) {
|
||||
logger.debug(`installing ship feature ${fromStoreItem(item)}`);
|
||||
await unlockShipFeature(inventory, fromStoreItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fixedLevelRewards.levelKeyRewards2) {
|
||||
for (const item of fixedLevelRewards.levelKeyRewards2) {
|
||||
if (
|
||||
item.rewardType == "RT_STORE_ITEM" &&
|
||||
item.itemType.startsWith("/Lotus/StoreItems/Types/Items/ShipFeatureItems/")
|
||||
) {
|
||||
logger.debug(`installing ship feature ${fromStoreItem(item.itemType)}`);
|
||||
await unlockShipFeature(inventory, fromStoreItem(item.itemType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const removeRequiredItems = async (inventory: TInventoryDatabaseDocument, typeName: string): Promise<void> => {
|
||||
switch (typeName) {
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianHelmetBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboHelmetKeyBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianSystemsBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboSystemsKeyBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/MagicianChassisBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Keys/LimboQuest/LimboChassisKeyBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/BrawlerBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Recipes/Components/InfestedIrradiatedBaitBallBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
await addItem(inventory, recipe.resultType, -1, false, undefined, undefined, true);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
|
||||
await addItems(inventory, [
|
||||
{
|
||||
ItemType:
|
||||
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingWingsBlueprint",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType:
|
||||
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingChassisBlueprint",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType:
|
||||
"/Lotus/Types/Recipes/ArchwingRecipes/StandardArchwing/StandardArchwingSystemsBlueprint",
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Keys/ModQuest/ModQuestKeyChain": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Recipes/Components/VorBoltRemoverBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/ChromaBlueprint": {
|
||||
await addItems(inventory, [
|
||||
{
|
||||
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconABlueprint",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconBBlueprint",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType: "/Lotus/Types/Recipes/WarframeRecipes/ChromaBeaconCBlueprint",
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/OctaviaBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Keys/BardQuest/BardQuestSequencerBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, -1);
|
||||
await addItems(inventory, [
|
||||
{
|
||||
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartA",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartB",
|
||||
ItemCount: -1
|
||||
},
|
||||
{
|
||||
ItemType: "/Lotus/Types/Keys/BardQuest/BardQuestSequencerPartC",
|
||||
ItemCount: -1
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Game/CrewShip/Ships/RailJack": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Recipes/Railjack/RailjackCephalonBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
|
||||
await unlockShipFeature(inventory, recipe.resultType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Items/ShipDecos/MummyQuestVessel": {
|
||||
const gearItem = inventory.Consumables.find(
|
||||
i => i.ItemType == "/Lotus/Types/Keys/MummyQuest/MummyArtifact01GearItem"
|
||||
);
|
||||
if (gearItem && gearItem.ItemCount > 0) {
|
||||
await addItem(inventory, gearItem.ItemType, gearItem.ItemCount * -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Types/Recipes/WarframeRecipes/ConcreteFrameBlueprint": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Gameplay/EntratiLab/Quest/GargoyleRecipeItem"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
await addItem(inventory, recipe.resultType);
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "/Lotus/Upgrades/Skins/Umbra/UmbraAltHelmet": {
|
||||
const recipeItem = inventory.Recipes.find(
|
||||
i => i.ItemType == "/Lotus/Types/Recipes/WarframeRecipes/ExcaliburUmbraBlueprint"
|
||||
);
|
||||
if (recipeItem && recipeItem.ItemCount > 0) {
|
||||
const recipe = ExportRecipes[recipeItem.ItemType];
|
||||
if (!inventory.MiscItems.find(i => i.ItemType == recipe.resultType)) {
|
||||
const umbraModA = (
|
||||
await addItem(
|
||||
inventory,
|
||||
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModA",
|
||||
1,
|
||||
false,
|
||||
undefined,
|
||||
`{"lvl":5}`
|
||||
)
|
||||
).Upgrades![0];
|
||||
const umbraModB = (
|
||||
await addItem(
|
||||
inventory,
|
||||
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModB",
|
||||
1,
|
||||
false,
|
||||
undefined,
|
||||
`{"lvl":5}`
|
||||
)
|
||||
).Upgrades![0];
|
||||
const umbraModC = (
|
||||
await addItem(
|
||||
inventory,
|
||||
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModC",
|
||||
1,
|
||||
false,
|
||||
undefined,
|
||||
`{"lvl":5}`
|
||||
)
|
||||
).Upgrades![0];
|
||||
const sacrificeModA = (
|
||||
await addItem(
|
||||
inventory,
|
||||
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModA",
|
||||
1,
|
||||
false,
|
||||
undefined,
|
||||
`{"lvl":5}`
|
||||
)
|
||||
).Upgrades![0];
|
||||
const sacrificeModB = (
|
||||
await addItem(
|
||||
inventory,
|
||||
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModB",
|
||||
1,
|
||||
false,
|
||||
undefined,
|
||||
`{"lvl":5}`
|
||||
)
|
||||
).Upgrades![0];
|
||||
|
||||
await addPowerSuit(inventory, "/Lotus/Powersuits/Excalibur/ExcaliburUmbra", {
|
||||
Configs: [
|
||||
{
|
||||
Upgrades: [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
umbraModA.ItemId.$oid,
|
||||
umbraModB.ItemId.$oid,
|
||||
umbraModC.ItemId.$oid
|
||||
]
|
||||
}
|
||||
],
|
||||
XP: 900_000,
|
||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||
});
|
||||
inventory.XPInfo.push({
|
||||
ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||
XP: 900_000
|
||||
});
|
||||
|
||||
addEquipment(inventory, "Melee", "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana", {
|
||||
Configs: [
|
||||
{
|
||||
Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid]
|
||||
}
|
||||
],
|
||||
XP: 450_000,
|
||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||
});
|
||||
inventory.XPInfo.push({
|
||||
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||
XP: 450_000
|
||||
});
|
||||
if (recipe.consumeOnUse) await addItem(inventory, recipeItem.ItemType, recipeItem.ItemCount * -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,8 +12,8 @@ let httpServer: http.Server | undefined;
|
||||
let httpsServer: https.Server | undefined;
|
||||
|
||||
const tlsOptions = {
|
||||
key: fs.readFileSync("static/certs/key.pem"),
|
||||
cert: fs.readFileSync("static/certs/cert.pem")
|
||||
key: fs.readFileSync("static/cert/key.pem"),
|
||||
cert: fs.readFileSync("static/cert/cert.pem")
|
||||
};
|
||||
|
||||
export const startWebServer = (): void => {
|
||||
|
||||
@ -10,7 +10,7 @@ import invasionNodes from "../../static/fixed_responses/worldState/invasionNodes
|
||||
import invasionRewards from "../../static/fixed_responses/worldState/invasionRewards.json" with { type: "json" };
|
||||
import pvpChallenges from "../../static/fixed_responses/worldState/pvpChallenges.json" with { type: "json" };
|
||||
import { buildConfig } from "./buildConfigService.ts";
|
||||
import { unixTimesInMs } from "../constants/timeConstants.ts";
|
||||
import { EPOCH, unixTimesInMs } from "../constants/timeConstants.ts";
|
||||
import { config } from "./configService.ts";
|
||||
import { getRandomElement, getRandomInt, sequentiallyUniqueRandomElement, SRng } from "./rngService.ts";
|
||||
import type { IMissionReward, IRegion, TFaction } from "warframe-public-export-plus";
|
||||
@ -41,6 +41,7 @@ import type {
|
||||
import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import { DailyDeal, Fissure } from "../models/worldStateModel.ts";
|
||||
import { getConquest } from "./conquestService.ts";
|
||||
|
||||
const sortieBosses = [
|
||||
"SORTIE_BOSS_HYENA",
|
||||
@ -276,8 +277,6 @@ const microplanetEndlessJobs: readonly string[] = [
|
||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty"
|
||||
];
|
||||
|
||||
export const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
||||
|
||||
const isBeforeNextExpectedWorldStateRefresh = (nowMs: number, thenMs: number): boolean => {
|
||||
return nowMs + 300_000 > thenMs;
|
||||
};
|
||||
@ -3182,7 +3181,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
// Nightwave Challenges
|
||||
const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
|
||||
if (nightwaveSyndicateTag) {
|
||||
const nightwaveStartTimestamp = 1747851300000;
|
||||
const nightwaveStartTimestamp = nightwaveTagToActivation[nightwaveSyndicateTag] ?? 1747851300000;
|
||||
const nightwaveSeason = nightwaveTagToSeason[nightwaveSyndicateTag];
|
||||
worldState.SeasonInfo = {
|
||||
Activation: { $date: { $numberLong: nightwaveStartTimestamp.toString() } },
|
||||
@ -3469,6 +3468,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
}
|
||||
}
|
||||
|
||||
// Void Storms
|
||||
const hour = Math.trunc(timeMs / unixTimesInMs.hour);
|
||||
const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute;
|
||||
const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
|
||||
if (overLastHourStormExpiry > timeMs) {
|
||||
pushVoidStorms(worldState.VoidStorms, hour - 2);
|
||||
}
|
||||
pushVoidStorms(worldState.VoidStorms, hour - 1);
|
||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) {
|
||||
pushVoidStorms(worldState.VoidStorms, hour);
|
||||
}
|
||||
|
||||
// Sortie & syndicate missions cycling every day (at 16:00 or 17:00 UTC depending on if London, OT is observing DST)
|
||||
{
|
||||
const rollover = getSortieTime(day);
|
||||
@ -3551,16 +3562,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
|
||||
}
|
||||
|
||||
// Void Storms
|
||||
const hour = Math.trunc(timeMs / unixTimesInMs.hour);
|
||||
const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute;
|
||||
const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
|
||||
if (overLastHourStormExpiry > timeMs) {
|
||||
pushVoidStorms(worldState.VoidStorms, hour - 2);
|
||||
}
|
||||
pushVoidStorms(worldState.VoidStorms, hour - 1);
|
||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) {
|
||||
pushVoidStorms(worldState.VoidStorms, hour);
|
||||
if (!buildLabel || version_compare(buildLabel, "2025.10.14.16.10") >= 0) {
|
||||
worldState.Conquests = [];
|
||||
{
|
||||
const season = (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[week % 4];
|
||||
worldState.Conquests.push(getConquest("CT_LAB", week, null));
|
||||
worldState.Conquests.push(getConquest("CT_HEX", week, season));
|
||||
}
|
||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) {
|
||||
const season = (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[(week + 1) % 4];
|
||||
worldState.Conquests.push(getConquest("CT_LAB", week, null));
|
||||
worldState.Conquests.push(getConquest("CT_HEX", week, season));
|
||||
}
|
||||
}
|
||||
|
||||
// Sentient Anomaly + Xtra Cheese cycles
|
||||
@ -3777,7 +3790,10 @@ export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string
|
||||
valid_values: Object.keys(nightwaveTagToSeason)
|
||||
});
|
||||
}
|
||||
if (!buildLabel || version_compare(buildLabel, "2025.05.20.10.18") >= 0) {
|
||||
if (!buildLabel || version_compare(buildLabel, "2025.10.14.16.10") >= 0) {
|
||||
return "RadioLegionIntermission14Syndicate";
|
||||
}
|
||||
if (version_compare(buildLabel, "2025.05.20.10.18") >= 0) {
|
||||
return "RadioLegionIntermission13Syndicate";
|
||||
}
|
||||
if (version_compare(buildLabel, "2025.02.05.11.19") >= 0) {
|
||||
@ -3787,6 +3803,7 @@ export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string
|
||||
};
|
||||
|
||||
const nightwaveTagToSeason: Record<string, number> = {
|
||||
RadioLegionIntermission14Syndicate: 16, // Nora's Mix: Dreams of the Dead
|
||||
RadioLegionIntermission13Syndicate: 15, // Nora's Mix Vol. 9
|
||||
RadioLegionIntermission12Syndicate: 14, // Nora's Mix Vol. 8
|
||||
RadioLegionIntermission11Syndicate: 13, // Nora's Mix Vol. 7
|
||||
@ -3805,6 +3822,10 @@ const nightwaveTagToSeason: Record<string, number> = {
|
||||
RadioLegionSyndicate: 0 // The Wolf of Saturn Six
|
||||
};
|
||||
|
||||
const nightwaveTagToActivation: Record<string, number> = {
|
||||
RadioLegionIntermission14Syndicate: 1761589199000
|
||||
};
|
||||
|
||||
const updateFissures = async (): Promise<void> => {
|
||||
const fissures = await Fissure.find();
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import type { IOrbiterClient } from "../personalRoomsTypes.ts";
|
||||
import type { ICountedStoreItem } from "warframe-public-export-plus";
|
||||
import type { IEquipmentClient, IEquipmentDatabase, ITraits } from "../equipmentTypes.ts";
|
||||
import type { ILoadOutPresets } from "../saveLoadoutTypes.ts";
|
||||
import type { CalendarSeasonType } from "../worldStateTypes.ts";
|
||||
|
||||
export type InventoryDatabaseEquipment = {
|
||||
[_ in TEquipmentKey]: IEquipmentDatabase[];
|
||||
@ -1180,7 +1181,7 @@ export interface IMarker {
|
||||
}
|
||||
|
||||
export interface ISeasonProgress {
|
||||
SeasonType: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||
SeasonType: CalendarSeasonType;
|
||||
LastCompletedDayIdx: number;
|
||||
LastCompletedChallengeDayIdx: number;
|
||||
ActivatedChallenges: string[];
|
||||
|
||||
@ -32,6 +32,7 @@ export interface IWorldState {
|
||||
ActiveChallenges: ISeasonChallenge[];
|
||||
};
|
||||
KnownCalendarSeasons: ICalendarSeason[];
|
||||
Conquests?: IConquest[];
|
||||
Tmp?: string;
|
||||
}
|
||||
|
||||
@ -352,10 +353,11 @@ export interface ISeasonChallenge {
|
||||
Challenge: string;
|
||||
}
|
||||
|
||||
export type CalendarSeasonType = "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||
export interface ICalendarSeason {
|
||||
Activation: IMongoDate;
|
||||
Expiry: IMongoDate;
|
||||
Season: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||
Season: CalendarSeasonType;
|
||||
Days: ICalendarDay[];
|
||||
YearIteration: number;
|
||||
Version: number;
|
||||
@ -416,6 +418,33 @@ export interface IGameMarketCategory {
|
||||
Items?: string[];
|
||||
}
|
||||
|
||||
// >= 40.0.0
|
||||
export type TConquestType = "CT_LAB" | "CT_HEX";
|
||||
export interface IConquest {
|
||||
Activation: IMongoDate;
|
||||
Expiry: IMongoDate;
|
||||
Type: TConquestType;
|
||||
Missions: IConquestMission[];
|
||||
Variables: [string, string, string, string];
|
||||
RandomSeed: number;
|
||||
}
|
||||
export interface IConquestMission {
|
||||
faction: TFaction;
|
||||
missionType: TMissionType;
|
||||
difficulties: [
|
||||
{
|
||||
type: "CD_NORMAL";
|
||||
deviation: string;
|
||||
risks: [string];
|
||||
},
|
||||
{
|
||||
type: "CD_HARD";
|
||||
deviation: string;
|
||||
risks: [string, string];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export interface ITmp {
|
||||
cavabegin: string;
|
||||
PurchasePlatformLockEnabled: boolean; // Seems unused
|
||||
@ -423,6 +452,8 @@ export interface ITmp {
|
||||
ennnd?: boolean; // True if 1999 demo is available (no effect for >=38.6.0)
|
||||
mbrt?: boolean; // Related to mobile app rating request
|
||||
fbst: IFbst;
|
||||
lqo?: IConquestOverride;
|
||||
hqo?: IConquestOverride;
|
||||
sfn: number;
|
||||
edg?: TCircuitGameMode[]; // The Circuit game modes overwrite
|
||||
}
|
||||
@ -451,3 +482,12 @@ interface IFbst {
|
||||
e: number;
|
||||
n: number;
|
||||
}
|
||||
|
||||
// < 40.0.0
|
||||
interface IConquestOverride {
|
||||
mt?: string[]; // mission types but "Exterminate" instead of "MT_EXTERMINATION", etc. and "DualDefense" instead of "Defense" for hex conquest
|
||||
mv?: string[];
|
||||
mf?: number[]; // hex conquest only
|
||||
c?: [string, string][];
|
||||
fv?: string[];
|
||||
}
|
||||
|
||||
70
static/cert/cert.pem
Normal file
70
static/cert/cert.pem
Normal file
@ -0,0 +1,70 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF/DCCBGSgAwIBAgIQH1nGumKdC869SnXDdjpRizANBgkqhkiG9w0BAQsFADBg
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
|
||||
Ey5TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gQ0EgRFYgUjM2
|
||||
MB4XDTI1MTAzMTAwMDAwMFoXDTI2MDMwNjIzNTk1OVowGDEWMBQGA1UEAwwNKi5m
|
||||
YWtldGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZt+8pe
|
||||
ZABBMSORWDlJBKykSbbNeEX2vPNrsQBqa3aBzQLdp6dm8qw099a5mn/vuQzdtFhc
|
||||
QbaemxoVViszzM3dpTlOgLyl2r4cr8KMXJ/rRMqLeaYks+BVYJyxKAlVIduJCpP+
|
||||
cxYUIiz+zNGMucuFdanzeNfCRhakDkzHH/LKZFYDHeqdR8vdUnOH8n9xuGR7sC6I
|
||||
PbfML8SXCnazMpcPAeIFzJeZW3fbFIQ5R6B7X38k9+wUzKXrJo0+Q8U1mIAsV7fh
|
||||
4gn+xgrFOJ7T2Vd8EtHgnr5nzNRDk4prE+ecTxBveL4QGuNoPaABtor6OLBR54AQ
|
||||
8ycj29lQ094BrJcCAwEAAaOCAngwggJ0MB8GA1UdIwQYMBaAFGjAEhYYDq/O9oem
|
||||
MlejRlFdywcnMB0GA1UdDgQWBBRqYi9dBjbiV9wE6GEtzyzUM6cQmjAOBgNVHQ8B
|
||||
Af8EBAMCBaAwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATBJBgNV
|
||||
HSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2Vj
|
||||
dGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEEeDB2ME8GCCsGAQUF
|
||||
BzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNTZXJ2ZXJB
|
||||
dXRoZW50aWNhdGlvbkNBRFZSMzYuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz
|
||||
cC5zZWN0aWdvLmNvbTAlBgNVHREEHjAcgg0qLmZha2V0bHMuY29tggtmYWtldGxz
|
||||
LmNvbTCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AJaXZL9VWJet90OHaDcIQnfp
|
||||
8DrV9qTzNm5GpD8PyqnGAAABmjqerq4AAAQDAEcwRQIgY1YdLRDkbq9U9qGLpX5M
|
||||
IESNpCLFKVgoPLyNQQejtPUCIQCGlFB13fGO7GpVZLXyuOrXIWRZQUxnm1GqhvOP
|
||||
BoovPgB2ANFuqaVoB35mNaA/N6XdvAOlPEESFNSIGPXpMbMjy5UEAAABmjqerwkA
|
||||
AAQDAEcwRQIhAMxyLWnCpof354KMPYiWQmqd+2D+yyV5ZL7rmvIJw0ojAiAxxsid
|
||||
se3hTmdo39MJLKyVqlZKUua5dmLckUYUImsogTANBgkqhkiG9w0BAQsFAAOCAYEA
|
||||
ByJlO00LMIgL6d5xfouZHl1OL2w0DDiWHQa87BM9AqUFSgE1IsWyUAMTVoxNp3bM
|
||||
c4fiBoJ9P32hDft2gJRCtJ+xOlU9ufQqCfpN9pBxe8eEldJdnHi7q9Y1dIVwRA+y
|
||||
xY2r1xgTmjYgv1Uo5mQoOjgvrRdUNTyW0Rkp9+9zr6NFxi4orqypt4KKOFY2DlV9
|
||||
wKmS4HPXSNR6QEylUR1+IsCP7iQzgTcZDYYLH2vAekJ1vFJkxZyB8a1vjuUxohPi
|
||||
JoXnOqBu5T9JdE81/Rm01bHQ6XAiAHpQRCyZZ3TBUgpPd10DrV8K/gMuBduKOkgk
|
||||
BnwNZjOCcCwgI66F5kmoeT95ovn8ApKO9aT3EfYXx3XM+xaWjEQRpXulB9AYjQvg
|
||||
wxdW+cpHAa/ttPEnrb4y2Az4uYMM2016U5p1o6SP3/feGbWSsJ33OF4VvSaS1x0h
|
||||
DgzfqIX4/8yeYsfNNsoSpcwV9UGBZ7Zs0Avy1Mm5ah0Z6CGGKVWb7Qqse1YR9MSa
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGTDCCBDSgAwIBAgIQOXpmzCdWNi4NqofKbqvjsTANBgkqhkiG9w0BAQwFADBf
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
|
||||
Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
|
||||
HhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5WjBgMQswCQYDVQQGEwJHQjEY
|
||||
MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFB1Ymxp
|
||||
YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gQ0EgRFYgUjM2MIIBojANBgkqhkiG9w0B
|
||||
AQEFAAOCAY8AMIIBigKCAYEAljZf2HIz7+SPUPQCQObZYcrxLTHYdf1ZtMRe7Yeq
|
||||
RPSwygz16qJ9cAWtWNTcuICc++p8Dct7zNGxCpqmEtqifO7NvuB5dEVexXn9RFFH
|
||||
12Hm+NtPRQgXIFjx6MSJcNWuVO3XGE57L1mHlcQYj+g4hny90aFh2SCZCDEVkAja
|
||||
EMMfYPKuCjHuuF+bzHFb/9gV8P9+ekcHENF2nR1efGWSKwnfG5RawlkaQDpRtZTm
|
||||
M64TIsv/r7cyFO4nSjs1jLdXYdz5q3a4L0NoabZfbdxVb+CUEHfB0bpulZQtH1Rv
|
||||
38e/lIdP7OTTIlZh6OYL6NhxP8So0/sht/4J9mqIGxRFc0/pC8suja+wcIUna0HB
|
||||
pXKfXTKpzgis+zmXDL06ASJf5E4A2/m+Hp6b84sfPAwQ766rI65mh50S0Di9E3Pn
|
||||
2WcaJc+PILsBmYpgtmgWTR9eV9otfKRUBfzHUHcVgarub/XluEpRlTtZudU5xbFN
|
||||
xx/DgMrXLUAPaI60fZ6wA+PTAgMBAAGjggGBMIIBfTAfBgNVHSMEGDAWgBRWc1hk
|
||||
lfmSGrASKgRieaFAFYghSTAdBgNVHQ4EFgQUaMASFhgOr872h6YyV6NGUV3LBycw
|
||||
DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI
|
||||
KwYBBQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEw
|
||||
VAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdv
|
||||
UHVibGljU2VydmVyQXV0aGVudGljYXRpb25Sb290UjQ2LmNybDCBhAYIKwYBBQUH
|
||||
AQEEeDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3Rp
|
||||
Z29QdWJsaWNTZXJ2ZXJBdXRoZW50aWNhdGlvblJvb3RSNDYucDdjMCMGCCsGAQUF
|
||||
BzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA
|
||||
YtOC9Fy+TqECFw40IospI92kLGgoSZGPOSQXMBqmsGWZUQ7rux7cj1du6d9rD6C8
|
||||
ze1B2eQjkrGkIL/OF1s7vSmgYVafsRoZd/IHUrkoQvX8FZwUsmPu7amgBfaY3g+d
|
||||
q1x0jNGKb6I6Bzdl6LgMD9qxp+3i7GQOnd9J8LFSietY6Z4jUBzVoOoz8iAU84OF
|
||||
h2HhAuiPw1ai0VnY38RTI+8kepGWVfGxfBWzwH9uIjeooIeaosVFvE8cmYUB4TSH
|
||||
5dUyD0jHct2+8ceKEtIoFU/FfHq/mDaVnvcDCZXtIgitdMFQdMZaVehmObyhRdDD
|
||||
4NQCs0gaI9AAgFj4L9QtkARzhQLNyRf87Kln+YU0lgCGr9HLg3rGO8q+Y4ppLsOd
|
||||
unQZ6ZxPNGIfOApbPVf5hCe58EZwiWdHIMn9lPP6+F404y8NNugbQixBber+x536
|
||||
WrZhFZLjEkhp7fFXf9r32rNPfb74X/U90Bdy4lzp3+X1ukh1BuMxA/EEhDoTOS3l
|
||||
7ABvc7BYSQubQ2490OcdkIzUh3ZwDrakMVrbaTxUM2p24N6dB+ns2zptWCva6jzW
|
||||
r8IWKIMxzxLPv5Kt3ePKcUdvkBU/smqujSczTzzSjIoR5QqQA6lN1ZRSnuHIWCvh
|
||||
JEltkYnTAH41QJ6SAWO66GrrUESwN/cgZzL4JLEqz1Y=
|
||||
-----END CERTIFICATE-----
|
||||
28
static/cert/key.pem
Normal file
28
static/cert/key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmbfvKXmQAQTEj
|
||||
kVg5SQSspEm2zXhF9rzza7EAamt2gc0C3aenZvKsNPfWuZp/77kM3bRYXEG2npsa
|
||||
FVYrM8zN3aU5ToC8pdq+HK/CjFyf60TKi3mmJLPgVWCcsSgJVSHbiQqT/nMWFCIs
|
||||
/szRjLnLhXWp83jXwkYWpA5Mxx/yymRWAx3qnUfL3VJzh/J/cbhke7AuiD23zC/E
|
||||
lwp2szKXDwHiBcyXmVt32xSEOUege19/JPfsFMyl6yaNPkPFNZiALFe34eIJ/sYK
|
||||
xTie09lXfBLR4J6+Z8zUQ5OKaxPnnE8Qb3i+EBrjaD2gAbaK+jiwUeeAEPMnI9vZ
|
||||
UNPeAayXAgMBAAECggEAOYwMJVRwFZp1KExIij5STHPePURc0yxW94CESpWBpQ+K
|
||||
2PPV1c+GF7+U9v1ki9pTTTyX8HmuCzxaezFngza9GW4LhH49i3153oTCzW2FVZKf
|
||||
Tb3eiXFldStwZZ3oLxntxCBltPilyLubeZ19KvQTBmmWXvaeEVTOsWN2wluUE3oT
|
||||
QEEFJmvWSj6Ow5HwA2xZP5dD4gv7nCY1swTePVLgWtJDC3AWDmKv3mB28brmtaDw
|
||||
wP/Oq9LLlHJDK+AzJEuUs+VDFQi7j6yqXWglSjO3Jwkkfkqg/SSoZ9BKdd6i0DLs
|
||||
UnUWHHATpv0Lwsa7w8csQBwfskUxsXECZpwzpCgsIQKBgQDYl2wvwjjG6qZtr060
|
||||
rj4PDkFLxFbtlmBiyW9ShM6iqK6FWQJJ1FNr6MdM2zBqw+n4tldpU3DnuZQphgZK
|
||||
57jejWFsHH5DYkS8k0k021AYT2IyCFHoEF43LlbRDXQguw1fADnoy6FpJBaRzuxx
|
||||
jPEHdB/aYqngmTXglFYkizN2BwKBgQDEthR1FV5iPdQXKSR+Yu2irBzpxY1xhdd2
|
||||
V5082etd2vBvAT7e4k8MroNMuYqL8miu2SeTJEyNkpCVoxQPF4uavandoRuEFIZl
|
||||
8VPVvG5xqYIqXAJ4XlSImEgUww+jJfyLzHT0TZi6rrdHV/8zUXEimjc6OBZVafDg
|
||||
FP6Lqo/w8QKBgQCxx3B8rv3tgDNFOqzur0qvDvNXnnv/nfvVeiPO5sW5S52cRJgV
|
||||
Q5uJqlLUaeGO8Oo+RGTxRhUZjwDnKGRH3XWn7wI1PBoDc0iaRIbFRPK0UYx3Js8c
|
||||
HTtILdgC1fko2IA8JzJhO6tsYrvHyMHY3mgExzNSDMQFX5ySjw86BawixwKBgBGc
|
||||
J0qwBgoPdOw53618179HXzNCXz45eCd9AnOPIrX9Qqb9Wo6DfgYpnVGCDrgmlF6K
|
||||
zDMs/bly1ITA26vaNMI+lnVj1d3GJJ39s76fpteAEEoQgJwb/b9YuqM5Ly4w2WH+
|
||||
hL3WMIUN3RSC+TKz6MfrPGR23vD4kfrNhlgkhcxRAoGAEb6nXwyWe5hg9+qE2fcf
|
||||
W27VApoalmnDOGFHtGhUitbBw7mHPb6wsSh4mx5Ucccfb5WUO3Cq5aW3qsDdkM+a
|
||||
YrBDbvw7PPcAX0vokpyFQvHH35AsIXQuYlQyGzcCdZkpFPIB5gVbLvbgxpBvEbVZ
|
||||
mGJpw7X/6Pg0ux0Ze11cr2c=
|
||||
-----END PRIVATE KEY-----
|
||||
@ -1,71 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGMDCCBRigAwIBAgIQX4800cgswlDH/QexMSnnnjANBgkqhkiG9w0BAQsFADCB
|
||||
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
|
||||
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
|
||||
MB4XDTI1MDMwNjAwMDAwMFoXDTI2MDMwNjIzNTk1OVowGDEWMBQGA1UEAwwNKi5m
|
||||
YWtldGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMe42XWK
|
||||
HJuR7doFTX79zrEKfTlD2hjRIif3dHKJNTJNvZa52mIoHelP7RVUuFOhp7aZCNLh
|
||||
IEzDyZObl8vwO6L2PVu5tbBEEoNixbpfhc8ZICEBuVo2UAhnJFcMJtuvtrCq+7ye
|
||||
oczM/k/nh8FBz2WnLzWs4CZt1sa5knZXFmBmsHJQtQIC6vx7QzVcKGOlAosIEHSK
|
||||
X4nIz5fLgWSzor1Gay56j31PTk+qRvlPQM2aKiLWnlLfRED4zHJqLe94itu8llPX
|
||||
b6g+cLxxRKUpMqtG/15cDdBZwv40Dja7bmNfe1u4w2QCVLjvHVaVpNXbcRay/Mhn
|
||||
M1w5LzDZmV58b18CAwEAAaOCAvwwggL4MB8GA1UdIwQYMBaAFI2MXsRUrYrhd+mb
|
||||
+ZsF4bgBjWHhMB0GA1UdDgQWBBS6/x/N38wMJrQq/cE1oIcRERMonTAOBgNVHQ8B
|
||||
Af8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICBzAlMCMGCCsGAQUFBwIBFhdo
|
||||
dHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEwgYQGCCsGAQUFBwEBBHgw
|
||||
djBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNB
|
||||
RG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEFBQcwAYYX
|
||||
aHR0cDovL29jc3Auc2VjdGlnby5jb20wJQYDVR0RBB4wHIINKi5mYWtldGxzLmNv
|
||||
bYILZmFrZXRscy5jb20wggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AJaXZL9V
|
||||
WJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnGAAABlWsz5fgAAAQDAEcwRQIgTN7Y
|
||||
/mDqiD3RbGVLEOQK2wvXsboBolBRwGJFuFEsDScCIQCQ0qfb/0V8qqSxrkx/PiVS
|
||||
1lSn5gBEnQUiQOkefcnW0gB2ABmG1Mcoqm/+ugNveCpNAZGqzi1yMQ+uzl1wQS0l
|
||||
TMfUAAABlWsz5dAAAAQDAEcwRQIhAJnQJyrSCWWdi9Kyoa7XuMGyDKt183jJMY0E
|
||||
71abTuBOAiBC+WnK1esG6xr8aVGHRcc+1U/I7LiaG3LCRMYtCKrTGwB2AMs49xWJ
|
||||
fIShRF9bwd37yW7ymlnNRwppBYWwyxTDFFjnAAABlWsz5f4AAAQDAEcwRQIhAJUs
|
||||
4PWDwyQJnCxCyEwFlFUY2uYQkGrQPA9f9Sw5Xk1fAiB63eQtZQGjvzvhOghy6z9a
|
||||
8oGYbDfDQ/zfisMYO7rM6zANBgkqhkiG9w0BAQsFAAOCAQEAEHnSoeBbWiK3CS3a
|
||||
px0BL+YXxRxdUcTMHgn5o+LlI9sWlpf+JLXmn7Z4QA6fAwT4k/Ue7xsmIq0OraDk
|
||||
/pEVXWm1HO/9wUkGQg0DBi77BpfHircd7OWIMdt250Q8UAmZkOyhVgnwBcScqMwq
|
||||
2T5CPaYvYGgYWx/qkIBv7JqhVbrP82rnF9b9ZUZ8GIE31chBmtMva9AsnAN5dmRw
|
||||
81bVvPWXUfX30CYu5sxeWL06Zpy9nfJumxZri1SWXNTBjSvud2jsZ8tSCUAWLL/4
|
||||
ui3Vien9m2oMOpaA8xbS88ZTk9Alm/o5febEKJZUPlytQzij8gQpiovFw2v+Cdei
|
||||
+tFXKw==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
|
||||
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
|
||||
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
|
||||
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
|
||||
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
|
||||
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
|
||||
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
|
||||
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
|
||||
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
|
||||
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
|
||||
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
|
||||
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
|
||||
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
|
||||
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
|
||||
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
|
||||
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
|
||||
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
|
||||
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
|
||||
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
|
||||
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
|
||||
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
|
||||
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
|
||||
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
|
||||
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
|
||||
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
|
||||
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
|
||||
-----END CERTIFICATE-----
|
||||
@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHuNl1ihybke3a
|
||||
BU1+/c6xCn05Q9oY0SIn93RyiTUyTb2WudpiKB3pT+0VVLhToae2mQjS4SBMw8mT
|
||||
m5fL8Dui9j1bubWwRBKDYsW6X4XPGSAhAblaNlAIZyRXDCbbr7awqvu8nqHMzP5P
|
||||
54fBQc9lpy81rOAmbdbGuZJ2VxZgZrByULUCAur8e0M1XChjpQKLCBB0il+JyM+X
|
||||
y4Fks6K9Rmsueo99T05Pqkb5T0DNmioi1p5S30RA+Mxyai3veIrbvJZT12+oPnC8
|
||||
cUSlKTKrRv9eXA3QWcL+NA42u25jX3tbuMNkAlS47x1WlaTV23EWsvzIZzNcOS8w
|
||||
2ZlefG9fAgMBAAECggEAT1Tti/LASks8300b60WFxG0WMJjzGMh5eMaiSpyVtNWM
|
||||
aUKJrFOjDfnhgoeUcCPWKoG/L4Sc/+EFQMydDzTte120IasysEFZ2TZytAUdcZXZ
|
||||
XUMCDQNl5vCRTsJU7Q5u0t4YAGRCgMcsfTDKi8lISGiQKBHzN1CJ74Xm13rgOInd
|
||||
lAc0wd5S89sL6RYmRTj1LvuZ95EHXHqQGdv0fIFEyP3pF1iPwcoTuIVEeICqnEvW
|
||||
vd8CVO68eH3HFIwioqjp4qW3pxPZMhVq4161805uAMkoQlE+7MtEVenmP++1u1gM
|
||||
FjvAs3j9CZqOHZKcLlOtcGSwDlD++fCMMT4slLgLgQKBgQDy58E5nuYXdxlFQQk4
|
||||
QccUKpyJ2aVXyp9xvTFBot/5Pik1SkuDzv2XU1OTxdxf3EongLy91nMJ2/6/39Je
|
||||
lf0/2MjzCtJ/lSzZ/zpJAu86UkBkWBAA5loGIof6OKedbEIgqpJqtK59S+j3ExO9
|
||||
eqa+uFrtt1UfaJG4A7TT+dIvIwKBgQDSfSOdSM5Dh3KsQHVnIWcIkzwTtlJlO+rG
|
||||
6rDEADxw6Kp8VIL/dq4Foe8yW4VqLVrWUuZsU6jzC9GdnyYi6VaqZ/iSUtGkBMOT
|
||||
WTTYhqXlURaQ13jhqdwCZJRbVI72JbXn2OGEv8DgXnk//QKED/8VdKqAzCSr1t1f
|
||||
3yfwei0AlQKBgD19KU66yKg7/+umEP1quUiDmOjUbaSRqFcUe3mQD356m9ffnMob
|
||||
BdrevxNzTNv/Wc4yKpUryic+x3gu4oQLF/annAbaQHsHejkdANYmpgRvedls6XAw
|
||||
360Z5K4U1WlmVD8Mrs/QOTOCmdChxad7euZgqLPwat3ujKS2W3oljW1dAoGBAM4/
|
||||
AB6lsDZLCfnuTxt2h1bHrh5CkAnR5AJ1BC+Ja6/WyvZ4eMOIroumWJKnStr3BgLr
|
||||
yAxtDSbZddNUljGvIdRnfBEkRXbJlDlVN4rSpMtF4S6bcz7rCUDu/M9g05Qs70j2
|
||||
IkPJAFzZNUWVzFlKs096uXbqkSQvrUq7ho8DqAThAoGBAL7Nrbr5LWcBgvwEhEla
|
||||
VRfYb0FUrDwLIrVWntJjW566/pVQQ4BmatsblLjlQYWk9MCIYXWZbnB+2fRx9yjQ
|
||||
Adggez7Dws/Mrh/wVudKgayHCy5Lgd8rYjNgC+VZf8XGrWX3QXMJ6UWAyQLTeoO7
|
||||
hToW9o9CQMIhaR43G8di1kjF
|
||||
-----END PRIVATE KEY-----
|
||||
@ -1152,7 +1152,7 @@
|
||||
<button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(addMissingHelminthRecipes);" data-loc="cheats_addMissingSubsumedAbilities"></button>
|
||||
<button class="btn btn-primary" onclick="doIntrinsicsUnlockAll();" data-loc="cheats_intrinsicsUnlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="inventory_maxPlexus"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="cheats_maxPlexus"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(unlockAllProfitTakerStages);" data-loc="cheats_unlockAllProfitTakerStages"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(unlockAllSimarisResearchEntries);" data-loc="cheats_unlockAllSimarisResearchEntries"></button>
|
||||
</div>
|
||||
@ -1474,6 +1474,7 @@
|
||||
<label class="form-label" for="worldState.nightwaveOverride" data-loc="worldState_nightwaveOverride"></label>
|
||||
<select class="form-control" id="worldState.nightwaveOverride" data-default="">
|
||||
<option value="" data-loc="disabled"></option>
|
||||
<option value="RadioLegionIntermission14Syndicate" data-loc="worldState_RadioLegionIntermission14Syndicate"></option>
|
||||
<option value="RadioLegionIntermission13Syndicate" data-loc="worldState_RadioLegionIntermission13Syndicate"></option>
|
||||
<option value="RadioLegionIntermission12Syndicate" data-loc="worldState_RadioLegionIntermission12Syndicate"></option>
|
||||
<option value="RadioLegionIntermission11Syndicate" data-loc="worldState_RadioLegionIntermission11Syndicate"></option>
|
||||
|
||||
@ -646,7 +646,7 @@ function fetchItemList() {
|
||||
if ("badReason" in item) {
|
||||
if (item.badReason == "starter") {
|
||||
item.name = loc("code_starter").split("|MOD|").join(item.name);
|
||||
} else {
|
||||
} else if (item.badReason != "notraw") {
|
||||
item.name += " " + loc("code_badItem");
|
||||
}
|
||||
}
|
||||
@ -1454,7 +1454,11 @@ function updateInventory() {
|
||||
{
|
||||
const td = document.createElement("td");
|
||||
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
|
||||
if (itemMap[item.ItemType]?.badReason == "notraw") {
|
||||
// Assuming this is a riven with a pending challenge, so rank would be N/A, but otherwise it's fine.
|
||||
} else {
|
||||
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
|
||||
}
|
||||
tr.appendChild(td);
|
||||
}
|
||||
{
|
||||
@ -1542,14 +1546,17 @@ function updateInventory() {
|
||||
|
||||
if (item) {
|
||||
document.getElementById("detailedView-loading").classList.add("d-none");
|
||||
|
||||
const itemName = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||
if (item.ItemName) {
|
||||
$("#detailedView-title").text(item.ItemName);
|
||||
$("#detailedView-route .text-body-secondary").text(
|
||||
itemMap[item.ItemType]?.name ?? item.ItemType
|
||||
);
|
||||
const pipeIndex = item.ItemName.indexOf("|");
|
||||
if (pipeIndex != -1) {
|
||||
$("#detailedView-title").text(item.ItemName.substr(1 + pipeIndex) + " " + itemName);
|
||||
} else {
|
||||
$("#detailedView-title").text(item.ItemName);
|
||||
$("#detailedView-route .text-body-secondary").text(itemName);
|
||||
}
|
||||
} else {
|
||||
$("#detailedView-title").text(itemMap[item.ItemType]?.name ?? item.ItemType);
|
||||
$("#detailedView-title").text(itemName);
|
||||
}
|
||||
|
||||
if (category == "Suits") {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// German translation by Animan8000
|
||||
dict = {
|
||||
general_inventoryUpdateNote: `Hinweis: Um Änderungen im Spiel zu sehen, musst du dein Inventar neu synchronisieren, z. B. mit dem /sync Befehl des Bootstrappers im Spielchat, durch Besuch eines Dojo/Relais oder durch erneutes Einloggen.`,
|
||||
general_inventoryUpdateNote: `Hinweis: Um Änderungen im Spiel zu sehen, musst du dein Inventar neu synchronisieren, z. B. durch Besuch eines Dojo/Relais oder durch erneutes Anmelden.`,
|
||||
general_inventoryUpdateNoteGameWs: `Hinweis: Möglicherweise musst du ein Menü neu öffnen, damit die Änderungen sichtbar werden.`,
|
||||
general_addButton: `Hinzufügen`,
|
||||
general_setButton: `Festlegen`,
|
||||
@ -51,7 +51,7 @@ dict = {
|
||||
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden.`,
|
||||
code_addModsConfirm: `Bist du sicher, dass du |COUNT| Mods zu deinem Account hinzufügen möchtest?`,
|
||||
code_succImport: `Erfolgreich importiert.`,
|
||||
code_succRelog: `Fertig. Bitte beachte, dass du dich neu einloggen musst, um Änderungen im Spiel zu sehen.`,
|
||||
code_succRelog: `Fertig. Bitte beachte, dass du dich neu anmelden musst, um Änderungen im Spiel zu sehen.`,
|
||||
code_nothingToDo: `Fertig. Es gab nichts zu tun.`,
|
||||
code_gild: `Veredeln`,
|
||||
code_moa: `Moa`,
|
||||
@ -134,8 +134,7 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
|
||||
inventory_maxPlexus: `Plexus auf Max. Rang`,
|
||||
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
|
||||
inventory_removeIsNew: `Entferne Ausrufezeichen bei neuem Equipment`,
|
||||
|
||||
quests_list: `Quests`,
|
||||
quests_completeAll: `Alle Quests abschließen`,
|
||||
@ -200,9 +199,9 @@ dict = {
|
||||
cheats_skipTutorial: `Tutorial überspringen`,
|
||||
cheats_skipAllDialogue: `Alle Dialoge überspringen`,
|
||||
cheats_unlockAllScans: `Alle Scans freischalten`,
|
||||
cheats_unlockSuccRelog: `Erfolgreich. Bitte beachte, dass du dich neu einloggen musst, damit der Client dies aktualisiert.`,
|
||||
cheats_unlockSuccRelog: `Erfolgreich. Bitte beachte, dass du dich neu anmelden musst, damit der Client dies aktualisiert.`,
|
||||
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 anmelden musst, damit die Sternenkarte aktualisiert wird.`,
|
||||
cheats_infiniteCredits: `Unendlich Credits`,
|
||||
cheats_infinitePlatinum: `Unendlich Platinum`,
|
||||
cheats_infiniteEndo: `Unendlich Endo`,
|
||||
@ -214,7 +213,7 @@ dict = {
|
||||
cheats_dontSubtractPurchaseItemCost: `Gegenstände beim Kauf nicht verbrauchen`,
|
||||
cheats_dontSubtractPurchaseStandingCost: `Ansehen beim Kauf nicht verbrauchen`,
|
||||
cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`,
|
||||
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
|
||||
cheats_dontSubtractConsumables: `Verbrauchsgüter (Ausrüstung) nicht verbrauchen`,
|
||||
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
|
||||
cheats_unlockAllSkins: `Alle Skins freischalten`,
|
||||
cheats_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro hat volles Inventar`,
|
||||
cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`,
|
||||
cheats_unlockAllProfitTakerStages: `Alle Profiteintreiber-Phasen freischalten`,
|
||||
cheats_unlockSuccInventory: `Erfolgreich. Bitte beachte, dass du dein Inventar neu synchronisieren musst, z. B. mit dem /sync Befehl des Bootstrappers im Spielchat, durch Besuch eines Dojo/Relais oder durch erneutes Einloggen.`,
|
||||
cheats_unlockSuccInventory: `Erfolgreich. Bitte beachte, dass du dein Inventar neu synchronisieren musst, z. B. durch Besuch eines Dojo/Relais oder durch erneutes Anmelden.`,
|
||||
cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`,
|
||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
|
||||
cheats_addMissingSubsumedAbilities: `Fehlende konsumierte Fähigkeiten hinzufügen`,
|
||||
cheats_intrinsicsUnlockAll: `Alle Inhärenzen auf Max. Rang`,
|
||||
cheats_maxPlexus: `Plexus auf Max. Rang`,
|
||||
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
||||
cheats_changeButton: `Ändern`,
|
||||
cheats_markAllAsRead: `Posteingang als gelesen markieren`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `Trauer`,
|
||||
worldState_fear: `Angst`,
|
||||
worldState_nightwaveOverride: `Nightwave-Überschreibung`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `Noras Mix: Träume der Toten`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Noras Mix - Vol. 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Noras Mix - Vol. 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Noras Mix - Vol. 7`,
|
||||
@ -385,10 +386,10 @@ dict = {
|
||||
upgrade_AvatarAbilityRange: `+7.5% Fähigkeitsreichweite`,
|
||||
upgrade_AvatarAbilityEfficiency: `+5% Fähigkeitseffizienz`,
|
||||
upgrade_AvatarEnergyRegen: `+0.5 Energieregeneration pro Sekunde`,
|
||||
upgrade_AvatarEnemyRadar: `+5m Feindradar`,
|
||||
upgrade_AvatarEnemyRadar: `+5m Gegnerradar`,
|
||||
upgrade_AvatarLootRadar: `+7m Beuteradar`,
|
||||
upgrade_WeaponAmmoMax: `+15% Max. Munition`,
|
||||
upgrade_EnemyArmorReductionAura: `-3% Rüstung bei Feinden`,
|
||||
upgrade_EnemyArmorReductionAura: `-3% Rüstung für Gegner`,
|
||||
upgrade_OnExecutionAmmo: `+100% Magazinfüllung für Primär- und Sekundärwaffen bei Gnadenstoß`,
|
||||
upgrade_OnExecutionHealthDrop: `+100% Gesundheitskugel Chance bei Gnadenstoß`,
|
||||
upgrade_OnExecutionEnergyDrop: `+50% Energiekugel Chance bei Gnadenstoß`,
|
||||
@ -398,7 +399,7 @@ dict = {
|
||||
upgrade_OnExecutionParkourSpeed: `+60% Parkourgeschwindigkeit für 15s nach Gnadenstoß`,
|
||||
upgrade_AvatarTimeLimitIncrease: `+8s extra Zeit beim Hacken`,
|
||||
upgrade_ElectrifyOnHack: `Setze beim Hacken Gegner innerhalb von 20m unter Strom`,
|
||||
upgrade_OnExecutionTerrify: `+50% Chance bei Gnadenstoß, dass Feinde innerhalb von 15m vor Furcht für 8s kauern`,
|
||||
upgrade_OnExecutionTerrify: `+50% Chance bei Gnadenstoß, dass Gegner innerhalb von 15m vor Furcht für 8s kauern`,
|
||||
upgrade_OnHackLockers: `Schließe nach dem Hacken 5 Spinde innerhalb von 20m auf`,
|
||||
upgrade_OnExecutionBlind: `Blende bei einem Gnadenstoß Gegner innerhalb von 18m`,
|
||||
upgrade_OnExecutionDrainPower: `Nächste Fähigkeit erhält +50% Fähigkeitsstärke nach Gnadenstoß`,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
dict = {
|
||||
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_inventoryUpdateNote: `Note: To see changes in-game, you need to resync your inventory, e.g. by 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_addButton: `Add`,
|
||||
general_setButton: `Set`,
|
||||
@ -133,7 +133,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
|
||||
inventory_maxPlexus: `Max Rank Plexus`,
|
||||
inventory_removeIsNew: `Remove New Equipment Exclamation Icon`,
|
||||
|
||||
quests_list: `Quests`,
|
||||
@ -233,7 +232,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro Fully Stocked`,
|
||||
cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`,
|
||||
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 in game chat, visiting a dojo/relay, or relogging.`,
|
||||
cheats_unlockSuccInventory: `Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`,
|
||||
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
|
||||
@ -259,6 +258,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
|
||||
cheats_addMissingSubsumedAbilities: `Add Missing Subsumed Abilities`,
|
||||
cheats_intrinsicsUnlockAll: `Max Rank All Intrinsics`,
|
||||
cheats_maxPlexus: `Max Rank Plexus`,
|
||||
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
||||
cheats_changeButton: `Change`,
|
||||
cheats_markAllAsRead: `Mark Inbox As Read`,
|
||||
@ -323,6 +323,7 @@ dict = {
|
||||
worldState_sorrow: `Sorrow`,
|
||||
worldState_fear: `Fear`,
|
||||
worldState_nightwaveOverride: `Nightwave Override`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Nora's Mix Vol. 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Nora's Mix Vol. 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Nora's Mix Vol. 7`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Spanish translation by hxedcl, Slayer55555
|
||||
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: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
general_inventoryUpdateNoteGameWs: `Nota: Puede que necesites reabrir cualquier menú en el que te encuentres para que los cambios se reflejen.`,
|
||||
general_addButton: `Agregar`,
|
||||
general_setButton: `Establecer`,
|
||||
@ -134,7 +134,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
|
||||
inventory_maxPlexus: `Rango máximo de Plexus`,
|
||||
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
|
||||
|
||||
quests_list: `Misiones`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro con stock completo`,
|
||||
cheats_syndicateMissionsRepeatable: `Misiones de sindicato rejugables`,
|
||||
cheats_unlockAllProfitTakerStages: `Desbloquea todas las etapas del Roba-ganancias`,
|
||||
cheats_unlockSuccInventory: `Éxito. Ten en cuenta que deberás volver a sincronizar tu inventario. Para hacerlo, puedes usar el comando /sync en el Bootstrapper, visitar un dojo o repetidor, o volver a iniciar sesión.`,
|
||||
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `Terminar desafío de agrietado inmediatamente`,
|
||||
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
|
||||
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
|
||||
cheats_addMissingSubsumedAbilities: `Agregar habilidades subsumidas faltantes`,
|
||||
cheats_intrinsicsUnlockAll: `Maximizar todos los intrínsecos`,
|
||||
cheats_maxPlexus: `Rango máximo de Plexus`,
|
||||
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
|
||||
cheats_changeButton: `Cambiar`,
|
||||
cheats_markAllAsRead: `Marcar bandeja de entrada como leída`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `Tristeza`,
|
||||
worldState_fear: `Miedo`,
|
||||
worldState_nightwaveOverride: `Volúmen de Onda Nocturna`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `[UNTRANSLATED] Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Mix de Nora Vol. 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Mix de Nora Vol. 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Mix de Nora Vol. 7`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// French translation by Vitruvio
|
||||
dict = {
|
||||
general_inventoryUpdateNote: `Note : Pour voir les changements en jeu, l'inventaire doit être actualisé. Cela se fait en tapant /sync dans le tchat, en visitant un dojo/relais ou en se reconnectant.`,
|
||||
general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
general_inventoryUpdateNoteGameWs: `Note : Rouvrir un menu est nécessaire pour voir les changements.`,
|
||||
general_addButton: `Ajouter`,
|
||||
general_setButton: `Définir`,
|
||||
@ -134,7 +134,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
|
||||
inventory_maxPlexus: `Plexus au rang max`,
|
||||
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
|
||||
|
||||
quests_list: `Quêtes`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Stock de Baro au max`,
|
||||
cheats_syndicateMissionsRepeatable: `Mission syndicat répétables`,
|
||||
cheats_unlockAllProfitTakerStages: `Débloquer toutes les étapes du Preneur de Profit`,
|
||||
cheats_unlockSuccInventory: `Succès. Une resynchronisation est nécessaire en tapant "/sync" dans le tchat, en visitant un relais ou en se reconnectant.`,
|
||||
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `Débloquer le challenge Riven instantanément`,
|
||||
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
|
||||
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Helminth niveau max`,
|
||||
cheats_addMissingSubsumedAbilities: `Ajouter les capacités subsumées manquantes`,
|
||||
cheats_intrinsicsUnlockAll: `Inhérences niveau max`,
|
||||
cheats_maxPlexus: `Plexus au rang max`,
|
||||
cheats_changeSupportedSyndicate: `Allégeance`,
|
||||
cheats_changeButton: `Changer`,
|
||||
cheats_markAllAsRead: `Marquer la boîte de réception comme lue`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `hagrin`,
|
||||
worldState_fear: `Peur`,
|
||||
worldState_nightwaveOverride: `Saison d'Ondes Nocturnes`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `[UNTRANSLATED] Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Mix de Nora Vol. 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Mix de Nora Vol. 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Mix de Nora Vol. 7`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Russian translation by AMelonInsideLemon, LoseFace
|
||||
dict = {
|
||||
general_inventoryUpdateNote: `Примечание: Чтобы увидеть изменения в игре, вам нужно повторно синхронизировать свой инвентарь, например, используя команду загрузчика /sync в чате игры, посетив Додзё/Реле или перезагрузив игру.`,
|
||||
general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
general_inventoryUpdateNoteGameWs: `Примечание: для того, чтобы изменения вступили в силу, может потребоваться повторно открыть меню, в котором вы находитесь.`,
|
||||
general_addButton: `Добавить`,
|
||||
general_setButton: `Установить`,
|
||||
@ -134,7 +134,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Макс. ранг всех Стражей`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Макс. ранг всего оружия Стражей`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Макс. ранг всех эволюций Инкарнонов`,
|
||||
inventory_maxPlexus: `Макс. ранг Плексуса`,
|
||||
inventory_removeIsNew: `Удалить значок восклицательного знака нового снаряжения`,
|
||||
|
||||
quests_list: `Квесты`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Баро полностью укомплектован`,
|
||||
cheats_syndicateMissionsRepeatable: `Повторять миссии синдиката`,
|
||||
cheats_unlockAllProfitTakerStages: `Разблокировать все этапы Сферы извлечения прибыли`,
|
||||
cheats_unlockSuccInventory: `Успех. Обратите внимание, что вам необходимо будет повторно синхронизировать свой инвентарь, например, с помощью команды загрузчика /sync в чате игры, посетив Додзё/Реле или повторно войдя в игру.`,
|
||||
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `Мгновенное завершение испытания мода Разлома`,
|
||||
cheats_instantResourceExtractorDrones: `Мгновенно добывающие Дроны-сборщики`,
|
||||
cheats_noResourceExtractorDronesDamage: `Без урона по Дронам-сборщикам`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
|
||||
cheats_addMissingSubsumedAbilities: `Добавить отсутствующие поглощённые способности`,
|
||||
cheats_intrinsicsUnlockAll: `Полностью улучшить Модуляры`,
|
||||
cheats_maxPlexus: `Макс. ранг Плексуса`,
|
||||
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
||||
cheats_changeButton: `Изменить`,
|
||||
cheats_markAllAsRead: `Пометить все входящие как прочитанные`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `Печаль`,
|
||||
worldState_fear: `Страх`,
|
||||
worldState_nightwaveOverride: `Сезон Ночной волны`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `[UNTRANSLATED] Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Микс Норы, Диск 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Микс Норы, Диск 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Микс Норы, Диск 7`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Ukrainian translation by LoseFace
|
||||
dict = {
|
||||
general_inventoryUpdateNote: `Пам'ятка: Щоб побачити зміни в грі, вам потрібно повторно синхронізувати своє спорядження, наприклад, використовуючи команду завантажувача /sync у чаті гри, відвідавши Доджьо/Реле або перезавантаживши гру.`,
|
||||
general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
general_inventoryUpdateNoteGameWs: `Примітка: для відображення змін може знадобитися повторно відкрити меню, в якому ви перебуваєте.`,
|
||||
general_addButton: `Добавити`,
|
||||
general_setButton: `Встановити`,
|
||||
@ -134,7 +134,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `Макс. рівень всіх Вартових`,
|
||||
inventory_bulkRankUpSentinelWeapons: `Макс. рівень всієї зброї Вартових`,
|
||||
inventory_bulkRankUpEvolutionProgress: `Макс. рівень всіх еволюцій Інкарнонів`,
|
||||
inventory_maxPlexus: `Макс. рівень Плексу`,
|
||||
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
|
||||
|
||||
quests_list: `Пригоди`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Баро повністю укомплектований`,
|
||||
cheats_syndicateMissionsRepeatable: `Повторювати місії синдиката`,
|
||||
cheats_unlockAllProfitTakerStages: `Розблокувати всі етапи Привласнювачки`,
|
||||
cheats_unlockSuccInventory: `Успішно. Зверніть увагу, що вам потрібно буде повторно синхронізувати своє спорядження, наприклад, за допомогою команди завантажувача /sync у чаті гри, відвідавши Доджьо/Реле або повторно увійшовши в гру.`,
|
||||
cheats_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `Миттєве завершення випробування модифікатора Розколу`,
|
||||
cheats_instantResourceExtractorDrones: `Миттєво добуваючі Дрони-видобувачі`,
|
||||
cheats_noResourceExtractorDronesDamage: `Без шкоди по Дронам-видобувачам`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `Повністю покращити Гельмінта`,
|
||||
cheats_addMissingSubsumedAbilities: `Додати відсутні поглинуті здібності`,
|
||||
cheats_intrinsicsUnlockAll: `Повністю покращити Кваліфікації`,
|
||||
cheats_maxPlexus: `Макс. рівень Плексу`,
|
||||
cheats_changeSupportedSyndicate: `Підтримуваний синдикат`,
|
||||
cheats_changeButton: `Змінити`,
|
||||
cheats_markAllAsRead: `Помітити всі вхідні як прочитані`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `Журба`,
|
||||
worldState_fear: `Страх`,
|
||||
worldState_nightwaveOverride: `Сезон Нічної хвилі`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `[UNTRANSLATED] Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `Вибірка Нори 9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `Вибірка Нори 8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `Вибірка Нори 7`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang, Corvus, qingchun
|
||||
dict = {
|
||||
general_inventoryUpdateNote: `注意: 要在游戏中查看更改,您需要重新同步库存,例如使用客户端的 /sync 命令,访问道场/中继站或重新登录.`,
|
||||
general_inventoryUpdateNote: `[UNTRANSLATED] Note: To see changes in-game, you need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
general_inventoryUpdateNoteGameWs: `[UNTRANSLATED] Note: You may need to reopen any menu you are on for changes to be reflected.`,
|
||||
general_addButton: `添加`,
|
||||
general_setButton: `设置`,
|
||||
@ -134,7 +134,6 @@ dict = {
|
||||
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
||||
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
||||
inventory_bulkRankUpEvolutionProgress: `所有灵化之源进度最大等级`,
|
||||
inventory_maxPlexus: `最大深控等级`,
|
||||
inventory_removeIsNew: `[UNTRANSLATED] Remove New Equipment Exclamation Icon`,
|
||||
|
||||
quests_list: `系列任务`,
|
||||
@ -234,7 +233,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `虚空商人贩卖所有商品`,
|
||||
cheats_syndicateMissionsRepeatable: `集团任务可重复完成`,
|
||||
cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`,
|
||||
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_unlockSuccInventory: `[UNTRANSLATED] Success. Please note that you'll need to resync your inventory, e.g. by visiting a dojo/relay or relogging.`,
|
||||
cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`,
|
||||
cheats_instantResourceExtractorDrones: `资源无人机即时完成`,
|
||||
cheats_noResourceExtractorDronesDamage: `资源无人机不会损毁`,
|
||||
@ -260,6 +259,7 @@ dict = {
|
||||
cheats_helminthUnlockAll: `完全升级Helminth`,
|
||||
cheats_addMissingSubsumedAbilities: `添加Helminth未汲取的战甲技能`,
|
||||
cheats_intrinsicsUnlockAll: `所有内源之力最大等级`,
|
||||
cheats_maxPlexus: `最大深控等级`,
|
||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||
cheats_changeButton: `更改`,
|
||||
cheats_markAllAsRead: `收件箱全部标记为已读`,
|
||||
@ -324,6 +324,7 @@ dict = {
|
||||
worldState_sorrow: `悲伤`,
|
||||
worldState_fear: `恐惧`,
|
||||
worldState_nightwaveOverride: `午夜电波系列`,
|
||||
worldState_RadioLegionIntermission14Syndicate: `[UNTRANSLATED] Nora's Mix: Dreams of the Dead`,
|
||||
worldState_RadioLegionIntermission13Syndicate: `诺拉的混选VOL.9`,
|
||||
worldState_RadioLegionIntermission12Syndicate: `诺拉的混选VOL.8`,
|
||||
worldState_RadioLegionIntermission11Syndicate: `诺拉的混选VOL.7`,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user