feat: opening relics in endless missions (#713)
This commit is contained in:
		
							parent
							
								
									8d7f69ce80
								
							
						
					
					
						commit
						3903b973e2
					
				
							
								
								
									
										99
									
								
								src/controllers/api/getVoidProjectionRewardsController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/controllers/api/getVoidProjectionRewardsController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
 | 
					import { addMiscItems, 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 { 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)) as IVoidProjectionRewardRequest;
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove relic
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					        addMiscItems(inventory, [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ItemType: data.ParticipantInfo.VoidProjection,
 | 
				
			||||||
 | 
					                ItemCount: -1
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Give reward
 | 
				
			||||||
 | 
					        await handleStoreItemAcquisition(reward.type, accountId, reward.itemCount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    VoidTier: string;
 | 
				
			||||||
 | 
					    DifficultyTier: number;
 | 
				
			||||||
 | 
					    VoidProjectionRemovalHash: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IVoidProjectionRewardResponse {
 | 
				
			||||||
 | 
					    CurrentWave: number;
 | 
				
			||||||
 | 
					    ParticipantInfo: IParticipantInfo;
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -26,6 +26,7 @@ import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsers
 | 
				
			|||||||
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
 | 
					import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
 | 
				
			||||||
import { getShipController } from "@/src/controllers/api/getShipController";
 | 
					import { getShipController } from "@/src/controllers/api/getShipController";
 | 
				
			||||||
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
 | 
					import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
 | 
				
			||||||
 | 
					import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
 | 
				
			||||||
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
 | 
					import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
 | 
				
			||||||
import { guildTechController } from "../controllers/api/guildTechController";
 | 
					import { guildTechController } from "../controllers/api/guildTechController";
 | 
				
			||||||
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
 | 
					import { hostSessionController } from "@/src/controllers/api/hostSessionController";
 | 
				
			||||||
@ -120,6 +121,7 @@ apiRouter.post("/focus.php", focusController);
 | 
				
			|||||||
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
 | 
					apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
 | 
				
			||||||
apiRouter.post("/genericUpdate.php", genericUpdateController);
 | 
					apiRouter.post("/genericUpdate.php", genericUpdateController);
 | 
				
			||||||
apiRouter.post("/getAlliance.php", getAllianceController);
 | 
					apiRouter.post("/getAlliance.php", getAllianceController);
 | 
				
			||||||
 | 
					apiRouter.post("/getVoidProjectionRewards.php", getVoidProjectionRewardsController);
 | 
				
			||||||
apiRouter.post("/gildWeapon.php", gildWeaponController);
 | 
					apiRouter.post("/gildWeapon.php", gildWeaponController);
 | 
				
			||||||
apiRouter.post("/guildTech.php", guildTechController);
 | 
					apiRouter.post("/guildTech.php", guildTechController);
 | 
				
			||||||
apiRouter.post("/hostSession.php", hostSessionController);
 | 
					apiRouter.post("/hostSession.php", hostSessionController);
 | 
				
			||||||
 | 
				
			|||||||
@ -40,3 +40,22 @@ export const getRandomWeightedReward = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return getRandomReward(resultPool);
 | 
					    return getRandomReward(resultPool);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getRandomWeightedReward2 = (
 | 
				
			||||||
 | 
					    pool: { type: string; itemCount: number; rarity: TRarity }[],
 | 
				
			||||||
 | 
					    weights: Record<TRarity, number>
 | 
				
			||||||
 | 
					): IRngResult | undefined => {
 | 
				
			||||||
 | 
					    const resultPool: IRngResult[] = [];
 | 
				
			||||||
 | 
					    const rarityCounts: Record<TRarity, number> = { COMMON: 0, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
 | 
				
			||||||
 | 
					    for (const entry of pool) {
 | 
				
			||||||
 | 
					        ++rarityCounts[entry.rarity];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (const entry of pool) {
 | 
				
			||||||
 | 
					        resultPool.push({
 | 
				
			||||||
 | 
					            type: entry.type,
 | 
				
			||||||
 | 
					            itemCount: entry.itemCount,
 | 
				
			||||||
 | 
					            probability: weights[entry.rarity] / rarityCounts[entry.rarity]
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return getRandomReward(resultPool);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user