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

SpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/SpaceNinjaServer

feat: randomly generate daily modular weapon sales (#1199)

Re #685 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1199

ecc2e355
Sainan <sainan@calamity.inc>
提交于

代码差异

5 个文件 +147 -95
Modified package-lock.json +4 -4
@@ -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",
Modified package.json +1 -1
@@ -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"
Modified src/controllers/api/modularWeaponSaleController.ts +119 -4
@@ -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 }
Modified src/services/rngService.ts +23 -0
@@ -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 }
Deleted static/fixed_responses/modularWeaponSale.json +0 -86
@@ -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 }