mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 09:50:43 -05:00
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
This commit is contained in:
parent
a9c48bc5c8
commit
810cd8abd6
@ -89,82 +89,172 @@
|
|||||||
"5422acb9af1c889c16000029": {
|
"5422acb9af1c889c16000029": {
|
||||||
"_name": "WEAPON",
|
"_name": "WEAPON",
|
||||||
"conditionChance": 0.2,
|
"conditionChance": 0.2,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.6,
|
"min": 0.6,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"543be5664bdc2dd4348b4569": {
|
"543be5664bdc2dd4348b4569": {
|
||||||
"_name": "MEDS",
|
"_name": "MEDS",
|
||||||
"conditionChance": 0.2,
|
"conditionChance": 0.2,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.6,
|
"min": 0.6,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5447e0e74bdc2d3c308b4567": {
|
"5447e0e74bdc2d3c308b4567": {
|
||||||
"_name": "SPEC_ITEM",
|
"_name": "SPEC_ITEM",
|
||||||
"conditionChance": 0.3,
|
"conditionChance": 0.3,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.02,
|
"min": 0.02,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"543be5e94bdc2df1348b4568": {
|
"543be5e94bdc2df1348b4568": {
|
||||||
"_name": "KEY",
|
"_name": "KEY",
|
||||||
"conditionChance": 0.04,
|
"conditionChance": 0.04,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.96,
|
"min": 0.96,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5448e5284bdc2dcb718b4567": {
|
"5448e5284bdc2dcb718b4567": {
|
||||||
"_name": "VEST",
|
"_name": "VEST",
|
||||||
"conditionChance": 0.2,
|
"conditionChance": 0.2,
|
||||||
"min": 0.05,
|
"current": {
|
||||||
|
"min": 0,
|
||||||
"max": 1
|
"max": 1
|
||||||
},
|
},
|
||||||
"65649eb40bf0ed77b8044453": {
|
"max": {
|
||||||
"_name": "BUILT_IN_INSERTS",
|
"min": 0.45,
|
||||||
"conditionChance": 0.3,
|
"max": 1
|
||||||
"min": 0.1,
|
}
|
||||||
|
},
|
||||||
|
"5448e54d4bdc2dcc718b4568": {
|
||||||
|
"_name": "ARMOR",
|
||||||
|
"conditionChance": 0.2,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
"max": 1
|
"max": 1
|
||||||
},
|
},
|
||||||
"57bef4c42459772e8d35a53b": {
|
"max": {
|
||||||
"_name": "ARMORED_EQUIPMENT",
|
"min": 0.45,
|
||||||
"conditionChance": 0.25,
|
|
||||||
"min": 0.05,
|
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"644120aa86ffbe10ee032b6f": {
|
"644120aa86ffbe10ee032b6f": {
|
||||||
"_name": "ARMOR_PLATE",
|
"_name": "ARMOR_PLATE",
|
||||||
"conditionChance": 0.45,
|
"conditionChance": 0.45,
|
||||||
"min": 0.2,
|
"current": {
|
||||||
|
"min": 0,
|
||||||
"max": 1
|
"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": {
|
"543be6674bdc2df1348b4569": {
|
||||||
"_name": "FOOD_DRINK",
|
"_name": "FOOD_DRINK",
|
||||||
"conditionChance": 0.05,
|
"conditionChance": 0.05,
|
||||||
|
"current": {
|
||||||
|
"min": 1,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.05,
|
"min": 0.05,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5d650c3e815116009f6201d2": {
|
"5d650c3e815116009f6201d2": {
|
||||||
"_name": "FUEL",
|
"_name": "FUEL",
|
||||||
"conditionChance": 0.12,
|
"conditionChance": 0.12,
|
||||||
|
"current": {
|
||||||
|
"min": 1,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.7,
|
"min": 0.7,
|
||||||
"max": 0.99
|
"max": 100
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5a341c4686f77469e155819e": {
|
"5a341c4686f77469e155819e": {
|
||||||
"_name": "FACECOVER",
|
"_name": "FACECOVER",
|
||||||
"conditionChance": 0.32,
|
"conditionChance": 0.32,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.6,
|
"min": 0.6,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5448e5724bdc2ddf718b4568": {
|
"5448e5724bdc2ddf718b4568": {
|
||||||
"_name": "VISORS",
|
"_name": "VISORS",
|
||||||
"conditionChance": 0.32,
|
"conditionChance": 0.32,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.7,
|
"min": 0.7,
|
||||||
"max": 1
|
"max": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"5a341c4086f77401f2541505": {
|
"5a341c4086f77401f2541505": {
|
||||||
"_name": "HELMETS",
|
"_name": "HELMETS",
|
||||||
"conditionChance": 0.20,
|
"conditionChance": 0.32,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
"min": 0.45,
|
"min": 0.45,
|
||||||
"max": 1
|
"max": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"57bef4c42459772e8d35a53b": {
|
||||||
|
"_name": "ARMORED_EQUIPMENT",
|
||||||
|
"conditionChance": 0.25,
|
||||||
|
"current": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
|
"min": 0.05,
|
||||||
|
"max": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"stackablePercent": {
|
"stackablePercent": {
|
||||||
"min": 10,
|
"min": 10,
|
||||||
"max": 600
|
"max": 600
|
||||||
|
@ -14,7 +14,7 @@ import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
|||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||||
import { Money } from "@spt-aki/models/enums/Money";
|
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 { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
@ -637,8 +637,12 @@ export class RagfairOfferGenerator
|
|||||||
{
|
{
|
||||||
const rootItem = itemWithMods[0];
|
const rootItem = itemWithMods[0];
|
||||||
|
|
||||||
const itemConditionValues = this.ragfairConfig.dynamic.condition[conditionSettingsId];
|
const itemConditionValues: Condition = this.ragfairConfig.dynamic.condition[conditionSettingsId];
|
||||||
const multiplier = this.randomUtil.getFloat(itemConditionValues.min, itemConditionValues.max);
|
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
|
// Randomise armor + plates + armor related things
|
||||||
if (
|
if (
|
||||||
@ -646,17 +650,7 @@ export class RagfairOfferGenerator
|
|||||||
|| this.itemHelper.isOfBaseclasses(rootItem._tpl, [BaseClasses.ARMOR_PLATE, BaseClasses.ARMORED_EQUIPMENT])
|
|| this.itemHelper.isOfBaseclasses(rootItem._tpl, [BaseClasses.ARMOR_PLATE, BaseClasses.ARMORED_EQUIPMENT])
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Chance to not adjust armor
|
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
|
||||||
if (
|
|
||||||
!this.randomUtil.getChance100(
|
|
||||||
this.ragfairConfig.dynamic.condition[BaseClasses.ARMORED_EQUIPMENT].conditionChance * 100,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.randomiseArmorDurabilityValues(itemWithMods);
|
|
||||||
|
|
||||||
// Add hits to visor
|
// Add hits to visor
|
||||||
const visorMod = itemWithMods.find((item) =>
|
const visorMod = itemWithMods.find((item) =>
|
||||||
@ -678,7 +672,7 @@ export class RagfairOfferGenerator
|
|||||||
// Randomise Weapons
|
// Randomise Weapons
|
||||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.WEAPON))
|
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.WEAPON))
|
||||||
{
|
{
|
||||||
this.randomiseWeaponDurabilityValues(itemWithMods[0], multiplier);
|
this.randomiseWeaponDurability(itemWithMods[0], itemDetails, maxMultiplier, currentMultiplier);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -686,7 +680,7 @@ export class RagfairOfferGenerator
|
|||||||
if (rootItem.upd.MedKit)
|
if (rootItem.upd.MedKit)
|
||||||
{
|
{
|
||||||
// randomize health
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
@ -694,7 +688,7 @@ export class RagfairOfferGenerator
|
|||||||
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
|
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
|
||||||
{
|
{
|
||||||
// randomize key uses
|
// 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;
|
|| 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -703,7 +697,7 @@ export class RagfairOfferGenerator
|
|||||||
if (rootItem.upd.FoodDrink)
|
if (rootItem.upd.FoodDrink)
|
||||||
{
|
{
|
||||||
// randomize food/drink value
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
@ -711,7 +705,7 @@ export class RagfairOfferGenerator
|
|||||||
if (rootItem.upd.RepairKit)
|
if (rootItem.upd.RepairKit)
|
||||||
{
|
{
|
||||||
// randomize repair kit (armor/weapon) uses
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
@ -719,81 +713,75 @@ export class RagfairOfferGenerator
|
|||||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.FUEL))
|
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.FUEL))
|
||||||
{
|
{
|
||||||
const totalCapacity = itemDetails._props.MaxResource;
|
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 };
|
rootItem.upd.Resource = { UnitsConsumed: totalCapacity - remainingFuel, Value: remainingFuel };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust an items durability/maxDurability value
|
* Adjust an items durability/maxDurability value
|
||||||
* @param item item (weapon/armor) to adjust
|
* @param item item (weapon/armor) to Adjust
|
||||||
* @param multiplier Value to multiple durability by
|
* @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
|
const lowestCurrentDurability = this.randomUtil.getFloat(currentMultiplier, 1) * chosenMaxDurability;
|
||||||
let tempMaxDurability =
|
const chosenCurrentDurability = Math.round(
|
||||||
Math.round(
|
this.randomUtil.getFloat(lowestCurrentDurability, chosenMaxDurability),
|
||||||
this.randomUtil.getFloat(item.upd.Repairable.Durability - 5, item.upd.Repairable.MaxDurability + 5),
|
);
|
||||||
) || item.upd.Repairable.Durability;
|
|
||||||
|
|
||||||
// clamp values to max/current
|
item.upd.Repairable.Durability = chosenCurrentDurability || 1; // Never let value become 0
|
||||||
if (tempMaxDurability >= item.upd.Repairable.MaxDurability)
|
item.upd.Repairable.MaxDurability = chosenMaxDurability;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomise the durabiltiy values for an armors plates and soft inserts
|
* Randomise the durabiltiy values for an armors plates and soft inserts
|
||||||
* @param armorWithMods Armor item with its child mods
|
* @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;
|
for (const armorItem of armorWithMods)
|
||||||
const childMultiplerValues = {};
|
|
||||||
for (const item of armorWithMods)
|
|
||||||
{
|
{
|
||||||
const itemDbDetails = this.itemHelper.getItem(item._tpl)[1];
|
const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1];
|
||||||
if ((parseInt(<string>itemDbDetails._props.armorClass)) > 1)
|
if ((parseInt(<string>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
|
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1)
|
||||||
if (!childMultiplerValues[itemDbDetails._parent])
|
* itemDbDetails._props.MaxDurability;
|
||||||
{
|
const chosenMaxDurability = Math.round(
|
||||||
childMultiplerValues[itemDbDetails._parent] =
|
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
|
||||||
this.randomUtil.getFloat(
|
);
|
||||||
itemDurabilityConfigDict[itemDbDetails._parent].min,
|
|
||||||
itemDurabilityConfigDict[itemDbDetails._parent].max,
|
|
||||||
) / itemDurabilityConfigDict[itemDbDetails._parent].max;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modMultipler = childMultiplerValues[itemDbDetails._parent];
|
const lowestCurrentDurability = this.randomUtil.getFloat(currentMultiplier, 1) * chosenMaxDurability;
|
||||||
const maxDurability = Math.round(
|
const chosenCurrentDurability = Math.round(
|
||||||
this.randomUtil.getFloat(
|
this.randomUtil.getFloat(lowestCurrentDurability, chosenMaxDurability),
|
||||||
itemDbDetails._props.MaxDurability * this.randomUtil.getFloat(modMultipler, 1),
|
|
||||||
itemDbDetails._props.MaxDurability,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
const durability = Math.round(
|
|
||||||
this.randomUtil.getFloat(maxDurability * this.randomUtil.getFloat(modMultipler, 1), maxDurability),
|
armorItem.upd.Repairable = {
|
||||||
);
|
Durability: chosenCurrentDurability || 1, // Never let value become 0
|
||||||
item.upd.Repairable = {
|
MaxDurability: chosenMaxDurability,
|
||||||
Durability: durability || 1, // Never let value become 0
|
|
||||||
MaxDurability: maxDurability,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,10 +141,12 @@ export interface OfferAdjustment
|
|||||||
priceThreshholdRub: number;
|
priceThreshholdRub: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Condition extends MinMax
|
export interface Condition
|
||||||
{
|
{
|
||||||
/** Percentage change durability is altered */
|
/** Percentage change durability is altered */
|
||||||
conditionChance: number;
|
conditionChance: number;
|
||||||
|
current: MinMax;
|
||||||
|
max: MinMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Blacklist
|
export interface Blacklist
|
||||||
|
Loading…
x
Reference in New Issue
Block a user