From 5b1d4cdd3e305845479922566271edc7d637d906 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:58:15 +0200 Subject: [PATCH] respect vendor offer seed for innate damage --- src/services/inventoryService.ts | 35 +++++++++++++++++++++----------- src/services/purchaseService.ts | 14 ++++++++++--- src/services/rngService.ts | 9 ++++++++ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 6eba1872..e62e51b9 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -69,7 +69,7 @@ import { addStartingGear } from "@/src/controllers/api/giveStartingGearControlle import { addQuestKey, completeQuest } from "@/src/services/questService"; import { handleBundleAcqusition } from "./purchaseService"; import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; -import { getRandomElement, getRandomInt } from "./rngService"; +import { getRandomElement, getRandomInt, SRng } from "./rngService"; import { createMessage } from "./inboxService"; export const createInventory = async ( @@ -230,7 +230,8 @@ export const addItem = async ( inventory: TInventoryDatabaseDocument, typeName: string, quantity: number = 1, - premiumPurchase: boolean = false + premiumPurchase: boolean = false, + seed?: bigint ): Promise => { // Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments. if (typeName in ExportBundles) { @@ -380,21 +381,31 @@ export const addItem = async ( defaultOverwrites.Features = EquipmentFeatures.DOUBLE_CAPACITY; } if (weapon.maxLevelCap == 40 && typeName.indexOf("BallasSword") == -1) { + if (!seed) { + seed = BigInt(Math.round(Math.random() * Number.MAX_SAFE_INTEGER)); + } + const rng = new SRng(seed); + const tag = rng.randomElement([ + "InnateElectricityDamage", + "InnateFreezeDamage", + "InnateHeatDamage", + "InnateImpactDamage", + "InnateMagDamage", + "InnateRadDamage", + "InnateToxinDamage" + ]); + const WeaponUpgradeValueAttenuationExponent = 2.25; + let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent); + if (value >= 0.941428) { + value = 1; + } defaultOverwrites.UpgradeType = "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod"; defaultOverwrites.UpgradeFingerprint = JSON.stringify({ compat: typeName, buffs: [ { - Tag: getRandomElement([ - "InnateElectricityDamage", - "InnateFreezeDamage", - "InnateHeatDamage", - "InnateImpactDamage", - "InnateMagDamage", - "InnateRadDamage", - "InnateToxinDamage" - ]), - Value: Math.trunc(Math.random() * 0x40000000) + Tag: tag, + Value: Math.trunc(value * 0x40000000) } ] }); diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index f2b71427..04525704 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -51,6 +51,7 @@ export const handlePurchase = async ( logger.debug("purchase request", purchaseRequest); const prePurchaseInventoryChanges: IInventoryChanges = {}; + let seed: bigint | undefined; if (purchaseRequest.PurchaseParams.Source == 7) { const rawManifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!); if (rawManifest) { @@ -74,6 +75,9 @@ export const handlePurchase = async ( prePurchaseInventoryChanges ); } + if (offer.LocTagRandSeed !== undefined) { + seed = BigInt(offer.LocTagRandSeed); + } if (!config.noVendorPurchaseLimits && ItemId) { inventory.RecentVendorPurchases ??= []; let vendorPurchases = inventory.RecentVendorPurchases.find( @@ -136,7 +140,10 @@ export const handlePurchase = async ( const purchaseResponse = await handleStoreItemAcquisition( purchaseRequest.PurchaseParams.StoreItem, inventory, - purchaseRequest.PurchaseParams.Quantity + purchaseRequest.PurchaseParams.Quantity, + undefined, + undefined, + seed ); combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges); @@ -324,7 +331,8 @@ export const handleStoreItemAcquisition = async ( inventory: TInventoryDatabaseDocument, quantity: number = 1, durability: TRarity = "COMMON", - ignorePurchaseQuantity: boolean = false + ignorePurchaseQuantity: boolean = false, + seed?: bigint ): Promise => { let purchaseResponse = { InventoryChanges: {} @@ -345,7 +353,7 @@ export const handleStoreItemAcquisition = async ( } switch (storeCategory) { default: { - purchaseResponse = { InventoryChanges: await addItem(inventory, internalName, quantity, true) }; + purchaseResponse = { InventoryChanges: await addItem(inventory, internalName, quantity, true, seed) }; break; } case "Types": diff --git a/src/services/rngService.ts b/src/services/rngService.ts index cb8f2cba..b98f7bd3 100644 --- a/src/services/rngService.ts +++ b/src/services/rngService.ts @@ -127,4 +127,13 @@ export class SRng { } return min; } + + randomElement(arr: T[]): T { + return arr[this.randomInt(0, arr.length - 1)]; + } + + randomFloat(): number { + this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn; + return (Number(this.state >> 38n) & 0xffffff) * 0.000000059604645; + } }