forked from OpenWF/SpaceNinjaServer
		
	feat: cracking relics in non-endless missions (#1010)
Closes #415 Reviewed-on: OpenWF/SpaceNinjaServer#1010 Co-authored-by: Sainan <sainan@calamity.inc> Co-committed-by: Sainan <sainan@calamity.inc>
This commit is contained in:
		
							parent
							
								
									f672f05db9
								
							
						
					
					
						commit
						39f0f7de9a
					
				@ -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<IVoidProjectionRewardRequest>(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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								src/helpers/relicHelper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/helpers/relicHelper.ts
									
									
									
									
									
										Normal file
									
								
							@ -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<void> => {
 | 
			
		||||
    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
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@ -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 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user