using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EpicLoot; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("HaldorExtraItems")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("HaldorExtraItems")] [assembly: AssemblyTitle("HaldorExtraItems")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HaldorExtraItems { [BepInPlugin("com.haldorextraitems.mod", "Haldor Extra Items", "1.9.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public sealed class MagicRecipe { public string EffectType; public float EffectValue; public ItemRarity Rarity; } public sealed class TradeOffer { public string PrefabName; public int Stack; public int Price; public string RequiredGlobalKey; } private sealed class ItemConfig { public ConfigEntry Enabled; public ConfigEntry Prefab; public ConfigEntry Enchantment; public ConfigEntry EnchantmentValue; public ConfigEntry Rarity; public ConfigEntry CoinsCost; public ConfigEntry Stack; } public const string PluginGuid = "com.haldorextraitems.mod"; public const string PluginName = "Haldor Extra Items"; public const string PluginVersion = "1.9.0"; internal static ManualLogSource Log; internal static readonly List Offers = new List(); internal static readonly Dictionary MagicByPrefab = new Dictionary(StringComparer.Ordinal); private bool _registered; private readonly ItemConfig[] _items = new ItemConfig[8]; private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; BindAllItemConfigs(); PrefabManager.OnPrefabsRegistered += TryRegister; ItemManager.OnItemsRegistered += TryRegister; new Harmony("com.haldorextraitems.mod").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Haldor Extra Items 1.9.0 loaded (normal Haldor shop only)."); } private void BindAllItemConfigs() { string[] array = new string[8] { "EtchedRunestoneMagic", "EtchedRunestoneMagic", "EtchedRunestoneRare", "EtchedRunestoneRare", "EtchedRunestoneEpic", "EtchedRunestoneEpic", "EtchedRunestoneLegendary", "EtchedRunestoneMythic" }; string[] array2 = new string[8] { "Magic", "Magic", "Rare", "Rare", "Epic", "Epic", "Legendary", "Mythic" }; float[] array3 = new float[8] { 10f, 15f, 20f, 25f, 30f, 35f, 40f, 50f }; int[] array4 = new int[8] { 350, 500, 800, 1100, 1800, 2400, 4000, 7500 }; for (int i = 0; i < 8; i++) { string text = $"Item {i + 1}"; ItemConfig itemConfig = new ItemConfig(); itemConfig.Enabled = ((BaseUnityPlugin)this).Config.Bind(text, "Enabled", true, "Enable this entry."); itemConfig.Prefab = ((BaseUnityPlugin)this).Config.Bind(text, "Prefab", array[i], "Prefab to clone."); itemConfig.Enchantment = ((BaseUnityPlugin)this).Config.Bind(text, "Enchantment", "Riches", "Magic effect type."); itemConfig.EnchantmentValue = ((BaseUnityPlugin)this).Config.Bind(text, "Enchantment Value", array3[i], "Effect strength."); itemConfig.Rarity = ((BaseUnityPlugin)this).Config.Bind(text, "Rarity", array2[i], "Magic, Rare, Epic, Legendary, Mythic."); itemConfig.CoinsCost = ((BaseUnityPlugin)this).Config.Bind(text, "Coins Cost", array4[i], "Coin price."); itemConfig.Stack = ((BaseUnityPlugin)this).Config.Bind(text, "Stack", 1, "Stack per purchase."); _items[i] = itemConfig; } } private void TryRegister() { if (_registered) { return; } if ((Object)(object)FindPrefab("RunestoneMagic") == (Object)null && (Object)(object)FindPrefab("EtchedRunestoneMagic") == (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Waiting for Epic Loot runestones..."); return; } _registered = true; PrefabManager.OnPrefabsRegistered -= TryRegister; ItemManager.OnItemsRegistered -= TryRegister; try { Offers.Clear(); MagicByPrefab.Clear(); for (int i = 0; i < 8; i++) { AddConfiguredItem(i); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Done. Trade offers: {Offers.Count}"); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Registration failed: {arg}"); _registered = false; } } private void AddConfiguredItem(int index) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected O, but got Unknown string text = $"Item {index + 1}"; ItemConfig itemConfig = _items[index]; if (!itemConfig.Enabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] disabled.")); return; } string text2 = ResolveSourceName(itemConfig.Prefab.Value); if (text2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] No source prefab found.")); return; } string value = itemConfig.Enchantment.Value; string value2 = itemConfig.Rarity.Value; float value3 = itemConfig.EnchantmentValue.Value; int value4 = itemConfig.CoinsCost.Value; int stack = Math.Max(1, itemConfig.Stack.Value); string text3 = $"HEI_{index + 1}_{Sanitize(value)}_{Sanitize(value2)}_{Mathf.RoundToInt(value3)}"; string text4 = ResolveEffectType(value); ItemRarity rarity = ParseRarity(value2); MagicRecipe magicRecipe = new MagicRecipe { EffectType = text4, EffectValue = value3, Rarity = rarity }; MagicByPrefab[text3] = magicRecipe; GameObject prefab = PrefabManager.Instance.GetPrefab(text3); if ((Object)(object)prefab == (Object)null) { prefab = PrefabManager.Instance.CreateClonedPrefab(text3, text2); if ((Object)(object)prefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] CreateClonedPrefab failed.")); return; } ItemDrop component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + text + "] No ItemDrop on clone.")); return; } ApplyMagicToItemData(component.m_itemData, magicRecipe); component.m_itemData.m_dropPrefab = prefab; ItemManager.Instance.AddItem(new CustomItem(prefab, false)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] Cloned '" + text3 + "' from '" + text2 + "'.")); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[" + text + "] '" + text3 + "' already present.")); ItemDrop component2 = prefab.GetComponent(); if ((Object)(object)component2 != (Object)null) { ApplyMagicToItemData(component2.m_itemData, magicRecipe); component2.m_itemData.m_dropPrefab = prefab; } } if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text3); if ((Object)(object)itemPrefab != (Object)null) { ItemDrop component3 = itemPrefab.GetComponent(); if ((Object)(object)component3 != (Object)null) { ApplyMagicToItemData(component3.m_itemData, magicRecipe); component3.m_itemData.m_dropPrefab = itemPrefab; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{text}] Magic applied: {text4}={value3}, rarity={value2}"); Offers.Add(new TradeOffer { PrefabName = text3, Stack = stack, Price = Math.Max(1, value4), RequiredGlobalKey = "" }); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{text}] -> Haldor shop @ {value4} coins"); } internal static void ApplyMagicToItemData(ItemData itemData, MagicRecipe recipe) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (itemData == null || recipe == null) { return; } MagicItem val = new MagicItem { Rarity = recipe.Rarity }; MagicItemEffect val2 = new MagicItemEffect(recipe.EffectType, 1f); SetNumericEffectValue(val2, recipe.EffectValue); val.Effects.Add(val2); ItemDataExtensions.SaveMagicItem(itemData, val); try { Type type = typeof(MagicItem).Assembly.GetType("EpicLoot.MagicItemComponent"); if (type == null) { return; } object obj = ((object)itemData).GetType().GetMethod("Data", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(itemData, null); if (obj != null) { MethodInfo method = obj.GetType().GetMethod("GetOrCreate"); if (!(method == null)) { object obj2 = method.MakeGenericMethod(type).Invoke(obj, null); type.GetMethod("SetMagicItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, new object[1] { val }); type.GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, null); } } } catch { } } private string ResolveSourceName(string requested) { string[] obj = new string[12] { requested, "EtchedRunestoneMagic", "EtchedRunestoneRare", "EtchedRunestoneEpic", "EtchedRunestoneLegendary", "EtchedRunestoneMythic", "RunestoneMagic", "RunestoneRare", "RunestoneEpic", "RunestoneLegendary", "RunestoneMythic", "Runestone" }; HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string[] array = obj; foreach (string text in array) { if (!string.IsNullOrEmpty(text) && hashSet.Add(text) && (Object)(object)FindPrefab(text) != (Object)null) { if (!text.Equals(requested, StringComparison.OrdinalIgnoreCase)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("'" + requested + "' missing – using '" + text + "'.")); } return text; } } return null; } private static GameObject FindPrefab(string name) { if (string.IsNullOrEmpty(name)) { return null; } GameObject val = ((PrefabManager.Instance != null) ? PrefabManager.Instance.GetPrefab(name) : null); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(name); } return val; } private static string ResolveEffectType(string value) { FieldInfo field = typeof(MagicEffectType).GetField(value, BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public); if (field != null && field.FieldType == typeof(string)) { string text = field.GetValue(null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } return value; } private static ItemRarity ParseRarity(string value) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!Enum.TryParse(value, ignoreCase: true, out ItemRarity result)) { throw new ArgumentException("Unknown rarity '" + value + "'."); } return result; } private static void SetNumericEffectValue(MagicItemEffect effect, float value) { Type type = ((object)effect).GetType(); string[] array = new string[4] { "EffectValue", "Value", "Power", "EffectPower" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && IsNumeric(field.FieldType)) { field.SetValue(effect, ConvertNumber(value, field.FieldType)); return; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite && IsNumeric(property.PropertyType)) { property.SetValue(effect, ConvertNumber(value, property.PropertyType), null); return; } } throw new MissingMemberException("No numeric member on MagicItemEffect."); } private static bool IsNumeric(Type t) { if (!(t == typeof(float)) && !(t == typeof(double)) && !(t == typeof(int))) { return t == typeof(long); } return true; } private static object ConvertNumber(float value, Type type) { if (type == typeof(float)) { return value; } if (type == typeof(double)) { return (double)value; } if (type == typeof(int)) { return (int)Math.Round(value); } if (type == typeof(long)) { return (long)Math.Round(value); } throw new NotSupportedException(type.FullName); } private static string Sanitize(string value) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { value = value.Replace(oldChar, '_'); } return value.Replace(' ', '_'); } } [HarmonyPatch(typeof(ItemData), "Clone")] internal static class ItemData_Clone_Patch { private static void Postfix(ItemData __instance, ItemData __result) { if (__result == null) { return; } string text = null; if ((Object)(object)__result.m_dropPrefab != (Object)null) { text = ((Object)__result.m_dropPrefab).name; } else if ((Object)(object)__instance?.m_dropPrefab != (Object)null) { text = ((Object)__instance.m_dropPrefab).name; __result.m_dropPrefab = __instance.m_dropPrefab; } if (!string.IsNullOrEmpty(text) && text.StartsWith("HEI_", StringComparison.Ordinal) && Plugin.MagicByPrefab.TryGetValue(text, out var value)) { Plugin.ApplyMagicToItemData(__result, value); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Clone] Re-applied magic on '" + text + "'.")); } } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] internal static class Inventory_AddItem_Patch { private static void Prefix(ItemData item) { if ((Object)(object)item?.m_dropPrefab == (Object)null) { return; } string name = ((Object)item.m_dropPrefab).name; if (!name.StartsWith("HEI_", StringComparison.Ordinal) || !Plugin.MagicByPrefab.TryGetValue(name, out var value)) { return; } try { MagicItem magicItem = ItemDataExtensions.GetMagicItem(item); if (magicItem != null && magicItem.Effects != null && magicItem.Effects.Count > 0) { return; } } catch { } Plugin.ApplyMagicToItemData(item, value); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Inventory] Re-applied magic on '" + name + "'.")); } } } [HarmonyPatch(typeof(Trader), "GetAvailableItems")] internal static class Trader_GetAvailableItems_Patch { private static void Postfix(Trader __instance, ref List __result) { //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown if (Plugin.Offers.Count == 0 || __result == null || (Object)(object)ObjectDB.instance == (Object)null || !IsHaldor(__instance)) { return; } int num = 0; foreach (Plugin.TradeOffer offer in Plugin.Offers) { GameObject val = ObjectDB.instance.GetItemPrefab(offer.PrefabName); if ((Object)(object)val == (Object)null && PrefabManager.Instance != null) { val = PrefabManager.Instance.GetPrefab(offer.PrefabName); } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Shop] '" + offer.PrefabName + "' not in ObjectDB.")); } continue; } ItemDrop component = val.GetComponent(); if ((Object)(object)component == (Object)null) { continue; } if (Plugin.MagicByPrefab.TryGetValue(offer.PrefabName, out var value)) { Plugin.ApplyMagicToItemData(component.m_itemData, value); component.m_itemData.m_dropPrefab = val; } bool flag = false; foreach (TradeItem item in __result) { if ((Object)(object)item?.m_prefab != (Object)null && ((Object)item.m_prefab).name == ((Object)component).name) { flag = true; break; } } if (!flag) { __result.Add(new TradeItem { m_prefab = component, m_stack = offer.Stack, m_price = offer.Price, m_requiredGlobalKey = (offer.RequiredGlobalKey ?? "") }); num++; } } if (num > 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[Shop] Added {num} item(s) to {((Object)((Component)__instance).gameObject).name}."); } } } private static bool IsHaldor(Trader trader) { string name = ((Object)((Component)trader).gameObject).name; if (name.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (name.IndexOf("Vendor_BlackForest", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (trader.m_items != null) { foreach (TradeItem item in trader.m_items) { if (!((Object)(object)item?.m_prefab == (Object)null)) { switch (((Object)item.m_prefab).name) { case "YmirRemains": case "FishingRod": case "Thunderstone": return true; } } } } return false; } } }