feat: cracking relics in non-endless missions (#1010)
Closes #415 Reviewed-on: #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 { 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 { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
|
||||||
import { getRandomWeightedReward2 } from "@/src/services/rngService";
|
|
||||||
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
|
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const data = getJSONfromString<IVoidProjectionRewardRequest>(String(req.body));
|
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 = {
|
const response: IVoidProjectionRewardResponse = {
|
||||||
CurrentWave: data.CurrentWave,
|
CurrentWave: data.CurrentWave,
|
||||||
ParticipantInfo: data.ParticipantInfo,
|
ParticipantInfo: data.ParticipantInfo,
|
||||||
DifficultyTier: data.DifficultyTier
|
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);
|
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 {
|
interface IVoidProjectionRewardRequest {
|
||||||
CurrentWave: number;
|
CurrentWave: number;
|
||||||
ParticipantInfo: IParticipantInfo;
|
ParticipantInfo: IVoidTearParticipantInfo;
|
||||||
VoidTier: string;
|
VoidTier: string;
|
||||||
DifficultyTier: number;
|
DifficultyTier: number;
|
||||||
VoidProjectionRemovalHash: string;
|
VoidProjectionRemovalHash: string;
|
||||||
@ -79,20 +33,6 @@ interface IVoidProjectionRewardRequest {
|
|||||||
|
|
||||||
interface IVoidProjectionRewardResponse {
|
interface IVoidProjectionRewardResponse {
|
||||||
CurrentWave: number;
|
CurrentWave: number;
|
||||||
ParticipantInfo: IParticipantInfo;
|
ParticipantInfo: IVoidTearParticipantInfo;
|
||||||
DifficultyTier: number;
|
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 { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { handleStoreItemAcquisition } from "./purchaseService";
|
import { handleStoreItemAcquisition } from "./purchaseService";
|
||||||
import { IMissionReward } from "../types/missionTypes";
|
import { IMissionReward } from "../types/missionTypes";
|
||||||
|
import { crackRelic } from "@/src/helpers/relicHelper";
|
||||||
|
|
||||||
const getRotations = (rotationCount: number): number[] => {
|
const getRotations = (rotationCount: number): number[] => {
|
||||||
if (rotationCount === 0) return [0];
|
if (rotationCount === 0) return [0];
|
||||||
@ -221,7 +222,8 @@ export const addMissionRewards = async (
|
|||||||
RewardInfo: rewardInfo,
|
RewardInfo: rewardInfo,
|
||||||
LevelKeyName: levelKeyName,
|
LevelKeyName: levelKeyName,
|
||||||
Missions: missions,
|
Missions: missions,
|
||||||
RegularCredits: creditDrops
|
RegularCredits: creditDrops,
|
||||||
|
VoidTearParticipantsCurrWave: voidTearWave
|
||||||
}: IMissionInventoryUpdateRequest
|
}: IMissionInventoryUpdateRequest
|
||||||
) => {
|
) => {
|
||||||
if (!rewardInfo) {
|
if (!rewardInfo) {
|
||||||
@ -291,6 +293,15 @@ export const addMissionRewards = async (
|
|||||||
rngRewardCredits: inventoryChanges.RegularCredits ?? 0
|
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 };
|
return { inventoryChanges, MissionRewards, credits };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,6 +87,11 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
PlayerSkillGains: IPlayerSkills;
|
PlayerSkillGains: IPlayerSkills;
|
||||||
CustomMarkers?: ICustomMarkers[];
|
CustomMarkers?: ICustomMarkers[];
|
||||||
LoreFragmentScans?: ILoreFragmentScan[];
|
LoreFragmentScans?: ILoreFragmentScan[];
|
||||||
|
VoidTearParticipantsCurrWave?: {
|
||||||
|
Wave: number;
|
||||||
|
IsFinalWave: boolean;
|
||||||
|
Participants: IVoidTearParticipantInfo[];
|
||||||
|
};
|
||||||
} & {
|
} & {
|
||||||
[K in TEquipmentKey]?: IEquipmentClient[];
|
[K in TEquipmentKey]?: IEquipmentClient[];
|
||||||
};
|
};
|
||||||
@ -136,3 +141,17 @@ export interface IUnlockShipFeatureRequest {
|
|||||||
KeyChain: string;
|
KeyChain: string;
|
||||||
ChainStage: number;
|
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