feat: randomly generate daily modular weapon sales
All checks were successful
Build / build (22) (push) Successful in 42s
Build / build (20) (push) Successful in 1m5s
Build / build (18) (push) Successful in 1m19s
Build / build (18) (pull_request) Successful in 45s
Build / build (20) (pull_request) Successful in 1m5s
Build / build (22) (pull_request) Successful in 1m9s
All checks were successful
Build / build (22) (push) Successful in 42s
Build / build (20) (push) Successful in 1m5s
Build / build (18) (push) Successful in 1m19s
Build / build (18) (pull_request) Successful in 45s
Build / build (20) (pull_request) Successful in 1m5s
Build / build (22) (pull_request) Successful in 1m9s
This commit is contained in:
parent
2d6e096fde
commit
ba54700526
8
package-lock.json
generated
8
package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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<string, string[]> = {};
|
||||
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<string, number> = {
|
||||
Ostron: 0.9,
|
||||
SolarisUnitedHoverboard: 0.85,
|
||||
SolarisUnitedMoaPet: 0.95,
|
||||
SolarisUnitedKitGun: 0.9
|
||||
};
|
||||
|
||||
const getModularWeaponSale = (
|
||||
partTypeToParts: Record<string, string[]>,
|
||||
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[];
|
||||
}
|
||||
|
@ -69,3 +69,26 @@ export const getRandomWeightedRewardUc = <T extends { Rarity: TRarity }>(
|
||||
}
|
||||
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<T>(arr: T[]): T {
|
||||
return arr[Math.floor(this.random() * arr.length)];
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user