diff --git a/src/controllers/api/getVoidProjectionRewardsController.ts b/src/controllers/api/getVoidProjectionRewardsController.ts index 9a577cf5c..3a09f4ba0 100644 --- a/src/controllers/api/getVoidProjectionRewardsController.ts +++ b/src/controllers/api/getVoidProjectionRewardsController.ts @@ -1,77 +1,31 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers"; -import { addMiscItems, getInventory } from "@/src/services/inventoryService"; +import { crackRelic } from "@/src/helpers/relicHelper"; +import { getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; -import { getRandomWeightedReward2 } from "@/src/services/rngService"; -import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes"; -import { logger } from "@/src/utils/logger"; +import { IVoidTearParticipantInfo } from "@/src/types/requestTypes"; import { RequestHandler } from "express"; -import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus"; export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); const data = getJSONfromString(String(req.body)); + + if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) { + const inventory = await getInventory(accountId); + await crackRelic(inventory, data.ParticipantInfo); + await inventory.save(); + } + const response: IVoidProjectionRewardResponse = { CurrentWave: data.CurrentWave, ParticipantInfo: data.ParticipantInfo, DifficultyTier: data.DifficultyTier }; - if (data.ParticipantInfo.QualifiesForReward) { - const relic = ExportRelics[data.ParticipantInfo.VoidProjection]; - const weights = refinementToWeights[relic.quality]; - logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights); - const reward = getRandomWeightedReward2( - ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics - weights - )!; - logger.debug(`relic rolled`, reward); - response.ParticipantInfo.Reward = reward.type; - - const inventory = await getInventory(accountId); - // Remove relic - addMiscItems(inventory, [ - { - ItemType: data.ParticipantInfo.VoidProjection, - ItemCount: -1 - } - ]); - // Give reward - await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount); - await inventory.save(); - } res.json(response); }; -const refinementToWeights = { - VPQ_BRONZE: { - COMMON: 0.76, - UNCOMMON: 0.22, - RARE: 0.02, - LEGENDARY: 0 - }, - VPQ_SILVER: { - COMMON: 0.7, - UNCOMMON: 0.26, - RARE: 0.04, - LEGENDARY: 0 - }, - VPQ_GOLD: { - COMMON: 0.6, - UNCOMMON: 0.34, - RARE: 0.06, - LEGENDARY: 0 - }, - VPQ_PLATINUM: { - COMMON: 0.5, - UNCOMMON: 0.4, - RARE: 0.1, - LEGENDARY: 0 - } -}; - interface IVoidProjectionRewardRequest { CurrentWave: number; - ParticipantInfo: IParticipantInfo; + ParticipantInfo: IVoidTearParticipantInfo; VoidTier: string; DifficultyTier: number; VoidProjectionRemovalHash: string; @@ -79,20 +33,6 @@ interface IVoidProjectionRewardRequest { interface IVoidProjectionRewardResponse { CurrentWave: number; - ParticipantInfo: IParticipantInfo; + ParticipantInfo: IVoidTearParticipantInfo; DifficultyTier: number; } - -interface IParticipantInfo { - AccountId: string; - Name: string; - ChosenRewardOwner: string; - MissionHash: string; - VoidProjection: string; - Reward: string; - QualifiesForReward: boolean; - HaveRewardResponse: boolean; - RewardsMultiplier: number; - RewardProjection: string; - HardModeReward: ITypeCount; -} diff --git a/src/helpers/relicHelper.ts b/src/helpers/relicHelper.ts new file mode 100644 index 000000000..6e28aef07 --- /dev/null +++ b/src/helpers/relicHelper.ts @@ -0,0 +1,60 @@ +import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; +import { IVoidTearParticipantInfo } from "@/src/types/requestTypes"; +import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus"; +import { getRandomWeightedReward2 } from "@/src/services/rngService"; +import { logger } from "@/src/utils/logger"; +import { addMiscItems } from "@/src/services/inventoryService"; +import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; + +export const crackRelic = async ( + inventory: TInventoryDatabaseDocument, + participant: IVoidTearParticipantInfo +): Promise => { + const relic = ExportRelics[participant.VoidProjection]; + const weights = refinementToWeights[relic.quality]; + logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights); + const reward = getRandomWeightedReward2( + ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics + weights + )!; + logger.debug(`relic rolled`, reward); + participant.Reward = reward.type; + + // Remove relic + addMiscItems(inventory, [ + { + ItemType: participant.VoidProjection, + ItemCount: -1 + } + ]); + + // Give reward + await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount); +}; + +const refinementToWeights = { + VPQ_BRONZE: { + COMMON: 0.76, + UNCOMMON: 0.22, + RARE: 0.02, + LEGENDARY: 0 + }, + VPQ_SILVER: { + COMMON: 0.7, + UNCOMMON: 0.26, + RARE: 0.04, + LEGENDARY: 0 + }, + VPQ_GOLD: { + COMMON: 0.6, + UNCOMMON: 0.34, + RARE: 0.06, + LEGENDARY: 0 + }, + VPQ_PLATINUM: { + COMMON: 0.5, + UNCOMMON: 0.4, + RARE: 0.1, + LEGENDARY: 0 + } +}; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 61ade8b26..5bd509be2 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -33,6 +33,7 @@ import { getEntriesUnsafe } from "@/src/utils/ts-utils"; import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { handleStoreItemAcquisition } from "./purchaseService"; import { IMissionReward } from "../types/missionTypes"; +import { crackRelic } from "@/src/helpers/relicHelper"; const getRotations = (rotationCount: number): number[] => { if (rotationCount === 0) return [0]; @@ -221,7 +222,8 @@ export const addMissionRewards = async ( RewardInfo: rewardInfo, LevelKeyName: levelKeyName, Missions: missions, - RegularCredits: creditDrops + RegularCredits: creditDrops, + VoidTearParticipantsCurrWave: voidTearWave }: IMissionInventoryUpdateRequest ) => { if (!rewardInfo) { @@ -291,6 +293,15 @@ export const addMissionRewards = async ( rngRewardCredits: inventoryChanges.RegularCredits ?? 0 }); + if ( + voidTearWave && + voidTearWave.Participants[0].QualifiesForReward && + !voidTearWave.Participants[0].HaveRewardResponse + ) { + await crackRelic(inventory, voidTearWave.Participants[0]); + MissionRewards.push({ StoreItem: voidTearWave.Participants[0].Reward, ItemCount: 1 }); + } + return { inventoryChanges, MissionRewards, credits }; }; diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index e7706d017..0220240ac 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -87,6 +87,11 @@ export type IMissionInventoryUpdateRequest = { PlayerSkillGains: IPlayerSkills; CustomMarkers?: ICustomMarkers[]; LoreFragmentScans?: ILoreFragmentScan[]; + VoidTearParticipantsCurrWave?: { + Wave: number; + IsFinalWave: boolean; + Participants: IVoidTearParticipantInfo[]; + }; } & { [K in TEquipmentKey]?: IEquipmentClient[]; }; @@ -136,3 +141,17 @@ export interface IUnlockShipFeatureRequest { KeyChain: string; ChainStage: number; } + +export interface IVoidTearParticipantInfo { + AccountId: string; + Name: string; + ChosenRewardOwner: string; + MissionHash: string; + VoidProjection: string; + Reward: string; + QualifiesForReward: boolean; + HaveRewardResponse: boolean; + RewardsMultiplier: number; + RewardProjection: string; + HardModeReward: ITypeCount; +}