forked from OpenWF/SpaceNinjaServer
Compare commits
25 Commits
564aa06762
...
9f0cd91105
Author | SHA1 | Date | |
---|---|---|---|
9f0cd91105 | |||
ebfef52fb1 | |||
dd7bacd22e | |||
c00967931e | |||
b15a635e11 | |||
7e618539fa | |||
a29398fae6 | |||
601091f1c0 | |||
f561884f2c | |||
6e1cb0c9f9 | |||
9286627668 | |||
f94f2005d3 | |||
9901b7af54 | |||
2fa846f465 | |||
541ec3d702 | |||
0a28eab65d | |||
8e639a16bd | |||
522924a823 | |||
48e3f324e2 | |||
8f77c722cb | |||
e7287933b5 | |||
b21bca7a6d | |||
d30d450311 | |||
b62e326920 | |||
8b4bc114f6 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ">=20.6.0"
|
node-version: ">=20.6.0"
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: cp config.json.example config.json
|
- run: cp config-vanilla.json config.json
|
||||||
- run: npm run verify
|
- run: npm run verify
|
||||||
- run: npm run lint:ci
|
- run: npm run lint:ci
|
||||||
- run: npm run prettier
|
- run: npm run prettier
|
||||||
|
@ -2,4 +2,4 @@ src/routes/api.ts
|
|||||||
static/webui/libs/
|
static/webui/libs/
|
||||||
*.html
|
*.html
|
||||||
*.md
|
*.md
|
||||||
config.json.example
|
config-vanilla.json
|
||||||
|
@ -10,7 +10,7 @@ To get an idea of what functionality you can expect to be missing [have a look t
|
|||||||
|
|
||||||
## config.json
|
## config.json
|
||||||
|
|
||||||
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled.
|
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config-vanilla.json](config-vanilla.json), which has most cheats disabled.
|
||||||
|
|
||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
||||||
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
||||||
|
@ -70,8 +70,9 @@
|
|||||||
"creditBoost": false,
|
"creditBoost": false,
|
||||||
"affinityBoost": false,
|
"affinityBoost": false,
|
||||||
"resourceBoost": false,
|
"resourceBoost": false,
|
||||||
"starDays": true,
|
"tennoLiveRelay": false,
|
||||||
"galleonOfGhouls": 0,
|
"galleonOfGhouls": 0,
|
||||||
|
"starDaysOverride": null,
|
||||||
"eidolonOverride": "",
|
"eidolonOverride": "",
|
||||||
"vallisOverride": "",
|
"vallisOverride": "",
|
||||||
"duviriOverride": "",
|
"duviriOverride": "",
|
@ -2,7 +2,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ ! -f conf/config.json ]; then
|
if [ ! -f conf/config.json ]; then
|
||||||
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json
|
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec npm run start -- --configPath conf/config.json
|
exec npm run start -- --configPath conf/config.json
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -23,7 +23,7 @@
|
|||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"undici": "^7.10.0",
|
"undici": "^7.10.0",
|
||||||
"warframe-public-export-plus": "^0.5.78",
|
"warframe-public-export-plus": "^0.5.79",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
@ -5507,9 +5507,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.78",
|
"version": "0.5.79",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.78.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.79.tgz",
|
||||||
"integrity": "sha512-Zvg7N+EdXS8cOAZIxqCbqiqyvQZBgh2xTxEwpHnoyJjNBpm3sP/7dtXmzHaxAZjyaCL4pvi9e7kTvxmpH8Pcag=="
|
"integrity": "sha512-mPaFGX7bmSo1FP0xzo//vNCkbzMRz517NHiQB1ZU8gyoRm41IaGQ7/pFWCP8iY8KWbEMvPty4pj1hZtxsujCIA=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"undici": "^7.10.0",
|
"undici": "^7.10.0",
|
||||||
"warframe-public-export-plus": "^0.5.78",
|
"warframe-public-export-plus": "^0.5.79",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
|
@ -335,6 +335,17 @@ export const getInventoryResponse = async (
|
|||||||
for (const uniqueName in ExportFlavour) {
|
for (const uniqueName in ExportFlavour) {
|
||||||
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
||||||
}
|
}
|
||||||
|
} else if (config.worldState?.baroTennoConRelay) {
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2022EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2023EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2024EarlyAccess",
|
||||||
|
"/Lotus/Types/Items/Events/TennoConRelay2025EarlyAccess"
|
||||||
|
].forEach(uniqueName => {
|
||||||
|
if (!inventoryResponse.FlavourItems.some(x => x.ItemType == uniqueName)) {
|
||||||
|
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.unlockAllSkins) {
|
if (config.unlockAllSkins) {
|
||||||
|
@ -10,6 +10,7 @@ import { logger } from "@/src/utils/logger";
|
|||||||
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
||||||
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
|
logger.debug(`challenge report:`, challenges);
|
||||||
|
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
account._id.toString(),
|
account._id.toString(),
|
||||||
@ -17,7 +18,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
let affiliationMods: IAffiliationMods[] = [];
|
let affiliationMods: IAffiliationMods[] = [];
|
||||||
if (challenges.ChallengeProgress) {
|
if (challenges.ChallengeProgress) {
|
||||||
affiliationMods = addChallenges(
|
affiliationMods = await addChallenges(
|
||||||
account,
|
account,
|
||||||
inventory,
|
inventory,
|
||||||
challenges.ChallengeProgress,
|
challenges.ChallengeProgress,
|
||||||
|
33
src/controllers/custom/abilityOverrideController.ts
Normal file
33
src/controllers/custom/abilityOverrideController.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const abilityOverrideController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IAbilityOverrideRequest;
|
||||||
|
if (request.category === "Suits") {
|
||||||
|
const inventory = await getInventory(accountId, request.category);
|
||||||
|
const item = inventory[request.category].id(request.oid);
|
||||||
|
if (item) {
|
||||||
|
if (request.action == "set") {
|
||||||
|
item.Configs[request.configIndex].AbilityOverride = request.AbilityOverride;
|
||||||
|
} else {
|
||||||
|
item.Configs[request.configIndex].AbilityOverride = undefined;
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IAbilityOverrideRequest {
|
||||||
|
category: TEquipmentKey;
|
||||||
|
oid: string;
|
||||||
|
action: "set" | "remove";
|
||||||
|
configIndex: number;
|
||||||
|
AbilityOverride: {
|
||||||
|
Ability: string;
|
||||||
|
Index: number;
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getDict, getItemName, getString } from "@/src/services/itemDataService";
|
import { getDict, getItemName, getString } from "@/src/services/itemDataService";
|
||||||
import {
|
import {
|
||||||
|
ExportAbilities,
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportAvionics,
|
ExportAvionics,
|
||||||
ExportBoosters,
|
ExportBoosters,
|
||||||
@ -57,6 +58,7 @@ interface ItemLists {
|
|||||||
mods: ListedItem[];
|
mods: ListedItem[];
|
||||||
Boosters: ListedItem[];
|
Boosters: ListedItem[];
|
||||||
VarziaOffers: ListedItem[];
|
VarziaOffers: ListedItem[];
|
||||||
|
Abilities: ListedItem[];
|
||||||
//circuitGameModes: ListedItem[];
|
//circuitGameModes: ListedItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +96,8 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
EvolutionProgress: [],
|
EvolutionProgress: [],
|
||||||
mods: [],
|
mods: [],
|
||||||
Boosters: [],
|
Boosters: [],
|
||||||
VarziaOffers: []
|
VarziaOffers: [],
|
||||||
|
Abilities: []
|
||||||
/*circuitGameModes: [
|
/*circuitGameModes: [
|
||||||
{
|
{
|
||||||
uniqueName: "Survival",
|
uniqueName: "Survival",
|
||||||
@ -132,6 +135,12 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
name: getString(item.name, lang),
|
name: getString(item.name, lang),
|
||||||
exalted: item.exalted
|
exalted: item.exalted
|
||||||
});
|
});
|
||||||
|
item.abilities.forEach(ability => {
|
||||||
|
res.Abilities.push({
|
||||||
|
uniqueName: ability.uniqueName,
|
||||||
|
name: getString(ability.name || uniqueName, lang)
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
||||||
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
||||||
@ -144,18 +153,21 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
|
||||||
if (item.partType) {
|
if (item.partType) {
|
||||||
if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) {
|
if (!uniqueName.split("/")[7]?.startsWith("PvPVariant")) {
|
||||||
res.ModularParts.push({
|
// not a pvp variant
|
||||||
uniqueName,
|
if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) {
|
||||||
name: getString(item.name, lang),
|
res.ModularParts.push({
|
||||||
partType: item.partType
|
uniqueName,
|
||||||
});
|
name: getString(item.name, lang),
|
||||||
}
|
partType: item.partType
|
||||||
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
});
|
||||||
res.miscitems.push({
|
}
|
||||||
uniqueName: uniqueName,
|
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
||||||
name: getString(item.name, lang)
|
res.miscitems.push({
|
||||||
});
|
uniqueName: uniqueName,
|
||||||
|
name: getString(item.name, lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (item.totalDamage !== 0) {
|
} else if (item.totalDamage !== 0) {
|
||||||
if (
|
if (
|
||||||
@ -348,6 +360,13 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const [uniqueName, ability] of Object.entries(ExportAbilities)) {
|
||||||
|
res.Abilities.push({
|
||||||
|
uniqueName,
|
||||||
|
name: getString(ability.name || uniqueName, lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
response.json(res);
|
response.json(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ try {
|
|||||||
if (fs.existsSync("config.json")) {
|
if (fs.existsSync("config.json")) {
|
||||||
console.log("Failed to load " + configPath + ": " + (e as Error).message);
|
console.log("Failed to load " + configPath + ": " + (e as Error).message);
|
||||||
} else {
|
} else {
|
||||||
console.log("Failed to load " + configPath + ". You can copy config.json.example to create your config file.");
|
console.log("Failed to load " + configPath + ". You can copy config-vanilla.json to create your config file.");
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import { webuiFileChangeDetectedController } from "@/src/controllers/custom/webu
|
|||||||
import { completeAllMissionsController } from "@/src/controllers/custom/completeAllMissionsController";
|
import { completeAllMissionsController } from "@/src/controllers/custom/completeAllMissionsController";
|
||||||
import { addMissingHelminthBlueprintsController } from "@/src/controllers/custom/addMissingHelminthBlueprintsController";
|
import { addMissingHelminthBlueprintsController } from "@/src/controllers/custom/addMissingHelminthBlueprintsController";
|
||||||
|
|
||||||
|
import { abilityOverrideController } from "@/src/controllers/custom/abilityOverrideController";
|
||||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||||
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
||||||
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
|
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
|
||||||
@ -47,6 +48,7 @@ customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController);
|
|||||||
customRouter.get("/completeAllMissions", completeAllMissionsController);
|
customRouter.get("/completeAllMissions", completeAllMissionsController);
|
||||||
customRouter.get("/addMissingHelminthBlueprints", addMissingHelminthBlueprintsController);
|
customRouter.get("/addMissingHelminthBlueprints", addMissingHelminthBlueprintsController);
|
||||||
|
|
||||||
|
customRouter.post("/abilityOverride", abilityOverrideController);
|
||||||
customRouter.post("/createAccount", createAccountController);
|
customRouter.post("/createAccount", createAccountController);
|
||||||
customRouter.post("/createMessage", createMessageController);
|
customRouter.post("/createMessage", createMessageController);
|
||||||
customRouter.post("/addCurrency", addCurrencyController);
|
customRouter.post("/addCurrency", addCurrencyController);
|
||||||
|
@ -81,8 +81,10 @@ export interface IConfig {
|
|||||||
creditBoost?: boolean;
|
creditBoost?: boolean;
|
||||||
affinityBoost?: boolean;
|
affinityBoost?: boolean;
|
||||||
resourceBoost?: boolean;
|
resourceBoost?: boolean;
|
||||||
starDays?: boolean;
|
tennoLiveRelay?: boolean;
|
||||||
|
baroTennoConRelay?: boolean;
|
||||||
galleonOfGhouls?: number;
|
galleonOfGhouls?: number;
|
||||||
|
starDaysOverride?: boolean;
|
||||||
eidolonOverride?: string;
|
eidolonOverride?: string;
|
||||||
vallisOverride?: string;
|
vallisOverride?: string;
|
||||||
duviriOverride?: string;
|
duviriOverride?: string;
|
||||||
|
@ -25,7 +25,8 @@ import {
|
|||||||
INemesisWeaponTargetFingerprint,
|
INemesisWeaponTargetFingerprint,
|
||||||
INemesisPetTargetFingerprint,
|
INemesisPetTargetFingerprint,
|
||||||
IDialogueDatabase,
|
IDialogueDatabase,
|
||||||
IKubrowPetPrintClient
|
IKubrowPetPrintClient,
|
||||||
|
equipmentKeys
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "@/src/types/genericUpdate";
|
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "@/src/types/genericUpdate";
|
||||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
@ -1341,7 +1342,7 @@ export const addStanding = (
|
|||||||
|
|
||||||
// TODO: AffiliationMods support (Nightwave).
|
// TODO: AffiliationMods support (Nightwave).
|
||||||
export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<IUpdateNodeIntrosResponse> => {
|
export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<IUpdateNodeIntrosResponse> => {
|
||||||
const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems");
|
const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems ShipDecorations");
|
||||||
|
|
||||||
// Make it an array for easier parsing.
|
// Make it an array for easier parsing.
|
||||||
if (typeof data.NodeIntrosCompleted === "string") {
|
if (typeof data.NodeIntrosCompleted === "string") {
|
||||||
@ -1350,7 +1351,15 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string): Pr
|
|||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
for (const node of data.NodeIntrosCompleted) {
|
for (const node of data.NodeIntrosCompleted) {
|
||||||
if (node == "KayaFirstVisitPack") {
|
if (node == "TC2025") {
|
||||||
|
inventoryChanges.ShipDecorations = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/ShipDecos/TauGrineerLancerBobbleHead",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addShipDecorations(inventory, inventoryChanges.ShipDecorations);
|
||||||
|
} else if (node == "KayaFirstVisitPack") {
|
||||||
inventoryChanges.MiscItems = [
|
inventoryChanges.MiscItems = [
|
||||||
{
|
{
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack",
|
ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack",
|
||||||
@ -1903,25 +1912,87 @@ export const addLoreFragmentScans = (inventory: TInventoryDatabaseDocument, arr:
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addChallenges = (
|
const challengeRewardsInboxMessages: Record<string, IMessageCreationTemplate> = {
|
||||||
|
SentEvoEphemeraRankOne: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockAName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockADesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraB"]
|
||||||
|
},
|
||||||
|
SentEvoEphemeraRankTwo: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBDesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraC"]
|
||||||
|
},
|
||||||
|
SentEvoSyandanaRankOne: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockAName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockADesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaBCape"]
|
||||||
|
},
|
||||||
|
SentEvoSyandanaRankTwo: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBDesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaCCape"]
|
||||||
|
},
|
||||||
|
SentEvoSekharaRankOne: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockAName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockADesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemB"]
|
||||||
|
},
|
||||||
|
SentEvoSekharaRankTwo: {
|
||||||
|
sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBName",
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBDesc",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemC"]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addChallenges = async (
|
||||||
account: TAccountDocument,
|
account: TAccountDocument,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
ChallengeProgress: IChallengeProgress[],
|
ChallengeProgress: IChallengeProgress[],
|
||||||
SeasonChallengeCompletions: ISeasonChallenge[] | undefined
|
SeasonChallengeCompletions: ISeasonChallenge[] | undefined
|
||||||
): IAffiliationMods[] => {
|
): Promise<IAffiliationMods[]> => {
|
||||||
ChallengeProgress.forEach(({ Name, Progress }) => {
|
for (const { Name, Progress, Completed } of ChallengeProgress) {
|
||||||
const itemIndex = inventory.ChallengeProgress.findIndex(i => i.Name === Name);
|
let dbChallenge = inventory.ChallengeProgress.find(x => x.Name == Name);
|
||||||
|
if (dbChallenge) {
|
||||||
if (itemIndex !== -1) {
|
dbChallenge.Progress = Progress;
|
||||||
inventory.ChallengeProgress[itemIndex].Progress = Progress;
|
|
||||||
} else {
|
} else {
|
||||||
inventory.ChallengeProgress.push({ Name, Progress });
|
dbChallenge = { Name, Progress };
|
||||||
|
inventory.ChallengeProgress.push(dbChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Name.startsWith("Calendar")) {
|
if (Name.startsWith("Calendar")) {
|
||||||
addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name);
|
addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if ((Completed?.length ?? 0) > (dbChallenge.Completed?.length ?? 0)) {
|
||||||
|
dbChallenge.Completed ??= [];
|
||||||
|
for (const completion of Completed!) {
|
||||||
|
if (dbChallenge.Completed.indexOf(completion) == -1) {
|
||||||
|
if (completion == "challengeRewards") {
|
||||||
|
if (Name in challengeRewardsInboxMessages) {
|
||||||
|
await createMessage(account._id, [challengeRewardsInboxMessages[Name]]);
|
||||||
|
dbChallenge.Completed.push(completion);
|
||||||
|
// Would love to somehow let the client know about inbox or inventory changes, but there doesn't seem to anything for updateChallengeProgress.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.warn(`ignoring unknown challenge completion`, { challenge: Name, completion });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const affiliationMods: IAffiliationMods[] = [];
|
const affiliationMods: IAffiliationMods[] = [];
|
||||||
if (SeasonChallengeCompletions) {
|
if (SeasonChallengeCompletions) {
|
||||||
@ -2117,6 +2188,21 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
|
|||||||
inventory.LotusCustomization.syancol = {};
|
inventory.LotusCustomization.syancol = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let numFixed = 0;
|
||||||
|
for (const equipmentKey of equipmentKeys) {
|
||||||
|
for (const item of inventory[equipmentKey]) {
|
||||||
|
if (item.ModularParts?.length === 0) {
|
||||||
|
item.ModularParts = undefined;
|
||||||
|
++numFixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numFixed != 0) {
|
||||||
|
logger.debug(`removed ModularParts from ${numFixed} non-modular items`);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {
|
export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {
|
||||||
|
@ -292,7 +292,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
addRecipes(inventory, value);
|
addRecipes(inventory, value);
|
||||||
break;
|
break;
|
||||||
case "ChallengeProgress":
|
case "ChallengeProgress":
|
||||||
addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions);
|
await addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions);
|
||||||
break;
|
break;
|
||||||
case "FusionTreasures":
|
case "FusionTreasures":
|
||||||
addFusionTreasures(inventory, value);
|
addFusionTreasures(inventory, value);
|
||||||
@ -972,7 +972,8 @@ export const addMissionRewards = async (
|
|||||||
Missions: missions,
|
Missions: missions,
|
||||||
RegularCredits: creditDrops,
|
RegularCredits: creditDrops,
|
||||||
VoidTearParticipantsCurrWave: voidTearWave,
|
VoidTearParticipantsCurrWave: voidTearWave,
|
||||||
StrippedItems: strippedItems
|
StrippedItems: strippedItems,
|
||||||
|
AffiliationChanges: AffiliationMods
|
||||||
}: IMissionInventoryUpdateRequest,
|
}: IMissionInventoryUpdateRequest,
|
||||||
firstCompletion: boolean
|
firstCompletion: boolean
|
||||||
): Promise<AddMissionRewardsReturnType> => {
|
): Promise<AddMissionRewardsReturnType> => {
|
||||||
@ -992,7 +993,6 @@ export const addMissionRewards = async (
|
|||||||
);
|
);
|
||||||
logger.debug("random mission drops:", MissionRewards);
|
logger.debug("random mission drops:", MissionRewards);
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
const AffiliationMods: IAffiliationMods[] = [];
|
|
||||||
let SyndicateXPItemReward;
|
let SyndicateXPItemReward;
|
||||||
let ConquestCompletedMissionsCount;
|
let ConquestCompletedMissionsCount;
|
||||||
|
|
||||||
@ -1302,6 +1302,9 @@ export const addMissionRewards = async (
|
|||||||
ItemCount: medallionAmount
|
ItemCount: medallionAmount
|
||||||
});
|
});
|
||||||
SyndicateXPItemReward = medallionAmount;
|
SyndicateXPItemReward = medallionAmount;
|
||||||
|
logger.debug(
|
||||||
|
`Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if (rewardInfo.JobTier! >= 0) {
|
if (rewardInfo.JobTier! >= 0) {
|
||||||
addStanding(
|
addStanding(
|
||||||
@ -1331,6 +1334,9 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (jobType == "/Lotus/Types/Gameplay/Eidolon/Jobs/NewbieJob") {
|
||||||
|
addStanding(inventory, "CetusSyndicate", Math.floor(200 / (rewardInfo.Q ? 0.8 : 1)), AffiliationMods);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rewardInfo.challengeMissionId) {
|
if (rewardInfo.challengeMissionId) {
|
||||||
@ -1347,6 +1353,7 @@ export const addMissionRewards = async (
|
|||||||
ItemCount: medallionAmount
|
ItemCount: medallionAmount
|
||||||
});
|
});
|
||||||
SyndicateXPItemReward = medallionAmount;
|
SyndicateXPItemReward = medallionAmount;
|
||||||
|
logger.debug(`Giving ${medallionAmount} medallions for the ${tier} tier bounty`);
|
||||||
} else {
|
} else {
|
||||||
let standingAmount = (tier + 1) * 1000;
|
let standingAmount = (tier + 1) * 1000;
|
||||||
if (tier > 5) standingAmount = 7500; // InfestedLichBounty
|
if (tier > 5) standingAmount = 7500; // InfestedLichBounty
|
||||||
@ -1772,6 +1779,11 @@ function getRandomMissionDrops(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (jobType == "/Lotus/Types/Gameplay/Eidolon/Jobs/NewbieJob") {
|
||||||
|
rewardManifests = ["/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/TierATableARewards"];
|
||||||
|
rotations = [3];
|
||||||
|
if (RewardInfo.Q) rotations.push(3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (RewardInfo.challengeMissionId) {
|
} else if (RewardInfo.challengeMissionId) {
|
||||||
const rewardTables: Record<string, string[]> = {
|
const rewardTables: Record<string, string[]> = {
|
||||||
|
@ -1038,13 +1038,13 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface ITimeConstraint {
|
interface ITimeConstraint {
|
||||||
//name: string;
|
name: string;
|
||||||
isValidTime: (timeSecs: number) => boolean;
|
isValidTime: (timeSecs: number) => boolean;
|
||||||
getIdealTimeBefore: (timeSecs: number) => number;
|
getIdealTimeBefore: (timeSecs: number) => number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eidolonDayConstraint: ITimeConstraint = {
|
const eidolonDayConstraint: ITimeConstraint = {
|
||||||
//name: "eidolon day",
|
name: "eidolon day",
|
||||||
isValidTime: (timeSecs: number): boolean => {
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const eidolonEpoch = 1391992660;
|
const eidolonEpoch = 1391992660;
|
||||||
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
@ -1062,7 +1062,7 @@ const eidolonDayConstraint: ITimeConstraint = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const eidolonNightConstraint: ITimeConstraint = {
|
const eidolonNightConstraint: ITimeConstraint = {
|
||||||
//name: "eidolon night",
|
name: "eidolon night",
|
||||||
isValidTime: (timeSecs: number): boolean => {
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const eidolonEpoch = 1391992660;
|
const eidolonEpoch = 1391992660;
|
||||||
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
@ -1089,7 +1089,7 @@ const eidolonNightConstraint: ITimeConstraint = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const venusColdConstraint: ITimeConstraint = {
|
const venusColdConstraint: ITimeConstraint = {
|
||||||
//name: "venus cold",
|
name: "venus cold",
|
||||||
isValidTime: (timeSecs: number): boolean => {
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const vallisEpoch = 1541837628;
|
const vallisEpoch = 1541837628;
|
||||||
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
@ -1115,7 +1115,7 @@ const venusColdConstraint: ITimeConstraint = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const venusWarmConstraint: ITimeConstraint = {
|
const venusWarmConstraint: ITimeConstraint = {
|
||||||
//name: "venus warm",
|
name: "venus warm",
|
||||||
isValidTime: (timeSecs: number): boolean => {
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const vallisEpoch = 1541837628;
|
const vallisEpoch = 1541837628;
|
||||||
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
@ -1157,6 +1157,25 @@ const getIdealTimeSatsifyingConstraints = (constraints: ITimeConstraint[]): numb
|
|||||||
return timeSecs;
|
return timeSecs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fullyStockBaro = (vt: IVoidTrader): void => {
|
||||||
|
for (const armorSet of baro.armorSets) {
|
||||||
|
if (Array.isArray(armorSet[0])) {
|
||||||
|
for (const set of armorSet as IVoidTraderOffer[][]) {
|
||||||
|
for (const item of set) {
|
||||||
|
vt.Manifest.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const item of armorSet as IVoidTraderOffer[]) {
|
||||||
|
vt.Manifest.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const item of baro.rest) {
|
||||||
|
vt.Manifest.push(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getVarziaRotation = (week: number): string => {
|
const getVarziaRotation = (week: number): string => {
|
||||||
const seed = new SRng(week).randomInt(0, 100_000);
|
const seed = new SRng(week).randomInt(0, 100_000);
|
||||||
const rng = new SRng(seed);
|
const rng = new SRng(seed);
|
||||||
@ -1321,7 +1340,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
constraints.push({
|
constraints.push({
|
||||||
//name: `duviri ${config.worldState.duviriOverride}`,
|
name: `duviri ${config.worldState.duviriOverride}`,
|
||||||
isValidTime: (timeSecs: number): boolean => {
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const moodIndex = Math.trunc(timeSecs / 7200);
|
const moodIndex = Math.trunc(timeSecs / 7200);
|
||||||
return moodIndex % 5 == desiredMood;
|
return moodIndex % 5 == desiredMood;
|
||||||
@ -1336,11 +1355,20 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const timeSecs = getIdealTimeSatsifyingConstraints(constraints);
|
const timeSecs = getIdealTimeSatsifyingConstraints(constraints);
|
||||||
|
if (constraints.length != 0) {
|
||||||
|
const delta = Math.trunc(Date.now() / 1000) - timeSecs;
|
||||||
|
if (delta > 1) {
|
||||||
|
logger.debug(
|
||||||
|
`reported time is ${delta} seconds behind real time to satisfy selected constraints (${constraints.map(x => x.name).join(", ")})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
const timeMs = timeSecs * 1000;
|
const timeMs = timeSecs * 1000;
|
||||||
const day = Math.trunc((timeMs - EPOCH) / 86400000);
|
const day = Math.trunc((timeMs - EPOCH) / 86400000);
|
||||||
const week = Math.trunc(day / 7);
|
const week = Math.trunc(day / 7);
|
||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
|
const date = new Date(timeMs);
|
||||||
|
|
||||||
const worldState: IWorldState = {
|
const worldState: IWorldState = {
|
||||||
BuildLabel: typeof buildLabel == "string" ? buildLabel.split(" ").join("+") : buildConfig.buildLabel,
|
BuildLabel: typeof buildLabel == "string" ? buildLabel.split(" ").join("+") : buildConfig.buildLabel,
|
||||||
@ -1367,11 +1395,77 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
worldState.PVPChallengeInstances = [];
|
worldState.PVPChallengeInstances = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.worldState?.starDays) {
|
if (config.worldState?.tennoLiveRelay) {
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: {
|
||||||
|
$oid: "687bf9400000000000000000"
|
||||||
|
},
|
||||||
|
Activation: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: "1752955200000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expiry: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: "2000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Count: 0,
|
||||||
|
Goal: 0,
|
||||||
|
Success: 0,
|
||||||
|
Personal: true,
|
||||||
|
Desc: "/Lotus/Language/Locations/RelayStationTennoConB",
|
||||||
|
ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDescB",
|
||||||
|
Icon: "/Lotus/Interface/Icons/Categories/IconTennoLive.png",
|
||||||
|
Tag: "TennoConRelayB",
|
||||||
|
Node: "TennoConBHUB6"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (config.worldState?.baroTennoConRelay) {
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: { $oid: "687bb2f00000000000000000" },
|
||||||
|
Activation: { $date: { $numberLong: "1752937200000" } },
|
||||||
|
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
Count: 0,
|
||||||
|
Goal: 0,
|
||||||
|
Success: 0,
|
||||||
|
Personal: true,
|
||||||
|
//"Faction": "FC_GRINEER",
|
||||||
|
Desc: "/Lotus/Language/Locations/RelayStationTennoCon",
|
||||||
|
ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDesc",
|
||||||
|
Icon: "/Lotus/Interface/Icons/Categories/IconTennoConSigil.png",
|
||||||
|
Tag: "TennoConRelay",
|
||||||
|
Node: "TennoConHUB2"
|
||||||
|
});
|
||||||
|
const vt: IVoidTrader = {
|
||||||
|
_id: { $oid: "687809030379266d790495c6" },
|
||||||
|
Activation: { $date: { $numberLong: "1752937200000" } },
|
||||||
|
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||||
|
Character: "Baro'Ki Teel",
|
||||||
|
Node: "TennoConHUB2",
|
||||||
|
Manifest: []
|
||||||
|
};
|
||||||
|
worldState.VoidTraders.push(vt);
|
||||||
|
fullyStockBaro(vt);
|
||||||
|
}
|
||||||
|
const isFebruary = date.getUTCMonth() == 1;
|
||||||
|
if (config.worldState?.starDaysOverride ?? isFebruary) {
|
||||||
worldState.Goals.push({
|
worldState.Goals.push({
|
||||||
_id: { $oid: "67a4dcce2a198564d62e1647" },
|
_id: { $oid: "67a4dcce2a198564d62e1647" },
|
||||||
Activation: { $date: { $numberLong: "1738868400000" } },
|
Activation: {
|
||||||
Expiry: { $date: { $numberLong: "2000000000000" } },
|
$date: {
|
||||||
|
$numberLong: config.worldState?.starDaysOverride
|
||||||
|
? "1738868400000"
|
||||||
|
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expiry: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: config.worldState?.starDaysOverride
|
||||||
|
? "2000000000000"
|
||||||
|
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
Count: 0,
|
Count: 0,
|
||||||
Goal: 0,
|
Goal: 0,
|
||||||
Success: 0,
|
Success: 0,
|
||||||
@ -1585,24 +1679,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
};
|
};
|
||||||
worldState.VoidTraders.push(vt);
|
worldState.VoidTraders.push(vt);
|
||||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, baroActualStart)) {
|
if (isBeforeNextExpectedWorldStateRefresh(timeMs, baroActualStart)) {
|
||||||
vt.Manifest = [];
|
|
||||||
if (config.baroFullyStocked) {
|
if (config.baroFullyStocked) {
|
||||||
for (const armorSet of baro.armorSets) {
|
fullyStockBaro(vt);
|
||||||
if (Array.isArray(armorSet[0])) {
|
|
||||||
for (const set of armorSet as IVoidTraderOffer[][]) {
|
|
||||||
for (const item of set) {
|
|
||||||
vt.Manifest.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const item of armorSet as IVoidTraderOffer[]) {
|
|
||||||
vt.Manifest.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const item of baro.rest) {
|
|
||||||
vt.Manifest.push(item);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const rng = new SRng(new SRng(baroIndex).randomInt(0, 100_000));
|
const rng = new SRng(new SRng(baroIndex).randomInt(0, 100_000));
|
||||||
// TOVERIFY: Constraint for upgrades amount?
|
// TOVERIFY: Constraint for upgrades amount?
|
||||||
@ -1823,7 +1901,10 @@ export const populateFissures = async (worldState: IWorldState): Promise<void> =
|
|||||||
_id: toOid(fissure._id),
|
_id: toOid(fissure._id),
|
||||||
Region: meta.systemIndex + 1,
|
Region: meta.systemIndex + 1,
|
||||||
Seed: 1337,
|
Seed: 1337,
|
||||||
Activation: toMongoDate(fissure.Activation),
|
Activation:
|
||||||
|
fissure.Activation.getTime() < Date.now() // Activation is in the past?
|
||||||
|
? { $date: { $numberLong: "1000000000000" } } // Let the client know 'explicitly' to avoid interference from time constraints.
|
||||||
|
: toMongoDate(fissure.Activation),
|
||||||
Expiry: toMongoDate(fissure.Expiry),
|
Expiry: toMongoDate(fissure.Expiry),
|
||||||
Node: fissure.Node,
|
Node: fissure.Node,
|
||||||
MissionType: eMissionType[meta.missionIndex].tag,
|
MissionType: eMissionType[meta.missionIndex].tag,
|
||||||
|
@ -74,6 +74,7 @@ export type IInventoryChanges = {
|
|||||||
InfestedFoundry?: IInfestedFoundryClient;
|
InfestedFoundry?: IInfestedFoundryClient;
|
||||||
Drones?: IDroneClient[];
|
Drones?: IDroneClient[];
|
||||||
MiscItems?: IMiscItem[];
|
MiscItems?: IMiscItem[];
|
||||||
|
ShipDecorations?: ITypeCount[];
|
||||||
EmailItems?: ITypeCount[];
|
EmailItems?: ITypeCount[];
|
||||||
CrewShipRawSalvage?: ITypeCount[];
|
CrewShipRawSalvage?: ITypeCount[];
|
||||||
Nemesis?: Partial<INemesisClient>;
|
Nemesis?: Partial<INemesisClient>;
|
||||||
|
@ -431,7 +431,7 @@
|
|||||||
{ "ItemType": "/Lotus/StoreItems/Types/Items/SongItems/KuvaLichLoginSongItem", "PrimePrice": 140, "RegularPrice": 170000 },
|
{ "ItemType": "/Lotus/StoreItems/Types/Items/SongItems/KuvaLichLoginSongItem", "PrimePrice": 140, "RegularPrice": 170000 },
|
||||||
{ "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyBaro", "PrimePrice": 100, "RegularPrice": 125000 },
|
{ "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyBaro", "PrimePrice": 100, "RegularPrice": 125000 },
|
||||||
{ "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyInaros", "PrimePrice": 120, "RegularPrice": 90000 },
|
{ "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyInaros", "PrimePrice": 120, "RegularPrice": 90000 },
|
||||||
{ "ItemType": "/Lotus/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageMurmursExpert", "PrimePrice": 375, "RegularPrice": 130000 }
|
{ "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageMurmursExpert", "PrimePrice": 375, "RegularPrice": 130000 }
|
||||||
],
|
],
|
||||||
"allIfAny": [
|
"allIfAny": [
|
||||||
[
|
[
|
||||||
|
@ -388,11 +388,11 @@
|
|||||||
<div class="card" style="height: 400px;">
|
<div class="card" style="height: 400px;">
|
||||||
<h5 class="card-header" data-loc="inventory_hoverboards"></h5>
|
<h5 class="card-header" data-loc="inventory_hoverboards"></h5>
|
||||||
<div class="card-body overflow-auto">
|
<div class="card-body overflow-auto">
|
||||||
<form class="input-group mb-3" onsubmit="doAcquireModularEquipment('HoverBoards');return false;">
|
<form class="input-group mb-3" onsubmit="doAcquireModularEquipment('Hoverboards');return false;">
|
||||||
<input class="form-control" id="acquire-type-HoverBoards-HB_DECK" list="datalist-ModularParts-HB_DECK" />
|
<input class="form-control" id="acquire-type-Hoverboards-HB_DECK" list="datalist-ModularParts-HB_DECK" />
|
||||||
<input class="form-control" id="acquire-type-HoverBoards-HB_ENGINE" list="datalist-ModularParts-HB_ENGINE" />
|
<input class="form-control" id="acquire-type-Hoverboards-HB_ENGINE" list="datalist-ModularParts-HB_ENGINE" />
|
||||||
<input class="form-control" id="acquire-type-HoverBoards-HB_FRONT" list="datalist-ModularParts-HB_FRONT" />
|
<input class="form-control" id="acquire-type-Hoverboards-HB_FRONT" list="datalist-ModularParts-HB_FRONT" />
|
||||||
<input class="form-control" id="acquire-type-HoverBoards-HB_JET" list="datalist-ModularParts-HB_JET" />
|
<input class="form-control" id="acquire-type-Hoverboards-HB_JET" list="datalist-ModularParts-HB_JET" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
</form>
|
</form>
|
||||||
<table class="table table-hover w-100">
|
<table class="table table-hover w-100">
|
||||||
@ -460,6 +460,13 @@
|
|||||||
<h3 id="detailedView-loading" class="mb-0" data-loc="general_loading"></h3>
|
<h3 id="detailedView-loading" class="mb-0" data-loc="general_loading"></h3>
|
||||||
<h3 id="detailedView-title" class="mb-0"></h3>
|
<h3 id="detailedView-title" class="mb-0"></h3>
|
||||||
<p class="text-body-secondary"></p>
|
<p class="text-body-secondary"></p>
|
||||||
|
<div id="loadout-card" class="card mb-3 d-none">
|
||||||
|
<h5 class="card-header" data-loc="detailedView_loadoutLabel"></h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<ul class="nav nav-tabs" id="loadoutTabs"></ul>
|
||||||
|
<div class="tab-content mt-3" id="loadoutTabsContent"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="archonShards-card" class="card mb-3 d-none">
|
<div id="archonShards-card" class="card mb-3 d-none">
|
||||||
<h5 class="card-header" data-loc="detailedView_archonShardsLabel"></h5>
|
<h5 class="card-header" data-loc="detailedView_archonShardsLabel"></h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -919,8 +926,12 @@
|
|||||||
<label class="form-check-label" for="worldState.resourceBoost" data-loc="worldState_resourceBoost"></label>
|
<label class="form-check-label" for="worldState.resourceBoost" data-loc="worldState_resourceBoost"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="worldState.starDays" />
|
<input class="form-check-input" type="checkbox" id="worldState.tennoLiveRelay" />
|
||||||
<label class="form-check-label" for="worldState.starDays" data-loc="worldState_starDays"></label>
|
<label class="form-check-label" for="worldState.tennoLiveRelay" data-loc="worldState_tennoLiveRelay"></label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="worldState.baroTennoConRelay" />
|
||||||
|
<label class="form-check-label" for="worldState.baroTennoConRelay" data-loc="worldState_baroTennoConRelay"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="worldState.varziaFullyStocked" />
|
<input class="form-check-input" type="checkbox" id="worldState.varziaFullyStocked" />
|
||||||
@ -935,6 +946,14 @@
|
|||||||
<option value="3" data-loc="worldState_we3"></option>
|
<option value="3" data-loc="worldState_we3"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group mt-2">
|
||||||
|
<label class="form-label" for="worldState.starDaysOverride" data-loc="worldState_starDays"></label>
|
||||||
|
<select class="form-control" id="worldState.starDaysOverride" data-default="null">
|
||||||
|
<option value="null" data-loc="normal"></option>
|
||||||
|
<option value="true" data-loc="enabled"></option>
|
||||||
|
<option value="false" data-loc="disabled"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="form-group mt-2">
|
<div class="form-group mt-2">
|
||||||
<label class="form-label" for="worldState.eidolonOverride" data-loc="worldState_eidolonOverride"></label>
|
<label class="form-label" for="worldState.eidolonOverride" data-loc="worldState_eidolonOverride"></label>
|
||||||
<select class="form-control" id="worldState.eidolonOverride" data-default="">
|
<select class="form-control" id="worldState.eidolonOverride" data-default="">
|
||||||
@ -1073,6 +1092,7 @@
|
|||||||
<datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
|
<datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
|
||||||
<datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
|
<datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
|
||||||
<datalist id="datalist-Boosters"></datalist>
|
<datalist id="datalist-Boosters"></datalist>
|
||||||
|
<datalist id="datalist-Abilities"></datalist>
|
||||||
<datalist id="datalist-circuitGameModes">
|
<datalist id="datalist-circuitGameModes">
|
||||||
<option>Survival</option>
|
<option>Survival</option>
|
||||||
<option>VoidFlood</option>
|
<option>VoidFlood</option>
|
||||||
|
@ -28,7 +28,8 @@ const sendAuth = isRegister => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function openWebSocket() {
|
function openWebSocket() {
|
||||||
window.ws = new WebSocket("/custom/ws");
|
const wsProto = location.protocol === "https:" ? "wss://" : "ws://";
|
||||||
|
window.ws = new WebSocket(wsProto + location.host + "/custom/ws");
|
||||||
window.ws.onopen = () => {
|
window.ws.onopen = () => {
|
||||||
ws_is_open = true;
|
ws_is_open = true;
|
||||||
sendAuth(false);
|
sendAuth(false);
|
||||||
@ -1241,6 +1242,117 @@ function updateInventory() {
|
|||||||
document.getElementById("dv-invigoration-offensive").value = OffensiveUpgrade;
|
document.getElementById("dv-invigoration-offensive").value = OffensiveUpgrade;
|
||||||
document.getElementById("dv-invigoration-defensive").value = DefensiveUpgrade;
|
document.getElementById("dv-invigoration-defensive").value = DefensiveUpgrade;
|
||||||
document.getElementById("dv-invigoration-expiry").value = UpgradesExpiry;
|
document.getElementById("dv-invigoration-expiry").value = UpgradesExpiry;
|
||||||
|
|
||||||
|
{
|
||||||
|
document.getElementById("loadout-card").classList.remove("d-none");
|
||||||
|
const maxModConfigNum = Math.min(2 + (item.ModSlotPurchases ?? 0), 5);
|
||||||
|
|
||||||
|
const configs = item.Configs ?? [];
|
||||||
|
|
||||||
|
const loadoutTabs = document.getElementById("loadoutTabs");
|
||||||
|
const loadoutTabsContent = document.getElementById("loadoutTabsContent");
|
||||||
|
loadoutTabs.innerHTML = "";
|
||||||
|
loadoutTabsContent.innerHTML = "";
|
||||||
|
for (let i = 0; i <= maxModConfigNum; i++) {
|
||||||
|
const config = configs[i] ?? {};
|
||||||
|
|
||||||
|
{
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.classList.add("nav-item");
|
||||||
|
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.classList.add("nav-link");
|
||||||
|
if (i === 0) button.classList.add("active");
|
||||||
|
button.id = `config${i}-tab`;
|
||||||
|
button.setAttribute("data-bs-toggle", "tab");
|
||||||
|
button.setAttribute("data-bs-target", `#config${i}`);
|
||||||
|
button.innerHTML = config.Name?.trim() || String.fromCharCode(65 + i);
|
||||||
|
|
||||||
|
li.appendChild(button);
|
||||||
|
loadoutTabs.appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tabDiv = document.createElement("div");
|
||||||
|
tabDiv.classList = "tab-pane";
|
||||||
|
if (i === 0) tabDiv.classList.add("show", "active");
|
||||||
|
|
||||||
|
tabDiv.id = `config${i}`;
|
||||||
|
|
||||||
|
{
|
||||||
|
const abilityOverrideForm = document.createElement("form");
|
||||||
|
abilityOverrideForm.classList = "form-group mt-2";
|
||||||
|
abilityOverrideForm.setAttribute(
|
||||||
|
"onsubmit",
|
||||||
|
`handleAbilityOverride(event, ${i});return false;`
|
||||||
|
);
|
||||||
|
|
||||||
|
const abilityOverrideFormLabel = document.createElement("label");
|
||||||
|
abilityOverrideFormLabel.setAttribute("data-loc", "abilityOverride_label");
|
||||||
|
abilityOverrideFormLabel.innerHTML = loc("abilityOverride_label");
|
||||||
|
abilityOverrideFormLabel.classList = "form-label";
|
||||||
|
abilityOverrideFormLabel.setAttribute("for", "abilityOverride-ability");
|
||||||
|
abilityOverrideForm.appendChild(abilityOverrideFormLabel);
|
||||||
|
|
||||||
|
const abilityOverrideInputGroup = document.createElement("div");
|
||||||
|
abilityOverrideInputGroup.classList = "input-group";
|
||||||
|
abilityOverrideForm.appendChild(abilityOverrideInputGroup);
|
||||||
|
|
||||||
|
const abilityOverrideInput = document.createElement("input");
|
||||||
|
abilityOverrideInput.id = "abilityOverride-ability";
|
||||||
|
abilityOverrideInput.classList = "form-control";
|
||||||
|
abilityOverrideInput.setAttribute("list", "datalist-Abilities");
|
||||||
|
if (config.AbilityOverride) {
|
||||||
|
const datalist = document.getElementById("datalist-Abilities");
|
||||||
|
const options = Array.from(datalist.options);
|
||||||
|
abilityOverrideInput.value = options.find(
|
||||||
|
option =>
|
||||||
|
config.AbilityOverride.Ability == option.getAttribute("data-key")
|
||||||
|
).value;
|
||||||
|
}
|
||||||
|
abilityOverrideInputGroup.appendChild(abilityOverrideInput);
|
||||||
|
|
||||||
|
const abilityOverrideOnSlot = document.createElement("span");
|
||||||
|
abilityOverrideOnSlot.classList = "input-group-text";
|
||||||
|
abilityOverrideOnSlot.setAttribute("data-loc", "abilityOverride_onSlot");
|
||||||
|
abilityOverrideOnSlot.innerHTML = loc("abilityOverride_onSlot");
|
||||||
|
abilityOverrideInputGroup.appendChild(abilityOverrideOnSlot);
|
||||||
|
|
||||||
|
const abilityOverrideSecondInput = document.createElement("input");
|
||||||
|
abilityOverrideSecondInput.id = "abilityOverride-ability-index";
|
||||||
|
abilityOverrideSecondInput.classList = "form-control";
|
||||||
|
abilityOverrideSecondInput.setAttribute("type", "number");
|
||||||
|
abilityOverrideSecondInput.setAttribute("min", "0");
|
||||||
|
abilityOverrideSecondInput.setAttribute("max", "3");
|
||||||
|
if (config.AbilityOverride)
|
||||||
|
abilityOverrideSecondInput.value = config.AbilityOverride.Index;
|
||||||
|
abilityOverrideInputGroup.appendChild(abilityOverrideSecondInput);
|
||||||
|
|
||||||
|
const abilityOverrideSetButton = document.createElement("button");
|
||||||
|
abilityOverrideSetButton.classList = "btn btn-primary";
|
||||||
|
abilityOverrideSetButton.setAttribute("type", "submit");
|
||||||
|
abilityOverrideSetButton.setAttribute("value", "set");
|
||||||
|
abilityOverrideSetButton.setAttribute("data-loc", "general_setButton");
|
||||||
|
abilityOverrideSetButton.innerHTML = loc("general_setButton");
|
||||||
|
abilityOverrideInputGroup.appendChild(abilityOverrideSetButton);
|
||||||
|
|
||||||
|
const abilityOverrideRemoveButton = document.createElement("button");
|
||||||
|
abilityOverrideRemoveButton.classList = "btn btn-danger";
|
||||||
|
abilityOverrideRemoveButton.setAttribute("type", "submit");
|
||||||
|
abilityOverrideRemoveButton.setAttribute("value", "remove");
|
||||||
|
abilityOverrideRemoveButton.setAttribute("data-loc", "code_remove");
|
||||||
|
abilityOverrideRemoveButton.innerHTML = loc("code_remove");
|
||||||
|
abilityOverrideInputGroup.appendChild(abilityOverrideRemoveButton);
|
||||||
|
|
||||||
|
abilityOverrideForm.appendChild(abilityOverrideInputGroup);
|
||||||
|
|
||||||
|
tabDiv.appendChild(abilityOverrideForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadoutTabsContent.appendChild(tabDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (["LongGuns", "Pistols", "Melee", "SpaceGuns", "SpaceMelee"].includes(category)) {
|
} else if (["LongGuns", "Pistols", "Melee", "SpaceGuns", "SpaceMelee"].includes(category)) {
|
||||||
document.getElementById("valenceBonus-card").classList.remove("d-none");
|
document.getElementById("valenceBonus-card").classList.remove("d-none");
|
||||||
document.getElementById("valenceBonus-innateDamage").value = "";
|
document.getElementById("valenceBonus-innateDamage").value = "";
|
||||||
@ -1987,7 +2099,13 @@ for (const id of uiConfigs) {
|
|||||||
if (elm.tagName == "SELECT") {
|
if (elm.tagName == "SELECT") {
|
||||||
elm.onchange = function () {
|
elm.onchange = function () {
|
||||||
let value = this.value;
|
let value = this.value;
|
||||||
if (!isNaN(parseInt(value))) {
|
if (value == "true") {
|
||||||
|
value = true;
|
||||||
|
} else if (value == "false") {
|
||||||
|
value = false;
|
||||||
|
} else if (value == "null") {
|
||||||
|
value = null;
|
||||||
|
} else if (!isNaN(parseInt(value))) {
|
||||||
value = parseInt(value);
|
value = parseInt(value);
|
||||||
}
|
}
|
||||||
$.post({
|
$.post({
|
||||||
@ -2248,6 +2366,7 @@ single.getRoute("#detailedView-route").on("beforeload", function () {
|
|||||||
document.getElementById("detailedView-loading").classList.remove("d-none");
|
document.getElementById("detailedView-loading").classList.remove("d-none");
|
||||||
document.getElementById("detailedView-title").textContent = "";
|
document.getElementById("detailedView-title").textContent = "";
|
||||||
document.querySelector("#detailedView-route .text-body-secondary").textContent = "";
|
document.querySelector("#detailedView-route .text-body-secondary").textContent = "";
|
||||||
|
document.getElementById("loadout-card").classList.add("d-none");
|
||||||
document.getElementById("archonShards-card").classList.add("d-none");
|
document.getElementById("archonShards-card").classList.add("d-none");
|
||||||
document.getElementById("edit-suit-invigorations-card").classList.add("d-none");
|
document.getElementById("edit-suit-invigorations-card").classList.add("d-none");
|
||||||
document.getElementById("modularParts-card").classList.add("d-none");
|
document.getElementById("modularParts-card").classList.add("d-none");
|
||||||
@ -2963,3 +3082,29 @@ async function editSuitInvigorationUpgrade(oid, data) {
|
|||||||
updateInventory();
|
updateInventory();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAbilityOverride(event, configIndex) {
|
||||||
|
event.preventDefault();
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const action = event.submitter.value;
|
||||||
|
const Ability = getKey(document.getElementById("abilityOverride-ability"));
|
||||||
|
const Index = document.getElementById("abilityOverride-ability-index").value;
|
||||||
|
revalidateAuthz().then(() => {
|
||||||
|
$.post({
|
||||||
|
url: "/custom/abilityOverride?" + window.authz,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify({
|
||||||
|
category: urlParams.get("productCategory"),
|
||||||
|
oid: urlParams.get("itemId"),
|
||||||
|
configIndex,
|
||||||
|
action,
|
||||||
|
AbilityOverride: {
|
||||||
|
Ability,
|
||||||
|
Index
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).done(function () {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -128,6 +128,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `Du kannst den Valenz-Bonus deiner Waffe festlegen oder entfernen.`,
|
detailedView_valenceBonusDescription: `Du kannst den Valenz-Bonus deiner Waffe festlegen oder entfernen.`,
|
||||||
detailedView_modularPartsLabel: `Modulare Teile ändern`,
|
detailedView_modularPartsLabel: `Modulare Teile ändern`,
|
||||||
detailedView_suitInvigorationLabel: `Warframe-Kräftigung`,
|
detailedView_suitInvigorationLabel: `Warframe-Kräftigung`,
|
||||||
|
detailedView_loadoutLabel: `Loadouts`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `+200% Fähigkeitsstärke`,
|
invigorations_offensive_AbilityStrength: `+200% Fähigkeitsstärke`,
|
||||||
invigorations_offensive_AbilityRange: `+100% Fähigkeitsreichweite`,
|
invigorations_offensive_AbilityRange: `+100% Fähigkeitsreichweite`,
|
||||||
@ -155,6 +156,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `Defensives Upgrade`,
|
invigorations_defensiveLabel: `Defensives Upgrade`,
|
||||||
invigorations_expiryLabel: `Upgrades Ablaufdatum (optional)`,
|
invigorations_expiryLabel: `Upgrades Ablaufdatum (optional)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `Fähigkeitsüberschreibung`,
|
||||||
|
abilityOverride_onSlot: `auf Slot`,
|
||||||
|
|
||||||
mods_addRiven: `Riven hinzufügen`,
|
mods_addRiven: `Riven hinzufügen`,
|
||||||
mods_fingerprint: `Fingerabdruck`,
|
mods_fingerprint: `Fingerabdruck`,
|
||||||
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
|
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
|
||||||
@ -238,8 +242,11 @@ dict = {
|
|||||||
worldState_creditBoost: `Event Booster: Credit`,
|
worldState_creditBoost: `Event Booster: Credit`,
|
||||||
worldState_affinityBoost: `Event Booster: Erfahrung`,
|
worldState_affinityBoost: `Event Booster: Erfahrung`,
|
||||||
worldState_resourceBoost: `Event Booster: Ressourcen`,
|
worldState_resourceBoost: `Event Booster: Ressourcen`,
|
||||||
|
worldState_tennoLiveRelay: `TennoLive Relais`,
|
||||||
|
worldState_baroTennoConRelay: `Baros TennoCon Relais`,
|
||||||
worldState_starDays: `Sternen-Tage`,
|
worldState_starDays: `Sternen-Tage`,
|
||||||
worldState_galleonOfGhouls: `Galeone der Ghule`,
|
worldState_galleonOfGhouls: `Galeone der Ghule`,
|
||||||
|
enabled: `Aktiviert`,
|
||||||
disabled: `Deaktiviert`,
|
disabled: `Deaktiviert`,
|
||||||
worldState_we1: `Wochenende 1`,
|
worldState_we1: `Wochenende 1`,
|
||||||
worldState_we2: `Wochenende 2`,
|
worldState_we2: `Wochenende 2`,
|
||||||
|
@ -127,6 +127,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `You can set or remove the Valence Bonus from your weapon.`,
|
detailedView_valenceBonusDescription: `You can set or remove the Valence Bonus from your weapon.`,
|
||||||
detailedView_modularPartsLabel: `Change Modular Parts`,
|
detailedView_modularPartsLabel: `Change Modular Parts`,
|
||||||
detailedView_suitInvigorationLabel: `Warframe Invigoration`,
|
detailedView_suitInvigorationLabel: `Warframe Invigoration`,
|
||||||
|
detailedView_loadoutLabel: `Loadouts`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `+200% Ability Strength`,
|
invigorations_offensive_AbilityStrength: `+200% Ability Strength`,
|
||||||
invigorations_offensive_AbilityRange: `+100% Ability Range`,
|
invigorations_offensive_AbilityRange: `+100% Ability Range`,
|
||||||
@ -154,6 +155,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `Defensive Upgrade`,
|
invigorations_defensiveLabel: `Defensive Upgrade`,
|
||||||
invigorations_expiryLabel: `Upgrades Expiry (optional)`,
|
invigorations_expiryLabel: `Upgrades Expiry (optional)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `Ability Override`,
|
||||||
|
abilityOverride_onSlot: `on slot`,
|
||||||
|
|
||||||
mods_addRiven: `Add Riven`,
|
mods_addRiven: `Add Riven`,
|
||||||
mods_fingerprint: `Fingerprint`,
|
mods_fingerprint: `Fingerprint`,
|
||||||
mods_fingerprintHelp: `Need help with the fingerprint?`,
|
mods_fingerprintHelp: `Need help with the fingerprint?`,
|
||||||
@ -237,15 +241,18 @@ dict = {
|
|||||||
worldState_creditBoost: `Credit Boost`,
|
worldState_creditBoost: `Credit Boost`,
|
||||||
worldState_affinityBoost: `Affinity Boost`,
|
worldState_affinityBoost: `Affinity Boost`,
|
||||||
worldState_resourceBoost: `Resource Boost`,
|
worldState_resourceBoost: `Resource Boost`,
|
||||||
|
worldState_tennoLiveRelay: `TennoLive Relay`,
|
||||||
|
worldState_baroTennoConRelay: `Baro's TennoCon Relay`,
|
||||||
worldState_starDays: `Star Days`,
|
worldState_starDays: `Star Days`,
|
||||||
worldState_galleonOfGhouls: `Galleon of Ghouls`,
|
worldState_galleonOfGhouls: `Galleon of Ghouls`,
|
||||||
|
enabled: `Enabled`,
|
||||||
disabled: `Disabled`,
|
disabled: `Disabled`,
|
||||||
worldState_we1: `Weekend 1`,
|
worldState_we1: `Weekend 1`,
|
||||||
worldState_we2: `Weekend 2`,
|
worldState_we2: `Weekend 2`,
|
||||||
worldState_we3: `Weekend 3`,
|
worldState_we3: `Weekend 3`,
|
||||||
worldState_eidolonOverride: `Eidolon Override`,
|
worldState_eidolonOverride: `Eidolon/Deimos Override`,
|
||||||
worldState_day: `Day`,
|
worldState_day: `Day/Fass`,
|
||||||
worldState_night: `Night`,
|
worldState_night: `Night/Vome`,
|
||||||
worldState_vallisOverride: `Orb Vallis Override`,
|
worldState_vallisOverride: `Orb Vallis Override`,
|
||||||
worldState_warm: `Warm`,
|
worldState_warm: `Warm`,
|
||||||
worldState_cold: `Cold`,
|
worldState_cold: `Cold`,
|
||||||
|
@ -128,6 +128,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `Puedes establecer o quitar el bono de valencia de tu arma.`,
|
detailedView_valenceBonusDescription: `Puedes establecer o quitar el bono de valencia de tu arma.`,
|
||||||
detailedView_modularPartsLabel: `Cambiar partes modulares`,
|
detailedView_modularPartsLabel: `Cambiar partes modulares`,
|
||||||
detailedView_suitInvigorationLabel: `Vigorización de Warframe`,
|
detailedView_suitInvigorationLabel: `Vigorización de Warframe`,
|
||||||
|
detailedView_loadoutLabel: `Equipamientos`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `+200% Fuerza de Habilidad`,
|
invigorations_offensive_AbilityStrength: `+200% Fuerza de Habilidad`,
|
||||||
invigorations_offensive_AbilityRange: `+100% Alcance de Habilidad`,
|
invigorations_offensive_AbilityRange: `+100% Alcance de Habilidad`,
|
||||||
@ -155,6 +156,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `Mejora Defensiva`,
|
invigorations_defensiveLabel: `Mejora Defensiva`,
|
||||||
invigorations_expiryLabel: `Caducidad de Mejoras (opcional)`,
|
invigorations_expiryLabel: `Caducidad de Mejoras (opcional)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `[UNTRANSLATED] Ability Override`,
|
||||||
|
abilityOverride_onSlot: `[UNTRANSLATED] on slot`,
|
||||||
|
|
||||||
mods_addRiven: `Agregar Agrietado`,
|
mods_addRiven: `Agregar Agrietado`,
|
||||||
mods_fingerprint: `Huella digital`,
|
mods_fingerprint: `Huella digital`,
|
||||||
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
|
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
|
||||||
@ -238,8 +242,11 @@ dict = {
|
|||||||
worldState_creditBoost: `Potenciador de Créditos`,
|
worldState_creditBoost: `Potenciador de Créditos`,
|
||||||
worldState_affinityBoost: `Potenciador de Afinidad`,
|
worldState_affinityBoost: `Potenciador de Afinidad`,
|
||||||
worldState_resourceBoost: `Potenciador de Recursos`,
|
worldState_resourceBoost: `Potenciador de Recursos`,
|
||||||
|
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
|
||||||
|
worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`,
|
||||||
worldState_starDays: `Días estelares`,
|
worldState_starDays: `Días estelares`,
|
||||||
worldState_galleonOfGhouls: `Galeón de Gules`,
|
worldState_galleonOfGhouls: `Galeón de Gules`,
|
||||||
|
enabled: `[UNTRANSLATED] Enabled`,
|
||||||
disabled: `Desactivado`,
|
disabled: `Desactivado`,
|
||||||
worldState_we1: `Semana 1`,
|
worldState_we1: `Semana 1`,
|
||||||
worldState_we2: `Semana 2`,
|
worldState_we2: `Semana 2`,
|
||||||
|
@ -128,6 +128,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `Définir le Bonus Valence de l'arme.`,
|
detailedView_valenceBonusDescription: `Définir le Bonus Valence de l'arme.`,
|
||||||
detailedView_modularPartsLabel: `Changer l'équipement modulaire`,
|
detailedView_modularPartsLabel: `Changer l'équipement modulaire`,
|
||||||
detailedView_suitInvigorationLabel: `Invigoration de Warframe`,
|
detailedView_suitInvigorationLabel: `Invigoration de Warframe`,
|
||||||
|
detailedView_loadoutLabel: `Équipements`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `+200% de puissance de pouvoir`,
|
invigorations_offensive_AbilityStrength: `+200% de puissance de pouvoir`,
|
||||||
invigorations_offensive_AbilityRange: `+100% de portée de pouvoir`,
|
invigorations_offensive_AbilityRange: `+100% de portée de pouvoir`,
|
||||||
@ -155,6 +156,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `Amélioration défensive`,
|
invigorations_defensiveLabel: `Amélioration défensive`,
|
||||||
invigorations_expiryLabel: `Expiration de l'invigoration (optionnel)`,
|
invigorations_expiryLabel: `Expiration de l'invigoration (optionnel)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `[UNTRANSLATED] Ability Override`,
|
||||||
|
abilityOverride_onSlot: `[UNTRANSLATED] on slot`,
|
||||||
|
|
||||||
mods_addRiven: `Ajouter un riven`,
|
mods_addRiven: `Ajouter un riven`,
|
||||||
mods_fingerprint: `Empreinte`,
|
mods_fingerprint: `Empreinte`,
|
||||||
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
|
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
|
||||||
@ -238,8 +242,11 @@ dict = {
|
|||||||
worldState_creditBoost: `Booster de Crédit`,
|
worldState_creditBoost: `Booster de Crédit`,
|
||||||
worldState_affinityBoost: `Booster d'Affinité`,
|
worldState_affinityBoost: `Booster d'Affinité`,
|
||||||
worldState_resourceBoost: `Booster de Ressource`,
|
worldState_resourceBoost: `Booster de Ressource`,
|
||||||
|
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
|
||||||
|
worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`,
|
||||||
worldState_starDays: `Jours Stellaires`,
|
worldState_starDays: `Jours Stellaires`,
|
||||||
worldState_galleonOfGhouls: `Galion des Goules`,
|
worldState_galleonOfGhouls: `Galion des Goules`,
|
||||||
|
enabled: `[UNTRANSLATED] Enabled`,
|
||||||
disabled: `Désactivé`,
|
disabled: `Désactivé`,
|
||||||
worldState_we1: `Weekend 1`,
|
worldState_we1: `Weekend 1`,
|
||||||
worldState_we2: `Weekend 2`,
|
worldState_we2: `Weekend 2`,
|
||||||
|
@ -128,6 +128,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `Вы можете установить или убрать бонус валентности с вашего оружия.`,
|
detailedView_valenceBonusDescription: `Вы можете установить или убрать бонус валентности с вашего оружия.`,
|
||||||
detailedView_modularPartsLabel: `Изменить Модульные Части`,
|
detailedView_modularPartsLabel: `Изменить Модульные Части`,
|
||||||
detailedView_suitInvigorationLabel: `[UNTRANSLATED] Warframe Invigoration`,
|
detailedView_suitInvigorationLabel: `[UNTRANSLATED] Warframe Invigoration`,
|
||||||
|
detailedView_loadoutLabel: `Конфигурации`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `[UNTRANSLATED] +200% Ability Strength`,
|
invigorations_offensive_AbilityStrength: `[UNTRANSLATED] +200% Ability Strength`,
|
||||||
invigorations_offensive_AbilityRange: `[UNTRANSLATED] +100% Ability Range`,
|
invigorations_offensive_AbilityRange: `[UNTRANSLATED] +100% Ability Range`,
|
||||||
@ -155,6 +156,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `[UNTRANSLATED] Defensive Upgrade`,
|
invigorations_defensiveLabel: `[UNTRANSLATED] Defensive Upgrade`,
|
||||||
invigorations_expiryLabel: `[UNTRANSLATED] Upgrades Expiry (optional)`,
|
invigorations_expiryLabel: `[UNTRANSLATED] Upgrades Expiry (optional)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `Переопределение способности`,
|
||||||
|
abilityOverride_onSlot: `в ячейке`,
|
||||||
|
|
||||||
mods_addRiven: `Добавить Мод Разлома`,
|
mods_addRiven: `Добавить Мод Разлома`,
|
||||||
mods_fingerprint: `Отпечаток`,
|
mods_fingerprint: `Отпечаток`,
|
||||||
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
|
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
|
||||||
@ -238,15 +242,18 @@ dict = {
|
|||||||
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
||||||
worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`,
|
worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`,
|
||||||
worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`,
|
worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`,
|
||||||
|
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
|
||||||
|
worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`,
|
||||||
worldState_starDays: `[UNTRANSLATED] Star Days`,
|
worldState_starDays: `[UNTRANSLATED] Star Days`,
|
||||||
worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`,
|
worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`,
|
||||||
|
enabled: `[UNTRANSLATED] Enabled`,
|
||||||
disabled: `[UNTRANSLATED] Disabled`,
|
disabled: `[UNTRANSLATED] Disabled`,
|
||||||
worldState_we1: `[UNTRANSLATED] Weekend 1`,
|
worldState_we1: `[UNTRANSLATED] Weekend 1`,
|
||||||
worldState_we2: `[UNTRANSLATED] Weekend 2`,
|
worldState_we2: `[UNTRANSLATED] Weekend 2`,
|
||||||
worldState_we3: `[UNTRANSLATED] Weekend 3`,
|
worldState_we3: `[UNTRANSLATED] Weekend 3`,
|
||||||
worldState_eidolonOverride: `[UNTRANSLATED] Eidolon Override`,
|
worldState_eidolonOverride: `[UNTRANSLATED] Eidolon/Deimos Override`,
|
||||||
worldState_day: `[UNTRANSLATED] Day`,
|
worldState_day: `[UNTRANSLATED] Day/Fass`,
|
||||||
worldState_night: `[UNTRANSLATED] Night`,
|
worldState_night: `[UNTRANSLATED] Night/Vome`,
|
||||||
worldState_vallisOverride: `[UNTRANSLATED] Orb Vallis Override`,
|
worldState_vallisOverride: `[UNTRANSLATED] Orb Vallis Override`,
|
||||||
worldState_warm: `[UNTRANSLATED] Warm`,
|
worldState_warm: `[UNTRANSLATED] Warm`,
|
||||||
worldState_cold: `[UNTRANSLATED] Cold`,
|
worldState_cold: `[UNTRANSLATED] Cold`,
|
||||||
|
@ -128,6 +128,7 @@ dict = {
|
|||||||
detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成.`,
|
detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成.`,
|
||||||
detailedView_modularPartsLabel: `更换部件`,
|
detailedView_modularPartsLabel: `更换部件`,
|
||||||
detailedView_suitInvigorationLabel: `编辑战甲活化属性`,
|
detailedView_suitInvigorationLabel: `编辑战甲活化属性`,
|
||||||
|
detailedView_loadoutLabel: `配置`,
|
||||||
|
|
||||||
invigorations_offensive_AbilityStrength: `+200%技能强度`,
|
invigorations_offensive_AbilityStrength: `+200%技能强度`,
|
||||||
invigorations_offensive_AbilityRange: `+100%技能范围`,
|
invigorations_offensive_AbilityRange: `+100%技能范围`,
|
||||||
@ -155,6 +156,9 @@ dict = {
|
|||||||
invigorations_defensiveLabel: `功能型属性`,
|
invigorations_defensiveLabel: `功能型属性`,
|
||||||
invigorations_expiryLabel: `活化时效(可选)`,
|
invigorations_expiryLabel: `活化时效(可选)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `技能替换`,
|
||||||
|
abilityOverride_onSlot: `槽位`,
|
||||||
|
|
||||||
mods_addRiven: `添加裂罅MOD`,
|
mods_addRiven: `添加裂罅MOD`,
|
||||||
mods_fingerprint: `印记`,
|
mods_fingerprint: `印记`,
|
||||||
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
||||||
@ -238,8 +242,11 @@ dict = {
|
|||||||
worldState_creditBoost: `现金加成`,
|
worldState_creditBoost: `现金加成`,
|
||||||
worldState_affinityBoost: `经验加成`,
|
worldState_affinityBoost: `经验加成`,
|
||||||
worldState_resourceBoost: `资源加成`,
|
worldState_resourceBoost: `资源加成`,
|
||||||
|
worldState_tennoLiveRelay: `TennoLive中继站`,
|
||||||
|
worldState_baroTennoConRelay: `Baro的TennoCon中继站`,
|
||||||
worldState_starDays: `活动:星日`,
|
worldState_starDays: `活动:星日`,
|
||||||
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
|
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
|
||||||
|
enabled: `启用`,
|
||||||
disabled: `关闭/取消配置`,
|
disabled: `关闭/取消配置`,
|
||||||
worldState_we1: `活动阶段:第一周`,
|
worldState_we1: `活动阶段:第一周`,
|
||||||
worldState_we2: `活动阶段:第二周`,
|
worldState_we2: `活动阶段:第二周`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user