From 2322a994c6f9d1fbd02451a9ccb7137bd94d25cb Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Tue, 21 Oct 2025 00:43:15 -0700 Subject: [PATCH] feat: rewards for overriden enemy caches (#2919) Closes #2913 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2919 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> --- package-lock.json | 8 +-- package.json | 2 +- src/services/inventoryService.ts | 19 +++-- src/services/loginService.ts | 2 +- src/services/missionInventoryUpdateService.ts | 70 ++++++++++++++++++- src/types/worldStateTypes.ts | 1 + 6 files changed, 85 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c0ed2ee..7981d879 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "morgan": "^1.10.0", "ncp": "^2.0.0", "undici": "^7.10.0", - "warframe-public-export-plus": "^0.5.91", + "warframe-public-export-plus": "^0.5.92", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", @@ -5534,9 +5534,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.91", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.91.tgz", - "integrity": "sha512-xp8rq/dvFC6+urb6vVFRtAmm1v0iE/ZALI3uVGBpblsVB/PWmGxjBBp8l00dCZs67JsqEKcrCcogKwtKTwDc1w==" + "version": "0.5.92", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.92.tgz", + "integrity": "sha512-5O5VtyVXxKtl5QdpzoVyKov5GX6t3z/U5tqPq73kjoSyA5NQT2V9sWsZK4ASyY8Edv9hNsdwlZdsdP8QmYbubg==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index 130e1cf1..8e97d778 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "morgan": "^1.10.0", "ncp": "^2.0.0", "undici": "^7.10.0", - "warframe-public-export-plus": "^0.5.91", + "warframe-public-export-plus": "^0.5.92", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 50daff71..7fc7be4e 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -117,6 +117,7 @@ export const createInventory = async ( inventory.PlayedParkourTutorial = true; await addStartingGear(inventory); await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain"); + await completeQuest(inventory, "/Lotus/Types/Keys/ModQuest/ModQuestKeyChain"); const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"]; @@ -134,16 +135,6 @@ export const createInventory = async ( } }; -//TODO: RawUpgrades might need to return a LastAdded -const awakeningRewards = [ - "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1", - "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2", - "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3", - "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4", - "/Lotus/Types/Restoratives/LisetAutoHack", - "/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod" -]; - export const addStartingGear = async ( inventory: TInventoryDatabaseDocument, startingGear?: TPartialStartingGear @@ -196,6 +187,14 @@ export const addStartingGear = async ( inventory.RegularCredits = 3000; inventoryChanges.RegularCredits = 3000; + const awakeningRewards = [ + "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1", + "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2", + "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3", + "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4", + "/Lotus/Types/Restoratives/LisetAutoHack" + ]; + for (const item of awakeningRewards) { const inventoryDelta = await addItem(inventory, item); combineInventoryChanges(inventoryChanges, inventoryDelta); diff --git a/src/services/loginService.ts b/src/services/loginService.ts index b9e200cf..f2947b6a 100644 --- a/src/services/loginService.ts +++ b/src/services/loginService.ts @@ -65,7 +65,7 @@ export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Typ activeShipId: shipId }); if (config.skipTutorial) { - // unlocked during Vor's Prize + // unlocked during Vor's Prize and The Teacher quests const defaultFeatures = [ "/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem", "/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem", diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 7b2256e0..4fe2931b 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -8,6 +8,7 @@ import { ExportAnimals, ExportEnemies, ExportFusionBundles, + ExportKeys, ExportRegions, ExportRelics, ExportRewards @@ -1141,6 +1142,7 @@ export const addMissionRewards = async ( const MissionRewards: IMissionReward[] = getRandomMissionDrops( inventory, rewardInfo, + levelKeyName, missions, wagerTier, firstCompletion @@ -1756,6 +1758,7 @@ function getLevelCreditRewards(node: IRegion): number { function getRandomMissionDrops( inventory: TInventoryDatabaseDocument, RewardInfo: IRewardInfo, + levelKeyName: string | undefined, mission: IMission | undefined, tierOverride: number | undefined, firstCompletion: boolean @@ -2193,7 +2196,7 @@ function getRandomMissionDrops( } } - if (region.cacheRewardManifest && RewardInfo.EnemyCachesFound) { + if (region.cacheRewardManifest && RewardInfo.EnemyCachesFound && !RewardInfo.goalId) { const deck = ExportRewards[region.cacheRewardManifest]; for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) { const drop = getRandomRewardByChance(deck[rotation]); @@ -2259,6 +2262,71 @@ function getRandomMissionDrops( } } + if (RewardInfo.EnemyCachesFound) { + if (RewardInfo.goalId) { + const goal = getWorldState().Goals.find(x => x._id.$oid == RewardInfo.goalId); + if (goal) { + let currentMissionKey: string | undefined; + if (RewardInfo.node == goal.Node) { + currentMissionKey = goal.MissionKeyName; + } else if (goal.ConcurrentNodes && goal.ConcurrentMissionKeyNames) { + for (let i = 0; i < goal.ConcurrentNodes.length; i++) { + if (RewardInfo.node == goal.ConcurrentNodes[i]) { + currentMissionKey = goal.ConcurrentMissionKeyNames[i]; + break; + } + } + } + if (currentMissionKey) { + const keyMeta = ExportKeys[currentMissionKey]; + if (keyMeta.cacheRewardManifest) { + const deck = ExportRewards[keyMeta.cacheRewardManifest]; + for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) { + const drop = getRandomRewardByChance(deck[rotation]); + if (drop) { + drops.push({ + StoreItem: drop.type, + ItemCount: drop.itemCount, + FromEnemyCache: true + }); + } + } + } + } + } + } else if (RewardInfo.alertId) { + const alert = getWorldState().Alerts.find(x => x._id.$oid == RewardInfo.alertId); + if (alert && alert.MissionInfo.enemyCacheOverride) { + const deck = ExportRewards[alert.MissionInfo.enemyCacheOverride]; + for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) { + const drop = getRandomRewardByChance(deck[rotation]); + if (drop) { + drops.push({ + StoreItem: drop.type, + ItemCount: drop.itemCount, + FromEnemyCache: true + }); + } + } + } + } else if (levelKeyName) { + const keyMeta = ExportKeys[levelKeyName]; + if (keyMeta.cacheRewardManifest) { + const deck = ExportRewards[keyMeta.cacheRewardManifest]; + for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) { + const drop = getRandomRewardByChance(deck[rotation]); + if (drop) { + drops.push({ + StoreItem: drop.type, + ItemCount: drop.itemCount, + FromEnemyCache: true + }); + } + } + } + } + } + if (inventory.missionsCanGiveAllRelics) { for (const drop of drops) { const itemType = fromStoreItem(drop.StoreItem); diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index 7aa6f5a9..358e4e80 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -58,6 +58,7 @@ export interface IAlertMissionInfo { maxEnemyLevel?: number; maxWaveNum?: number; descText?: string; + enemyCacheOverride?: string; maxRotations?: number; // SNS specific field }