From 810cd8abd65c1af4c82f6c470189412c51db5083 Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 8 Feb 2024 14:52:09 +0000 Subject: [PATCH] Improve flea offer item durability randomisation Expanded `condition` config system to separate out current and max durability Added missing armor config settings Rewrote weapon durability method `randomiseWeaponDurabilityValues()` to do work similar to `randomiseArmorDurabilityValues()` Fixed various items being classified as ARMORED_EQUIPMENT and using the wrong category config values Moved ARMORED_EQUIPMENT to bottom of config so its chosen last, fixes vests being flagged as wrong item --- project/assets/configs/ragfair.json | 160 ++++++++++++++---- .../src/generators/RagfairOfferGenerator.ts | 126 +++++++------- .../src/models/spt/config/IRagfairConfig.ts | 4 +- 3 files changed, 185 insertions(+), 105 deletions(-) diff --git a/project/assets/configs/ragfair.json b/project/assets/configs/ragfair.json index 25c3da62..84ed77ee 100644 --- a/project/assets/configs/ragfair.json +++ b/project/assets/configs/ragfair.json @@ -89,81 +89,171 @@ "5422acb9af1c889c16000029": { "_name": "WEAPON", "conditionChance": 0.2, - "min": 0.6, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.6, + "max": 1 + } }, "543be5664bdc2dd4348b4569": { "_name": "MEDS", "conditionChance": 0.2, - "min": 0.6, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.6, + "max": 1 + } }, "5447e0e74bdc2d3c308b4567": { "_name": "SPEC_ITEM", "conditionChance": 0.3, - "min": 0.02, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.02, + "max": 1 + } }, "543be5e94bdc2df1348b4568": { "_name": "KEY", "conditionChance": 0.04, - "min": 0.96, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.96, + "max": 1 + } }, "5448e5284bdc2dcb718b4567": { "_name": "VEST", "conditionChance": 0.2, - "min": 0.05, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.45, + "max": 1 + } }, - "65649eb40bf0ed77b8044453": { - "_name": "BUILT_IN_INSERTS", - "conditionChance": 0.3, - "min": 0.1, - "max": 1 - }, - "57bef4c42459772e8d35a53b": { - "_name": "ARMORED_EQUIPMENT", - "conditionChance": 0.25, - "min": 0.05, - "max": 1 + "5448e54d4bdc2dcc718b4568": { + "_name": "ARMOR", + "conditionChance": 0.2, + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.45, + "max": 1 + } }, "644120aa86ffbe10ee032b6f": { "_name": "ARMOR_PLATE", "conditionChance": 0.45, - "min": 0.2, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.7, + "max": 1 + } }, + "65649eb40bf0ed77b8044453": { + "_name": "BUILT_IN_INSERTS", + "conditionChance": 0.3, + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.3, + "max": 1 + } + }, "543be6674bdc2df1348b4569": { "_name": "FOOD_DRINK", "conditionChance": 0.05, - "min": 0.05, - "max": 1 + "current": { + "min": 1, + "max": 1 + }, + "max": { + "min": 0.05, + "max": 1 + } }, "5d650c3e815116009f6201d2": { "_name": "FUEL", "conditionChance": 0.12, - "min": 0.7, - "max": 0.99 + "current": { + "min": 1, + "max": 1 + }, + "max": { + "min": 0.7, + "max": 100 + } }, "5a341c4686f77469e155819e": { "_name": "FACECOVER", "conditionChance": 0.32, - "min": 0.6, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.6, + "max": 1 + } }, "5448e5724bdc2ddf718b4568": { "_name": "VISORS", "conditionChance": 0.32, - "min": 0.7, - "max": 1 + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.7, + "max": 1 + } }, "5a341c4086f77401f2541505": { "_name": "HELMETS", - "conditionChance": 0.20, - "min": 0.45, - "max": 1 - } + "conditionChance": 0.32, + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.45, + "max": 1 + } + }, + "57bef4c42459772e8d35a53b": { + "_name": "ARMORED_EQUIPMENT", + "conditionChance": 0.25, + "current": { + "min": 0, + "max": 1 + }, + "max": { + "min": 0.05, + "max": 1 + } + } }, "stackablePercent": { "min": 10, diff --git a/project/src/generators/RagfairOfferGenerator.ts b/project/src/generators/RagfairOfferGenerator.ts index d4827350..e912e8c4 100644 --- a/project/src/generators/RagfairOfferGenerator.ts +++ b/project/src/generators/RagfairOfferGenerator.ts @@ -14,7 +14,7 @@ import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { MemberCategory } from "@spt-aki/models/enums/MemberCategory"; import { Money } from "@spt-aki/models/enums/Money"; -import { Dynamic, IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig"; +import { Condition, Dynamic, IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; @@ -637,8 +637,12 @@ export class RagfairOfferGenerator { const rootItem = itemWithMods[0]; - const itemConditionValues = this.ragfairConfig.dynamic.condition[conditionSettingsId]; - const multiplier = this.randomUtil.getFloat(itemConditionValues.min, itemConditionValues.max); + const itemConditionValues: Condition = this.ragfairConfig.dynamic.condition[conditionSettingsId]; + const maxMultiplier = this.randomUtil.getFloat(itemConditionValues.max.min, itemConditionValues.max.max); + const currentMultiplier = this.randomUtil.getFloat( + itemConditionValues.current.min, + itemConditionValues.current.max, + ); // Randomise armor + plates + armor related things if ( @@ -646,17 +650,7 @@ export class RagfairOfferGenerator || this.itemHelper.isOfBaseclasses(rootItem._tpl, [BaseClasses.ARMOR_PLATE, BaseClasses.ARMORED_EQUIPMENT]) ) { - // Chance to not adjust armor - if ( - !this.randomUtil.getChance100( - this.ragfairConfig.dynamic.condition[BaseClasses.ARMORED_EQUIPMENT].conditionChance * 100, - ) - ) - { - return; - } - - this.randomiseArmorDurabilityValues(itemWithMods); + this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier); // Add hits to visor const visorMod = itemWithMods.find((item) => @@ -678,7 +672,7 @@ export class RagfairOfferGenerator // Randomise Weapons if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.WEAPON)) { - this.randomiseWeaponDurabilityValues(itemWithMods[0], multiplier); + this.randomiseWeaponDurability(itemWithMods[0], itemDetails, maxMultiplier, currentMultiplier); return; } @@ -686,7 +680,7 @@ export class RagfairOfferGenerator if (rootItem.upd.MedKit) { // randomize health - rootItem.upd.MedKit.HpResource = Math.round(rootItem.upd.MedKit.HpResource * multiplier) || 1; + rootItem.upd.MedKit.HpResource = Math.round(rootItem.upd.MedKit.HpResource * maxMultiplier) || 1; return; } @@ -694,7 +688,7 @@ export class RagfairOfferGenerator if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1) { // randomize key uses - rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - multiplier)) + rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier)) || 0; return; @@ -703,7 +697,7 @@ export class RagfairOfferGenerator if (rootItem.upd.FoodDrink) { // randomize food/drink value - rootItem.upd.FoodDrink.HpPercent = Math.round(itemDetails._props.MaxResource * multiplier) || 1; + rootItem.upd.FoodDrink.HpPercent = Math.round(itemDetails._props.MaxResource * maxMultiplier) || 1; return; } @@ -711,7 +705,7 @@ export class RagfairOfferGenerator if (rootItem.upd.RepairKit) { // randomize repair kit (armor/weapon) uses - rootItem.upd.RepairKit.Resource = Math.round(itemDetails._props.MaxRepairResource * multiplier) || 1; + rootItem.upd.RepairKit.Resource = Math.round(itemDetails._props.MaxRepairResource * maxMultiplier) || 1; return; } @@ -719,81 +713,75 @@ export class RagfairOfferGenerator if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.FUEL)) { const totalCapacity = itemDetails._props.MaxResource; - const remainingFuel = Math.round(totalCapacity * multiplier); + const remainingFuel = Math.round(totalCapacity * maxMultiplier); rootItem.upd.Resource = { UnitsConsumed: totalCapacity - remainingFuel, Value: remainingFuel }; } } /** * Adjust an items durability/maxDurability value - * @param item item (weapon/armor) to adjust - * @param multiplier Value to multiple durability by + * @param item item (weapon/armor) to Adjust + * @param itemDbDetails Weapon details from db + * @param maxMultiplier Value to multiply max durability by + * @param currentMultiplier Value to multiply current durability by */ - protected randomiseWeaponDurabilityValues(item: Item, multiplier: number): void + protected randomiseWeaponDurability( + item: Item, + itemDbDetails: ITemplateItem, + maxMultiplier: number, + currentMultiplier: number, + ): void { - item.upd.Repairable.Durability = Math.round(item.upd.Repairable.Durability * multiplier) || 1; + const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1) * itemDbDetails._props.MaxDurability; + const chosenMaxDurability = Math.round( + this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability), + ); - // randomize max durability, store to a temporary value so we can still compare the max durability - let tempMaxDurability = - Math.round( - this.randomUtil.getFloat(item.upd.Repairable.Durability - 5, item.upd.Repairable.MaxDurability + 5), - ) || item.upd.Repairable.Durability; + const lowestCurrentDurability = this.randomUtil.getFloat(currentMultiplier, 1) * chosenMaxDurability; + const chosenCurrentDurability = Math.round( + this.randomUtil.getFloat(lowestCurrentDurability, chosenMaxDurability), + ); - // clamp values to max/current - if (tempMaxDurability >= item.upd.Repairable.MaxDurability) - { - tempMaxDurability = item.upd.Repairable.MaxDurability; - } - if (tempMaxDurability < item.upd.Repairable.Durability) - { - tempMaxDurability = item.upd.Repairable.Durability; - } - - // after clamping, assign to the item's properties - item.upd.Repairable.MaxDurability = tempMaxDurability; + item.upd.Repairable.Durability = chosenCurrentDurability || 1; // Never let value become 0 + item.upd.Repairable.MaxDurability = chosenMaxDurability; } /** * Randomise the durabiltiy values for an armors plates and soft inserts * @param armorWithMods Armor item with its child mods + * @param currentMultiplier Chosen multipler to use for current durability value + * @param maxMultiplier Chosen multipler to use for max durability value */ - protected randomiseArmorDurabilityValues(armorWithMods: Item[]): void + protected randomiseArmorDurabilityValues( + armorWithMods: Item[], + currentMultiplier: number, + maxMultiplier: number, + ): void { - const itemDurabilityConfigDict = this.ragfairConfig.dynamic.condition; - const childMultiplerValues = {}; - for (const item of armorWithMods) + for (const armorItem of armorWithMods) { - const itemDbDetails = this.itemHelper.getItem(item._tpl)[1]; + const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1]; if ((parseInt(itemDbDetails._props.armorClass)) > 1) { - if (!item.upd) + if (!armorItem.upd) { - item.upd = {}; + armorItem.upd = {}; } - // Store mod types durabiltiy multiplier for later use in current/max durability value calculation - if (!childMultiplerValues[itemDbDetails._parent]) - { - childMultiplerValues[itemDbDetails._parent] = - this.randomUtil.getFloat( - itemDurabilityConfigDict[itemDbDetails._parent].min, - itemDurabilityConfigDict[itemDbDetails._parent].max, - ) / itemDurabilityConfigDict[itemDbDetails._parent].max; - } + const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1) + * itemDbDetails._props.MaxDurability; + const chosenMaxDurability = Math.round( + this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability), + ); - const modMultipler = childMultiplerValues[itemDbDetails._parent]; - const maxDurability = Math.round( - this.randomUtil.getFloat( - itemDbDetails._props.MaxDurability * this.randomUtil.getFloat(modMultipler, 1), - itemDbDetails._props.MaxDurability, - ), + const lowestCurrentDurability = this.randomUtil.getFloat(currentMultiplier, 1) * chosenMaxDurability; + const chosenCurrentDurability = Math.round( + this.randomUtil.getFloat(lowestCurrentDurability, chosenMaxDurability), ); - const durability = Math.round( - this.randomUtil.getFloat(maxDurability * this.randomUtil.getFloat(modMultipler, 1), maxDurability), - ); - item.upd.Repairable = { - Durability: durability || 1, // Never let value become 0 - MaxDurability: maxDurability, + + armorItem.upd.Repairable = { + Durability: chosenCurrentDurability || 1, // Never let value become 0 + MaxDurability: chosenMaxDurability, }; } } diff --git a/project/src/models/spt/config/IRagfairConfig.ts b/project/src/models/spt/config/IRagfairConfig.ts index 067140a0..1601c391 100644 --- a/project/src/models/spt/config/IRagfairConfig.ts +++ b/project/src/models/spt/config/IRagfairConfig.ts @@ -141,10 +141,12 @@ export interface OfferAdjustment priceThreshholdRub: number; } -export interface Condition extends MinMax +export interface Condition { /** Percentage change durability is altered */ conditionChance: number; + current: MinMax; + max: MinMax; } export interface Blacklist