XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat(goals): cetus events (#2598)

Includes `Plague Star` and `Ghoul Purge`. Translation for webUI taken from game files. Re #1103 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2598 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>

51c0ddda
AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
提交于

代码差异

13 个文件 +305 -38
Modified config-vanilla.json +2 -0
@@ -72,6 +72,8 @@
72 72 "resourceBoost": false,
73 73 "tennoLiveRelay": false,
74 74 "galleonOfGhouls": 0,
75 "ghoulEmergenceOverride": null,
76 "plagueStarOverride": null,
75 77 "starDaysOverride": null,
76 78 "eidolonOverride": "",
77 79 "vallisOverride": "",
Modified src/services/configService.ts +2 -0
@@ -84,6 +84,8 @@ export interface IConfig {
84 84 tennoLiveRelay?: boolean;
85 85 baroTennoConRelay?: boolean;
86 86 galleonOfGhouls?: number;
87 ghoulEmergenceOverride?: boolean;
88 plagueStarOverride?: boolean;
87 89 starDaysOverride?: boolean;
88 90 eidolonOverride?: string;
89 91 vallisOverride?: string;
Modified src/services/missionInventoryUpdateService.ts +68 -22
@@ -76,7 +76,7 @@ import {
76 76 } from "@/src/services/worldStateService";
77 77 import { config } from "@/src/services/configService";
78 78 import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
79 import { ISyndicateMissionInfo } from "@/src/types/worldStateTypes";
79 import { IGoal, ISyndicateMissionInfo } from "@/src/types/worldStateTypes";
80 80 import { fromOid } from "@/src/helpers/inventoryHelpers";
81 81 import { TAccountDocument } from "@/src/services/loginService";
82 82 import { ITypeCount } from "@/src/types/commonTypes";
@@ -1259,6 +1259,8 @@ export const addMissionRewards = async (
1259 1259 }
1260 1260 }
1261 1261
1262 AffiliationMods ??= [];
1263
1262 1264 if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
1263 1265 // eslint-disable-next-line @typescript-eslint/no-unused-vars
1264 1266 const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_");
@@ -1266,9 +1268,29 @@ export const addMissionRewards = async (
1266 1268 if (syndicateMissionId) {
1267 1269 pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
1268 1270 }
1269 const syndicateEntry = syndicateMissions.find(m => m._id.$oid === syndicateMissionId);
1271 let syndicateEntry: ISyndicateMissionInfo | IGoal | undefined = syndicateMissions.find(
1272 m => m._id.$oid === syndicateMissionId
1273 );
1274 if (
1275 [
1276 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
1277 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
1278 ].some(prefix => jobType.startsWith(prefix))
1279 ) {
1280 const { Goals } = getWorldState(undefined);
1281 syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
1282 if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
1283 }
1270 1284 if (syndicateEntry && syndicateEntry.Jobs) {
1271 1285 let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
1286 if (
1287 [
1288 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
1289 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
1290 ].some(prefix => jobType.startsWith(prefix))
1291 ) {
1292 currentJob = syndicateEntry.Jobs.find(j => j.jobType === jobType)!;
1293 }
1272 1294 if (syndicateEntry.Tag === "EntratiSyndicate") {
1273 1295 if (
1274 1296 [
@@ -1311,31 +1333,35 @@ export const addMissionRewards = async (
1311 1333 `Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
1312 1334 );
1313 1335 } else {
1314 if (rewardInfo.JobTier! >= 0) {
1315 addStanding(
1316 inventory,
1317 syndicateEntry.Tag,
1318 Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)),
1319 AffiliationMods
1320 );
1321 } else {
1322 if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) {
1323 addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
1324 }
1325 if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) {
1326 addStanding(inventory, syndicateEntry.Tag, 5000, AffiliationMods);
1327 }
1328 if (
1329 [
1336 const specialCase = [
1337 { endings: ["Heists/HeistProfitTakerBountyOne"], stage: 2, amount: 1000 },
1338 { endings: ["Hunts/AllTeralystsHunt"], stage: 2, amount: 5000 },
1339 {
1340 endings: [
1330 1341 "Hunts/TeralystHunt",
1331 1342 "Heists/HeistProfitTakerBountyTwo",
1332 1343 "Heists/HeistProfitTakerBountyThree",
1333 1344 "Heists/HeistProfitTakerBountyFour",
1334 1345 "Heists/HeistExploiterBountyOne"
1335 ].some(ending => jobType.endsWith(ending))
1336 ) {
1337 addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
1346 ],
1347 amount: 1000
1338 1348 }
1349 ];
1350 const specialCaseReward = specialCase.find(
1351 rule =>
1352 rule.endings.some(e => jobType.endsWith(e)) &&
1353 (rule.stage === undefined || rewardInfo.JobStage === rule.stage)
1354 );
1355
1356 if (specialCaseReward) {
1357 addStanding(inventory, syndicateEntry.Tag, specialCaseReward.amount, AffiliationMods);
1358 } else {
1359 addStanding(
1360 inventory,
1361 syndicateEntry.Tag,
1362 Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)),
1363 AffiliationMods
1364 );
1339 1365 }
1340 1366 }
1341 1367 }
@@ -1672,7 +1698,19 @@ function getRandomMissionDrops(
1672 1698 if (syndicateMissionId) {
1673 1699 pushClassicBounties(syndicateMissions, idToBountyCycle(syndicateMissionId));
1674 1700 }
1675 const syndicateEntry = syndicateMissions.find(m => m._id.$oid === syndicateMissionId);
1701 let syndicateEntry: ISyndicateMissionInfo | IGoal | undefined = syndicateMissions.find(
1702 m => m._id.$oid === syndicateMissionId
1703 );
1704 if (
1705 [
1706 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
1707 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
1708 ].some(prefix => jobType.startsWith(prefix))
1709 ) {
1710 const { Goals } = getWorldState(undefined);
1711 syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
1712 if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
1713 }
1676 1714 if (syndicateEntry && syndicateEntry.Jobs) {
1677 1715 let job = syndicateEntry.Jobs[RewardInfo.JobTier!];
1678 1716
@@ -1757,6 +1795,14 @@ function getRandomMissionDrops(
1757 1795 }
1758 1796 }
1759 1797 }
1798 if (
1799 [
1800 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
1801 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBounty"
1802 ].some(prefix => jobType.startsWith(prefix))
1803 ) {
1804 job = syndicateEntry.Jobs.find(j => j.jobType === jobType)!;
1805 }
1760 1806 rewardManifests = [job.rewards];
1761 1807 if (job.xpAmounts.length > 1) {
1762 1808 const curentStage = RewardInfo.JobStage! + 1;
Modified src/services/worldStateService.ts +170 -0
@@ -131,6 +131,13 @@ const eidolonNarmerJobs: readonly string[] = [
131 131 "/Lotus/Types/Gameplay/Eidolon/Jobs/Narmer/AttritionBountyLib"
132 132 ];
133 133
134 const eidolonGhoulJobs: readonly string[] = [
135 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyAss",
136 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyExt",
137 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyHunt",
138 "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/GhoulAlertBountyRes"
139 ];
140
134 141 const venusJobs: readonly string[] = [
135 142 "/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobAmbush",
136 143 "/Lotus/Types/Gameplay/Venus/Jobs/VenusArtifactJobExcavation",
@@ -1556,6 +1563,72 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1556 1563 });
1557 1564 }
1558 1565
1566 const firstNovemberWeekday = new Date(Date.UTC(date.getUTCFullYear(), 10, 1)).getUTCDay();
1567 const firstNovemberMondayOffset = (8 - firstNovemberWeekday) % 7;
1568
1569 const plagueStarStart = Date.UTC(date.getUTCFullYear(), 10, firstNovemberMondayOffset + 1, 16);
1570 const plagueStarEnd = Date.UTC(date.getUTCFullYear(), 10, firstNovemberMondayOffset + 15, 16);
1571
1572 const isPlagueStarActive = timeMs >= plagueStarStart && timeMs < plagueStarEnd;
1573 if (config.worldState?.plagueStarOverride ?? isPlagueStarActive) {
1574 worldState.Goals.push({
1575 _id: { $oid: "654a5058c757487cdb11824f" },
1576 Activation: {
1577 $date: {
1578 $numberLong: config.worldState?.plagueStarOverride ? "1699372800000" : plagueStarStart.toString()
1579 }
1580 },
1581 Expiry: {
1582 $date: {
1583 $numberLong: config.worldState?.plagueStarOverride ? "2000000000000" : plagueStarEnd.toString()
1584 }
1585 },
1586 Tag: "InfestedPlains",
1587 RegionIdx: 2,
1588 Faction: "FC_INFESTATION",
1589 Desc: "/Lotus/Language/InfestedPlainsEvent/InfestedPlainsBountyName",
1590 ToolTip: "/Lotus/Language/InfestedPlainsEvent/InfestedPlainsBountyDesc",
1591 Icon: "/Lotus/Materials/Emblems/PlagueStarEventBadge_e.png",
1592 JobAffiliationTag: "EventSyndicate",
1593 Jobs: [
1594 {
1595 jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBounty",
1596 rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableRewards",
1597 minEnemyLevel: 15,
1598 maxEnemyLevel: 25,
1599 xpAmounts: [50, 300, 100, 575]
1600 },
1601 {
1602 jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBountyAdvanced",
1603 rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableRewards",
1604 minEnemyLevel: 55,
1605 maxEnemyLevel: 65,
1606 xpAmounts: [200, 1000, 300, 1700],
1607 requiredItems: [
1608 "/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventIngredient",
1609 "/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventClanIngredient"
1610 ],
1611 useRequiredItemsAsMiscItemFee: true
1612 },
1613 {
1614 jobType: "/Lotus/Types/Gameplay/Eidolon/Jobs/Events/InfestedPlainsBountySteelPath",
1615 rewards: "/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/PlagueStarTableSteelPathRewards",
1616 minEnemyLevel: 100,
1617 maxEnemyLevel: 110,
1618 xpAmounts: [200, 1100, 400, 2100],
1619 masteryReq: 10,
1620 requiredItems: [
1621 "/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventIngredient",
1622 "/Lotus/StoreItems/Types/Items/Eidolon/InfestedEventClanIngredient"
1623 ],
1624 useRequiredItemsAsMiscItemFee: true
1625 }
1626 ],
1627 Transmission: "/Lotus/Sounds/Dialog/PlainsMeteorLeadUp/LeadUp/DLeadUp0021Lotus",
1628 InstructionalItem: "/Lotus/Types/StoreItems/Packages/PlagueStarEventStoreItem"
1629 });
1630 }
1631
1559 1632 // Nightwave Challenges
1560 1633 const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
1561 1634 if (nightwaveSyndicateTag) {
@@ -1626,6 +1699,103 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1626 1699 pushClassicBounties(worldState.SyndicateMissions, bountyCycle);
1627 1700 } while (isBeforeNextExpectedWorldStateRefresh(timeMs, bountyCycleEnd) && ++bountyCycle);
1628 1701
1702 const ghoulsCycleDay = day % 21;
1703 const isGhoulEmergenceActive = ghoulsCycleDay >= 17 && ghoulsCycleDay <= 20; // 4 days for event and 17 days for break
1704 if (config.worldState?.ghoulEmergenceOverride ?? isGhoulEmergenceActive) {
1705 const ghoulPool = [...eidolonGhoulJobs];
1706 const pastGhoulPool = [...eidolonGhoulJobs];
1707
1708 const seed = new SRng(bountyCycle).randomInt(0, 100_000);
1709 const pastSeed = new SRng(bountyCycle - 1).randomInt(0, 100_000);
1710
1711 const rng = new SRng(seed);
1712 const pastRng = new SRng(pastSeed);
1713
1714 const activeStartDay = day - ghoulsCycleDay + 17;
1715 const activeEndDay = activeStartDay + 5;
1716 const dayWithFraction = (timeMs - EPOCH) / 86400000;
1717
1718 const progress = (dayWithFraction - activeStartDay) / (activeEndDay - activeStartDay);
1719 const healthPct = 1 - Math.min(Math.max(progress, 0), 1);
1720
1721 worldState.Goals.push({
1722 _id: { $oid: "687ebbe6d1d17841c9c59f38" },
1723 Activation: {
1724 $date: {
1725 $numberLong: config.worldState?.ghoulEmergenceOverride
1726 ? "1753204900185"
1727 : Date.UTC(
1728 date.getUTCFullYear(),
1729 date.getUTCMonth(),
1730 date.getUTCDate() + (day - ghoulsCycleDay + 17)
1731 ).toString()
1732 }
1733 },
1734 Expiry: {
1735 $date: {
1736 $numberLong: config.worldState?.ghoulEmergenceOverride
1737 ? "2000000000000"
1738 : Date.UTC(
1739 date.getUTCFullYear(),
1740 date.getUTCMonth(),
1741 date.getUTCDate() + (day - ghoulsCycleDay + 21)
1742 ).toString()
1743 }
1744 },
1745 HealthPct: config.worldState?.ghoulEmergenceOverride ? 1 : healthPct,
1746 VictimNode: "SolNode228",
1747 Regions: [2],
1748 Success: 0,
1749 Desc: "/Lotus/Language/GameModes/RecurringGhoulAlert",
1750 ToolTip: "/Lotus/Language/GameModes/RecurringGhoulAlertDesc",
1751 Icon: "/Lotus/Interface/Icons/Categories/IconGhouls256.png",
1752 Tag: "GhoulEmergence",
1753 JobAffiliationTag: "CetusSyndicate",
1754 JobCurrentVersion: {
1755 $oid: ((bountyCycle * 9000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
1756 },
1757 Jobs: [
1758 {
1759 jobType: rng.randomElementPop(ghoulPool),
1760 rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards`,
1761 masteryReq: 1,
1762 minEnemyLevel: 15,
1763 maxEnemyLevel: 25,
1764 xpAmounts: [270, 270, 270, 400] // not faithful
1765 },
1766 {
1767 jobType: rng.randomElementPop(ghoulPool),
1768 rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards`,
1769 masteryReq: 3,
1770 minEnemyLevel: 40,
1771 maxEnemyLevel: 50,
1772 xpAmounts: [480, 480, 480, 710] // not faithful
1773 }
1774 ],
1775 JobPreviousVersion: {
1776 $oid: (((bountyCycle - 1) * 9000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
1777 },
1778 PreviousJobs: [
1779 {
1780 jobType: pastRng.randomElementPop(pastGhoulPool),
1781 rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableARewards`,
1782 masteryReq: 1,
1783 minEnemyLevel: 15,
1784 maxEnemyLevel: 25,
1785 xpAmounts: [270, 270, 270, 400] // not faithful
1786 },
1787 {
1788 jobType: pastRng.randomElementPop(pastGhoulPool),
1789 rewards: `/Lotus/Types/Game/MissionDecks/EidolonJobMissionRewards/GhoulBountyTableBRewards`,
1790 masteryReq: 3,
1791 minEnemyLevel: 40,
1792 maxEnemyLevel: 50,
1793 xpAmounts: [480, 480, 480, 710] // not faithful
1794 }
1795 ]
1796 });
1797 }
1798
1629 1799 if (config.worldState?.creditBoost) {
1630 1800 worldState.GlobalUpgrades.push({
1631 1801 _id: { $oid: "5b23106f283a555109666672" },
Modified src/types/worldStateTypes.ts +33 -16
@@ -37,19 +37,46 @@ export interface IGoal {
37 37 _id: IOid;
38 38 Activation: IMongoDate;
39 39 Expiry: IMongoDate;
40 Count: number;
41 Goal: number;
42 Success: number;
43 Personal: boolean;
40 Count?: number;
41 Goal?: number;
42 HealthPct?: number;
43 Success?: number;
44 Personal?: boolean;
44 45 Bounty?: boolean;
46 Faction?: string;
45 47 ClampNodeScores?: boolean;
46 48 Desc: string;
47 49 ToolTip?: string;
50 Transmission?: string;
51 InstructionalItem?: string;
48 52 Icon: string;
49 53 Tag: string;
50 Node: string;
54 Node?: string;
55 VictimNode?: string;
56 RegionIdx?: number;
57 Regions?: number[];
51 58 MissionKeyName?: string;
52 59 Reward?: IMissionReward;
60
61 JobAffiliationTag?: string;
62 Jobs?: ISyndicateJob[];
63 PreviousJobs?: ISyndicateJob[];
64 JobCurrentVersion?: IOid;
65 JobPreviousVersion?: IOid;
66 }
67
68 export interface ISyndicateJob {
69 jobType?: string;
70 rewards: string;
71 masteryReq?: number;
72 minEnemyLevel: number;
73 maxEnemyLevel: number;
74 xpAmounts: number[];
75 endless?: boolean;
76 locationTag?: string;
77 isVault?: boolean;
78 requiredItems?: string[];
79 useRequiredItemsAsMiscItemFee?: boolean;
53 80 }
54 81
55 82 export interface ISyndicateMissionInfo {
@@ -59,17 +86,7 @@ export interface ISyndicateMissionInfo {
59 86 Tag: string;
60 87 Seed: number;
61 88 Nodes: string[];
62 Jobs?: {
63 jobType?: string;
64 rewards: string;
65 masteryReq: number;
66 minEnemyLevel: number;
67 maxEnemyLevel: number;
68 xpAmounts: number[];
69 endless?: boolean;
70 locationTag?: string;
71 isVault?: boolean;
72 }[];
89 Jobs?: ISyndicateJob[];
73 90 }
74 91
75 92 export interface IGlobalUpgrade {
Modified static/webui/index.html +16 -0
@@ -946,6 +946,22 @@
946 946 <option value="3" data-loc="worldState_we3"></option>
947 947 </select>
948 948 </div>
949 <div class="form-group mt-2">
950 <label class="form-label" for="worldState.ghoulEmergenceOverride" data-loc="worldState_ghoulEmergence"></label>
951 <select class="form-control" id="worldState.ghoulEmergenceOverride" data-default="null">
952 <option value="null" data-loc="normal"></option>
953 <option value="true" data-loc="enabled"></option>
954 <option value="false" data-loc="disabled"></option>
955 </select>
956 </div>
957 <div class="form-group mt-2">
958 <label class="form-label" for="worldState.plagueStarOverride" data-loc="worldState_plagueStar"></label>
959 <select class="form-control" id="worldState.plagueStarOverride" data-default="null">
960 <option value="null" data-loc="normal"></option>
961 <option value="true" data-loc="enabled"></option>
962 <option value="false" data-loc="disabled"></option>
963 </select>
964 </div>
949 965 <div class="form-group mt-2">
950 966 <label class="form-label" for="worldState.starDaysOverride" data-loc="worldState_starDays"></label>
951 967 <select class="form-control" id="worldState.starDaysOverride" data-default="null">
Modified static/webui/translations/de.js +2 -0
@@ -246,6 +246,8 @@ dict = {
246 246 worldState_baroTennoConRelay: `Baros TennoCon Relais`,
247 247 worldState_starDays: `Sternen-Tage`,
248 248 worldState_galleonOfGhouls: `Galeone der Ghule`,
249 worldState_ghoulEmergence: `Ghul Ausrottung`,
250 worldState_plagueStar: `Plagenstern`,
249 251 enabled: `Aktiviert`,
250 252 disabled: `Deaktiviert`,
251 253 worldState_we1: `Wochenende 1`,
Modified static/webui/translations/en.js +2 -0
@@ -245,6 +245,8 @@ dict = {
245 245 worldState_baroTennoConRelay: `Baro's TennoCon Relay`,
246 246 worldState_starDays: `Star Days`,
247 247 worldState_galleonOfGhouls: `Galleon of Ghouls`,
248 worldState_ghoulEmergence: `Ghoul Purge`,
249 worldState_plagueStar: `Plague Star`,
248 250 enabled: `Enabled`,
249 251 disabled: `Disabled`,
250 252 worldState_we1: `Weekend 1`,
Modified static/webui/translations/es.js +2 -0
@@ -246,6 +246,8 @@ dict = {
246 246 worldState_baroTennoConRelay: `Repetidor de Baro de la TennoCon`,
247 247 worldState_starDays: `Días estelares`,
248 248 worldState_galleonOfGhouls: `Galeón de Gules`,
249 worldState_ghoulEmergence: `Purga de Gules`,
250 worldState_plagueStar: `Estrella Infestada`,
249 251 enabled: `Activado`,
250 252 disabled: `Desactivado`,
251 253 worldState_we1: `Semana 1`,
Modified static/webui/translations/fr.js +2 -0
@@ -246,6 +246,8 @@ dict = {
246 246 worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`,
247 247 worldState_starDays: `Jours Stellaires`,
248 248 worldState_galleonOfGhouls: `Galion des Goules`,
249 worldState_ghoulEmergence: `Purge des Goules`,
250 worldState_plagueStar: `Fléau Céleste`,
249 251 enabled: `[UNTRANSLATED] Enabled`,
250 252 disabled: `Désactivé`,
251 253 worldState_we1: `Weekend 1`,
Modified static/webui/translations/ru.js +2 -0
@@ -246,6 +246,8 @@ dict = {
246 246 worldState_baroTennoConRelay: `Реле Баро TennoCon`,
247 247 worldState_starDays: `Звёздные дни`,
248 248 worldState_galleonOfGhouls: `Галеон Гулей`,
249 worldState_ghoulEmergence: `Избавление от гулей`,
250 worldState_plagueStar: `Чумная звезда`,
249 251 enabled: `Включено`,
250 252 disabled: `Отключено`,
251 253 worldState_we1: `Выходные 1`,
Modified static/webui/translations/uk.js +2 -0
@@ -246,6 +246,8 @@ dict = {
246 246 worldState_baroTennoConRelay: `Реле Баро TennoCon`,
247 247 worldState_starDays: `Зоряні дні`,
248 248 worldState_galleonOfGhouls: `Гульський Галеон`,
249 worldState_ghoulEmergence: `Зачищення від гулів`,
250 worldState_plagueStar: `Морова зірка`,
249 251 enabled: `Увімкнено`,
250 252 disabled: `Вимкнено`,
251 253 worldState_we1: `Вихідні 1`,
Modified static/webui/translations/zh.js +2 -0