XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFESpaceNinjaServer

feat: cracking relics in non-endless missions (#1010)

Closes #415 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1010 Co-authored-by: Sainan <sainan@calamity.inc> Co-committed-by: Sainan <sainan@calamity.inc>

39f0f7de
Sainan <sainan@calamity.inc>
提交于

代码差异

4 个文件 +103 -73
Modified src/controllers/api/getVoidProjectionRewardsController.ts +12 -72
@@ -1,77 +1,31 @@
1 1 import { getJSONfromString } from "@/src/helpers/stringHelpers";
2 import { addMiscItems, getInventory } from "@/src/services/inventoryService";
2 import { crackRelic } from "@/src/helpers/relicHelper";
3 import { getInventory } from "@/src/services/inventoryService";
3 4 import { getAccountIdForRequest } from "@/src/services/loginService";
4 import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
5 import { getRandomWeightedReward2 } from "@/src/services/rngService";
6 import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
7 import { logger } from "@/src/utils/logger";
5 import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
8 6 import { RequestHandler } from "express";
9 import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
10 7
11 8 export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
12 9 const accountId = await getAccountIdForRequest(req);
13 10 const data = getJSONfromString<IVoidProjectionRewardRequest>(String(req.body));
11
12 if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) {
13 const inventory = await getInventory(accountId);
14 await crackRelic(inventory, data.ParticipantInfo);
15 await inventory.save();
16 }
17
14 18 const response: IVoidProjectionRewardResponse = {
15 19 CurrentWave: data.CurrentWave,
16 20 ParticipantInfo: data.ParticipantInfo,
17 21 DifficultyTier: data.DifficultyTier
18 22 };
19 if (data.ParticipantInfo.QualifiesForReward) {
20 const relic = ExportRelics[data.ParticipantInfo.VoidProjection];
21 const weights = refinementToWeights[relic.quality];
22 logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
23 const reward = getRandomWeightedReward2(
24 ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
25 weights
26 )!;
27 logger.debug(`relic rolled`, reward);
28 response.ParticipantInfo.Reward = reward.type;
29
30 const inventory = await getInventory(accountId);
31 // Remove relic
32 addMiscItems(inventory, [
33 {
34 ItemType: data.ParticipantInfo.VoidProjection,
35 ItemCount: -1
36 }
37 ]);
38 // Give reward
39 await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount);
40 await inventory.save();
41 }
42 23 res.json(response);
43 24 };
44 25
45 const refinementToWeights = {
46 VPQ_BRONZE: {
47 COMMON: 0.76,
48 UNCOMMON: 0.22,
49 RARE: 0.02,
50 LEGENDARY: 0
51 },
52 VPQ_SILVER: {
53 COMMON: 0.7,
54 UNCOMMON: 0.26,
55 RARE: 0.04,
56 LEGENDARY: 0
57 },
58 VPQ_GOLD: {
59 COMMON: 0.6,
60 UNCOMMON: 0.34,
61 RARE: 0.06,
62 LEGENDARY: 0
63 },
64 VPQ_PLATINUM: {
65 COMMON: 0.5,
66 UNCOMMON: 0.4,
67 RARE: 0.1,
68 LEGENDARY: 0
69 }
70 };
71
72 26 interface IVoidProjectionRewardRequest {
73 27 CurrentWave: number;
74 ParticipantInfo: IParticipantInfo;
28 ParticipantInfo: IVoidTearParticipantInfo;
75 29 VoidTier: string;
76 30 DifficultyTier: number;
77 31 VoidProjectionRemovalHash: string;
@@ -79,20 +33,6 @@ interface IVoidProjectionRewardRequest {
79 33
80 34 interface IVoidProjectionRewardResponse {
81 35 CurrentWave: number;
82 ParticipantInfo: IParticipantInfo;
36 ParticipantInfo: IVoidTearParticipantInfo;
83 37 DifficultyTier: number;
84 38 }
85
86 interface IParticipantInfo {
87 AccountId: string;
88 Name: string;
89 ChosenRewardOwner: string;
90 MissionHash: string;
91 VoidProjection: string;
92 Reward: string;
93 QualifiesForReward: boolean;
94 HaveRewardResponse: boolean;
95 RewardsMultiplier: number;
96 RewardProjection: string;
97 HardModeReward: ITypeCount;
98 }
Added src/helpers/relicHelper.ts +60 -0
@@ -0,0 +1,60 @@
1 import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
2 import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
3 import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
4 import { getRandomWeightedReward2 } from "@/src/services/rngService";
5 import { logger } from "@/src/utils/logger";
6 import { addMiscItems } from "@/src/services/inventoryService";
7 import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
8
9 export const crackRelic = async (
10 inventory: TInventoryDatabaseDocument,
11 participant: IVoidTearParticipantInfo
12 ): Promise<void> => {
13 const relic = ExportRelics[participant.VoidProjection];
14 const weights = refinementToWeights[relic.quality];
15 logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
16 const reward = getRandomWeightedReward2(
17 ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
18 weights
19 )!;
20 logger.debug(`relic rolled`, reward);
21 participant.Reward = reward.type;
22
23 // Remove relic
24 addMiscItems(inventory, [
25 {
26 ItemType: participant.VoidProjection,
27 ItemCount: -1
28 }
29 ]);
30
31 // Give reward
32 await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount);
33 };
34
35 const refinementToWeights = {
36 VPQ_BRONZE: {
37 COMMON: 0.76,
38 UNCOMMON: 0.22,
39 RARE: 0.02,
40 LEGENDARY: 0
41 },
42 VPQ_SILVER: {
43 COMMON: 0.7,
44 UNCOMMON: 0.26,
45 RARE: 0.04,
46 LEGENDARY: 0
47 },
48 VPQ_GOLD: {
49 COMMON: 0.6,
50 UNCOMMON: 0.34,
51 RARE: 0.06,
52 LEGENDARY: 0
53 },
54 VPQ_PLATINUM: {
55 COMMON: 0.5,
56 UNCOMMON: 0.4,
57 RARE: 0.1,
58 LEGENDARY: 0
59 }
60 };
Modified src/services/missionInventoryUpdateService.ts +12 -1
@@ -33,6 +33,7 @@ import { getEntriesUnsafe } from "@/src/utils/ts-utils";
33 33 import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
34 34 import { handleStoreItemAcquisition } from "./purchaseService";
35 35 import { IMissionReward } from "../types/missionTypes";
36 import { crackRelic } from "@/src/helpers/relicHelper";
36 37
37 38 const getRotations = (rotationCount: number): number[] => {
38 39 if (rotationCount === 0) return [0];
@@ -221,7 +222,8 @@ export const addMissionRewards = async (
221 222 RewardInfo: rewardInfo,
222 223 LevelKeyName: levelKeyName,
223 224 Missions: missions,
224 RegularCredits: creditDrops
225 RegularCredits: creditDrops,
226 VoidTearParticipantsCurrWave: voidTearWave
225 227 }: IMissionInventoryUpdateRequest
226 228 ) => {
227 229 if (!rewardInfo) {
@@ -291,6 +293,15 @@ export const addMissionRewards = async (
291 293 rngRewardCredits: inventoryChanges.RegularCredits ?? 0
292 294 });
293 295
296 if (
297 voidTearWave &&
298 voidTearWave.Participants[0].QualifiesForReward &&
299 !voidTearWave.Participants[0].HaveRewardResponse
300 ) {
301 await crackRelic(inventory, voidTearWave.Participants[0]);
302 MissionRewards.push({ StoreItem: voidTearWave.Participants[0].Reward, ItemCount: 1 });
303 }
304
294 305 return { inventoryChanges, MissionRewards, credits };
295 306 };
296 307
Modified src/types/requestTypes.ts +19 -0
@@ -87,6 +87,11 @@ export type IMissionInventoryUpdateRequest = {
87 87 PlayerSkillGains: IPlayerSkills;
88 88 CustomMarkers?: ICustomMarkers[];
89 89 LoreFragmentScans?: ILoreFragmentScan[];
90 VoidTearParticipantsCurrWave?: {
91 Wave: number;
92 IsFinalWave: boolean;
93 Participants: IVoidTearParticipantInfo[];
94 };
90 95 } & {
91 96 [K in TEquipmentKey]?: IEquipmentClient[];
92 97 };
@@ -136,3 +141,17 @@ export interface IUnlockShipFeatureRequest {
136 141 KeyChain: string;
137 142 ChainStage: number;
138 143 }
144
145 export interface IVoidTearParticipantInfo {
146 AccountId: string;
147 Name: string;
148 ChosenRewardOwner: string;
149 MissionHash: string;
150 VoidProjection: string;
151 Reward: string;
152 QualifiesForReward: boolean;
153 HaveRewardResponse: boolean;
154 RewardsMultiplier: number;
155 RewardProjection: string;
156 HardModeReward: ITypeCount;
157 }