using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using HarmonyLib; using JetBrains.Annotations; using UnityEngine; namespace FiniteItemRepairs { [UsedImplicitly] public class FiniteItemRepairsPatch { private const string MetaDataName = "DurabilityModifier"; private static readonly PassiveEffects EnumDegradationMax = EnumUtils.Parse (nameof (PassiveEffects.DegradationMax)); private const string CustomNameDegradationMax = "DegradationMax"; [HarmonyPatch(typeof(XUiC_RecipeStack))] [HarmonyPatch(nameof(XUiC_RecipeStack.outputStack))] public static class XUiC_RecipeStack_outputStack { private static readonly MethodInfo VanillaItemValueCloneMethod = AccessTools.Method(typeof(ItemValue), "Clone"); private static readonly MethodInfo GetHandleDegradationMethod = SymbolExtensions.GetMethodInfo(() => HandleDegradation(null)); [UsedImplicitly] private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { return new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Callvirt, VanillaItemValueCloneMethod) ).InsertAndAdvance( new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Call, GetHandleDegradationMethod) ).InstructionEnumeration(); } private static void HandleDegradation(ItemValue outItem) { float currentDurabilityModifier = 1; if (outItem.HasMetadata(MetaDataName, TypedMetadataValue.TypeTag.Float)) { object metadata = outItem.GetMetadata(MetaDataName); currentDurabilityModifier = (float)metadata; } currentDurabilityModifier = (1 - (1 - outItem.PercentUsesLeft) * Settings.Data.DegradationPercent) * currentDurabilityModifier; currentDurabilityModifier = Mathf.Max(currentDurabilityModifier, 0.01f); outItem.SetMetadata(MetaDataName, currentDurabilityModifier, TypedMetadataValue.TypeTag.Float); } } [HarmonyPatch(typeof(ItemValue))] [HarmonyPatch(nameof(ItemValue.MaxUseTimes))] [HarmonyPatch(MethodType.Getter)] public static class ItemValue_MaxUseTimes { [UsedImplicitly] private static void Postfix(ref int __result, ItemValue __instance) { __result = ModMaxUseTimes(__result, __instance); } } [HarmonyPatch(typeof(XUiM_ItemStack))] [HarmonyPatch(nameof(XUiM_ItemStack.GetStatItemValueTextWithCompareInfo))] public static class XUiM_ItemStack_GetStatItemValueTextWithCompareInfo { [UsedImplicitly] private static void Prefix (DisplayInfoEntry infoEntry) { if (infoEntry.StatType != EnumDegradationMax) { return; } infoEntry.CustomName = CustomNameDegradationMax; } } [HarmonyPatch(typeof(XUiM_ItemStack))] [HarmonyPatch(nameof(XUiM_ItemStack.GetStatItemValueTextWithModColoring))] public static class XUiM_ItemStack_GetStatItemValueTextWithModColoring { [UsedImplicitly] private static void Prefix (DisplayInfoEntry infoEntry) { if (infoEntry.StatType != EnumDegradationMax) { return; } infoEntry.CustomName = CustomNameDegradationMax; } } [HarmonyPatch(typeof(XUiM_ItemStack))] [HarmonyPatch(nameof(XUiM_ItemStack.GetStatItemValueTextWithModInfo))] public static class XUiM_ItemStack_GetStatItemValueTextWithModInfo { [UsedImplicitly] private static void Prefix (DisplayInfoEntry infoEntry) { if (infoEntry.StatType != EnumDegradationMax) { return; } infoEntry.CustomName = CustomNameDegradationMax; } } [HarmonyPatch(typeof(XUiM_ItemStack))] [HarmonyPatch(nameof(XUiM_ItemStack.GetCustomValue))] public static class XUiM_ItemStack_GetCustomValue { [UsedImplicitly] private static bool Prefix (ref float __result, DisplayInfoEntry entry, ItemValue itemValue, bool useMods) { if (entry.StatType != EnumDegradationMax) { return true; } __result = DegradationMaxMod(entry.StatType, itemValue, null, entry.tags, useMods, 0); return false; } } private static float DegradationMaxMod (PassiveEffects statType, ItemValue itemValue, EntityPlayer player, FastTags tags, bool useMods, float value) { if (statType != EnumDegradationMax) { return value; } value = EffectManager.GetValue(PassiveEffects.DegradationMax, itemValue, 0, player, tags: tags, calcEquipment: false, calcHoldingItem: false, calcProgression: false, calcBuffs: false, useMods: useMods); value = ModMaxUseTimes ((int)value, itemValue); return value; } private static int ModMaxUseTimes(int value, ItemValue iv) { if (value <= 0) { return value; } if (!iv.HasMetadata(MetaDataName, TypedMetadataValue.TypeTag.Float)) { return value; } object metadata = iv.GetMetadata(MetaDataName); float currentDurabilityModifier = (float)metadata; value = Mathf.RoundToInt(value * currentDurabilityModifier); value = Mathf.Max(value, 1); return value; } } }