From e443cd1e4391a97c41886cb81bd053714f9e8075 Mon Sep 17 00:00:00 2001 From: Slayer55555 Date: Mon, 6 Oct 2025 11:27:48 -0300 Subject: [PATCH] 2025 alerts --- config-vanilla.json | 1 + src/services/configService.ts | 1 + src/services/missionInventoryUpdateService.ts | 92 ++++++++++++------- src/services/worldStateService.ts | 87 ++++++++++++++++++ src/types/requestTypes.ts | 1 + src/types/worldStateTypes.ts | 26 +++++- static/webui/index.html | 4 + static/webui/translations/de.js | 1 + static/webui/translations/en.js | 1 + static/webui/translations/es.js | 1 + static/webui/translations/fr.js | 1 + static/webui/translations/ru.js | 21 +++-- static/webui/translations/uk.js | 21 +++-- static/webui/translations/zh.js | 1 + 14 files changed, 202 insertions(+), 57 deletions(-) diff --git a/config-vanilla.json b/config-vanilla.json index b8810686..a0e8674f 100644 --- a/config-vanilla.json +++ b/config-vanilla.json @@ -31,6 +31,7 @@ "baroAlwaysAvailable": false, "baroFullyStocked": false, "varziaFullyStocked": false, + "voidCorruption": false, "wolfHunt": false, "orphixVenom": false, "longShadow": false, diff --git a/src/services/configService.ts b/src/services/configService.ts index 0c34e967..39df1756 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -41,6 +41,7 @@ export interface IConfig { baroAlwaysAvailable?: boolean; baroFullyStocked?: boolean; varziaFullyStocked?: boolean; + voidCorruption?: boolean; wolfHunt?: boolean; orphixVenom?: boolean; longShadow?: boolean; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index dfb6c815..70ade363 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1154,6 +1154,28 @@ export const addMissionRewards = async ( let ConquestCompletedMissionsCount; let missionCompletionCredits = 0; + + if (rewardInfo.alertId) { + const alert = getWorldState().Alerts.find(x => x._id.$oid == rewardInfo.alertId); + if (!alert) { + logger.warn(`mission completed unknown alert`, { alertId: rewardInfo.alertId }); + } else { + inventory.CompletedAlerts ??= []; + if (inventory.CompletedAlerts.includes(alert._id.$oid)) { + logger.debug(`alert ${alert._id.$oid} already completed, skipping alert reward`); + } else { + inventory.CompletedAlerts.push(alert._id.$oid); + if (alert.MissionInfo.missionReward) { + missionCompletionCredits += addFixedLevelRewards( + alert.MissionInfo.missionReward, + MissionRewards, + rewardInfo + ); + } + } + } + } + //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display if (rewardInfo.goalId) { @@ -2483,95 +2505,95 @@ const goalMessagesByKey: Record, SORTIE_BOSS_VOR: "SolNode108" }; +const voidCorruptionAlerts = [ + { + _id: { $oid: "677d452e2f324ee7b90f8ccf" }, + Activation: { $date: { $numberLong: "1736524800000" } }, + Expiry: { $date: { $numberLong: "1736784000000" } }, + MissionInfo: { + location: "SolNode61", + missionType: "MT_SABOTAGE", + faction: "FC_CORPUS", + difficulty: 1, + missionReward: { + credits: 30000, + items: ["/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedFireRateDamagePistol"] + }, + levelOverride: "/Lotus/Levels/Proc/Corpus/CorpusShipCoreSabotage", + enemySpec: "/Lotus/Types/Game/EnemySpecs/CorpusShipEnemySpecs/CorpusShipSquadA", + extraEnemySpec: "/Lotus/Types/Game/EnemySpecs/GamemodeExtraEnemySpecs/CorpusSabotageTiersA", + minEnemyLevel: 10, + maxEnemyLevel: 15 + } + }, + { + _id: { $oid: "677d45811daeae9de40e8c0f" }, + Activation: { $date: { $numberLong: "1737129600000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + MissionInfo: { + location: "SettlementNode11", + missionType: "MT_DEFENSE", + faction: "FC_CORPUS", + difficulty: 1, + missionReward: { + credits: 30000, + items: ["/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedCritChanceFireRatePistol"] + }, + levelOverride: "/Lotus/Levels/Proc/Corpus/CorpusShipDefense", + enemySpec: "/Lotus/Types/Game/EnemySpecs/CorpusShipEnemySpecs/CorpusShipSquadDefenseB", + minEnemyLevel: 20, + maxEnemyLevel: 25, + maxWaveNum: 10 + } + }, + { + _id: { $oid: "677d45a494ad716c90006b9a" }, + Activation: { $date: { $numberLong: "1737734400000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + MissionInfo: { + location: "SolNode118", + missionType: "MT_ARTIFACT", + faction: "FC_CORPUS", + difficulty: 1, + missionReward: { + credits: 30000, + items: ["/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedCritDamagePistol"] + }, + levelOverride: "/Lotus/Levels/Proc/Corpus/CorpusShipDisruption", + enemySpec: "/Lotus/Types/Game/EnemySpecs/CorpusShipEnemySpecs/CorpusShipSurvivalA", + extraEnemySpec: "/Lotus/Types/Game/EnemySpecs/SpecialMissionSpecs/DisruptionCorpusShip", + customAdvancedSpawners: ["/Lotus/Types/Enemies/AdvancedSpawners/ErrantSpecterInvasion"], + minEnemyLevel: 30, + maxEnemyLevel: 35 + } + }, + { + _id: { $oid: "677d4700682d173abb0e19fe" }, + Activation: { $date: { $numberLong: "1738339200000" } }, + Expiry: { $date: { $numberLong: "2000000000000" } }, + MissionInfo: { + location: "SolNode4", + missionType: "MT_EXTERMINATION", + faction: "FC_CORPUS", + difficulty: 1, + missionReward: { + credits: 30000, + items: ["/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedDamageRecoilPistol"] + }, + levelOverride: "/Lotus/Levels/Proc/Corpus/CorpusShipExterminate", + enemySpec: "/Lotus/Types/Game/EnemySpecs/CorpusShipEnemySpecs/CorpusShipExterminateMixed", + minEnemyLevel: 40, + maxEnemyLevel: 45 + } + } +] satisfies readonly IAlert[]; + const eidolonJobs: readonly string[] = [ "/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyAss", "/Lotus/Types/Gameplay/Eidolon/Jobs/AssassinateBountyCap", @@ -1481,6 +1565,9 @@ export const getWorldState = (buildLabel?: string): IWorldState => { worldState.VoidTraders.push(vt); fullyStockBaro(vt); } + if (config.worldState?.voidCorruption) { + worldState.Alerts.push(...voidCorruptionAlerts.map(alert => structuredClone(alert))); + } const isFebruary = date.getUTCMonth() == 1; if (config.worldState?.starDaysOverride ?? isFebruary) { worldState.Goals.push({ diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index 0dac8d75..d762edd8 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -178,6 +178,7 @@ export interface IRewardInfo { goalManifest?: string; invasionId?: string; invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS"; + alertId?: string; sortieId?: string; sortieTag?: "Mission1" | "Mission2" | "Final"; sortiePrereqs?: string[]; diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index f39c4bf7..723e8875 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -1,4 +1,4 @@ -import type { IMissionReward } from "warframe-public-export-plus"; +import type { IMissionReward, TFaction } from "warframe-public-export-plus"; import type { IMongoDate, IOid } from "./commonTypes.ts"; export interface IWorldState { @@ -7,7 +7,7 @@ export interface IWorldState { Time: number; InGameMarket: IInGameMarket; Goals: IGoal[]; - Alerts: []; + Alerts: IAlert[]; Sorties: ISortie[]; LiteSorties: ILiteSortie[]; SyndicateMissions: ISyndicateMissionInfo[]; @@ -35,6 +35,28 @@ export interface IWorldState { Tmp?: string; } +export interface IAlert { + _id: IOid; + Activation: IMongoDate; + Expiry: IMongoDate; + MissionInfo: IAlertMissionInfo; +} + +export interface IAlertMissionInfo { + location: string; + missionType: string; + faction: TFaction; + difficulty: number; + missionReward?: IMissionReward; + levelOverride?: string; + enemySpec?: string; + extraEnemySpec?: string; + customAdvancedSpawners?: string[]; + minEnemyLevel?: number; + maxEnemyLevel?: number; + maxWaveNum?: number; +} + export interface IGoal { _id: IOid; Activation: IMongoDate; diff --git a/static/webui/index.html b/static/webui/index.html index ba8e4b78..4f830ccf 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -1169,6 +1169,10 @@ +
+ + +
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index b642b800..77732278 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -279,6 +279,7 @@ dict = { worldState_dogDays: `Hitzefrei`, worldState_dogDaysRewards: `[UNTRANSLATED] Dog Days Rewards`, worldState_wolfHunt: `Wolfsjagd (2025)`, + worldState_voidCorruption: `[UNTRANSLATED] Void Corruption (2025)`, worldState_orphixVenom: `Orphix Gift`, worldState_longShadow: `Lange Schatten`, worldState_hallowedFlame: `Geweihte Flamme`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index 57a32595..569615e5 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -278,6 +278,7 @@ dict = { worldState_dogDays: `Dog Days`, worldState_dogDaysRewards: `Dog Days Rewards`, worldState_wolfHunt: `Wolf Hunt (2025)`, + worldState_voidCorruption: `Void Corruption (2025)`, worldState_orphixVenom: `Orphix Venom`, worldState_longShadow: `Long Shadow`, worldState_hallowedFlame: `Hallowed Flame`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 888f16da..5813151a 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -279,6 +279,7 @@ dict = { worldState_dogDays: `Canícula`, worldState_dogDaysRewards: `Recompensas de Canícula`, worldState_wolfHunt: `Cacería del Lobo (2025)`, + worldState_voidCorruption: `Corrupción del Vacío (2025)`, worldState_orphixVenom: `Veneno de Orphix`, worldState_longShadow: `Sombra Prolongada`, worldState_hallowedFlame: `Llama Sagrada`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 66fbad3c..d6e2a8a6 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -279,6 +279,7 @@ dict = { worldState_dogDays: `Bataille d'Eau`, worldState_dogDaysRewards: `Récompenses de la Bataille d'Eau`, worldState_wolfHunt: `Chasse au Loup (2025)`, + worldState_voidCorruption: `[UNTRANSLATED] Void Corruption (2025)`, worldState_orphixVenom: `Venin Orphix`, worldState_longShadow: `La Propagation des Ombres`, worldState_hallowedFlame: `Flamme Hantée`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 4de12099..689655d0 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -1,6 +1,6 @@ // Russian translation by AMelonInsideLemon, LoseFace dict = { - general_inventoryUpdateNote: `Примечание: Чтобы увидеть изменения в игре, вам нужно повторно синхронизировать свой инвентарь, например, используя команду загрузчика /sync в чате игры, посетив Додзё/Реле или перезагрузив игру.`, + general_inventoryUpdateNote: `Примечание: Чтобы увидеть изменения в игре, вам нужно повторно синхронизировать свой инвентарь, например, используя команду /sync в программе bootstrapper, посетив Додзё/Реле или перезагрузив игру.`, general_inventoryUpdateNoteGameWs: `Примечание: для того, чтобы изменения вступили в силу, может потребоваться повторно открыть меню, в котором вы находитесь.`, general_addButton: `Добавить`, general_setButton: `Установить`, @@ -45,7 +45,7 @@ dict = { code_rank: `Ранг`, code_rankUp: `Повысить ранг`, code_rankDown: `Понизить ранг`, - code_unlockLevelCap: `Разблокировать ограничение уровня`, + code_unlockLevelCap: `[UNTRANSLATED] Unlock level cap`, code_count: `Количество`, code_focusAllUnlocked: `Все школы Фокуса уже разблокированы.`, code_focusUnlocked: `Разблокировано |COUNT| новых школ Фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`, @@ -227,7 +227,7 @@ dict = { cheats_baroFullyStocked: `Баро полностью укомплектован`, cheats_syndicateMissionsRepeatable: `Повторять миссии синдиката`, cheats_unlockAllProfitTakerStages: `Разблокировать все этапы Сферы извлечения прибыли`, - cheats_unlockSuccInventory: `Успех. Обратите внимание, что вам необходимо будет повторно синхронизировать свой инвентарь, например, с помощью команды загрузчика /sync в чате игры, посетив Додзё/Реле или повторно войдя в игру.`, + cheats_unlockSuccInventory: `Успех. Обратите внимание, что вам необходимо будет повторно синхронизировать свой инвентарь, например, с помощью команды /sync в программе bootstrapper, посетив Додзё/Реле или повторно войдя в игру.`, cheats_instantFinishRivenChallenge: `Мгновенное завершение испытания мода Разлома`, cheats_instantResourceExtractorDrones: `Мгновенно добывающие Дроны-сборщики`, cheats_noResourceExtractorDronesDamage: `Без урона по Дронам-сборщикам`, @@ -257,12 +257,12 @@ dict = { cheats_changeButton: `Изменить`, cheats_markAllAsRead: `Пометить все входящие как прочитанные`, cheats_finishInvasionsInOneMission: `Завершать вторжение за одну миссию`, - cheats_nemesisHenchmenKillsMultiplierGrineer: `Мультипликатор прогресса ярости (Гринир)`, - cheats_nemesisHenchmenKillsMultiplierCorpus: `Мультипликатор прогресса ярости (Корпус)`, - cheats_nemesisAntivirusGainMultiplier: `Мультипликатор прогресса антивируса`, - cheats_nemesisHintProgressMultiplierGrineer: `Мультипликатор прогресса подсказки (Гринир)`, - cheats_nemesisHintProgressMultiplierCorpus: `Мультипликатор прогресса подсказки (Корпус)`, - cheats_nemesisExtraWeapon: `Дополнительное оружие/активный Кардиомиоцит за победу над Противником (0 для отключения)`, + cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`, + cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`, + cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`, + cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`, + cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`, + cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`, worldState: `Состояние мира`, worldState_creditBoost: `Глобальный бустер Кредитов`, @@ -279,12 +279,13 @@ dict = { worldState_dogDays: `Знойные дни`, worldState_dogDaysRewards: `Награды Знойных дней`, worldState_wolfHunt: `Волчья Охота (2025)`, + worldState_voidCorruption: `[UNTRANSLATED] Void Corruption (2025)`, worldState_orphixVenom: `Яд Орфикса`, worldState_longShadow: `Длинная Тень`, worldState_hallowedFlame: `Священное пламя`, worldState_hallowedNightmares: `Священные кошмары`, worldState_hallowedNightmaresRewards: `Награды Священных кошмаров`, - worldState_naberusNights: `Ночи Наберуса`, + worldState_naberusNights: `[UNTRANSLATED] Nights of Naberus`, worldState_proxyRebellion: `Восстание роботов`, worldState_proxyRebellionRewards: `Награды Восстания роботов`, worldState_bellyOfTheBeast: `Чрево зверя`, diff --git a/static/webui/translations/uk.js b/static/webui/translations/uk.js index dcfdc95c..267aba69 100644 --- a/static/webui/translations/uk.js +++ b/static/webui/translations/uk.js @@ -1,6 +1,6 @@ // Ukrainian translation by LoseFace dict = { - general_inventoryUpdateNote: `Пам'ятка: Щоб побачити зміни в грі, вам потрібно повторно синхронізувати своє спорядження, наприклад, використовуючи команду завантажувача /sync у чаті гри, відвідавши Доджьо/Реле або перезавантаживши гру.`, + general_inventoryUpdateNote: `Пам'ятка: Щоб побачити зміни в грі, вам потрібно повторно синхронізувати своє спорядження, наприклад, використовуючи команду /sync в програмі bootstrapper, відвідавши Доджьо/Реле або перезавантаживши гру.`, general_inventoryUpdateNoteGameWs: `Примітка: для відображення змін може знадобитися повторно відкрити меню, в якому ви перебуваєте.`, general_addButton: `Добавити`, general_setButton: `Встановити`, @@ -45,7 +45,7 @@ dict = { code_rank: `Рівень`, code_rankUp: `Підвищити рівень`, code_rankDown: `Понизити рівень`, - code_unlockLevelCap: `Розблокувати обмеження рівня`, + code_unlockLevelCap: `[UNTRANSLATED] Unlock level cap`, code_count: `Кількість`, code_focusAllUnlocked: `Всі школи Фокусу вже розблоковані.`, code_focusUnlocked: `Розблоковано |COUNT| нових шкіл Фокусу! Для відображення змін в грі знадобиться оновлення спорядження. Відвідування навігації — найпростіший спосіб цього досягти.`, @@ -227,7 +227,7 @@ dict = { cheats_baroFullyStocked: `Баро повністю укомплектований`, cheats_syndicateMissionsRepeatable: `Повторювати місії синдиката`, cheats_unlockAllProfitTakerStages: `Розблокувати всі етапи Привласнювачки`, - cheats_unlockSuccInventory: `Успішно. Зверніть увагу, що вам потрібно буде повторно синхронізувати своє спорядження, наприклад, за допомогою команди завантажувача /sync у чаті гри, відвідавши Доджьо/Реле або повторно увійшовши в гру.`, + cheats_unlockSuccInventory: `Успішно. Зверніть увагу, що вам потрібно буде повторно синхронізувати своє спорядження, наприклад, за допомогою команди /sync в програмі bootstrapper, відвідавши Доджьо/Реле або повторно увійшовши в гру.`, cheats_instantFinishRivenChallenge: `Миттєве завершення випробування модифікатора Розколу`, cheats_instantResourceExtractorDrones: `Миттєво добуваючі Дрони-видобувачі`, cheats_noResourceExtractorDronesDamage: `Без шкоди по Дронам-видобувачам`, @@ -257,12 +257,12 @@ dict = { cheats_changeButton: `Змінити`, cheats_markAllAsRead: `Помітити всі вхідні як прочитані`, cheats_finishInvasionsInOneMission: `Завершувати вторгнення за одну місію`, - cheats_nemesisHenchmenKillsMultiplierGrineer: `Множник прогресу люті (Ґрінери)`, - cheats_nemesisHenchmenKillsMultiplierCorpus: `Множник прогресу люті (Корпус)`, - cheats_nemesisAntivirusGainMultiplier: `Мультиплікатор прогресу антивіруса`, - cheats_nemesisHintProgressMultiplierGrineer: `Множник прогресу підсказки (Ґрінери)`, - cheats_nemesisHintProgressMultiplierCorpus: `Множник прогресу підсказки (Корпус)`, - cheats_nemesisExtraWeapon: `Додаткова зброя/Жива сердцевина за перемогу над Недругом (0 для вимкнення)`, + cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`, + cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`, + cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`, + cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`, + cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`, + cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`, worldState: `Стан світу`, worldState_creditBoost: `Глобальне посилення Кредитів`, @@ -279,12 +279,13 @@ dict = { worldState_dogDays: `Спекотні дні`, worldState_dogDaysRewards: `Нагороди Спекотних днів`, worldState_wolfHunt: `Полювання на Вовка (2025)`, + worldState_voidCorruption: `[UNTRANSLATED] Void Corruption (2025)`, worldState_orphixVenom: `Орфіксова отрута`, worldState_longShadow: `Довга тінь`, worldState_hallowedFlame: `Священне полум'я`, worldState_hallowedNightmares: `Священні жахіття`, worldState_hallowedNightmaresRewards: `Нагороди Священних жахіть`, - worldState_naberusNights: `Наберові ночі`, + worldState_naberusNights: `[UNTRANSLATED] Nights of Naberus`, worldState_proxyRebellion: `Повстання роботів`, worldState_proxyRebellionRewards: `Нагороди Повстання роботів`, worldState_bellyOfTheBeast: `У лігві звіра`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index 97a24244..cb581106 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -279,6 +279,7 @@ dict = { worldState_dogDays: `三伏天`, worldState_dogDaysRewards: `三伏天奖励设置`, worldState_wolfHunt: `恶狼狩猎 (2025)`, + worldState_voidCorruption: `[UNTRANSLATED] Void Corruption (2025)`, worldState_orphixVenom: `奥影之毒`, worldState_longShadow: `暗夜长影`, worldState_hallowedFlame: `万圣之焰`,