forked from OpenWF/SpaceNinjaServer
Compare commits
10 Commits
5d54e79e5d
...
ed82225ec1
Author | SHA1 | Date | |
---|---|---|---|
ed82225ec1 | |||
2e1326cde8 | |||
70be467cbf | |||
fac3ec01c6 | |||
ebdca760e6 | |||
51c0ddda38 | |||
9129bdb5fc | |||
a4922d4c35 | |||
679752633a | |||
67b5890f39 |
@ -72,7 +72,11 @@
|
|||||||
"resourceBoost": false,
|
"resourceBoost": false,
|
||||||
"tennoLiveRelay": false,
|
"tennoLiveRelay": false,
|
||||||
"galleonOfGhouls": 0,
|
"galleonOfGhouls": 0,
|
||||||
|
"ghoulEmergenceOverride": null,
|
||||||
|
"plagueStarOverride": null,
|
||||||
"starDaysOverride": null,
|
"starDaysOverride": null,
|
||||||
|
"waterFightOverride": null,
|
||||||
|
"waterFightRewardsOverride": null,
|
||||||
"eidolonOverride": "",
|
"eidolonOverride": "",
|
||||||
"vallisOverride": "",
|
"vallisOverride": "",
|
||||||
"duviriOverride": "",
|
"duviriOverride": "",
|
||||||
|
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.79",
|
"warframe-public-export-plus": "^0.5.80",
|
||||||
"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.79",
|
"version": "0.5.80",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.79.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.80.tgz",
|
||||||
"integrity": "sha512-mPaFGX7bmSo1FP0xzo//vNCkbzMRz517NHiQB1ZU8gyoRm41IaGQ7/pFWCP8iY8KWbEMvPty4pj1hZtxsujCIA=="
|
"integrity": "sha512-K5f1Ws3szVdnO0tBcxlNdhXoGHIw09cjHel7spKPGL7aF/vmEkbBGRmYQFvs8n5cGo+v+3qIDMre54Ghb3t0Iw=="
|
||||||
},
|
},
|
||||||
"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.79",
|
"warframe-public-export-plus": "^0.5.80",
|
||||||
"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",
|
||||||
|
62
src/controllers/api/getPastWeeklyChallengesController.ts
Normal file
62
src/controllers/api/getPastWeeklyChallengesController.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { EPOCH, getSeasonChallengePools, getWorldState, pushWeeklyActs } from "@/src/services/worldStateService";
|
||||||
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { ISeasonChallenge } from "@/src/types/worldStateTypes";
|
||||||
|
import { ExportChallenges } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const getPastWeeklyChallengesController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "SeasonChallengeHistory ChallengeProgress");
|
||||||
|
const worldState = getWorldState(undefined);
|
||||||
|
|
||||||
|
if (worldState.SeasonInfo) {
|
||||||
|
const pools = getSeasonChallengePools(worldState.SeasonInfo.AffiliationTag);
|
||||||
|
const nightwaveStartTimestamp = Number(worldState.SeasonInfo.Activation.$date.$numberLong);
|
||||||
|
const nightwaveSeason = worldState.SeasonInfo.Season;
|
||||||
|
const timeMs = worldState.Time * 1000;
|
||||||
|
const completedChallengesIds = new Set<string>();
|
||||||
|
|
||||||
|
inventory.SeasonChallengeHistory.forEach(challengeHistory => {
|
||||||
|
const entryNightwaveSeason = parseInt(challengeHistory.id.slice(0, 4), 10) - 1;
|
||||||
|
if (nightwaveSeason == entryNightwaveSeason) {
|
||||||
|
const meta = Object.entries(ExportChallenges).find(
|
||||||
|
([key]) => key.split("/").pop() === challengeHistory.challenge
|
||||||
|
);
|
||||||
|
if (meta) {
|
||||||
|
const [, challengeMeta] = meta;
|
||||||
|
const challengeProgress = inventory.ChallengeProgress.find(
|
||||||
|
c => c.Name === challengeHistory.challenge
|
||||||
|
);
|
||||||
|
|
||||||
|
if (challengeProgress && challengeProgress.Progress >= (challengeMeta.requiredCount ?? 1)) {
|
||||||
|
completedChallengesIds.add(challengeHistory.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const PastWeeklyChallenges: ISeasonChallenge[] = [];
|
||||||
|
|
||||||
|
let week = Math.trunc((timeMs - EPOCH) / unixTimesInMs.week) - 1;
|
||||||
|
|
||||||
|
while (EPOCH + week * unixTimesInMs.week >= nightwaveStartTimestamp && PastWeeklyChallenges.length < 3) {
|
||||||
|
const tempActs: ISeasonChallenge[] = [];
|
||||||
|
pushWeeklyActs(tempActs, pools, week, nightwaveStartTimestamp, nightwaveSeason);
|
||||||
|
|
||||||
|
for (const act of tempActs) {
|
||||||
|
if (!completedChallengesIds.has(act._id.$oid) && PastWeeklyChallenges.length < 3) {
|
||||||
|
if (act.Challenge.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")) {
|
||||||
|
act.Permanent = true;
|
||||||
|
}
|
||||||
|
PastWeeklyChallenges.push(act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
week--;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ PastWeeklyChallenges: PastWeeklyChallenges });
|
||||||
|
}
|
||||||
|
};
|
@ -13,7 +13,8 @@ import {
|
|||||||
addItems,
|
addItems,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
getEffectiveAvatarImageType,
|
getEffectiveAvatarImageType,
|
||||||
getInventory
|
getInventory,
|
||||||
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportFlavour } from "warframe-public-export-plus";
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
@ -100,6 +101,9 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (message.RegularCredits) {
|
||||||
|
updateCurrency(inventory, -message.RegularCredits, false, inventoryChanges);
|
||||||
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ InventoryChanges: inventoryChanges });
|
res.json({ InventoryChanges: inventoryChanges });
|
||||||
} else if (latestClientMessageId) {
|
} else if (latestClientMessageId) {
|
||||||
|
@ -6,7 +6,11 @@ import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/mi
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getInventoryResponse } from "@/src/controllers/api/inventoryController";
|
import { getInventoryResponse } from "@/src/controllers/api/inventoryController";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
|
import {
|
||||||
|
IMissionInventoryUpdateResponse,
|
||||||
|
IMissionInventoryUpdateResponseBackToDryDock,
|
||||||
|
IMissionInventoryUpdateResponseRailjackInterstitial
|
||||||
|
} from "@/src/types/missionTypes";
|
||||||
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
import { sendWsBroadcastTo } from "@/src/services/wsService";
|
||||||
import { generateRewardSeed } from "@/src/services/rngService";
|
import { generateRewardSeed } from "@/src/services/rngService";
|
||||||
|
|
||||||
@ -95,11 +99,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
inventory.RewardSeed = generateRewardSeed();
|
inventory.RewardSeed = generateRewardSeed();
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
|
||||||
|
|
||||||
//TODO: figure out when to send inventory. it is needed for many cases.
|
//TODO: figure out when to send inventory. it is needed for many cases.
|
||||||
res.json({
|
const deltas: IMissionInventoryUpdateResponseRailjackInterstitial = {
|
||||||
InventoryJson: JSON.stringify(inventoryResponse),
|
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
MissionRewards,
|
MissionRewards,
|
||||||
...credits,
|
...credits,
|
||||||
@ -108,7 +110,25 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
SyndicateXPItemReward,
|
SyndicateXPItemReward,
|
||||||
AffiliationMods,
|
AffiliationMods,
|
||||||
ConquestCompletedMissionsCount
|
ConquestCompletedMissionsCount
|
||||||
|
};
|
||||||
|
if (missionReport.RJ) {
|
||||||
|
logger.debug(`railjack interstitial request, sending only deltas`, deltas);
|
||||||
|
res.json(deltas);
|
||||||
|
} else if (missionReport.RewardInfo) {
|
||||||
|
logger.debug(`classic mission completion, sending everything`);
|
||||||
|
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
||||||
|
res.json({
|
||||||
|
InventoryJson: JSON.stringify(inventoryResponse),
|
||||||
|
...deltas
|
||||||
} satisfies IMissionInventoryUpdateResponse);
|
} satisfies IMissionInventoryUpdateResponse);
|
||||||
|
} else {
|
||||||
|
logger.debug(`no reward info, assuming this wasn't a mission completion and we should just sync inventory`);
|
||||||
|
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
|
||||||
|
res.json({
|
||||||
|
InventoryJson: JSON.stringify(inventoryResponse)
|
||||||
|
} satisfies IMissionInventoryUpdateResponseBackToDryDock);
|
||||||
|
}
|
||||||
|
|
||||||
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ export interface IMessage {
|
|||||||
acceptAction?: string;
|
acceptAction?: string;
|
||||||
declineAction?: string;
|
declineAction?: string;
|
||||||
hasAccountAction?: boolean;
|
hasAccountAction?: boolean;
|
||||||
|
RegularCredits?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Arg {
|
export interface Arg {
|
||||||
@ -139,7 +140,8 @@ const messageSchema = new Schema<IMessageDatabase>(
|
|||||||
contextInfo: String,
|
contextInfo: String,
|
||||||
acceptAction: String,
|
acceptAction: String,
|
||||||
declineAction: String,
|
declineAction: String,
|
||||||
hasAccountAction: Boolean
|
hasAccountAction: Boolean,
|
||||||
|
RegularCredits: Number
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
);
|
);
|
||||||
|
@ -66,6 +66,7 @@ import { getGuildLogController } from "@/src/controllers/api/getGuildLogControll
|
|||||||
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
|
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
|
||||||
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
|
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
|
||||||
import { getProfileViewingDataPostController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
import { getProfileViewingDataPostController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
||||||
|
import { getPastWeeklyChallengesController } from "@/src/controllers/api/getPastWeeklyChallengesController";
|
||||||
import { getShipController } from "@/src/controllers/api/getShipController";
|
import { getShipController } from "@/src/controllers/api/getShipController";
|
||||||
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
|
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
|
||||||
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
||||||
@ -195,6 +196,7 @@ apiRouter.get("/getGuildLog.php", getGuildLogController);
|
|||||||
apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController);
|
apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController);
|
||||||
apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17
|
apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17
|
||||||
apiRouter.get("/getNewRewardSeed.php", getNewRewardSeedController);
|
apiRouter.get("/getNewRewardSeed.php", getNewRewardSeedController);
|
||||||
|
apiRouter.get("/getPastWeeklyChallenges.php", getPastWeeklyChallengesController)
|
||||||
apiRouter.get("/getShip.php", getShipController);
|
apiRouter.get("/getShip.php", getShipController);
|
||||||
apiRouter.get("/getShipDecos.php", (_req, res) => { res.end(); }); // needed to log in on U22.8
|
apiRouter.get("/getShipDecos.php", (_req, res) => { res.end(); }); // needed to log in on U22.8
|
||||||
apiRouter.get("/getVendorInfo.php", getVendorInfoController);
|
apiRouter.get("/getVendorInfo.php", getVendorInfoController);
|
||||||
|
@ -84,7 +84,11 @@ export interface IConfig {
|
|||||||
tennoLiveRelay?: boolean;
|
tennoLiveRelay?: boolean;
|
||||||
baroTennoConRelay?: boolean;
|
baroTennoConRelay?: boolean;
|
||||||
galleonOfGhouls?: number;
|
galleonOfGhouls?: number;
|
||||||
|
ghoulEmergenceOverride?: boolean;
|
||||||
|
plagueStarOverride?: boolean;
|
||||||
starDaysOverride?: boolean;
|
starDaysOverride?: boolean;
|
||||||
|
waterFightOverride?: boolean;
|
||||||
|
waterFightRewardsOverride?: number;
|
||||||
eidolonOverride?: string;
|
eidolonOverride?: string;
|
||||||
vallisOverride?: string;
|
vallisOverride?: string;
|
||||||
duviriOverride?: string;
|
duviriOverride?: string;
|
||||||
|
@ -1980,18 +1980,21 @@ export const addChallenges = async (
|
|||||||
dbChallenge.Completed ??= [];
|
dbChallenge.Completed ??= [];
|
||||||
for (const completion of Completed!) {
|
for (const completion of Completed!) {
|
||||||
if (dbChallenge.Completed.indexOf(completion) == -1) {
|
if (dbChallenge.Completed.indexOf(completion) == -1) {
|
||||||
|
dbChallenge.Completed.push(completion);
|
||||||
if (completion == "challengeRewards") {
|
if (completion == "challengeRewards") {
|
||||||
if (Name in challengeRewardsInboxMessages) {
|
if (Name in challengeRewardsInboxMessages) {
|
||||||
await createMessage(account._id, [challengeRewardsInboxMessages[Name]]);
|
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.
|
// Would love to somehow let the client know about inbox or inventory changes, but there doesn't seem to anything for updateChallengeProgress.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
logger.warn(`ignoring unknown challenge completion`, { challenge: Name, completion });
|
logger.warn(`ignoring unknown challenge completion`, { challenge: Name, completion });
|
||||||
|
dbChallenge.Completed = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dbChallenge.Completed = Completed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const affiliationMods: IAffiliationMods[] = [];
|
const affiliationMods: IAffiliationMods[] = [];
|
||||||
|
@ -50,7 +50,7 @@ import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
|||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { IMissionCredits, IMissionReward } from "@/src/types/missionTypes";
|
import { IMissionCredits, IMissionReward } from "@/src/types/missionTypes";
|
||||||
import { crackRelic } from "@/src/helpers/relicHelper";
|
import { crackRelic } from "@/src/helpers/relicHelper";
|
||||||
import { createMessage } from "@/src/services/inboxService";
|
import { createMessage, IMessageCreationTemplate } from "@/src/services/inboxService";
|
||||||
import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.json";
|
import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.json";
|
||||||
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
|
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
|
||||||
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
|
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
|
||||||
@ -76,13 +76,18 @@ import {
|
|||||||
} from "@/src/services/worldStateService";
|
} from "@/src/services/worldStateService";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||||
import { ISyndicateMissionInfo } from "@/src/types/worldStateTypes";
|
import { IGoal, ISyndicateMissionInfo } from "@/src/types/worldStateTypes";
|
||||||
import { fromOid } from "@/src/helpers/inventoryHelpers";
|
import { fromOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { TAccountDocument } from "@/src/services/loginService";
|
import { TAccountDocument } from "@/src/services/loginService";
|
||||||
import { ITypeCount } from "@/src/types/commonTypes";
|
import { ITypeCount } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
import { IEquipmentClient } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
||||||
|
// Disruption missions just tell us (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2599)
|
||||||
|
if (rewardInfo.rewardTierOverrides) {
|
||||||
|
return rewardInfo.rewardTierOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
// For Spy missions, e.g. 3 vaults cracked = A, B, C
|
// For Spy missions, e.g. 3 vaults cracked = A, B, C
|
||||||
if (rewardInfo.VaultsCracked) {
|
if (rewardInfo.VaultsCracked) {
|
||||||
const rotations: number[] = [];
|
const rotations: number[] = [];
|
||||||
@ -619,36 +624,92 @@ export const addMissionInventoryUpdates = async (
|
|||||||
if (goal && goal.Personal) {
|
if (goal && goal.Personal) {
|
||||||
inventory.PersonalGoalProgress ??= [];
|
inventory.PersonalGoalProgress ??= [];
|
||||||
const goalProgress = inventory.PersonalGoalProgress.find(x => x.goalId.equals(goal._id.$oid));
|
const goalProgress = inventory.PersonalGoalProgress.find(x => x.goalId.equals(goal._id.$oid));
|
||||||
if (goalProgress) {
|
if (!goalProgress) {
|
||||||
goalProgress.Best = Math.max(goalProgress.Best, uploadProgress.Best);
|
|
||||||
goalProgress.Count += uploadProgress.Count;
|
|
||||||
} else {
|
|
||||||
inventory.PersonalGoalProgress.push({
|
inventory.PersonalGoalProgress.push({
|
||||||
Best: uploadProgress.Best,
|
Best: uploadProgress.Best,
|
||||||
Count: uploadProgress.Count,
|
Count: uploadProgress.Count,
|
||||||
Tag: goal.Tag,
|
Tag: goal.Tag,
|
||||||
goalId: new Types.ObjectId(goal._id.$oid)
|
goalId: new Types.ObjectId(goal._id.$oid)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentNode = inventoryUpdates.RewardInfo!.node;
|
||||||
|
let currentMissionKey;
|
||||||
|
if (currentNode == goal.Node) {
|
||||||
|
currentMissionKey = goal.MissionKeyName;
|
||||||
|
} else if (goal.ConcurrentNodes && goal.ConcurrentMissionKeyNames) {
|
||||||
|
for (let i = 0; i < goal.ConcurrentNodes.length; i++) {
|
||||||
|
if (currentNode == goal.ConcurrentNodes[i]) {
|
||||||
|
currentMissionKey = goal.ConcurrentMissionKeyNames[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentMissionKey && currentMissionKey in goalMessagesByKey) {
|
||||||
|
const totalCount = (goalProgress?.Count ?? 0) + uploadProgress.Count;
|
||||||
|
let reward;
|
||||||
|
|
||||||
|
if (goal.InterimGoals && goal.InterimRewards) {
|
||||||
|
for (let i = 0; i < goal.InterimGoals.length; i++) {
|
||||||
if (
|
if (
|
||||||
goal.Reward &&
|
goal.InterimGoals[i] &&
|
||||||
goal.Reward.items &&
|
goal.InterimGoals[i] <= totalCount &&
|
||||||
goal.MissionKeyName &&
|
(!goalProgress || goalProgress.Count < goal.InterimGoals[i]) &&
|
||||||
goal.MissionKeyName in goalMessagesByKey
|
goal.InterimRewards[i]
|
||||||
) {
|
) {
|
||||||
|
reward = goal.InterimRewards[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!reward &&
|
||||||
|
goal.Goal &&
|
||||||
|
goal.Goal <= totalCount &&
|
||||||
|
(!goalProgress || goalProgress.Count < goal.Goal) &&
|
||||||
|
goal.Reward
|
||||||
|
) {
|
||||||
|
reward = goal.Reward;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!reward &&
|
||||||
|
goal.BonusGoal &&
|
||||||
|
goal.BonusGoal <= totalCount &&
|
||||||
|
(!goalProgress || goalProgress.Count < goal.BonusGoal) &&
|
||||||
|
goal.BonusReward
|
||||||
|
) {
|
||||||
|
reward = goal.BonusReward;
|
||||||
|
}
|
||||||
|
if (reward) {
|
||||||
|
if (currentMissionKey in goalMessagesByKey) {
|
||||||
// Send reward via inbox
|
// Send reward via inbox
|
||||||
const info = goalMessagesByKey[goal.MissionKeyName];
|
const info = goalMessagesByKey[currentMissionKey];
|
||||||
await createMessage(inventory.accountOwnerId, [
|
const message: IMessageCreationTemplate = {
|
||||||
{
|
|
||||||
sndr: info.sndr,
|
sndr: info.sndr,
|
||||||
msg: info.msg,
|
msg: info.msg,
|
||||||
att: goal.Reward.items.map(x => (isStoreItem(x) ? fromStoreItem(x) : x)),
|
|
||||||
sub: info.sub,
|
sub: info.sub,
|
||||||
icon: info.icon,
|
icon: info.icon,
|
||||||
highPriority: true
|
highPriority: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (reward.items) {
|
||||||
|
message.att = reward.items.map(x => (isStoreItem(x) ? fromStoreItem(x) : x));
|
||||||
}
|
}
|
||||||
]);
|
if (reward.countedItems) {
|
||||||
|
message.countedAtt = reward.countedItems;
|
||||||
}
|
}
|
||||||
|
if (reward.credits) {
|
||||||
|
message.RegularCredits = reward.credits;
|
||||||
|
}
|
||||||
|
|
||||||
|
await createMessage(inventory.accountOwnerId, [message]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goalProgress) {
|
||||||
|
goalProgress.Best = Math.max(goalProgress.Best, uploadProgress.Best);
|
||||||
|
goalProgress.Count += uploadProgress.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1006,8 +1067,16 @@ export const addMissionRewards = async (
|
|||||||
|
|
||||||
if (rewardInfo.goalId) {
|
if (rewardInfo.goalId) {
|
||||||
const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
|
const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
|
||||||
if (goal?.MissionKeyName) {
|
if (goal) {
|
||||||
levelKeyName = goal.MissionKeyName;
|
if (rewardInfo.node == goal.Node && goal.MissionKeyName) levelKeyName = goal.MissionKeyName;
|
||||||
|
if (goal.ConcurrentNodes && goal.ConcurrentMissionKeyNames) {
|
||||||
|
for (let i = 0; i < goal.ConcurrentNodes.length && i < goal.ConcurrentMissionKeyNames.length; i++) {
|
||||||
|
if (rewardInfo.node == goal.ConcurrentNodes[i]) {
|
||||||
|
levelKeyName = goal.ConcurrentMissionKeyNames[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1259,6 +1328,8 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AffiliationMods ??= [];
|
||||||
|
|
||||||
if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
|
if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_");
|
const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_");
|
||||||
@ -1266,9 +1337,29 @@ export const addMissionRewards = async (
|
|||||||
if (syndicateMissionId) {
|
if (syndicateMissionId) {
|
||||||
pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
|
pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
|
||||||
}
|
}
|
||||||
const syndicateEntry = syndicateMissions.find(m => m._id.$oid === syndicateMissionId);
|
let syndicateEntry: ISyndicateMissionInfo | IGoal | undefined = syndicateMissions.find(
|
||||||
|
m => m._id.$oid === syndicateMissionId
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
|
||||||
|
].some(prefix => jobType.startsWith(prefix))
|
||||||
|
) {
|
||||||
|
const { Goals } = getWorldState(undefined);
|
||||||
|
syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
|
||||||
|
if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
|
||||||
|
}
|
||||||
if (syndicateEntry && syndicateEntry.Jobs) {
|
if (syndicateEntry && syndicateEntry.Jobs) {
|
||||||
let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
|
let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
|
||||||
|
].some(prefix => jobType.startsWith(prefix))
|
||||||
|
) {
|
||||||
|
currentJob = syndicateEntry.Jobs.find(j => j.jobType === jobType)!;
|
||||||
|
}
|
||||||
if (syndicateEntry.Tag === "EntratiSyndicate") {
|
if (syndicateEntry.Tag === "EntratiSyndicate") {
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
@ -1311,31 +1402,35 @@ export const addMissionRewards = async (
|
|||||||
`Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
`Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (rewardInfo.JobTier! >= 0) {
|
const specialCase = [
|
||||||
|
{ endings: ["Heists/HeistProfitTakerBountyOne"], stage: 2, amount: 1000 },
|
||||||
|
{ endings: ["Hunts/AllTeralystsHunt"], stage: 2, amount: 5000 },
|
||||||
|
{
|
||||||
|
endings: [
|
||||||
|
"Hunts/TeralystHunt",
|
||||||
|
"Heists/HeistProfitTakerBountyTwo",
|
||||||
|
"Heists/HeistProfitTakerBountyThree",
|
||||||
|
"Heists/HeistProfitTakerBountyFour",
|
||||||
|
"Heists/HeistExploiterBountyOne"
|
||||||
|
],
|
||||||
|
amount: 1000
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const specialCaseReward = specialCase.find(
|
||||||
|
rule =>
|
||||||
|
rule.endings.some(e => jobType.endsWith(e)) &&
|
||||||
|
(rule.stage === undefined || rewardInfo.JobStage === rule.stage)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (specialCaseReward) {
|
||||||
|
addStanding(inventory, syndicateEntry.Tag, specialCaseReward.amount, AffiliationMods);
|
||||||
|
} else {
|
||||||
addStanding(
|
addStanding(
|
||||||
inventory,
|
inventory,
|
||||||
syndicateEntry.Tag,
|
syndicateEntry.Tag,
|
||||||
Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)),
|
Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)),
|
||||||
AffiliationMods
|
AffiliationMods
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) {
|
|
||||||
addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
|
|
||||||
}
|
|
||||||
if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) {
|
|
||||||
addStanding(inventory, syndicateEntry.Tag, 5000, AffiliationMods);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
[
|
|
||||||
"Hunts/TeralystHunt",
|
|
||||||
"Heists/HeistProfitTakerBountyTwo",
|
|
||||||
"Heists/HeistProfitTakerBountyThree",
|
|
||||||
"Heists/HeistProfitTakerBountyFour",
|
|
||||||
"Heists/HeistExploiterBountyOne"
|
|
||||||
].some(ending => jobType.endsWith(ending))
|
|
||||||
) {
|
|
||||||
addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1672,7 +1767,19 @@ function getRandomMissionDrops(
|
|||||||
if (syndicateMissionId) {
|
if (syndicateMissionId) {
|
||||||
pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
|
pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
|
||||||
}
|
}
|
||||||
const syndicateEntry = syndicateMissions.find(m => m._id.$oid === syndicateMissionId);
|
let syndicateEntry: ISyndicateMissionInfo | IGoal | undefined = syndicateMissions.find(
|
||||||
|
m => m._id.$oid === syndicateMissionId
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
|
||||||
|
].some(prefix => jobType.startsWith(prefix))
|
||||||
|
) {
|
||||||
|
const { Goals } = getWorldState(undefined);
|
||||||
|
syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
|
||||||
|
if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
|
||||||
|
}
|
||||||
if (syndicateEntry && syndicateEntry.Jobs) {
|
if (syndicateEntry && syndicateEntry.Jobs) {
|
||||||
let job = syndicateEntry.Jobs[RewardInfo.JobTier!];
|
let job = syndicateEntry.Jobs[RewardInfo.JobTier!];
|
||||||
|
|
||||||
@ -1757,6 +1864,14 @@ function getRandomMissionDrops(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
|
||||||
|
].some(prefix => jobType.startsWith(prefix))
|
||||||
|
) {
|
||||||
|
job = syndicateEntry.Jobs.find(j => j.jobType === jobType)!;
|
||||||
|
}
|
||||||
rewardManifests = [job.rewards];
|
rewardManifests = [job.rewards];
|
||||||
if (job.xpAmounts.length > 1) {
|
if (job.xpAmounts.length > 1) {
|
||||||
const curentStage = RewardInfo.JobStage! + 1;
|
const curentStage = RewardInfo.JobStage! + 1;
|
||||||
@ -2098,5 +2213,29 @@ const goalMessagesByKey: Record<string, { sndr: string; msg: string; sub: string
|
|||||||
msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgC",
|
msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgC",
|
||||||
sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleC",
|
sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleC",
|
||||||
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
|
icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightA": {
|
||||||
|
sndr: "/Lotus/Language/Bosses/BossKelaDeThaym",
|
||||||
|
msg: "/Lotus/Language/Inbox/WaterFightRewardMsgA",
|
||||||
|
sub: "/Lotus/Language/Inbox/WaterFightRewardSubjectA",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Grineer/KelaDeThaym.png"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightB": {
|
||||||
|
sndr: "/Lotus/Language/Bosses/BossKelaDeThaym",
|
||||||
|
msg: "/Lotus/Language/Inbox/WaterFightRewardMsgB",
|
||||||
|
sub: "/Lotus/Language/Inbox/WaterFightRewardSubjectB",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Grineer/KelaDeThaym.png"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightC": {
|
||||||
|
sndr: "/Lotus/Language/Bosses/BossKelaDeThaym",
|
||||||
|
msg: "/Lotus/Language/Inbox/WaterFightRewardMsgC",
|
||||||
|
sub: "/Lotus/Language/Inbox/WaterFightRewardSubjectC",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Grineer/KelaDeThaym.png"
|
||||||
|
},
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightD": {
|
||||||
|
sndr: "/Lotus/Language/Bosses/BossKelaDeThaym",
|
||||||
|
msg: "/Lotus/Language/Inbox/WaterFightRewardMsgD",
|
||||||
|
sub: "/Lotus/Language/Inbox/WaterFightRewardSubjectD",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Grineer/KelaDeThaym.png"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -131,6 +131,13 @@ const eidolonNarmerJobs: readonly string[] = [
|
|||||||
"/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AttritionBountyLib"
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AttritionBountyLib"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const eidolonGhoulJobs: readonly string[] = [
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyAss",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyExt",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyHunt",
|
||||||
|
"/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyRes"
|
||||||
|
];
|
||||||
|
|
||||||
const venusJobs: readonly string[] = [
|
const venusJobs: readonly string[] = [
|
||||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobAmbush",
|
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobAmbush",
|
||||||
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobExcavation",
|
"/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobExcavation",
|
||||||
@ -180,7 +187,7 @@ const microplanetEndlessJobs: readonly string[] = [
|
|||||||
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty"
|
"/Lotus/Types/Gameplay/InfestedMicroplanet/Jobs/DeimosEndlessPurifyBounty"
|
||||||
];
|
];
|
||||||
|
|
||||||
const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
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 => {
|
const isBeforeNextExpectedWorldStateRefresh = (nowMs: number, thenMs: number): boolean => {
|
||||||
return nowMs + 300_000 > thenMs;
|
return nowMs + 300_000 > thenMs;
|
||||||
@ -365,10 +372,10 @@ interface IRotatingSeasonChallengePools {
|
|||||||
daily: string[];
|
daily: string[];
|
||||||
weekly: string[];
|
weekly: string[];
|
||||||
hardWeekly: string[];
|
hardWeekly: string[];
|
||||||
hasWeeklyPermanent: boolean;
|
weeklyPermanent: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallengePools => {
|
export const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallengePools => {
|
||||||
const syndicate = ExportSyndicates[syndicateTag];
|
const syndicate = ExportSyndicates[syndicateTag];
|
||||||
return {
|
return {
|
||||||
daily: syndicate.dailyChallenges!,
|
daily: syndicate.dailyChallenges!,
|
||||||
@ -380,7 +387,7 @@ const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallenge
|
|||||||
hardWeekly: syndicate.weeklyChallenges!.filter(x =>
|
hardWeekly: syndicate.weeklyChallenges!.filter(x =>
|
||||||
x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/")
|
x.startsWith("/Lotus/Types/Challenges/Seasons/WeeklyHard/")
|
||||||
),
|
),
|
||||||
hasWeeklyPermanent: syndicate.weeklyChallenges!.some(x =>
|
weeklyPermanent: syndicate.weeklyChallenges!.filter(x =>
|
||||||
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
|
x.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -401,6 +408,7 @@ const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: numb
|
|||||||
const pushSeasonWeeklyChallenge = (
|
const pushSeasonWeeklyChallenge = (
|
||||||
activeChallenges: ISeasonChallenge[],
|
activeChallenges: ISeasonChallenge[],
|
||||||
pool: string[],
|
pool: string[],
|
||||||
|
nightwaveSeason: number,
|
||||||
week: number,
|
week: number,
|
||||||
id: number
|
id: number
|
||||||
): void => {
|
): void => {
|
||||||
@ -413,51 +421,57 @@ const pushSeasonWeeklyChallenge = (
|
|||||||
challenge = rng.randomElement(pool)!;
|
challenge = rng.randomElement(pool)!;
|
||||||
} while (activeChallenges.some(x => x.Challenge == challenge));
|
} while (activeChallenges.some(x => x.Challenge == challenge));
|
||||||
activeChallenges.push({
|
activeChallenges.push({
|
||||||
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
_id: {
|
||||||
|
$oid:
|
||||||
|
(nightwaveSeason + 1).toString().padStart(4, "0") +
|
||||||
|
"bb2d9d00cb47" +
|
||||||
|
challengeId.toString().padStart(8, "0")
|
||||||
|
},
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: challenge
|
Challenge: challenge
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const pushWeeklyActs = (
|
export const pushWeeklyActs = (
|
||||||
activeChallenges: ISeasonChallenge[],
|
activeChallenges: ISeasonChallenge[],
|
||||||
pools: IRotatingSeasonChallengePools,
|
pools: IRotatingSeasonChallengePools,
|
||||||
week: number
|
week: number,
|
||||||
|
nightwaveStartTimestamp: number,
|
||||||
|
nightwaveSeason: number
|
||||||
): void => {
|
): void => {
|
||||||
const weekStart = EPOCH + week * 604800000;
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, nightwaveSeason, week, 0);
|
||||||
const weekEnd = weekStart + 604800000;
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, nightwaveSeason, week, 1);
|
||||||
|
if (pools.weeklyPermanent.length > 0) {
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 0);
|
const weekStart = EPOCH + week * unixTimesInMs.week;
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 1);
|
const weekEnd = weekStart + unixTimesInMs.week;
|
||||||
if (pools.hasWeeklyPermanent) {
|
const nightwaveWeekStart = ((): number => {
|
||||||
|
let ts = nightwaveStartTimestamp - EPOCH;
|
||||||
|
ts -= ts % unixTimesInMs.week;
|
||||||
|
return EPOCH + ts;
|
||||||
|
})();
|
||||||
|
const nightwaveWeek = Math.trunc((weekStart - nightwaveWeekStart) / unixTimesInMs.week);
|
||||||
|
const weeklyPermanentIndex = (nightwaveWeek * 3) % pools.weeklyPermanent.length;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
activeChallenges.push({
|
activeChallenges.push({
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
_id: {
|
||||||
|
$oid:
|
||||||
|
(nightwaveSeason + 1).toString().padStart(4, "0") +
|
||||||
|
"b96e9d00cb47" +
|
||||||
|
(week * 7 + 2 + i).toString().padStart(8, "0")
|
||||||
|
},
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions"
|
Challenge: pools.weeklyPermanent[weeklyPermanentIndex + i]
|
||||||
});
|
});
|
||||||
activeChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus"
|
|
||||||
});
|
|
||||||
activeChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies"
|
|
||||||
});
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 2);
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 3);
|
|
||||||
} else {
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 2);
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 3);
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, week, 4);
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 5);
|
|
||||||
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, week, 6);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, nightwaveSeason, week, 2);
|
||||||
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, nightwaveSeason, week, 3);
|
||||||
|
pushSeasonWeeklyChallenge(activeChallenges, pools.weekly, nightwaveSeason, week, 4);
|
||||||
|
}
|
||||||
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, nightwaveSeason, week, 5);
|
||||||
|
pushSeasonWeeklyChallenge(activeChallenges, pools.hardWeekly, nightwaveSeason, week, 6);
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateXpAmounts = (rng: SRng, stageCount: number, minXp: number, maxXp: number): number[] => {
|
const generateXpAmounts = (rng: SRng, stageCount: number, minXp: number, maxXp: number): number[] => {
|
||||||
@ -1378,6 +1392,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
Sorties: [],
|
Sorties: [],
|
||||||
LiteSorties: [],
|
LiteSorties: [],
|
||||||
ActiveMissions: [],
|
ActiveMissions: [],
|
||||||
|
FlashSales: [],
|
||||||
GlobalUpgrades: [],
|
GlobalUpgrades: [],
|
||||||
Invasions: [],
|
Invasions: [],
|
||||||
VoidTraders: [],
|
VoidTraders: [],
|
||||||
@ -1387,7 +1402,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
EndlessXpChoices: [],
|
EndlessXpChoices: [],
|
||||||
KnownCalendarSeasons: [],
|
KnownCalendarSeasons: [],
|
||||||
...staticWorldState,
|
...staticWorldState,
|
||||||
SyndicateMissions: [...staticWorldState.SyndicateMissions]
|
SyndicateMissions: [...staticWorldState.SyndicateMissions],
|
||||||
|
InGameMarket: staticWorldState.InGameMarket
|
||||||
};
|
};
|
||||||
|
|
||||||
// Old versions seem to really get hung up on not being able to load these.
|
// Old versions seem to really get hung up on not being able to load these.
|
||||||
@ -1549,14 +1565,375 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const firstNovemberWeekday = new Date(Date.UTC(date.getUTCFullYear(), 10, 1)).getUTCDay();
|
||||||
|
const firstNovemberMondayOffset = (8 - firstNovemberWeekday) % 7;
|
||||||
|
|
||||||
|
const plagueStarStart = Date.UTC(date.getUTCFullYear(), 10, firstNovemberMondayOffset + 1, 16);
|
||||||
|
const plagueStarEnd = Date.UTC(date.getUTCFullYear(), 10, firstNovemberMondayOffset + 15, 16);
|
||||||
|
|
||||||
|
const isPlagueStarActive = timeMs >= plagueStarStart && timeMs < plagueStarEnd;
|
||||||
|
if (config.worldState?.plagueStarOverride ?? isPlagueStarActive) {
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: { $oid: "654a5058c757487cdb11824f" },
|
||||||
|
Activation: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: config.worldState?.plagueStarOverride ? "1699372800000" : plagueStarStart.toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expiry: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: config.worldState?.plagueStarOverride ? "2000000000000" : plagueStarEnd.toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tag: "InfestedPlains",
|
||||||
|
RegionIdx: 2,
|
||||||
|
Faction: "FC_INFESTATION",
|
||||||
|
Desc: "/Lotus/Language/InfestedPlainsEvent/InfestedPlainsBountyName",
|
||||||
|
ToolTip: "/Lotus/Language/InfestedPlainsEvent/InfestedPlainsBountyDesc",
|
||||||
|
Icon: "/Lotus/Materials/Emblems/PlagueStarEventBadge_e.png",
|
||||||
|
JobAffiliationTag: "EventSyndicate",
|
||||||
|
Jobs: [
|
||||||
|
{
|
||||||
|
jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
|
||||||
|
rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableRewards",
|
||||||
|
minEnemyLevel: 15,
|
||||||
|
maxEnemyLevel: 25,
|
||||||
|
xpAmounts: [50, 300, 100, 575]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBountyAdvanced",
|
||||||
|
rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableRewards",
|
||||||
|
minEnemyLevel: 55,
|
||||||
|
maxEnemyLevel: 65,
|
||||||
|
xpAmounts: [200, 1000, 300, 1700],
|
||||||
|
requiredItems: [
|
||||||
|
"/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventIngredient",
|
||||||
|
"/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventClanIngredient"
|
||||||
|
],
|
||||||
|
useRequiredItemsAsMiscItemFee: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBountySteelPath",
|
||||||
|
rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableSteelPathRewards",
|
||||||
|
minEnemyLevel: 100,
|
||||||
|
maxEnemyLevel: 110,
|
||||||
|
xpAmounts: [200, 1100, 400, 2100],
|
||||||
|
masteryReq: 10,
|
||||||
|
requiredItems: [
|
||||||
|
"/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventIngredient",
|
||||||
|
"/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventClanIngredient"
|
||||||
|
],
|
||||||
|
useRequiredItemsAsMiscItemFee: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Transmission: "/Lotus/Sounds/Dialog/PlainsMeteorLeadUp/LeadUp/DLeadUp0021Lotus",
|
||||||
|
InstructionalItem: "/Lotus/Types/StoreItems/Packages/PlagueStarEventStoreItem"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstAugustWeekday = new Date(Date.UTC(date.getUTCFullYear(), 7, 1)).getUTCDay();
|
||||||
|
const firstAugustWednesdayOffset = (3 - firstAugustWeekday + 7) % 7;
|
||||||
|
const waterFightStart = Date.UTC(date.getUTCFullYear(), 7, 1 + firstAugustWednesdayOffset, 15);
|
||||||
|
|
||||||
|
const firstSeptemberWeekday = new Date(Date.UTC(date.getUTCFullYear(), 8, 1)).getUTCDay();
|
||||||
|
const firstSeptemberWednesdayOffset = (3 - firstSeptemberWeekday + 7) % 7;
|
||||||
|
const waterFightEnd = Date.UTC(date.getUTCFullYear(), 8, 1 + firstSeptemberWednesdayOffset, 15);
|
||||||
|
|
||||||
|
const isWaterFightActive = timeMs >= waterFightStart && timeMs < waterFightEnd;
|
||||||
|
logger.debug(isWaterFightActive);
|
||||||
|
if (config.worldState?.waterFightOverride ?? isWaterFightActive) {
|
||||||
|
const activationTimeStamp = config.worldState?.waterFightOverride
|
||||||
|
? "1699372800000"
|
||||||
|
: waterFightStart.toString();
|
||||||
|
const expiryTimeStamp = config.worldState?.waterFightOverride ? "2000000000000" : waterFightEnd.toString();
|
||||||
|
const rewards = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Upgrades/Skins/Weapons/Redeemer/RedeemerRelayWaterSkin"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileHydroidRelay"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/RelayHydroidBobbleHead"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
"/Lotus/StoreItems/Types/Items/MiscItems/OrokinReactor",
|
||||||
|
"/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Upgrades/Skins/Sigils/DogDays2023ASigil"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyBeachKavat"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyRucksackKubrow"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 75
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropCleaningDroneBeachcomber"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/StoreItems/AvatarImages/Seasonal/AvatarImageDogDays2024Glyph"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/DogDays2024Poster"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/DogDaysKubrowBadgeItem"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 75
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: ["/Lotus/StoreItems/Types/Items/ShipDecos/DogDays2024LisetPropCleaningDroneBeachcomber"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageDogDaysHydroidGlyph"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 25
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageDogDaysLokiGlyph"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageDogDaysNovaGlyph"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 75
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
credits: 50000,
|
||||||
|
items: ["/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageDogDaysValkyrGlyph"],
|
||||||
|
countedItems: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/WaterFightBucks",
|
||||||
|
ItemCount: 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const year = config.worldState?.waterFightRewardsOverride ?? 3;
|
||||||
|
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: {
|
||||||
|
$oid: ((waterFightStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "c57487c3768936df"
|
||||||
|
},
|
||||||
|
Activation: { $date: { $numberLong: activationTimeStamp } },
|
||||||
|
Expiry: { $date: { $numberLong: expiryTimeStamp } },
|
||||||
|
Count: 0,
|
||||||
|
Goal: 100,
|
||||||
|
InterimGoals: [25, 50],
|
||||||
|
BonusGoal: 200,
|
||||||
|
Success: 0,
|
||||||
|
Personal: true,
|
||||||
|
Bounty: true,
|
||||||
|
ClampNodeScores: true,
|
||||||
|
Node: "EventNode25",
|
||||||
|
ConcurrentMissionKeyNames: [
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightB",
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightC",
|
||||||
|
"/Lotus/Types/Keys/TacAlertKeyWaterFightD"
|
||||||
|
],
|
||||||
|
ConcurrentNodeReqs: [25, 50, 100],
|
||||||
|
ConcurrentNodes: ["EventNode24", "EventNode34", "EventNode35"],
|
||||||
|
MissionKeyName: "/Lotus/Types/Keys/TacAlertKeyWaterFightA",
|
||||||
|
Faction: "FC_CORPUS",
|
||||||
|
Desc: "/Lotus/Language/Alerts/TacAlertWaterFight",
|
||||||
|
Icon: "/Lotus/Interface/Icons/StoreIcons/Emblems/SplashEventIcon.png",
|
||||||
|
Tag: "WaterFight",
|
||||||
|
InterimRewards: rewards[year].slice(0, 2),
|
||||||
|
Reward: rewards[year][2],
|
||||||
|
BonusReward: rewards[year][3],
|
||||||
|
ScoreVar: "Team1Score",
|
||||||
|
NightLevel: "/Lotus/Levels/GrineerBeach/GrineerBeachEventNight.level"
|
||||||
|
});
|
||||||
|
|
||||||
|
const baseStoreItem = {
|
||||||
|
ShowInMarket: true,
|
||||||
|
HideFromMarket: false,
|
||||||
|
SupporterPack: false,
|
||||||
|
Discount: 0,
|
||||||
|
BogoBuy: 0,
|
||||||
|
BogoGet: 0,
|
||||||
|
StartDate: { $date: { $numberLong: activationTimeStamp } },
|
||||||
|
EndDate: { $date: { $numberLong: expiryTimeStamp } },
|
||||||
|
ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } }
|
||||||
|
};
|
||||||
|
|
||||||
|
const storeItems = [
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/StoreItems/Packages/WaterFightNoggleBundle",
|
||||||
|
PremiumOverride: 240,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFBeastMasterBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFChargerBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFEngineerBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFGruntBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImagePopsicleGrineerPurple",
|
||||||
|
PremiumOverride: 0,
|
||||||
|
RegularOverride: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHealerBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHeavyBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHellionBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFSniperBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFTankBobbleHead",
|
||||||
|
PremiumOverride: 35,
|
||||||
|
RegularOverride: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerRollers",
|
||||||
|
PremiumOverride: 75,
|
||||||
|
RegularOverride: 0
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
worldState.FlashSales.push(...storeItems.map(item => ({ ...baseStoreItem, ...item })));
|
||||||
|
|
||||||
|
const seasonalItems = storeItems.map(item => item.TypeName);
|
||||||
|
|
||||||
|
const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
|
||||||
|
|
||||||
|
if (seasonalCategory) {
|
||||||
|
seasonalCategory.Items ??= [];
|
||||||
|
seasonalCategory.Items.push(...seasonalItems);
|
||||||
|
} else {
|
||||||
|
worldState.InGameMarket.LandingPage.Categories.push({
|
||||||
|
CategoryName: "SEASONAL",
|
||||||
|
Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
|
||||||
|
Icon: "seasonal",
|
||||||
|
AddToMenu: true,
|
||||||
|
Items: seasonalItems
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Nightwave Challenges
|
// Nightwave Challenges
|
||||||
const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
|
const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
|
||||||
if (nightwaveSyndicateTag) {
|
if (nightwaveSyndicateTag) {
|
||||||
|
const nightwaveStartTimestamp = 1747851300000;
|
||||||
|
const nightwaveSeason = nightwaveTagToSeason[nightwaveSyndicateTag];
|
||||||
worldState.SeasonInfo = {
|
worldState.SeasonInfo = {
|
||||||
Activation: { $date: { $numberLong: "1715796000000" } },
|
Activation: { $date: { $numberLong: nightwaveStartTimestamp.toString() } },
|
||||||
Expiry: { $date: { $numberLong: "2000000000000" } },
|
Expiry: { $date: { $numberLong: "2000000000000" } },
|
||||||
AffiliationTag: nightwaveSyndicateTag,
|
AffiliationTag: nightwaveSyndicateTag,
|
||||||
Season: nightwaveTagToSeason[nightwaveSyndicateTag],
|
Season: nightwaveSeason,
|
||||||
Phase: 0,
|
Phase: 0,
|
||||||
Params: "",
|
Params: "",
|
||||||
ActiveChallenges: []
|
ActiveChallenges: []
|
||||||
@ -1568,9 +1945,15 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, EPOCH + (day + 1) * 86400000)) {
|
if (isBeforeNextExpectedWorldStateRefresh(timeMs, EPOCH + (day + 1) * 86400000)) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day + 1));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(pools, day + 1));
|
||||||
}
|
}
|
||||||
pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week);
|
pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week, nightwaveStartTimestamp, nightwaveSeason);
|
||||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) {
|
if (isBeforeNextExpectedWorldStateRefresh(timeMs, weekEnd)) {
|
||||||
pushWeeklyActs(worldState.SeasonInfo.ActiveChallenges, pools, week + 1);
|
pushWeeklyActs(
|
||||||
|
worldState.SeasonInfo.ActiveChallenges,
|
||||||
|
pools,
|
||||||
|
week + 1,
|
||||||
|
nightwaveStartTimestamp,
|
||||||
|
nightwaveSeason
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1611,6 +1994,103 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
pushClassicBounties(worldState.SyndicateMissions, bountyCycle);
|
pushClassicBounties(worldState.SyndicateMissions, bountyCycle);
|
||||||
} while (isBeforeNextExpectedWorldStateRefresh(timeMs, bountyCycleEnd) && ++bountyCycle);
|
} while (isBeforeNextExpectedWorldStateRefresh(timeMs, bountyCycleEnd) && ++bountyCycle);
|
||||||
|
|
||||||
|
const ghoulsCycleDay = day % 21;
|
||||||
|
const isGhoulEmergenceActive = ghoulsCycleDay >= 17 && ghoulsCycleDay <= 20; // 4 days for event and 17 days for break
|
||||||
|
if (config.worldState?.ghoulEmergenceOverride ?? isGhoulEmergenceActive) {
|
||||||
|
const ghoulPool = [...eidolonGhoulJobs];
|
||||||
|
const pastGhoulPool = [...eidolonGhoulJobs];
|
||||||
|
|
||||||
|
const seed = new SRng(bountyCycle).randomInt(0, 100_000);
|
||||||
|
const pastSeed = new SRng(bountyCycle - 1).randomInt(0, 100_000);
|
||||||
|
|
||||||
|
const rng = new SRng(seed);
|
||||||
|
const pastRng = new SRng(pastSeed);
|
||||||
|
|
||||||
|
const activeStartDay = day - ghoulsCycleDay + 17;
|
||||||
|
const activeEndDay = activeStartDay + 5;
|
||||||
|
const dayWithFraction = (timeMs - EPOCH) / 86400000;
|
||||||
|
|
||||||
|
const progress = (dayWithFraction - activeStartDay) / (activeEndDay - activeStartDay);
|
||||||
|
const healthPct = 1 - Math.min(Math.max(progress, 0), 1);
|
||||||
|
|
||||||
|
worldState.Goals.push({
|
||||||
|
_id: { $oid: "687ebbe6d1d17841c9c59f38" },
|
||||||
|
Activation: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: config.worldState?.ghoulEmergenceOverride
|
||||||
|
? "1753204900185"
|
||||||
|
: Date.UTC(
|
||||||
|
date.getUTCFullYear(),
|
||||||
|
date.getUTCMonth(),
|
||||||
|
date.getUTCDate() + (day - ghoulsCycleDay + 17)
|
||||||
|
).toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expiry: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: config.worldState?.ghoulEmergenceOverride
|
||||||
|
? "2000000000000"
|
||||||
|
: Date.UTC(
|
||||||
|
date.getUTCFullYear(),
|
||||||
|
date.getUTCMonth(),
|
||||||
|
date.getUTCDate() + (day - ghoulsCycleDay + 21)
|
||||||
|
).toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HealthPct: config.worldState?.ghoulEmergenceOverride ? 1 : healthPct,
|
||||||
|
VictimNode: "SolNode228",
|
||||||
|
Regions: [2],
|
||||||
|
Success: 0,
|
||||||
|
Desc: "/Lotus/Language/GameModes/RecurringGhoulAlert",
|
||||||
|
ToolTip: "/Lotus/Language/GameModes/RecurringGhoulAlertDesc",
|
||||||
|
Icon: "/Lotus/Interface/Icons/Categories/IconGhouls256.png",
|
||||||
|
Tag: "GhoulEmergence",
|
||||||
|
JobAffiliationTag: "CetusSyndicate",
|
||||||
|
JobCurrentVersion: {
|
||||||
|
$oid: ((bountyCycle * 9000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
|
||||||
|
},
|
||||||
|
Jobs: [
|
||||||
|
{
|
||||||
|
jobType: rng.randomElementPop(ghoulPool),
|
||||||
|
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards`,
|
||||||
|
masteryReq: 1,
|
||||||
|
minEnemyLevel: 15,
|
||||||
|
maxEnemyLevel: 25,
|
||||||
|
xpAmounts: [270, 270, 270, 400] // not faithful
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jobType: rng.randomElementPop(ghoulPool),
|
||||||
|
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards`,
|
||||||
|
masteryReq: 3,
|
||||||
|
minEnemyLevel: 40,
|
||||||
|
maxEnemyLevel: 50,
|
||||||
|
xpAmounts: [480, 480, 480, 710] // not faithful
|
||||||
|
}
|
||||||
|
],
|
||||||
|
JobPreviousVersion: {
|
||||||
|
$oid: (((bountyCycle - 1) * 9000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
|
||||||
|
},
|
||||||
|
PreviousJobs: [
|
||||||
|
{
|
||||||
|
jobType: pastRng.randomElementPop(pastGhoulPool),
|
||||||
|
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards`,
|
||||||
|
masteryReq: 1,
|
||||||
|
minEnemyLevel: 15,
|
||||||
|
maxEnemyLevel: 25,
|
||||||
|
xpAmounts: [270, 270, 270, 400] // not faithful
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jobType: pastRng.randomElementPop(pastGhoulPool),
|
||||||
|
rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards`,
|
||||||
|
masteryReq: 3,
|
||||||
|
minEnemyLevel: 40,
|
||||||
|
maxEnemyLevel: 50,
|
||||||
|
xpAmounts: [480, 480, 480, 710] // not faithful
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (config.worldState?.creditBoost) {
|
if (config.worldState?.creditBoost) {
|
||||||
worldState.GlobalUpgrades.push({
|
worldState.GlobalUpgrades.push({
|
||||||
_id: { $oid: "5b23106f283a555109666672" },
|
_id: { $oid: "5b23106f283a555109666672" },
|
||||||
|
@ -23,12 +23,19 @@ export interface IMissionCredits {
|
|||||||
DailyMissionBonus?: boolean;
|
DailyMissionBonus?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMissionInventoryUpdateResponse extends Partial<IMissionCredits> {
|
export interface IMissionInventoryUpdateResponseRailjackInterstitial extends Partial<IMissionCredits> {
|
||||||
ConquestCompletedMissionsCount?: number;
|
ConquestCompletedMissionsCount?: number;
|
||||||
InventoryJson?: string;
|
|
||||||
MissionRewards?: IMissionReward[];
|
MissionRewards?: IMissionReward[];
|
||||||
InventoryChanges?: IInventoryChanges;
|
InventoryChanges?: IInventoryChanges;
|
||||||
FusionPoints?: number;
|
FusionPoints?: number;
|
||||||
SyndicateXPItemReward?: number;
|
SyndicateXPItemReward?: number;
|
||||||
AffiliationMods?: IAffiliationMods[];
|
AffiliationMods?: IAffiliationMods[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IMissionInventoryUpdateResponse extends IMissionInventoryUpdateResponseRailjackInterstitial {
|
||||||
|
InventoryJson?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMissionInventoryUpdateResponseBackToDryDock {
|
||||||
|
InventoryJson: string;
|
||||||
|
}
|
||||||
|
@ -148,6 +148,7 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
MultiProgress: unknown[];
|
MultiProgress: unknown[];
|
||||||
}[];
|
}[];
|
||||||
InvasionProgress?: IInvasionProgressClient[];
|
InvasionProgress?: IInvasionProgressClient[];
|
||||||
|
RJ?: boolean;
|
||||||
ConquestMissionsCompleted?: number;
|
ConquestMissionsCompleted?: number;
|
||||||
duviriSuitSelection?: string;
|
duviriSuitSelection?: string;
|
||||||
duviriPistolSelection?: string;
|
duviriPistolSelection?: string;
|
||||||
@ -184,6 +185,7 @@ export interface IRewardInfo {
|
|||||||
NemesisHintProgress?: number;
|
NemesisHintProgress?: number;
|
||||||
EOM_AFK?: number;
|
EOM_AFK?: number;
|
||||||
rewardQualifications?: string; // did a Survival for 5 minutes and this was "1"
|
rewardQualifications?: string; // did a Survival for 5 minutes and this was "1"
|
||||||
|
rewardTierOverrides?: number[]; // Disruption
|
||||||
PurgatoryRewardQualifications?: string;
|
PurgatoryRewardQualifications?: string;
|
||||||
rewardSeed?: number | bigint;
|
rewardSeed?: number | bigint;
|
||||||
periodicMissionTag?: string;
|
periodicMissionTag?: string;
|
||||||
|
@ -5,12 +5,14 @@ export interface IWorldState {
|
|||||||
Version: number; // for goals
|
Version: number; // for goals
|
||||||
BuildLabel: string;
|
BuildLabel: string;
|
||||||
Time: number;
|
Time: number;
|
||||||
|
InGameMarket: IInGameMarket;
|
||||||
Goals: IGoal[];
|
Goals: IGoal[];
|
||||||
Alerts: [];
|
Alerts: [];
|
||||||
Sorties: ISortie[];
|
Sorties: ISortie[];
|
||||||
LiteSorties: ILiteSortie[];
|
LiteSorties: ILiteSortie[];
|
||||||
SyndicateMissions: ISyndicateMissionInfo[];
|
SyndicateMissions: ISyndicateMissionInfo[];
|
||||||
ActiveMissions: IFissure[];
|
ActiveMissions: IFissure[];
|
||||||
|
FlashSales: IFlashSale[];
|
||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
Invasions: IInvasion[];
|
Invasions: IInvasion[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
@ -37,19 +39,56 @@ export interface IGoal {
|
|||||||
_id: IOid;
|
_id: IOid;
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
Expiry: IMongoDate;
|
Expiry: IMongoDate;
|
||||||
Count: number;
|
Count?: number;
|
||||||
Goal: number;
|
Goal?: number;
|
||||||
Success: number;
|
InterimGoals?: number[];
|
||||||
Personal: boolean;
|
BonusGoal?: number;
|
||||||
|
HealthPct?: number;
|
||||||
|
Success?: number;
|
||||||
|
Personal?: boolean;
|
||||||
Bounty?: boolean;
|
Bounty?: boolean;
|
||||||
|
Faction?: string;
|
||||||
ClampNodeScores?: boolean;
|
ClampNodeScores?: boolean;
|
||||||
Desc: string;
|
Desc: string;
|
||||||
ToolTip?: string;
|
ToolTip?: string;
|
||||||
|
Transmission?: string;
|
||||||
|
InstructionalItem?: string;
|
||||||
Icon: string;
|
Icon: string;
|
||||||
Tag: string;
|
Tag: string;
|
||||||
Node: string;
|
Node?: string;
|
||||||
|
VictimNode?: string;
|
||||||
|
ConcurrentMissionKeyNames?: string[];
|
||||||
|
ConcurrentNodeReqs?: number[];
|
||||||
|
ConcurrentNodes?: string[];
|
||||||
|
RegionIdx?: number;
|
||||||
|
Regions?: number[];
|
||||||
MissionKeyName?: string;
|
MissionKeyName?: string;
|
||||||
Reward?: IMissionReward;
|
Reward?: IMissionReward;
|
||||||
|
InterimRewards?: IMissionReward[];
|
||||||
|
BonusReward?: IMissionReward;
|
||||||
|
|
||||||
|
JobAffiliationTag?: string;
|
||||||
|
Jobs?: ISyndicateJob[];
|
||||||
|
PreviousJobs?: ISyndicateJob[];
|
||||||
|
JobCurrentVersion?: IOid;
|
||||||
|
JobPreviousVersion?: IOid;
|
||||||
|
|
||||||
|
ScoreVar?: string;
|
||||||
|
NightLevel?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISyndicateJob {
|
||||||
|
jobType?: string;
|
||||||
|
rewards: string;
|
||||||
|
masteryReq?: number;
|
||||||
|
minEnemyLevel: number;
|
||||||
|
maxEnemyLevel: number;
|
||||||
|
xpAmounts: number[];
|
||||||
|
endless?: boolean;
|
||||||
|
locationTag?: string;
|
||||||
|
isVault?: boolean;
|
||||||
|
requiredItems?: string[];
|
||||||
|
useRequiredItemsAsMiscItemFee?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISyndicateMissionInfo {
|
export interface ISyndicateMissionInfo {
|
||||||
@ -59,17 +98,7 @@ export interface ISyndicateMissionInfo {
|
|||||||
Tag: string;
|
Tag: string;
|
||||||
Seed: number;
|
Seed: number;
|
||||||
Nodes: string[];
|
Nodes: string[];
|
||||||
Jobs?: {
|
Jobs?: ISyndicateJob[];
|
||||||
jobType?: string;
|
|
||||||
rewards: string;
|
|
||||||
masteryReq: number;
|
|
||||||
minEnemyLevel: number;
|
|
||||||
maxEnemyLevel: number;
|
|
||||||
xpAmounts: number[];
|
|
||||||
endless?: boolean;
|
|
||||||
locationTag?: string;
|
|
||||||
isVault?: boolean;
|
|
||||||
}[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGlobalUpgrade {
|
export interface IGlobalUpgrade {
|
||||||
@ -265,6 +294,7 @@ export interface IEndlessXpChoice {
|
|||||||
export interface ISeasonChallenge {
|
export interface ISeasonChallenge {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
Daily?: boolean;
|
Daily?: boolean;
|
||||||
|
Permanent?: boolean; // only for getPastWeeklyChallenges response
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
Expiry: IMongoDate;
|
Expiry: IMongoDate;
|
||||||
Challenge: string;
|
Challenge: string;
|
||||||
@ -303,6 +333,37 @@ export type TCircuitGameMode =
|
|||||||
| "Assassination"
|
| "Assassination"
|
||||||
| "Alchemy";
|
| "Alchemy";
|
||||||
|
|
||||||
|
export interface IFlashSale {
|
||||||
|
TypeName: string;
|
||||||
|
ShowInMarket: boolean;
|
||||||
|
HideFromMarket: boolean;
|
||||||
|
SupporterPack: boolean;
|
||||||
|
Discount: number;
|
||||||
|
BogoBuy: number;
|
||||||
|
BogoGet: number;
|
||||||
|
PremiumOverride: number;
|
||||||
|
RegularOverride: number;
|
||||||
|
ProductExpiryOverride?: IMongoDate;
|
||||||
|
StartDate: IMongoDate;
|
||||||
|
EndDate: IMongoDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IInGameMarket {
|
||||||
|
LandingPage: ILandingPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILandingPage {
|
||||||
|
Categories: IGameMarketCategory[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGameMarketCategory {
|
||||||
|
CategoryName: string;
|
||||||
|
Name: string;
|
||||||
|
Icon: string;
|
||||||
|
AddToMenu?: boolean;
|
||||||
|
Items?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITmp {
|
export interface ITmp {
|
||||||
cavabegin: string;
|
cavabegin: string;
|
||||||
PurchasePlatformLockEnabled: boolean; // Seems unused
|
PurchasePlatformLockEnabled: boolean; // Seems unused
|
||||||
|
@ -946,6 +946,22 @@
|
|||||||
<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.ghoulEmergenceOverride" data-loc="worldState_ghoulEmergence"></label>
|
||||||
|
<select class="form-control" id="worldState.ghoulEmergenceOverride" 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">
|
||||||
|
<label class="form-label" for="worldState.plagueStarOverride" data-loc="worldState_plagueStar"></label>
|
||||||
|
<select class="form-control" id="worldState.plagueStarOverride" 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.starDaysOverride" data-loc="worldState_starDays"></label>
|
<label class="form-label" for="worldState.starDaysOverride" data-loc="worldState_starDays"></label>
|
||||||
<select class="form-control" id="worldState.starDaysOverride" data-default="null">
|
<select class="form-control" id="worldState.starDaysOverride" data-default="null">
|
||||||
@ -954,6 +970,26 @@
|
|||||||
<option value="false" data-loc="disabled"></option>
|
<option value="false" data-loc="disabled"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group mt-2 d-flex gap-2">
|
||||||
|
<div class="flex-fill">
|
||||||
|
<label class="form-label" for="worldState.waterFightOverride" data-loc="worldState_waterFight"></label>
|
||||||
|
<select class="form-control" id="worldState.waterFightOverride" 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="flex-fill">
|
||||||
|
<label class="form-label" for="worldState.waterFightRewardsOverride" data-loc="worldState_waterFightRewards"></label>
|
||||||
|
<select class="form-control" id="worldState.waterFightRewardsOverride" data-default="null">
|
||||||
|
<option value="null" data-loc="normal"></option>
|
||||||
|
<option value="3" data-loc="worldState_from_2025"></option>
|
||||||
|
<option value="2" data-loc="worldState_from_2024"></option>
|
||||||
|
<option value="1" data-loc="worldState_from_2023"></option>
|
||||||
|
<option value="0" data-loc="worldState_pre_2023"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</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="">
|
||||||
|
@ -212,7 +212,7 @@ function setActiveLanguage(lang) {
|
|||||||
document.querySelector("[data-lang=" + lang + "]").classList.add("active");
|
document.querySelector("[data-lang=" + lang + "]").classList.add("active");
|
||||||
|
|
||||||
window.dictPromise = new Promise(resolve => {
|
window.dictPromise = new Promise(resolve => {
|
||||||
const webui_lang = ["en", "ru", "fr", "de", "zh", "es"].indexOf(lang) == -1 ? "en" : lang;
|
const webui_lang = ["en", "ru", "fr", "de", "zh", "es", "uk"].indexOf(lang) == -1 ? "en" : lang;
|
||||||
let script = document.getElementById("translations");
|
let script = document.getElementById("translations");
|
||||||
if (script) document.documentElement.removeChild(script);
|
if (script) document.documentElement.removeChild(script);
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
margin-left: 7rem;
|
margin-left: 7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.logged-in:has([data-lang="de"].active) #main-content {
|
body.logged-in:has([data-lang="de"].active) #main-content,
|
||||||
|
body.logged-in:has([data-lang="uk"].active) #main-content {
|
||||||
margin-left: 8rem;
|
margin-left: 8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +246,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `Baros TennoCon Relais`,
|
worldState_baroTennoConRelay: `Baros TennoCon Relais`,
|
||||||
worldState_starDays: `Sternen-Tage`,
|
worldState_starDays: `Sternen-Tage`,
|
||||||
worldState_galleonOfGhouls: `Galeone der Ghule`,
|
worldState_galleonOfGhouls: `Galeone der Ghule`,
|
||||||
|
worldState_ghoulEmergence: `Ghul Ausrottung`,
|
||||||
|
worldState_plagueStar: `Plagenstern`,
|
||||||
|
worldState_waterFight: `Hitzefrei`,
|
||||||
|
worldState_waterFightRewards: `[UNTRANSLATED] Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `[UNTRANSLATED] from 2025`,
|
||||||
|
worldState_from_2024: `[UNTRANSLATED] from 2024`,
|
||||||
|
worldState_from_2023: `[UNTRANSLATED] from 2023`,
|
||||||
|
worldState_pre_2023: `[UNTRANSLATED] pre 2023`,
|
||||||
enabled: `Aktiviert`,
|
enabled: `Aktiviert`,
|
||||||
disabled: `Deaktiviert`,
|
disabled: `Deaktiviert`,
|
||||||
worldState_we1: `Wochenende 1`,
|
worldState_we1: `Wochenende 1`,
|
||||||
|
@ -245,6 +245,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `Baro's TennoCon 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`,
|
||||||
|
worldState_ghoulEmergence: `Ghoul Purge`,
|
||||||
|
worldState_plagueStar: `Plague Star`,
|
||||||
|
worldState_waterFight: `Dog Days`,
|
||||||
|
worldState_waterFightRewards: `Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `from 2025`,
|
||||||
|
worldState_from_2024: `from 2024`,
|
||||||
|
worldState_from_2023: `from 2023`,
|
||||||
|
worldState_pre_2023: `pre 2023`,
|
||||||
enabled: `Enabled`,
|
enabled: `Enabled`,
|
||||||
disabled: `Disabled`,
|
disabled: `Disabled`,
|
||||||
worldState_we1: `Weekend 1`,
|
worldState_we1: `Weekend 1`,
|
||||||
|
@ -246,6 +246,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `Repetidor de Baro de la TennoCon`,
|
worldState_baroTennoConRelay: `Repetidor de Baro de la TennoCon`,
|
||||||
worldState_starDays: `Días estelares`,
|
worldState_starDays: `Días estelares`,
|
||||||
worldState_galleonOfGhouls: `Galeón de Gules`,
|
worldState_galleonOfGhouls: `Galeón de Gules`,
|
||||||
|
worldState_ghoulEmergence: `Purga de Gules`,
|
||||||
|
worldState_plagueStar: `Estrella Infestada`,
|
||||||
|
worldState_waterFight: `Canícula`,
|
||||||
|
worldState_waterFightRewards: `[UNTRANSLATED] Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `[UNTRANSLATED] from 2025`,
|
||||||
|
worldState_from_2024: `[UNTRANSLATED] from 2024`,
|
||||||
|
worldState_from_2023: `[UNTRANSLATED] from 2023`,
|
||||||
|
worldState_pre_2023: `[UNTRANSLATED] pre 2023`,
|
||||||
enabled: `Activado`,
|
enabled: `Activado`,
|
||||||
disabled: `Desactivado`,
|
disabled: `Desactivado`,
|
||||||
worldState_we1: `Semana 1`,
|
worldState_we1: `Semana 1`,
|
||||||
|
@ -246,6 +246,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon 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`,
|
||||||
|
worldState_ghoulEmergence: `Purge des Goules`,
|
||||||
|
worldState_plagueStar: `Fléau Céleste`,
|
||||||
|
worldState_waterFight: `Bataille d'Eau`,
|
||||||
|
worldState_waterFightRewards: `[UNTRANSLATED] Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `[UNTRANSLATED] from 2025`,
|
||||||
|
worldState_from_2024: `[UNTRANSLATED] from 2024`,
|
||||||
|
worldState_from_2023: `[UNTRANSLATED] from 2023`,
|
||||||
|
worldState_pre_2023: `[UNTRANSLATED] pre 2023`,
|
||||||
enabled: `[UNTRANSLATED] Enabled`,
|
enabled: `[UNTRANSLATED] Enabled`,
|
||||||
disabled: `Désactivé`,
|
disabled: `Désactivé`,
|
||||||
worldState_we1: `Weekend 1`,
|
worldState_we1: `Weekend 1`,
|
||||||
|
@ -246,6 +246,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `Реле Баро TennoCon`,
|
worldState_baroTennoConRelay: `Реле Баро TennoCon`,
|
||||||
worldState_starDays: `Звёздные дни`,
|
worldState_starDays: `Звёздные дни`,
|
||||||
worldState_galleonOfGhouls: `Галеон Гулей`,
|
worldState_galleonOfGhouls: `Галеон Гулей`,
|
||||||
|
worldState_ghoulEmergence: `Избавление от гулей`,
|
||||||
|
worldState_plagueStar: `Чумная звезда`,
|
||||||
|
worldState_waterFight: `Знойные дни`,
|
||||||
|
worldState_waterFightRewards: `Награды Знойных дней`,
|
||||||
|
worldState_from_2025: `из 2025`,
|
||||||
|
worldState_from_2024: `из 2024`,
|
||||||
|
worldState_from_2023: `из 2023`,
|
||||||
|
worldState_pre_2023: `до 2023`,
|
||||||
enabled: `Включено`,
|
enabled: `Включено`,
|
||||||
disabled: `Отключено`,
|
disabled: `Отключено`,
|
||||||
worldState_we1: `Выходные 1`,
|
worldState_we1: `Выходные 1`,
|
||||||
|
368
static/webui/translations/uk.js
Normal file
368
static/webui/translations/uk.js
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
// Ukrainian translation by LoseFace
|
||||||
|
dict = {
|
||||||
|
general_inventoryUpdateNote: `Пам'ятка: Щоб побачити зміни в грі, вам потрібно повторно синхронізувати свій інвентар, наприклад, використовуючи команду /sync завантажувача, відвідавши Доджьо/Реле або перезавантаживши гру.`,
|
||||||
|
general_addButton: `Добавити`,
|
||||||
|
general_setButton: `Встановити`,
|
||||||
|
general_none: `Відсутній`,
|
||||||
|
general_bulkActions: `Масові дії`,
|
||||||
|
general_loading: `Завантаження...`,
|
||||||
|
|
||||||
|
code_loginFail: `Не вдалося увійти. Перевірте адресу електронної пошти та пароль.`,
|
||||||
|
code_regFail: `Не вдалося зареєструватися. Обліковий запис вже існує?`,
|
||||||
|
code_changeNameConfirm: `Яке ім'я ви хочете встановити для свого облікового запису?`,
|
||||||
|
code_deleteAccountConfirm: `Ви впевнені, що хочете видалити обліковий запис |DISPLAYNAME| (|EMAIL|)? Цю дію не можна скасувати.`,
|
||||||
|
code_archgun: `Арч-Пушка`,
|
||||||
|
code_melee: `Ближній бій`,
|
||||||
|
code_pistol: `Пістолет`,
|
||||||
|
code_rifle: `Гвинтівка`,
|
||||||
|
code_shotgun: `Рушниця`,
|
||||||
|
code_kitgun: `Складостріл`,
|
||||||
|
code_zaw: `Зо`,
|
||||||
|
code_moteAmp: `Порошинка`,
|
||||||
|
code_amp: `Підсилювач`,
|
||||||
|
code_kDrive: `К-Драйв`,
|
||||||
|
code_legendaryCore: `Легендарне ядро`,
|
||||||
|
code_traumaticPeculiar: `Травмуюча Странність`,
|
||||||
|
code_starter: `|MOD| (Пошкоджений)`,
|
||||||
|
code_badItem: `(Самозванець)`,
|
||||||
|
code_maxRank: `Максимальний рівень`,
|
||||||
|
code_rename: `Переіменувати`,
|
||||||
|
code_renamePrompt: `Введіть нове ім'я:`,
|
||||||
|
code_remove: `Видалити`,
|
||||||
|
code_addItemsConfirm: `Ви впевнені, що хочете додати |COUNT| предметів на ваш обліковий запис?`,
|
||||||
|
code_succRankUp: `Рівень успішно підвищено`,
|
||||||
|
code_noEquipmentToRankUp: `Немає спорядження для підвищення рівня.`,
|
||||||
|
code_succAdded: `Успішно додано.`,
|
||||||
|
code_succRemoved: `Успішно видалено.`,
|
||||||
|
code_buffsNumber: `Кількість позитивних ефектів`,
|
||||||
|
code_cursesNumber: `Кількість негативних ефектів`,
|
||||||
|
code_rerollsNumber: `Кількість рероллів`,
|
||||||
|
code_viewStats: `Перегляд характеристики`,
|
||||||
|
code_rank: `Рівень`,
|
||||||
|
code_rankUp: `Підвищити рівень`,
|
||||||
|
code_rankDown: `Понизити рівень`,
|
||||||
|
code_count: `Кількість`,
|
||||||
|
code_focusAllUnlocked: `Всі школи фокуса вже розблоковані.`,
|
||||||
|
code_focusUnlocked: `Розблоковано |COUNT| нових шкіл фокуса! Для відображення змін в грі знадобиться оновлення спорядження. Відвідування навігації — найпростіший спосіб цього досягти.`,
|
||||||
|
code_addModsConfirm: `Ви впевнені, що хочете додати |COUNT| модифікаторів на ваш обліковий запис?`,
|
||||||
|
code_succImport: `Успішно імпортовано.`,
|
||||||
|
code_succRelog: `Готово. Зверніть увагу, що вам потрібно буде перезайти, щоб побачити зміни в грі.`,
|
||||||
|
code_nothingToDo: `Готово. Немає що робити.`,
|
||||||
|
code_gild: `Покращити`,
|
||||||
|
code_moa: `МОА`,
|
||||||
|
code_zanuka: `Гончарка`,
|
||||||
|
code_stage: `Етап`,
|
||||||
|
code_complete: `Завершити`,
|
||||||
|
code_nextStage: `Наступний етап`,
|
||||||
|
code_prevStage: `Попередній етап`,
|
||||||
|
code_reset: `Скинути`,
|
||||||
|
code_setInactive: `Зробити пригоду неактивною`,
|
||||||
|
code_completed: `Завершено`,
|
||||||
|
code_active: `Активний`,
|
||||||
|
code_pigment: `Пігмент`,
|
||||||
|
code_mature: `Підготувати до бою`,
|
||||||
|
code_unmature: `Обернути старіння`,
|
||||||
|
code_succChange: `Успішно змінено.`,
|
||||||
|
code_requiredInvigorationUpgrade: `Ви повинні вибрати як атакуюче, так і допоміжне покращення.`,
|
||||||
|
login_description: `Увійдіть, використовуючи облікові дані OpenWF (ті ж, що й у грі при підключенні до цього сервера).`,
|
||||||
|
login_emailLabel: `Адреса електронної пошти`,
|
||||||
|
login_passwordLabel: `Пароль`,
|
||||||
|
login_loginButton: `Увійти`,
|
||||||
|
login_registerButton: `Зареєструватися`,
|
||||||
|
navbar_logout: `Вийти`,
|
||||||
|
navbar_renameAccount: `Переіменувати обліковий запис`,
|
||||||
|
navbar_deleteAccount: `Видалити обліковий запис`,
|
||||||
|
navbar_inventory: `Спорядження`,
|
||||||
|
navbar_mods: `Моди`,
|
||||||
|
navbar_quests: `Пригоди`,
|
||||||
|
navbar_cheats: `Чити`,
|
||||||
|
navbar_import: `Імпорт`,
|
||||||
|
inventory_addItems: `Додати предмети`,
|
||||||
|
inventory_suits: `Ворфрейми`,
|
||||||
|
inventory_longGuns: `Основне озброєння`,
|
||||||
|
inventory_pistols: `Допоміжне озброєння`,
|
||||||
|
inventory_melee: `Холодне озброєння`,
|
||||||
|
inventory_spaceSuits: `Арквінґи`,
|
||||||
|
inventory_spaceGuns: `Озброєння арквінґів`,
|
||||||
|
inventory_spaceMelee: `Холодне озброєння арквінґів`,
|
||||||
|
inventory_mechSuits: `Некрамехи`,
|
||||||
|
inventory_sentinels: `Вартові`,
|
||||||
|
inventory_sentinelWeapons: `Озброєння вартових`,
|
||||||
|
inventory_operatorAmps: `Підсилювачі`,
|
||||||
|
inventory_hoverboards: `К-Драйви`,
|
||||||
|
inventory_moaPets: `МОА`,
|
||||||
|
inventory_kubrowPets: `Тварини`,
|
||||||
|
inventory_evolutionProgress: `Прогрес Еволюції Інкарнонов`,
|
||||||
|
inventory_Boosters: `Бустери`,
|
||||||
|
inventory_bulkAddSuits: `Додати відсутні ворфрейми`,
|
||||||
|
inventory_bulkAddWeapons: `Додати відсутнє озброєння`,
|
||||||
|
inventory_bulkAddSpaceSuits: `Додати відсутні арквінґи`,
|
||||||
|
inventory_bulkAddSpaceWeapons: `Додати відсутнє озброєння арквінґів`,
|
||||||
|
inventory_bulkAddSentinels: `Додати відсутніх вартових`,
|
||||||
|
inventory_bulkAddSentinelWeapons: `Додати відсутнє озброєння вартових`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `Додати відсутній прогрес Еволюції Інкарнонов`,
|
||||||
|
inventory_bulkRankUpSuits: `Максимальний рівень всіх ворфреймів`,
|
||||||
|
inventory_bulkRankUpWeapons: `Максимальний рівень всього озброєння`,
|
||||||
|
inventory_bulkRankUpSpaceSuits: `Максимальний рівень всіх арквінґів`,
|
||||||
|
inventory_bulkRankUpSpaceWeapons: `Максимальний рівень всього озброєння арквінґів`,
|
||||||
|
inventory_bulkRankUpSentinels: `Максимальний рівень всіх вартових`,
|
||||||
|
inventory_bulkRankUpSentinelWeapons: `Максимальний рівень всього озброєння вартових`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `Максимальний рівень всіх еволюцій Інкарнонов`,
|
||||||
|
inventory_maxPlexus: `Максимальний рівень Плексу`,
|
||||||
|
|
||||||
|
quests_list: `Пригоди`,
|
||||||
|
quests_completeAll: `Закінчити всі пригоди`,
|
||||||
|
quests_resetAll: `Скинути прогрес всіх пригод`,
|
||||||
|
quests_giveAll: `Видати всі пригоди`,
|
||||||
|
|
||||||
|
currency_RegularCredits: `Кредити`,
|
||||||
|
currency_PremiumCredits: `Платина`,
|
||||||
|
currency_FusionPoints: `Ендо`,
|
||||||
|
currency_PrimeTokens: `Королівські Ая`,
|
||||||
|
currency_owned: `У тебе |COUNT|.`,
|
||||||
|
|
||||||
|
detailedView_archonShardsLabel: `Клітинки осколків архонта`,
|
||||||
|
detailedView_archonShardsDescription: `Ви можете використовувати ці необмежені клітинки для встановлення безлічі вдосконалень.`,
|
||||||
|
detailedView_archonShardsDescription2: `Зверніть увагу: кожен уламок архонта застосовується з затримкою при завантаженні.`,
|
||||||
|
detailedView_valenceBonusLabel: `Ознака Валентності`,
|
||||||
|
detailedView_valenceBonusDescription: `Ви можете встановити або прибрати ознака валентності з вашої зброї.`,
|
||||||
|
detailedView_modularPartsLabel: `Змінити Модульні Частини`,
|
||||||
|
detailedView_suitInvigorationLabel: `Зміцнення Ворфрейма`,
|
||||||
|
detailedView_loadoutLabel: `Конфігурації`,
|
||||||
|
|
||||||
|
invigorations_offensive_AbilityStrength: `+200% Потужності Здібностей`,
|
||||||
|
invigorations_offensive_AbilityRange: `+100% Досяжність Здібностей`,
|
||||||
|
invigorations_offensive_AbilityDuration: `+100% Тривалість Здібностей`,
|
||||||
|
invigorations_offensive_MeleeDamage: `+250% Шкода Ближнього Бою`,
|
||||||
|
invigorations_offensive_PrimaryDamage: `+250% Шкода Основного Озброєння`,
|
||||||
|
invigorations_offensive_SecondaryDamage: `+250% Шкода Допоміжного Озброєння`,
|
||||||
|
invigorations_offensive_PrimaryCritChance: `+200% Імовірність Критичної Шкоди Основного Озброєння`,
|
||||||
|
invigorations_offensive_SecondaryCritChance: `+200% Імовірність Критичної Шкоди Допоміжного Озброєння`,
|
||||||
|
invigorations_offensive_MeleeCritChance: `+200% Імовірність Критичної Шкоди Ближнього Бою`,
|
||||||
|
|
||||||
|
invigorations_utility_AbilityEfficiency: `+75% Ощадливість Здібностей`,
|
||||||
|
invigorations_utility_SprintSpeed: `+75% Швидкість Бігу`,
|
||||||
|
invigorations_utility_ParkourVelocity: `+75% Швидкість Паркура`,
|
||||||
|
invigorations_utility_HealthMax: `+1000 Здоров'я`,
|
||||||
|
invigorations_utility_EnergyMax: `+200% Максимум Енергії`,
|
||||||
|
invigorations_utility_StatusImmune: `Імунітет до Ефектів Статусу`,
|
||||||
|
invigorations_utility_ReloadSpeed: `+75% Швидкість Перезаряджання`,
|
||||||
|
invigorations_utility_HealthRegen: `+25 Здоров'я в секунду`,
|
||||||
|
invigorations_utility_ArmorMax: `+1000 Захисту`,
|
||||||
|
invigorations_utility_Jumps: `+5 Оновлень Стрибків`,
|
||||||
|
invigorations_utility_EnergyRegen: `+2 Енергії в секунду`,
|
||||||
|
|
||||||
|
invigorations_offensiveLabel: `Атакуюче Вдосконалення`,
|
||||||
|
invigorations_defensiveLabel: `Вспомогательное Вдосконалення`,
|
||||||
|
invigorations_expiryLabel: `Термін дії Зміцнення (необов'язково)`,
|
||||||
|
|
||||||
|
abilityOverride_label: `Перевизначення здібностей`,
|
||||||
|
abilityOverride_onSlot: `у клітинці`,
|
||||||
|
|
||||||
|
mods_addRiven: `Добавити Модифікатор Розколу`,
|
||||||
|
mods_fingerprint: `Відбиток`,
|
||||||
|
mods_fingerprintHelp: `Потрібна допомога з відбитком?`,
|
||||||
|
mods_rivens: `Модифікатори Розколу`,
|
||||||
|
mods_mods: `Модифікатори`,
|
||||||
|
mods_addMax: `Добавити максимально вдосконалений`,
|
||||||
|
mods_addMissingUnrankedMods: `Добавити недостаючі модифікатори без рівня`,
|
||||||
|
mods_removeUnranked: `Видалити модифікатори без рівня`,
|
||||||
|
mods_addMissingMaxRankMods: `Добавити недостаючі модифікатори максимального рівня`,
|
||||||
|
cheats_administratorRequirement: `Ви повинні бути адміністратором для використання цієї функції. Щоб стати адміністратором, додайте <code>\"|DISPLAYNAME|\"</code> в <code>administratorNames</code> в config.json.`,
|
||||||
|
cheats_server: `Сервер`,
|
||||||
|
cheats_skipTutorial: `Пропустити навчання`,
|
||||||
|
cheats_skipAllDialogue: `Пропустити всі діалоги`,
|
||||||
|
cheats_unlockAllScans: `Розблокувати всі сканування`,
|
||||||
|
cheats_unlockAllMissions: `Розблокувати всі місії`,
|
||||||
|
cheats_unlockAllMissions_ok: `Успіх. Будь ласка, зверніть увагу, що вам потрібно буде увійти в Доджьо/Реле або перезайти, щоб клієнт оновив зоряну мапу.`,
|
||||||
|
cheats_infiniteCredits: `Бескінечні кредити`,
|
||||||
|
cheats_infinitePlatinum: `Бескінечна платина`,
|
||||||
|
cheats_infiniteEndo: `Бескінечне ендо`,
|
||||||
|
cheats_infiniteRegalAya: `Бескінечна Королівська Ая`,
|
||||||
|
cheats_infiniteHelminthMaterials: `Бескінечні Секреції Гельмінта`,
|
||||||
|
cheats_claimingBlueprintRefundsIngredients: `Повернення інгредієнтів креслеників`,
|
||||||
|
cheats_dontSubtractPurchaseCreditCost: `Не вираховувати вартість кредитів при купівлі`,
|
||||||
|
cheats_dontSubtractPurchasePlatinumCost: `Не вираховувати вартість платини при купівлі`,
|
||||||
|
cheats_dontSubtractPurchaseItemCost: `Не вираховувати вартість предметів при купівлі`,
|
||||||
|
cheats_dontSubtractPurchaseStandingCost: `Не вираховувати вартість репутації при купівлі`,
|
||||||
|
cheats_dontSubtractVoidTraces: `Не вираховувати кількість Відголосків Безодні`,
|
||||||
|
cheats_dontSubtractConsumables: `Не вираховувати кількість витратних матеріалів`,
|
||||||
|
cheats_unlockAllShipFeatures: `Розблокувати всі функції судна`,
|
||||||
|
cheats_unlockAllShipDecorations: `Розблокувати всі прикраси судна`,
|
||||||
|
cheats_unlockAllFlavourItems: `Розблокувати всі <abbr title="Набори анімацій, гліфи, палітри і т. д.">унікальні предмети</abbr>`,
|
||||||
|
cheats_unlockAllSkins: `Розблокувати всі скіни`,
|
||||||
|
cheats_unlockAllCapturaScenes: `Розблокувати всі сцени Світлописця`,
|
||||||
|
cheats_unlockAllDecoRecipes: `Розблокувати всі рецепти декорацій Доджьо`,
|
||||||
|
cheats_universalPolarityEverywhere: `Будь-яка полярність скрізь`,
|
||||||
|
cheats_unlockDoubleCapacityPotatoesEverywhere: `Орокінські Реактори/Каталізатори скрізь`,
|
||||||
|
cheats_unlockExilusEverywhere: `Ексилотримач скрізь`,
|
||||||
|
cheats_unlockArcanesEverywhere: `Тримач містифікаторів скрізь`,
|
||||||
|
cheats_noDailyStandingLimits: `Без щоденних лімітів репутації`,
|
||||||
|
cheats_noDailyFocusLimit: `Без щоденних лімітів фокуса`,
|
||||||
|
cheats_noArgonCrystalDecay: `Без розпаду аргонових кристалів`,
|
||||||
|
cheats_noMasteryRankUpCooldown: `Підвищення ранга майстерності без очікування`,
|
||||||
|
cheats_noVendorPurchaseLimits: `Відсутність лімітів на купівлю у продавців`,
|
||||||
|
cheats_noDeathMarks: `Без позначок смерті`,
|
||||||
|
cheats_noKimCooldowns: `Чати KIM без очікування`,
|
||||||
|
cheats_fullyStockedVendors: `Повністю укомплектовані продавці`,
|
||||||
|
cheats_baroAlwaysAvailable: `Баро завжди доступний`,
|
||||||
|
cheats_baroFullyStocked: `Баро повністю укомплектований`,
|
||||||
|
cheats_syndicateMissionsRepeatable: `Повторювати місії синдиката`,
|
||||||
|
cheats_unlockAllProfitTakerStages: `Розблокувати всі етапи Привласнювачки`,
|
||||||
|
cheats_instantFinishRivenChallenge: `Миттєве завершення випробування Модифікатора Розколу`,
|
||||||
|
cheats_instantResourceExtractorDrones: `Миттєво добуваючі дрони-видобувачі`,
|
||||||
|
cheats_noResourceExtractorDronesDamage: `Без шкоди по дронам-видобувачам`,
|
||||||
|
cheats_skipClanKeyCrafting: `Пропустити створення кланового ключа`,
|
||||||
|
cheats_noDojoRoomBuildStage: `Миттєве будівництво Кімнат Доджьо`,
|
||||||
|
cheats_noDojoDecoBuildStage: `Миттєве будівництво Декорацій Доджьо`,
|
||||||
|
cheats_fastDojoRoomDestruction: `Миттєве знищення Кімнат Доджьо`,
|
||||||
|
cheats_noDojoResearchCosts: `Безкоштовні Дослідження Доджьо`,
|
||||||
|
cheats_noDojoResearchTime: `Миттєві Дослідження Доджьо`,
|
||||||
|
cheats_fastClanAscension: `Миттєве Піднесення Клану`,
|
||||||
|
cheats_missionsCanGiveAllRelics: `Місії можуть давати всі реліквії`,
|
||||||
|
cheats_exceptionalRelicsAlwaysGiveBronzeReward: `Вийняткові реліквії завжди дають бронзову нагороду`,
|
||||||
|
cheats_flawlessRelicsAlwaysGiveSilverReward: `Бездоганні реліквії завжди дають срібну нагороду`,
|
||||||
|
cheats_radiantRelicsAlwaysGiveGoldReward: `Сяйнисті реліквії завжди дають золоту нагороду`,
|
||||||
|
cheats_unlockAllSimarisResearchEntries: `Розблокувати всі записи досліджень Симаріса`,
|
||||||
|
cheats_disableDailyTribute: `Вимкнути щоденні нагороди`,
|
||||||
|
cheats_spoofMasteryRank: `Підроблений ранг майстерності (-1 для вимкнення)`,
|
||||||
|
cheats_relicRewardItemCountMultiplier: `Множник кількості предметів нагороди реліквії`,
|
||||||
|
cheats_nightwaveStandingMultiplier: `Множник репутації Нічної хвилі`,
|
||||||
|
cheats_save: `Зберегти`,
|
||||||
|
cheats_account: `Обліковий запис`,
|
||||||
|
cheats_unlockAllFocusSchools: `Розблокувати всі школи фокуса`,
|
||||||
|
cheats_helminthUnlockAll: `Повністю покращити Гельмінта`,
|
||||||
|
cheats_addMissingSubsumedAbilities: `Додати відсутні поглинуті здібності`,
|
||||||
|
cheats_intrinsicsUnlockAll: `Повністю покращити Кваліфікації`,
|
||||||
|
cheats_changeSupportedSyndicate: `Підтримуваний синдикат`,
|
||||||
|
cheats_changeButton: `Змінити`,
|
||||||
|
cheats_markAllAsRead: `Помітити всі вхідні як прочитані`,
|
||||||
|
|
||||||
|
worldState: `Стан світу`,
|
||||||
|
worldState_creditBoost: `Глобальний бустер кредитів`,
|
||||||
|
worldState_affinityBoost: `Глобальний бустер синтезу`,
|
||||||
|
worldState_resourceBoost: `Глобальний бустер ресурсів`,
|
||||||
|
worldState_tennoLiveRelay: `Реле TennoLive`,
|
||||||
|
worldState_baroTennoConRelay: `Реле Баро TennoCon`,
|
||||||
|
worldState_starDays: `Зоряні дні`,
|
||||||
|
worldState_galleonOfGhouls: `Гульський Галеон`,
|
||||||
|
worldState_ghoulEmergence: `Зачищення від гулів`,
|
||||||
|
worldState_plagueStar: `Морова зірка`,
|
||||||
|
worldState_waterFight: `Спекотні дні`,
|
||||||
|
worldState_waterFightRewards: `[UNTRANSLATED] Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `[UNTRANSLATED] from 2025`,
|
||||||
|
worldState_from_2024: `[UNTRANSLATED] from 2024`,
|
||||||
|
worldState_from_2023: `[UNTRANSLATED] from 2023`,
|
||||||
|
worldState_pre_2023: `[UNTRANSLATED] pre 2023`,
|
||||||
|
enabled: `Увімкнено`,
|
||||||
|
disabled: `Вимкнено`,
|
||||||
|
worldState_we1: `Вихідні 1`,
|
||||||
|
worldState_we2: `Вихідні 2`,
|
||||||
|
worldState_we3: `Вихідні 3`,
|
||||||
|
worldState_eidolonOverride: `Цикл Рівнин Ейдолонів/Деймоса`,
|
||||||
|
worldState_day: `День/Фасс`,
|
||||||
|
worldState_night: `Ніч/Воум`,
|
||||||
|
worldState_vallisOverride: `Цикл Долини куль`,
|
||||||
|
worldState_warm: `Тепло`,
|
||||||
|
worldState_cold: `Холод`,
|
||||||
|
worldState_duviriOverride: `Цикл Дувірі`,
|
||||||
|
worldState_joy: `Радість`,
|
||||||
|
worldState_anger: `Гнів`,
|
||||||
|
worldState_envy: `Заздрість`,
|
||||||
|
worldState_sorrow: `Скорбота`,
|
||||||
|
worldState_fear: `Страх`,
|
||||||
|
worldState_nightwaveOverride: `Сезон Нічної хвилі`,
|
||||||
|
worldState_RadioLegionIntermission13Syndicate: `Вибірка Нори 9`,
|
||||||
|
worldState_RadioLegionIntermission12Syndicate: `Вибірка Нори 8`,
|
||||||
|
worldState_RadioLegionIntermission11Syndicate: `Вибірка Нори 7`,
|
||||||
|
worldState_RadioLegionIntermission10Syndicate: `Вибірка Нори 6`,
|
||||||
|
worldState_RadioLegionIntermission9Syndicate: `Вибірка Нори 5`,
|
||||||
|
worldState_RadioLegionIntermission8Syndicate: `Вибірка Нори 4`,
|
||||||
|
worldState_RadioLegionIntermission7Syndicate: `Вибірка Нори 3`,
|
||||||
|
worldState_RadioLegionIntermission6Syndicate: `Вибірка Нори 2`,
|
||||||
|
worldState_RadioLegionIntermission5Syndicate: `Вибірка Нори 1`,
|
||||||
|
worldState_RadioLegionIntermission4Syndicate: `Вибір Нори`,
|
||||||
|
worldState_RadioLegionIntermission3Syndicate: `Антракт III`,
|
||||||
|
worldState_RadioLegion3Syndicate: `Скляр`,
|
||||||
|
worldState_RadioLegionIntermission2Syndicate: `Антракт II`,
|
||||||
|
worldState_RadioLegion2Syndicate: `Емісар`,
|
||||||
|
worldState_RadioLegionIntermissionSyndicate: `Антракт I`,
|
||||||
|
worldState_RadioLegionSyndicate: `Вовк із Сатурна-6`,
|
||||||
|
worldState_fissures: `Прориви порожнечі`,
|
||||||
|
normal: `Стандартні`,
|
||||||
|
worldState_allAtOnceNormal: `Всі одразу, в звичайному режимі`,
|
||||||
|
worldState_allAtOnceSteelPath: `Всі одразу, в режимі Шляху Сталі`,
|
||||||
|
worldState_theCircuitOverride: `Типи місій у підземеллі Дувірі`,
|
||||||
|
worldState_darvoStockMultiplier: `Множник Запасів Дарво`,
|
||||||
|
worldState_varziaFullyStocked: `Повний Асортимент Варзії`,
|
||||||
|
worldState_varziaOverride: `Зміна Ротації Варзії`,
|
||||||
|
|
||||||
|
import_importNote: `Ви можете завантажити повну або часткову відповідь спорядження (клієнтське представлення) тут. Всі підтримувані поля <b>будуть перезаписані</b> у вашому акаунті.`,
|
||||||
|
import_submit: `Відправити`,
|
||||||
|
import_samples: `Приклад:`,
|
||||||
|
import_samples_maxFocus: `Всі школи Фокуса максимального рівня`,
|
||||||
|
|
||||||
|
upgrade_Equilibrium: `+|VAL|% Енергія від підбирання здоров'я, +|VAL|% Здоров'я від підбирання енергії`,
|
||||||
|
upgrade_MeleeCritDamage: `+|VAL|% Критична шкода ближнього бою`,
|
||||||
|
upgrade_PrimaryStatusChance: `+|VAL|% Імовірність накладення ефекту стану основною зброєю`,
|
||||||
|
upgrade_SecondaryCritChance: `+|VAL|% Імовірність критичної шкоди допоміжною зброєю`,
|
||||||
|
upgrade_WarframeAbilityDuration: `+|VAL|% Тривалість здібностей`,
|
||||||
|
upgrade_WarframeAbilityStrength: `+|VAL|% Потужність здібностей`,
|
||||||
|
upgrade_WarframeArmorMax: `+|VAL| Захист`,
|
||||||
|
upgrade_WarframeBlastProc: `+|VAL| Щит при вбивстві з Вибуховим Уронoм`,
|
||||||
|
upgrade_WarframeCastingSpeed: `+|VAL|% Швидкість Застосування Здібностей`,
|
||||||
|
upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% Урон Здібностей по ворогам, ураженим Корозією`,
|
||||||
|
upgrade_WarframeCorrosiveStack: `Збільшити макс. стаки Корозії на +|VAL|`,
|
||||||
|
upgrade_WarframeCritDamageBoost: `+|VAL|% Критична шкода Ближнього Бою (Подвоюється при 500 Енергії)`,
|
||||||
|
upgrade_WarframeElectricDamage: `+|VAL1|% Урон Електрикою Основним Озброєнням (+|VAL2|% за кожен додатковий Уламок)`,
|
||||||
|
upgrade_WarframeElectricDamageBoost: `+|VAL|% Шкода Здібностей по ворогам, ураженим Електрикою`,
|
||||||
|
upgrade_WarframeEnergyMax: `+|VAL| Макс. Енергія`,
|
||||||
|
upgrade_WarframeGlobeEffectEnergy: `+|VAL|% Ефективність згустків Енергії`,
|
||||||
|
upgrade_WarframeGlobeEffectHealth: `+|VAL|% Ефективність згустків Здоров'я`,
|
||||||
|
upgrade_WarframeHealthMax: `+|VAL| Макс. Здоров'я`,
|
||||||
|
upgrade_WarframeHPBoostFromImpact: `+|VAL1| Здоров'я при вбивстві з Вибуховою шкодою (Макс. |VAL2| Здоров'я)`,
|
||||||
|
upgrade_WarframeParkourVelocity: `+|VAL|% Швидкість Паркура`,
|
||||||
|
upgrade_WarframeRadiationDamageBoost: `+|VAL|% Шкода Здібностей по ворогам, ураженим Радіацією`,
|
||||||
|
upgrade_WarframeHealthRegen: `+|VAL| Здоров'я в секунду`,
|
||||||
|
upgrade_WarframeShieldMax: `+|VAL| Щиту`,
|
||||||
|
upgrade_WarframeStartingEnergy: `+|VAL|% Енергії при Спавні`,
|
||||||
|
upgrade_WarframeToxinDamage: `+|VAL|% Шкода Токсином`,
|
||||||
|
upgrade_WarframeToxinHeal: `+|VAL| Здоров'я при нанесенні шкоди ворогам з Токсином`,
|
||||||
|
upgrade_WeaponCritBoostFromHeat: `+|VAL1|% Імовірність Критичної Шкоди Допоміжною Зброєю за кожного вбитого ворога, ураженого Термічною шкодою (Макс. |VAL2|%)`,
|
||||||
|
upgrade_AvatarAbilityRange: `+7.5% Досяжність Здібностей`,
|
||||||
|
upgrade_AvatarAbilityEfficiency: `+5% Ощадливість Здібностей`,
|
||||||
|
upgrade_AvatarEnergyRegen: `+0.5 Відновлення Енергії в секунду`,
|
||||||
|
upgrade_AvatarEnemyRadar: `+5m Виявлення ворогів`,
|
||||||
|
upgrade_AvatarLootRadar: `+7m Виявлення здобичі`,
|
||||||
|
upgrade_WeaponAmmoMax: `+15% Макс. Набоїв`,
|
||||||
|
upgrade_EnemyArmorReductionAura: `-3% Захист Ворогів`,
|
||||||
|
upgrade_OnExecutionAmmo: `+100% Заповнення Магазина Основного і Допоміжного Озброєння при вбивстві Милосердям`,
|
||||||
|
upgrade_OnExecutionHealthDrop: `+100% Імовірність Падіння згустка Здоров'я при вбивстві Милосердям`,
|
||||||
|
upgrade_OnExecutionEnergyDrop: `+50% Імовірність Падіння згустка Енергії при вбивстві Милосердям`,
|
||||||
|
upgrade_OnFailHackReset: `+50% Імовірність Повтора Зламу`,
|
||||||
|
upgrade_DamageReductionOnHack: `+75% Зменшення Шкоди під час Зламу`,
|
||||||
|
upgrade_OnExecutionReviveCompanion: `Вбивства Милосердям зменшують час відновлення Компаньйона на 15 секунд`,
|
||||||
|
upgrade_OnExecutionParkourSpeed: `+60% Швидкість Паркура після вбивства Милосердям на 15 секунд`,
|
||||||
|
upgrade_AvatarTimeLimitIncrease: `+8 секунд до Зламу`,
|
||||||
|
upgrade_ElectrifyOnHack: `Шокувати ворогів в межах 20 метрів під час Зламу`,
|
||||||
|
upgrade_OnExecutionTerrify: `+50% Імовірність, що вороги в межах 15 метрів будуть тремтіти від страху протягом 8 секунд після вбивства Милосердям`,
|
||||||
|
upgrade_OnHackLockers: `Відкрити 5 шафок в межах 20 метрів після Зламу`,
|
||||||
|
upgrade_OnExecutionBlind: `Засліпити ворогів в межах 18 метрів після вбивства Милосердям`,
|
||||||
|
upgrade_OnExecutionDrainPower: `Наступне застосування здібності отримує +50% Потужності Здібності після вбивства Милосердям`,
|
||||||
|
upgrade_OnHackSprintSpeed: `+75% Швидкість Бігу протягом 15 секунд після Зламу`,
|
||||||
|
upgrade_SwiftExecute: `+50% Швидкість Вбивства Милосердям`,
|
||||||
|
upgrade_OnHackInvis: `Невидимість протягом 15 секунд після Зламу`,
|
||||||
|
|
||||||
|
damageType_Electricity: `Електричний`,
|
||||||
|
damageType_Fire: `Трммічний`,
|
||||||
|
damageType_Freeze: `Крижаний`,
|
||||||
|
damageType_Impact: `Ударний`,
|
||||||
|
damageType_Magnetic: `Магнетичний`,
|
||||||
|
damageType_Poison: `Токсичний`,
|
||||||
|
damageType_Radiation: `Радіаційний`,
|
||||||
|
|
||||||
|
theme_dark: `Темна тема`,
|
||||||
|
theme_light: `Світла тема`,
|
||||||
|
|
||||||
|
prettier_sucks_ass: ``
|
||||||
|
};
|
@ -1,16 +1,16 @@
|
|||||||
// Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang & Corvus
|
// Chinese translation by meb154, bishan178, nyaoouo, qianlishun, CrazyZhang, Corvus, & qingchun
|
||||||
dict = {
|
dict = {
|
||||||
general_inventoryUpdateNote: `注意:要在游戏中查看更改,您需要重新同步库存,例如使用引导程序的 /sync 命令、访问道场/中继站或重新登录客户端.`,
|
general_inventoryUpdateNote: `注意: 要在游戏中查看更改,您需要重新同步库存,例如使用客户端的 /sync 命令,访问道场/中继站或重新登录。`,
|
||||||
general_addButton: `添加`,
|
general_addButton: `添加`,
|
||||||
general_setButton: `设置`,
|
general_setButton: `设置`,
|
||||||
general_none: `无`,
|
general_none: `无`,
|
||||||
general_bulkActions: `批量操作`,
|
general_bulkActions: `批量操作`,
|
||||||
general_loading: `加载中...`,
|
general_loading: `加载中...`,
|
||||||
|
|
||||||
code_loginFail: `登录失败.请检查邮箱和密码.`,
|
code_loginFail: `登录失败。请检查邮箱和密码。`,
|
||||||
code_regFail: `注册失败.账号已存在.`,
|
code_regFail: `注册失败。账号是否已存在?`,
|
||||||
code_changeNameConfirm: `您想将账户名称更改为?`,
|
code_changeNameConfirm: `您想将账户名称更改为?`,
|
||||||
code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME|(|EMAIL|)吗?此操作不可撤销。`,
|
code_deleteAccountConfirm: `确定要删除您的账户 |DISPLAYNAME|(|EMAIL|) 吗?此操作不可撤销。`,
|
||||||
code_archgun: `空战`,
|
code_archgun: `空战`,
|
||||||
code_melee: `近战`,
|
code_melee: `近战`,
|
||||||
code_pistol: `手枪`,
|
code_pistol: `手枪`,
|
||||||
@ -27,13 +27,13 @@ dict = {
|
|||||||
code_badItem: `(Imposter)`,
|
code_badItem: `(Imposter)`,
|
||||||
code_maxRank: `满级`,
|
code_maxRank: `满级`,
|
||||||
code_rename: `重命名`,
|
code_rename: `重命名`,
|
||||||
code_renamePrompt: `输入新的自定义名称:`,
|
code_renamePrompt: `输入新的自定义名称:`,
|
||||||
code_remove: `移除`,
|
code_remove: `移除`,
|
||||||
code_addItemsConfirm: `确定要向账户添加|COUNT|件物品吗?`,
|
code_addItemsConfirm: `确定要向您的账户添加 |COUNT| 件物品吗?`,
|
||||||
code_succRankUp: `等级已提升`,
|
code_succRankUp: `等级已提升`,
|
||||||
code_noEquipmentToRankUp: `没有可升级的装备。`,
|
code_noEquipmentToRankUp: `没有可升级的装备`,
|
||||||
code_succAdded: `已成功添加。`,
|
code_succAdded: `添加成功`,
|
||||||
code_succRemoved: `已成功移除。`,
|
code_succRemoved: `移除成功`,
|
||||||
code_buffsNumber: `增益数量`,
|
code_buffsNumber: `增益数量`,
|
||||||
code_cursesNumber: `负面数量`,
|
code_cursesNumber: `负面数量`,
|
||||||
code_rerollsNumber: `洗卡次数`,
|
code_rerollsNumber: `洗卡次数`,
|
||||||
@ -42,12 +42,12 @@ dict = {
|
|||||||
code_rankUp: `等级提升`,
|
code_rankUp: `等级提升`,
|
||||||
code_rankDown: `等级下降`,
|
code_rankDown: `等级下降`,
|
||||||
code_count: `数量`,
|
code_count: `数量`,
|
||||||
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
code_focusAllUnlocked: `所有专精学派均已解锁`,
|
||||||
code_focusUnlocked: `已解锁|COUNT|个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新.`,
|
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
||||||
code_addModsConfirm: `确定要向账户添加|COUNT|张MOD吗?`,
|
code_addModsConfirm: `确定要向您的账户添加 |COUNT| 张MOD吗?`,
|
||||||
code_succImport: `导入成功。`,
|
code_succImport: `导入成功`,
|
||||||
code_succRelog: `完成. 需要重新登录游戏才能看到变化.`,
|
code_succRelog: `完成。需要重新登录游戏才能看到变化。`,
|
||||||
code_nothingToDo: `完成. 没有可执行的操作.`,
|
code_nothingToDo: `完成。没有可执行的操作。`,
|
||||||
code_gild: `镀金`,
|
code_gild: `镀金`,
|
||||||
code_moa: `恐鸟`,
|
code_moa: `恐鸟`,
|
||||||
code_zanuka: `猎犬`,
|
code_zanuka: `猎犬`,
|
||||||
@ -62,9 +62,9 @@ dict = {
|
|||||||
code_pigment: `颜料`,
|
code_pigment: `颜料`,
|
||||||
code_mature: `成长并战备`,
|
code_mature: `成长并战备`,
|
||||||
code_unmature: `逆转衰老基因`,
|
code_unmature: `逆转衰老基因`,
|
||||||
code_succChange: `更改成功.`,
|
code_succChange: `更改成功`,
|
||||||
code_requiredInvigorationUpgrade: `您必须同时选择一个进攻型和一个功能型活化属性.`,
|
code_requiredInvigorationUpgrade: `您必须同时选择一个进攻型和一个功能型活化属性。`,
|
||||||
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同).`,
|
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)`,
|
||||||
login_emailLabel: `电子邮箱`,
|
login_emailLabel: `电子邮箱`,
|
||||||
login_passwordLabel: `密码`,
|
login_passwordLabel: `密码`,
|
||||||
login_loginButton: `登录`,
|
login_loginButton: `登录`,
|
||||||
@ -125,7 +125,7 @@ dict = {
|
|||||||
detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`,
|
detailedView_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`,
|
||||||
detailedView_archonShardsDescription2: `请注意,在加载时,每个执政官源力石都需要一定的时间来生效。`,
|
detailedView_archonShardsDescription2: `请注意,在加载时,每个执政官源力石都需要一定的时间来生效。`,
|
||||||
detailedView_valenceBonusLabel: `效价加成`,
|
detailedView_valenceBonusLabel: `效价加成`,
|
||||||
detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成.`,
|
detailedView_valenceBonusDescription: `您可以设置或移除武器上的效价加成。`,
|
||||||
detailedView_modularPartsLabel: `更换部件`,
|
detailedView_modularPartsLabel: `更换部件`,
|
||||||
detailedView_suitInvigorationLabel: `编辑战甲活化属性`,
|
detailedView_suitInvigorationLabel: `编辑战甲活化属性`,
|
||||||
detailedView_loadoutLabel: `配置`,
|
detailedView_loadoutLabel: `配置`,
|
||||||
@ -168,19 +168,19 @@ dict = {
|
|||||||
mods_addMissingUnrankedMods: `添加所有缺失的Mods`,
|
mods_addMissingUnrankedMods: `添加所有缺失的Mods`,
|
||||||
mods_removeUnranked: `删除所有未升级的Mods`,
|
mods_removeUnranked: `删除所有未升级的Mods`,
|
||||||
mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`,
|
mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`,
|
||||||
cheats_administratorRequirement: `您必须是管理员才能使用此功能.要成为管理员,请将 <code>|DISPLAYNAME|</code> 添加到 config.json 的 <code>administratorNames</code> 中.`,
|
cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请在 config.json 中将 <code>|DISPLAYNAME|</code> 添加到 <code>administratorNames</code>`,
|
||||||
cheats_server: `服务器`,
|
cheats_server: `服务器`,
|
||||||
cheats_skipTutorial: `跳过教程`,
|
cheats_skipTutorial: `跳过教程`,
|
||||||
cheats_skipAllDialogue: `跳过所有对话`,
|
cheats_skipAllDialogue: `跳过所有对话`,
|
||||||
cheats_unlockAllScans: `解锁所有扫描`,
|
cheats_unlockAllScans: `解锁所有扫描`,
|
||||||
cheats_unlockAllMissions: `解锁所有任务`,
|
cheats_unlockAllMissions: `解锁所有星图`,
|
||||||
cheats_unlockAllMissions_ok: `操作成功.请注意,您需要进入道场/中继站或重新登录客户端以刷新星图数据。`,
|
cheats_unlockAllMissions_ok: `操作成功。请注意,您需要进入道场/中继站或重新登录以刷新星图数据。`,
|
||||||
cheats_infiniteCredits: `无限现金`,
|
cheats_infiniteCredits: `无限现金`,
|
||||||
cheats_infinitePlatinum: `无限白金`,
|
cheats_infinitePlatinum: `无限白金`,
|
||||||
cheats_infiniteEndo: `无限内融核心`,
|
cheats_infiniteEndo: `无限内融核心`,
|
||||||
cheats_infiniteRegalAya: `无限御品阿耶`,
|
cheats_infiniteRegalAya: `无限御品阿耶`,
|
||||||
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
||||||
cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`,
|
cheats_claimingBlueprintRefundsIngredients: `蓝图制造完成领取后返还材料`,
|
||||||
cheats_dontSubtractPurchaseCreditCost: `购物时不减少现金花费`,
|
cheats_dontSubtractPurchaseCreditCost: `购物时不减少现金花费`,
|
||||||
cheats_dontSubtractPurchasePlatinumCost: `购物时不减少白金花费`,
|
cheats_dontSubtractPurchasePlatinumCost: `购物时不减少白金花费`,
|
||||||
cheats_dontSubtractPurchaseItemCost: `购物时不减少物品花费`,
|
cheats_dontSubtractPurchaseItemCost: `购物时不减少物品花费`,
|
||||||
@ -246,6 +246,14 @@ dict = {
|
|||||||
worldState_baroTennoConRelay: `Baro的TennoCon中继站`,
|
worldState_baroTennoConRelay: `Baro的TennoCon中继站`,
|
||||||
worldState_starDays: `活动:星日`,
|
worldState_starDays: `活动:星日`,
|
||||||
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
|
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
|
||||||
|
worldState_ghoulEmergence: `尸鬼净化`,
|
||||||
|
worldState_plagueStar: `瘟疫之星`,
|
||||||
|
worldState_waterFight: `三伏天`,
|
||||||
|
worldState_waterFightRewards: `[UNTRANSLATED] Dog Days Rewards`,
|
||||||
|
worldState_from_2025: `[UNTRANSLATED] from 2025`,
|
||||||
|
worldState_from_2024: `[UNTRANSLATED] from 2024`,
|
||||||
|
worldState_from_2023: `[UNTRANSLATED] from 2023`,
|
||||||
|
worldState_pre_2023: `[UNTRANSLATED] pre 2023`,
|
||||||
enabled: `启用`,
|
enabled: `启用`,
|
||||||
disabled: `关闭/取消配置`,
|
disabled: `关闭/取消配置`,
|
||||||
worldState_we1: `活动阶段:第一周`,
|
worldState_we1: `活动阶段:第一周`,
|
||||||
@ -289,7 +297,7 @@ dict = {
|
|||||||
worldState_varziaFullyStocked: `瓦奇娅开启全部库存商品`,
|
worldState_varziaFullyStocked: `瓦奇娅开启全部库存商品`,
|
||||||
worldState_varziaOverride: `瓦奇娅(Prime重生)轮换状态`,
|
worldState_varziaOverride: `瓦奇娅(Prime重生)轮换状态`,
|
||||||
|
|
||||||
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示).支持的所有字段<b>将被覆盖</b>到您的账户中.`,
|
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
|
||||||
import_submit: `提交`,
|
import_submit: `提交`,
|
||||||
import_samples: `示例:`,
|
import_samples: `示例:`,
|
||||||
import_samples_maxFocus: `所有专精学派完全精通`,
|
import_samples_maxFocus: `所有专精学派完全精通`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user