using SptCommon.Annotations; using Core.Models.Eft.Common.Tables; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Servers; using Core.Services; using Core.Utils; using Core.Utils.Cloners; using LogLevel = Core.Models.Spt.Logging.LogLevel; namespace Core.Helpers; [Injectable] public class RepairHelper( ISptLogger _logger, RandomUtil _randomUtil, DatabaseService _databaseService, ConfigServer _configServer, ICloner _cloner ) { protected RepairConfig _repairConfig = _configServer.GetConfig(); /// /// Alter an items durability after a repair by trader/repair kit /// /// item to update durability details /// db details of item to repair /// Is item being repaired a piece of armor /// how many unit of durability to repair /// Is item being repaired with a repair kit /// Trader quality value from traders base json /// should item have max durability reduced public void UpdateItemDurability( Item itemToRepair, TemplateItem itemToRepairDetails, bool isArmor, double amountToRepair, bool useRepairKit, double traderQualityMultipler, bool applyMaxDurabilityDegradation = true ) { if (_logger.IsLogEnabled(LogLevel.Debug)) { _logger.Debug($"Adding {amountToRepair} to {itemToRepairDetails.Name} using kit: {useRepairKit}"); } var itemMaxDurability = _cloner.Clone(itemToRepair.Upd.Repairable.MaxDurability); var itemCurrentDurability = _cloner.Clone(itemToRepair.Upd.Repairable.Durability); var itemCurrentMaxDurability = _cloner.Clone(itemToRepair.Upd.Repairable.MaxDurability); var newCurrentDurability = itemCurrentDurability + amountToRepair; var newCurrentMaxDurability = itemCurrentMaxDurability + amountToRepair; // Ensure new max isnt above items max if (newCurrentMaxDurability > itemMaxDurability) { newCurrentMaxDurability = itemMaxDurability; } // Ensure new current isnt above items max if (newCurrentDurability > itemMaxDurability) { newCurrentDurability = itemMaxDurability; } // Update Repairable properties with new values after repair itemToRepair.Upd.Repairable = new UpdRepairable { Durability = newCurrentDurability, MaxDurability = newCurrentMaxDurability }; // when modders set the repair coefficient to 0 it means that they dont want to lose durability on items // the code below generates a random degradation on the weapon durability if (applyMaxDurabilityDegradation) { var randomisedWearAmount = isArmor ? GetRandomisedArmorRepairDegradationValue( itemToRepairDetails.Properties.ArmorMaterial, useRepairKit, itemCurrentMaxDurability ?? 0, traderQualityMultipler ) : GetRandomisedWeaponRepairDegradationValue( itemToRepairDetails.Properties, useRepairKit, itemCurrentMaxDurability ?? 0, traderQualityMultipler ); // Apply wear to durability itemToRepair.Upd.Repairable.MaxDurability -= randomisedWearAmount; // After adjusting max durability with degradation, ensure current dura isnt above max if (itemToRepair.Upd.Repairable.Durability > itemToRepair.Upd.Repairable.MaxDurability) { itemToRepair.Upd.Repairable.Durability = itemToRepair.Upd.Repairable.MaxDurability; } } // Repair mask cracks if (itemToRepair.Upd.FaceShield is not null && itemToRepair.Upd.FaceShield?.Hits > 0) { itemToRepair.Upd.FaceShield.Hits = 0; } } /// /// Repairing armor reduces the total durability value slightly, get a randomised (to 2dp) amount based on armor material /// /// What material is the armor being repaired made of /// Was a repair kit used /// Max amount of durability item can have /// Different traders produce different loss values /// Amount to reduce max durability by protected double GetRandomisedArmorRepairDegradationValue( string armorMaterial, bool isRepairKit, double armorMax, double traderQualityMultipler ) { // Degradation value is based on the armor material var armorMaterialSettings = _databaseService.GetGlobals().Configuration.ArmorMaterials[armorMaterial]; var minMultiplier = isRepairKit ? armorMaterialSettings.MinRepairKitDegradation : armorMaterialSettings.MinRepairDegradation; var maxMultiplier = isRepairKit ? armorMaterialSettings.MaxRepairKitDegradation : armorMaterialSettings.MaxRepairDegradation; var duraLossPercent = _randomUtil.GetDouble((double)minMultiplier, (double)maxMultiplier); var duraLossMultipliedByTraderMultiplier = duraLossPercent * armorMax * traderQualityMultipler; return Math.Round(duraLossMultipliedByTraderMultiplier, 2); } /// /// Repairing weapons reduces the total durability value slightly, get a randomised (to 2dp) amount /// /// Weapon properties /// Was a repair kit used /// Max amount of durability item can have /// Different traders produce different loss values /// Amount to reduce max durability by protected double GetRandomisedWeaponRepairDegradationValue( Props itemProps, bool isRepairKit, double weaponMax, double traderQualityMultipler ) { var minRepairDeg = isRepairKit ? itemProps.MinRepairKitDegradation : itemProps.MinRepairDegradation; var maxRepairDeg = isRepairKit ? itemProps.MaxRepairKitDegradation : itemProps.MaxRepairDegradation; // WORKAROUND: Some items are always 0 when repairkit is true if (maxRepairDeg == 0) { maxRepairDeg = itemProps.MaxRepairDegradation; } var duraLossPercent = _randomUtil.GetDouble((double)minRepairDeg, (double)maxRepairDeg); var duraLossMultipliedByTraderMultiplier = duraLossPercent * weaponMax * traderQualityMultipler; return Math.Round(duraLossMultipliedByTraderMultiplier, 2); } }