From 288b91944c110f2a1d9c8a114e4ad507506271af Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:05:03 +0200 Subject: [PATCH 1/2] feat: thermia fractures Re #1103 --- config-vanilla.json | 2 + src/services/configService.ts | 2 + src/services/missionInventoryUpdateService.ts | 166 ++++++++++++------ src/services/worldStateService.ts | 87 ++++++++- src/types/worldStateTypes.ts | 12 +- static/webui/index.html | 19 ++ static/webui/translations/de.js | 2 + static/webui/translations/en.js | 2 + static/webui/translations/es.js | 2 + static/webui/translations/fr.js | 2 + static/webui/translations/ru.js | 2 + static/webui/translations/uk.js | 2 + static/webui/translations/zh.js | 2 + 13 files changed, 243 insertions(+), 59 deletions(-) diff --git a/config-vanilla.json b/config-vanilla.json index 7a72dc10..c7cf618c 100644 --- a/config-vanilla.json +++ b/config-vanilla.json @@ -86,6 +86,8 @@ "bellyOfTheBeastProgressOverride": 0, "eightClaw": false, "eightClawProgressOverride": 0, + "thermiaFracturesOverride": null, + "thermiaFracturesProgressOverride": 0, "eidolonOverride": "", "vallisOverride": "", "duviriOverride": "", diff --git a/src/services/configService.ts b/src/services/configService.ts index 7d6a8337..1ecba208 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -98,6 +98,8 @@ export interface IConfig { bellyOfTheBeastProgressOverride?: number; eightClaw?: boolean; eightClawProgressOverride?: number; + thermiaFracturesOverride?: boolean; + thermiaFracturesProgressOverride?: number; eidolonOverride?: string; vallisOverride?: string; duviriOverride?: string; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 28e40ec5..c07bb5fb 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -640,7 +640,7 @@ export const addMissionInventoryUpdates = async ( } const currentNode = inventoryUpdates.RewardInfo!.node; - let currentMissionKey; + let currentMissionKey: string | undefined; if (currentNode == goal.Node) { currentMissionKey = goal.MissionKeyName; } else if (goal.ConcurrentNodes && goal.ConcurrentMissionKeyNames) { @@ -651,15 +651,15 @@ export const addMissionInventoryUpdates = async ( } } } - if (currentMissionKey && currentMissionKey in goalMessagesByKey) { - let countBeforeUpload = goalProgress?.Count ?? 0; - let totalCount = countBeforeUpload + uploadProgress.Count; - if (goal.Best) { - countBeforeUpload = goalProgress?.Best ?? 0; - totalCount = uploadProgress.Best; - } - let reward; + const rewards = []; + let countBeforeUpload = goalProgress?.Count ?? 0; + let totalCount = countBeforeUpload + uploadProgress.Count; + if (goal.Best) { + countBeforeUpload = goalProgress?.Best ?? 0; + totalCount = uploadProgress.Best; + } + { if (goal.InterimGoals && goal.InterimRewards) { for (let i = 0; i < goal.InterimGoals.length; i++) { if ( @@ -668,70 +668,95 @@ export const addMissionInventoryUpdates = async ( (!goalProgress || countBeforeUpload < goal.InterimGoals[i]) && goal.InterimRewards[i] ) { - reward = goal.InterimRewards[i]; + rewards.push(goal.InterimRewards[i]); break; } } } if ( - !reward && goal.Goal && goal.Goal <= totalCount && (!goalProgress || countBeforeUpload < goal.Goal) && goal.Reward ) { - reward = goal.Reward; + rewards.push(goal.Reward); } if ( - !reward && goal.BonusGoal && goal.BonusGoal <= totalCount && (!goalProgress || countBeforeUpload < goal.BonusGoal) && goal.BonusReward ) { - reward = goal.BonusReward; - } - if (reward) { - if (currentMissionKey in goalMessagesByKey) { - // Send reward via inbox - const info = goalMessagesByKey[currentMissionKey]; - const message: IMessageCreationTemplate = { - sndr: info.sndr, - msg: info.msg, - sub: info.sub, - icon: info.icon, - 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; - } - if (info.arg) { - const args: Record = { - PLAYER_NAME: account.DisplayName, - CREDIT_REWARD: reward.credits ?? 0 - }; - - info.arg.forEach(key => { - const value = args[key]; - if (value) { - message.arg ??= []; - message.arg.push({ Key: key, Tag: value }); - } - }); - } - - await createMessage(inventory.accountOwnerId, [message]); - } + rewards.push(goal.BonusReward); } } + const messages: IMessageCreationTemplate[] = []; + const infos: { + sndr: string; + msg: string; + sub: string; + icon: string; + arg?: string[]; + }[] = []; + + { + if (currentMissionKey && currentMissionKey in goalMessagesByKey) { + infos.push(goalMessagesByKey[currentMissionKey]); + } else if (goal.Tag in goalMessagesByTag) { + const combinedGoals = [...(goal.InterimGoals || []), goal.Goal, goal.BonusGoal]; + combinedGoals.forEach((n, i) => { + if (n !== undefined && n > countBeforeUpload && n <= totalCount) { + infos.push(goalMessagesByTag[goal.Tag][i]); + } + }); + } + } + + for (let i = 0; i < rewards.length; i++) { + if (infos[i]) { + const info = infos[i]; + const reward = rewards[i]; + const message: IMessageCreationTemplate = { + sndr: info.sndr, + msg: info.msg, + sub: info.sub, + icon: info.icon, + 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; + } + if (info.arg) { + const args: Record = { + PLAYER_NAME: account.DisplayName, + CREDIT_REWARD: reward.credits ?? 0 + }; + + for (let j = 0; j < info.arg.length; j++) { + const key = info.arg[j]; + const value = args[key]; + if (value) { + message.arg ??= []; + message.arg.push({ + Key: key, + Tag: value + }); + } + } + } + messages.push(message); + } + } + + if (messages.length > 0) await createMessage(inventory.accountOwnerId, messages); + if (goalProgress) { goalProgress.Best = Math.max(goalProgress.Best!, uploadProgress.Best); goalProgress.Count += uploadProgress.Count; @@ -2617,3 +2642,38 @@ const goalMessagesByKey: Record = { + HeatFissure: [ + { + sndr: "/Lotus/Language/Npcs/Eudico", + msg: "/Lotus/Language/Messages/OrbHeistEventRewardAInboxMessageBody", + sub: "/Lotus/Language/Messages/OrbHeistEventRewardAInboxMessageTitle", + icon: "/Lotus/Interface/Icons/Npcs/Eudico.png" + }, + { + sndr: "/Lotus/Language/Npcs/Eudico", + msg: "/Lotus/Language/Messages/OrbHeistEventRewardBInboxMessageBody", + sub: "/Lotus/Language/Messages/OrbHeistEventRewardBInboxMessageTitle", + icon: "/Lotus/Interface/Icons/Npcs/Eudico.png" + }, + { + sndr: "/Lotus/Language/Npcs/Eudico", + msg: "/Lotus/Language/Messages/OrbHeistEventRewardCInboxMessageBody", + sub: "/Lotus/Language/Messages/OrbHeistEventRewardCInboxMessageTitle", + icon: "/Lotus/Interface/Icons/Npcs/Eudico.png" + }, + { + sndr: "/Lotus/Language/Npcs/Eudico", + msg: "/Lotus/Language/Messages/OrbHeistEventRewardDInboxMessageBody", + sub: "/Lotus/Language/Messages/OrbHeistEventRewardDInboxMessageTitle", + icon: "/Lotus/Interface/Icons/Npcs/Eudico.png" + }, + { + sndr: "/Lotus/Language/Npcs/Eudico", + msg: "/Lotus/Language/Messages/OrbHeistEventRewardEInboxMessageBody", + sub: "/Lotus/Language/Messages/OrbHeistEventRewardEInboxMessageTitle", + icon: "/Lotus/Interface/Icons/Npcs/Eudico.png" + } + ] +}; diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index b85b3728..a5a7349f 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -2629,6 +2629,89 @@ export const getWorldState = (buildLabel?: string): IWorldState => { ); } + const thermiaFracturesCycleDay = day % 32; + const isThermiaFracturesActive = thermiaFracturesCycleDay < 14; + if (config.worldState?.thermiaFracturesOverride ?? isThermiaFracturesActive) { + const activeStartDay = day - thermiaFracturesCycleDay; + + const count = config.worldState?.thermiaFracturesProgressOverride ?? 0; + const activation = config.worldState?.thermiaFracturesOverride ? 1740416400000 : getSortieTime(activeStartDay); + const expiry = config.worldState?.thermiaFracturesOverride + ? 2000000000000 + : activation + 14 * unixTimesInMs.day; + + worldState.Goals.push({ + _id: { $oid: "5c7cb0d00000000000000000" }, + Activation: { $date: { $numberLong: activation.toString() } }, + Expiry: { $date: { $numberLong: expiry.toString() } }, + Node: "SolNode129", + ScoreVar: "FissuresClosed", + ScoreLocTag: "/Lotus/Language/G1Quests/HeatFissuresEventScore", + Count: count, + HealthPct: count / 100, + Regions: [1], + Desc: "/Lotus/Language/G1Quests/HeatFissuresEventName", + ToolTip: "/Lotus/Language/G1Quests/HeatFissuresEventDesc", + OptionalInMission: true, + Tag: "HeatFissure", + UpgradeIds: [{ $oid: "5c81cefa4c4566791728eaa7" }, { $oid: "5c81cefa4c4566791728eaa6" }], + Personal: true, + Community: true, + Goal: 100, + Reward: { + items: ["/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpBFG/Vandal/VandalCrpBFG"] + }, + InterimGoals: [5, 25, 50, 75], + InterimRewards: [ + { items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/OrbBadgeItem"] }, + { + items: [ + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Shotgun/ShotgunMedicMod", + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Rifle/SerratedRushMod" + ] + }, + { + items: [ + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Pistol/MultishotDodgeMod", + "/Lotus/StoreItems/Upgrades/Mods/DualSource/Melee/CritDamageChargeSpeedMod" + ] + }, + { items: ["/Lotus/StoreItems/Upgrades/Skins/Sigils/OrbSigil"] } + ] + }); + worldState.NodeOverrides.push({ + _id: { $oid: "5c7cb0d00000000000000000" }, + Activation: { $date: { $numberLong: activation.toString() } }, + Expiry: { $date: { $numberLong: expiry.toString() } }, + Node: "SolNode129", + Faction: "FC_CORPUS", + CustomNpcEncounters: ["/Lotus/Types/Gameplay/Venus/Encounters/Heists/ExploiterHeistFissure"] + }); + if (count >= 35) { + worldState.GlobalUpgrades.push({ + _id: { $oid: "5c81cefa4c4566791728eaa6" }, + Activation: { $date: { $numberLong: activation.toString() } }, + ExpiryDate: { $date: { $numberLong: expiry.toString() } }, + UpgradeType: "GAMEPLAY_MONEY_REWARD_AMOUNT", + OperationType: "MULTIPLY", + Value: 2, + Nodes: ["SolNode129"] + }); + } + // Not sure about that + if (count == 100) { + worldState.GlobalUpgrades.push({ + _id: { $oid: "5c81cefa4c4566791728eaa7" }, + Activation: { $date: { $numberLong: activation.toString() } }, + ExpiryDate: { $date: { $numberLong: expiry.toString() } }, + UpgradeType: "GAMEPLAY_PICKUP_AMOUNT", + OperationType: "MULTIPLY", + Value: 2, + Nodes: ["SolNode129"] + }); + } + } + // Nightwave Challenges const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel); if (nightwaveSyndicateTag) { @@ -2727,7 +2810,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => { : Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), - date.getUTCDate() + (day - ghoulsCycleDay + 17) + date.getUTCDate() + activeStartDay ).toString() } }, @@ -2738,7 +2821,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => { : Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), - date.getUTCDate() + (day - ghoulsCycleDay + 21) + date.getUTCDate() + activeEndDay ).toString() } }, diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index fbb3547f..40463345 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -43,7 +43,7 @@ export interface IGoal { Count?: number; HealthPct?: number; - Icon: string; + Icon?: string; Desc: string; ToolTip?: string; Faction?: string; @@ -94,6 +94,9 @@ export interface IGoal { MissionKeyRotation?: string[]; MissionKeyRotationInterval?: number; + OptionalInMission?: boolean; + UpgradeIds?: IOid[]; + NightLevel?: string; } @@ -128,8 +131,9 @@ export interface IGlobalUpgrade { UpgradeType: string; OperationType: string; Value: number; - LocalizeTag: string; - LocalizeDescTag: string; + LocalizeTag?: string; + LocalizeDescTag?: string; + Nodes?: string[]; } export interface IInvasion { @@ -183,7 +187,7 @@ export interface INodeOverride { Seed?: number; LevelOverride?: string; Faction?: string; - CustomNpcEncounters?: string; + CustomNpcEncounters?: string[]; } export interface ISortie { diff --git a/static/webui/index.html b/static/webui/index.html index 83730e06..fc60a986 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -1103,6 +1103,25 @@ +
+
+ + +
+
+
+ +
+ + +
+
+
+