返回提交历史
Added
src/controllers/api/getVoidProjectionRewardsController.ts
+99
-0
Modified
src/routes/api.ts
+2
-0
Modified
src/services/rngService.ts
+19
-0
XFEstudio/SpaceNinjaServer
feat: opening relics in endless missions (#713)
3903b973
代码差异
3 个文件
+120
-0
@@ -0,0 +1,99 @@
1
import { getJSONfromString } from "@/src/helpers/stringHelpers";
2
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
3
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";
8
import { RequestHandler } from "express";
9
import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
10
11
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
12
const accountId = await getAccountIdForRequest(req);
13
const data = getJSONfromString(String(req.body)) as IVoidProjectionRewardRequest;
14
const response: IVoidProjectionRewardResponse = {
15
CurrentWave: data.CurrentWave,
16
ParticipantInfo: data.ParticipantInfo,
17
DifficultyTier: data.DifficultyTier
18
};
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
// Remove relic
31
const inventory = await getInventory(accountId);
32
addMiscItems(inventory, [
33
{
34
ItemType: data.ParticipantInfo.VoidProjection,
35
ItemCount: -1
36
}
37
]);
38
await inventory.save();
39
40
// Give reward
41
await handleStoreItemAcquisition(reward.type, accountId, reward.itemCount);
42
}
43
res.json(response);
44
};
45
46
const refinementToWeights = {
47
VPQ_BRONZE: {
48
COMMON: 0.76,
49
UNCOMMON: 0.22,
50
RARE: 0.02,
51
LEGENDARY: 0
52
},
53
VPQ_SILVER: {
54
COMMON: 0.7,
55
UNCOMMON: 0.26,
56
RARE: 0.04,
57
LEGENDARY: 0
58
},
59
VPQ_GOLD: {
60
COMMON: 0.6,
61
UNCOMMON: 0.34,
62
RARE: 0.06,
63
LEGENDARY: 0
64
},
65
VPQ_PLATINUM: {
66
COMMON: 0.5,
67
UNCOMMON: 0.4,
68
RARE: 0.1,
69
LEGENDARY: 0
70
}
71
};
72
73
interface IVoidProjectionRewardRequest {
74
CurrentWave: number;
75
ParticipantInfo: IParticipantInfo;
76
VoidTier: string;
77
DifficultyTier: number;
78
VoidProjectionRemovalHash: string;
79
}
80
81
interface IVoidProjectionRewardResponse {
82
CurrentWave: number;
83
ParticipantInfo: IParticipantInfo;
84
DifficultyTier: number;
85
}
86
87
interface IParticipantInfo {
88
AccountId: string;
89
Name: string;
90
ChosenRewardOwner: string;
91
MissionHash: string;
92
VoidProjection: string;
93
Reward: string;
94
QualifiesForReward: boolean;
95
HaveRewardResponse: boolean;
96
RewardsMultiplier: number;
97
RewardProjection: string;
98
HardModeReward: ITypeCount;
99
}
@@ -26,6 +26,7 @@ import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsers
26
26
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
27
27
import { getShipController } from "@/src/controllers/api/getShipController";
28
28
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
29
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
29
30
import { gildWeaponController } from "@/src/controllers/api/gildWeaponController";
30
31
import { guildTechController } from "../controllers/api/guildTechController";
31
32
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
@@ -120,6 +121,7 @@ apiRouter.post("/focus.php", focusController);
120
121
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
121
122
apiRouter.post("/genericUpdate.php", genericUpdateController);
122
123
apiRouter.post("/getAlliance.php", getAllianceController);
124
apiRouter.post("/getVoidProjectionRewards.php", getVoidProjectionRewardsController);
123
125
apiRouter.post("/gildWeapon.php", gildWeaponController);
124
126
apiRouter.post("/guildTech.php", guildTechController);
125
127
apiRouter.post("/hostSession.php", hostSessionController);
@@ -40,3 +40,22 @@ export const getRandomWeightedReward = (
40
40
}
41
41
return getRandomReward(resultPool);
42
42
};
43
44
export const getRandomWeightedReward2 = (
45
pool: { type: string; itemCount: number; rarity: TRarity }[],
46
weights: Record<TRarity, number>
47
): IRngResult | undefined => {
48
const resultPool: IRngResult[] = [];
49
const rarityCounts: Record<TRarity, number> = { COMMON: 0, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
50
for (const entry of pool) {
51
++rarityCounts[entry.rarity];
52
}
53
for (const entry of pool) {
54
resultPool.push({
55
type: entry.type,
56
itemCount: entry.itemCount,
57
probability: weights[entry.rarity] / rarityCounts[entry.rarity]
58
});
59
}
60
return getRandomReward(resultPool);
61
};