返回提交历史
Modified
package-lock.json
+4
-4
Modified
package.json
+1
-1
Modified
src/controllers/api/modularWeaponSaleController.ts
+119
-4
Modified
src/services/rngService.ts
+23
-0
Deleted
static/fixed_responses/modularWeaponSale.json
+0
-86
XFEstudio/XFESpaceNinjaServer
feat: randomly generate daily modular weapon sales (#1199)
Re #685 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1199
ecc2e355
代码差异
5 个文件
+147
-95
@@ -17,7 +17,7 @@
17
17
"mongoose": "^8.11.0",
18
18
"morgan": "^1.10.0",
19
19
"typescript": ">=5.5 <5.6.0",
20
"warframe-public-export-plus": "^0.5.44",
20
"warframe-public-export-plus": "^0.5.46",
21
21
"warframe-riven-info": "^0.1.2",
22
22
"winston": "^3.17.0",
23
23
"winston-daily-rotate-file": "^5.0.0"
@@ -4006,9 +4006,9 @@
4006
4006
}
4007
4007
},
4008
4008
"node_modules/warframe-public-export-plus": {
4009
"version": "0.5.44",
4010
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.44.tgz",
4011
"integrity": "sha512-0EH3CQBCuuELiLBL1brc/o6Qx8CK723TJF5o68VXc60ha93Juo6LQ+dV+QgzFvVQ5RZTjBLtKB4MP8qw3YHCUQ=="
4009
"version": "0.5.46",
4010
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.46.tgz",
4011
"integrity": "sha512-bgxM8A+ccIydpTDRbISKmGt3XJb0rwX5cx04xGtqqhKX1Qs1OJM6NMGa3CKdqy6OiB7xXCPNLbi+KdqvJp9p9A=="
4012
4012
},
4013
4013
"node_modules/warframe-riven-info": {
4014
4014
"version": "0.1.2",
@@ -22,7 +22,7 @@
22
22
"mongoose": "^8.11.0",
23
23
"morgan": "^1.10.0",
24
24
"typescript": ">=5.5 <5.6.0",
25
"warframe-public-export-plus": "^0.5.44",
25
"warframe-public-export-plus": "^0.5.46",
26
26
"warframe-riven-info": "^0.1.2",
27
27
"winston": "^3.17.0",
28
28
"winston-daily-rotate-file": "^5.0.0"
@@ -1,8 +1,123 @@
1
1
import { RequestHandler } from "express";
2
import modularWeaponSale from "@/static/fixed_responses/modularWeaponSale.json";
2
import { ExportWeapons } from "warframe-public-export-plus";
3
import { IMongoDate } from "@/src/types/commonTypes";
4
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
5
import { CRng } from "@/src/services/rngService";
3
6
4
const modularWeaponSaleController: RequestHandler = (_req, res) => {
5
res.json(modularWeaponSale);
7
// op=SyncAll
8
export const modularWeaponSaleController: RequestHandler = (_req, res) => {
9
const partTypeToParts: Record<string, string[]> = {};
10
for (const [uniqueName, data] of Object.entries(ExportWeapons)) {
11
if (data.partType) {
12
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
13
partTypeToParts[data.partType] ??= [];
14
partTypeToParts[data.partType].push(uniqueName);
15
}
16
}
17
18
const today: number = Math.trunc(Date.now() / 86400000);
19
const kitgunIsPrimary: boolean = (today & 1) != 0;
20
res.json({
21
SaleInfos: [
22
getModularWeaponSale(
23
partTypeToParts,
24
today,
25
"Ostron",
26
["LWPT_HILT", "LWPT_BLADE", "LWPT_HILT_WEIGHT"],
27
() => "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon"
28
),
29
getModularWeaponSale(
30
partTypeToParts,
31
today,
32
"SolarisUnitedHoverboard",
33
["LWPT_HB_DECK", "LWPT_HB_ENGINE", "LWPT_HB_FRONT", "LWPT_HB_JET"],
34
() => "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit"
35
),
36
getModularWeaponSale(
37
partTypeToParts,
38
today,
39
"SolarisUnitedMoaPet",
40
["LWPT_MOA_LEG", "LWPT_MOA_HEAD", "LWPT_MOA_ENGINE", "LWPT_MOA_PAYLOAD"],
41
() => "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetPowerSuit"
42
),
43
getModularWeaponSale(
44
partTypeToParts,
45
today,
46
"SolarisUnitedKitGun",
47
[
48
kitgunIsPrimary ? "LWPT_GUN_PRIMARY_HANDLE" : "LWPT_GUN_SECONDARY_HANDLE",
49
"LWPT_GUN_BARREL",
50
"LWPT_GUN_CLIP"
51
],
52
(parts: string[]) => {
53
const barrel = parts[1];
54
const gunType = ExportWeapons[barrel].gunType!;
55
if (kitgunIsPrimary) {
56
return {
57
GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary",
58
GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun",
59
GT_BEAM: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam"
60
}[gunType];
61
} else {
62
return {
63
GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary",
64
GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun",
65
GT_BEAM: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam"
66
}[gunType];
67
}
68
}
69
)
70
]
71
});
72
};
73
74
const priceFactor: Record<string, number> = {
75
Ostron: 0.9,
76
SolarisUnitedHoverboard: 0.85,
77
SolarisUnitedMoaPet: 0.95,
78
SolarisUnitedKitGun: 0.9
6
79
};
7
80
8
export { modularWeaponSaleController };
81
const getModularWeaponSale = (
82
partTypeToParts: Record<string, string[]>,
83
day: number,
84
name: string,
85
partTypes: string[],
86
getItemType: (parts: string[]) => string
87
): IModularWeaponSaleInfo => {
88
const rng = new CRng(day);
89
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType]));
90
let partsCost = 0;
91
for (const part of parts) {
92
const meta = ExportWeapons[part];
93
if (!meta.premiumPrice) {
94
throw new Error(`no premium price for ${part}`);
95
}
96
partsCost += meta.premiumPrice;
97
}
98
return {
99
Name: name,
100
Expiry: toMongoDate(new Date((day + 1) * 86400000)),
101
Revision: day,
102
Weapons: [
103
{
104
ItemType: getItemType(parts),
105
PremiumPrice: Math.trunc(partsCost * priceFactor[name]),
106
ModularParts: parts
107
}
108
]
109
};
110
};
111
112
interface IModularWeaponSaleInfo {
113
Name: string;
114
Expiry: IMongoDate;
115
Revision: number;
116
Weapons: IModularWeaponSaleItem[];
117
}
118
119
interface IModularWeaponSaleItem {
120
ItemType: string;
121
PremiumPrice: number;
122
ModularParts: string[];
123
}
@@ -69,3 +69,26 @@ export const getRandomWeightedRewardUc = <T extends { Rarity: TRarity }>(
69
69
}
70
70
return getRandomReward(resultPool);
71
71
};
72
73
export class CRng {
74
state: number;
75
76
constructor(seed: number = 1) {
77
this.state = seed;
78
}
79
80
random(): number {
81
this.state = (this.state * 1103515245 + 12345) & 0x7fffffff;
82
return (this.state & 0x3fffffff) / 0x3fffffff;
83
}
84
85
randomInt(min: number, max: number): number {
86
min = Math.ceil(min);
87
max = Math.floor(max);
88
return Math.floor(this.random() * (max - min + 1)) + min;
89
}
90
91
randomElement<T>(arr: T[]): T {
92
return arr[Math.floor(this.random() * arr.length)];
93
}
94
}
@@ -1,86 +0,0 @@
1
{
2
"SaleInfos": [
3
{
4
"Name": "Ostron",
5
"Expiry": {
6
"$date": {
7
"$numberLong": "9999999900000"
8
}
9
},
10
"Revision": 3453,
11
"Weapons": [
12
{
13
"ItemType": "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon",
14
"PremiumPrice": 162,
15
"ModularParts": [
16
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Handle/HandleFive",
17
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Tip/TipFour",
18
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Balance/BalanceSpeedICritII"
19
]
20
}
21
]
22
},
23
{
24
"Name": "SolarisUnitedHoverboard",
25
"Expiry": {
26
"$date": {
27
"$numberLong": "9999999900000"
28
}
29
},
30
"Revision": 2058,
31
"Weapons": [
32
{
33
"ItemType": "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit",
34
"PremiumPrice": 51,
35
"ModularParts": [
36
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisADeck",
37
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusA/HoverboardCorpusAEngine",
38
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisAFront",
39
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusB/HoverboardCorpusBJet"
40
]
41
}
42
]
43
},
44
{
45
"Name": "SolarisUnitedMoaPet",
46
"Expiry": {
47
"$date": {
48
"$numberLong": "9999999900000"
49
}
50
},
51
"Revision": 2058,
52
"Weapons": [
53
{
54
"ItemType": "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetPowerSuit",
55
"PremiumPrice": 180,
56
"ModularParts": [
57
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetLegB",
58
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetHeadPara",
59
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetEngineArcotek",
60
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetPayloadMunitron"
61
]
62
}
63
]
64
},
65
{
66
"Name": "SolarisUnitedKitGun",
67
"Expiry": {
68
"$date": {
69
"$numberLong": "9999999900000"
70
}
71
},
72
"Revision": 2058,
73
"Weapons": [
74
{
75
"ItemType": "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary",
76
"PremiumPrice": 184,
77
"ModularParts": [
78
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Handle/SUModularSecondaryHandleCPart",
79
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelBPart",
80
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Clip/SUModularStatIReloadIIClipPart"
81
]
82
}
83
]
84
}
85
]
86
}