diff --git a/package-lock.json b/package-lock.json index c7a9d1bfa..9dacff87f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "mongoose": "^8.11.0", "morgan": "^1.10.0", "typescript": ">=5.5 <5.6.0", - "warframe-public-export-plus": "^0.5.44", + "warframe-public-export-plus": "^0.5.46", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -4006,9 +4006,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.44", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.44.tgz", - "integrity": "sha512-0EH3CQBCuuELiLBL1brc/o6Qx8CK723TJF5o68VXc60ha93Juo6LQ+dV+QgzFvVQ5RZTjBLtKB4MP8qw3YHCUQ==" + "version": "0.5.46", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.46.tgz", + "integrity": "sha512-bgxM8A+ccIydpTDRbISKmGt3XJb0rwX5cx04xGtqqhKX1Qs1OJM6NMGa3CKdqy6OiB7xXCPNLbi+KdqvJp9p9A==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index 3cb5e8cce..c4e001816 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "mongoose": "^8.11.0", "morgan": "^1.10.0", "typescript": ">=5.5 <5.6.0", - "warframe-public-export-plus": "^0.5.44", + "warframe-public-export-plus": "^0.5.46", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" diff --git a/src/controllers/api/modularWeaponSaleController.ts b/src/controllers/api/modularWeaponSaleController.ts index fac479f3d..7d36984de 100644 --- a/src/controllers/api/modularWeaponSaleController.ts +++ b/src/controllers/api/modularWeaponSaleController.ts @@ -1,8 +1,123 @@ import { RequestHandler } from "express"; -import modularWeaponSale from "@/static/fixed_responses/modularWeaponSale.json"; +import { ExportWeapons } from "warframe-public-export-plus"; +import { IMongoDate } from "@/src/types/commonTypes"; +import { toMongoDate } from "@/src/helpers/inventoryHelpers"; +import { CRng } from "@/src/services/rngService"; -const modularWeaponSaleController: RequestHandler = (_req, res) => { - res.json(modularWeaponSale); +// op=SyncAll +export const modularWeaponSaleController: RequestHandler = (_req, res) => { + const partTypeToParts: Record = {}; + for (const [uniqueName, data] of Object.entries(ExportWeapons)) { + if (data.partType) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + partTypeToParts[data.partType] ??= []; + partTypeToParts[data.partType].push(uniqueName); + } + } + + const today: number = Math.trunc(Date.now() / 86400000); + const kitgunIsPrimary: boolean = (today & 1) != 0; + res.json({ + SaleInfos: [ + getModularWeaponSale( + partTypeToParts, + today, + "Ostron", + ["LWPT_HILT", "LWPT_BLADE", "LWPT_HILT_WEIGHT"], + () => "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon" + ), + getModularWeaponSale( + partTypeToParts, + today, + "SolarisUnitedHoverboard", + ["LWPT_HB_DECK", "LWPT_HB_ENGINE", "LWPT_HB_FRONT", "LWPT_HB_JET"], + () => "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit" + ), + getModularWeaponSale( + partTypeToParts, + today, + "SolarisUnitedMoaPet", + ["LWPT_MOA_LEG", "LWPT_MOA_HEAD", "LWPT_MOA_ENGINE", "LWPT_MOA_PAYLOAD"], + () => "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetPowerSuit" + ), + getModularWeaponSale( + partTypeToParts, + today, + "SolarisUnitedKitGun", + [ + kitgunIsPrimary ? "LWPT_GUN_PRIMARY_HANDLE" : "LWPT_GUN_SECONDARY_HANDLE", + "LWPT_GUN_BARREL", + "LWPT_GUN_CLIP" + ], + (parts: string[]) => { + const barrel = parts[1]; + const gunType = ExportWeapons[barrel].gunType!; + if (kitgunIsPrimary) { + return { + GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary", + GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun", + GT_BEAM: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam" + }[gunType]; + } else { + return { + GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary", + GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun", + GT_BEAM: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam" + }[gunType]; + } + } + ) + ] + }); }; -export { modularWeaponSaleController }; +const priceFactor: Record = { + Ostron: 0.9, + SolarisUnitedHoverboard: 0.85, + SolarisUnitedMoaPet: 0.95, + SolarisUnitedKitGun: 0.9 +}; + +const getModularWeaponSale = ( + partTypeToParts: Record, + day: number, + name: string, + partTypes: string[], + getItemType: (parts: string[]) => string +): IModularWeaponSaleInfo => { + const rng = new CRng(day); + const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])); + let partsCost = 0; + for (const part of parts) { + const meta = ExportWeapons[part]; + if (!meta.premiumPrice) { + throw new Error(`no premium price for ${part}`); + } + partsCost += meta.premiumPrice; + } + return { + Name: name, + Expiry: toMongoDate(new Date((day + 1) * 86400000)), + Revision: day, + Weapons: [ + { + ItemType: getItemType(parts), + PremiumPrice: Math.trunc(partsCost * priceFactor[name]), + ModularParts: parts + } + ] + }; +}; + +interface IModularWeaponSaleInfo { + Name: string; + Expiry: IMongoDate; + Revision: number; + Weapons: IModularWeaponSaleItem[]; +} + +interface IModularWeaponSaleItem { + ItemType: string; + PremiumPrice: number; + ModularParts: string[]; +} diff --git a/src/services/rngService.ts b/src/services/rngService.ts index e20e5ce43..3a119e6fc 100644 --- a/src/services/rngService.ts +++ b/src/services/rngService.ts @@ -69,3 +69,26 @@ export const getRandomWeightedRewardUc = ( } return getRandomReward(resultPool); }; + +export class CRng { + state: number; + + constructor(seed: number = 1) { + this.state = seed; + } + + random(): number { + this.state = (this.state * 1103515245 + 12345) & 0x7fffffff; + return (this.state & 0x3fffffff) / 0x3fffffff; + } + + randomInt(min: number, max: number): number { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(this.random() * (max - min + 1)) + min; + } + + randomElement(arr: T[]): T { + return arr[Math.floor(this.random() * arr.length)]; + } +} diff --git a/static/fixed_responses/modularWeaponSale.json b/static/fixed_responses/modularWeaponSale.json deleted file mode 100644 index 6d5bd172e..000000000 --- a/static/fixed_responses/modularWeaponSale.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "SaleInfos": [ - { - "Name": "Ostron", - "Expiry": { - "$date": { - "$numberLong": "9999999900000" - } - }, - "Revision": 3453, - "Weapons": [ - { - "ItemType": "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon", - "PremiumPrice": 162, - "ModularParts": [ - "/Lotus/Weapons/Ostron/Melee/ModularMelee01/Handle/HandleFive", - "/Lotus/Weapons/Ostron/Melee/ModularMelee01/Tip/TipFour", - "/Lotus/Weapons/Ostron/Melee/ModularMelee01/Balance/BalanceSpeedICritII" - ] - } - ] - }, - { - "Name": "SolarisUnitedHoverboard", - "Expiry": { - "$date": { - "$numberLong": "9999999900000" - } - }, - "Revision": 2058, - "Weapons": [ - { - "ItemType": "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit", - "PremiumPrice": 51, - "ModularParts": [ - "/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisADeck", - "/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusA/HoverboardCorpusAEngine", - "/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisAFront", - "/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusB/HoverboardCorpusBJet" - ] - } - ] - }, - { - "Name": "SolarisUnitedMoaPet", - "Expiry": { - "$date": { - "$numberLong": "9999999900000" - } - }, - "Revision": 2058, - "Weapons": [ - { - "ItemType": "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetPowerSuit", - "PremiumPrice": 180, - "ModularParts": [ - "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetLegB", - "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetHeadPara", - "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetEngineArcotek", - "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetPayloadMunitron" - ] - } - ] - }, - { - "Name": "SolarisUnitedKitGun", - "Expiry": { - "$date": { - "$numberLong": "9999999900000" - } - }, - "Revision": 2058, - "Weapons": [ - { - "ItemType": "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary", - "PremiumPrice": 184, - "ModularParts": [ - "/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Handle/SUModularSecondaryHandleCPart", - "/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelBPart", - "/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Clip/SUModularStatIReloadIIClipPart" - ] - } - ] - } - ] -}