Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of EtchedRunes v1.0.6
Orgetorix.EtchedRunes.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("Orgetorix.EtchedRunes")] [assembly: AssemblyDescription("Etched Runestones for Epic Loot – Haldor shop")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Orgetorix")] [assembly: AssemblyProduct("Orgetorix.EtchedRunes")] [assembly: AssemblyCopyright("Copyright © Orgetorix 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a1b2c3d4-e5f6-7890-abcd-ef1234567890")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyVersion("1.0.6.0")] namespace Orgetorix.EtchedRunes { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInPlugin("Orgetorix.EtchedRunes", "Orgetorix Etched Runes", "1.0.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class EtchedRunesPlugin : BaseUnityPlugin { public const string PluginGUID = "Orgetorix.EtchedRunes"; public const string PluginName = "Orgetorix Etched Runes"; public const string PluginVersion = "1.0.6"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("Orgetorix.EtchedRunes"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; Log.LogInfo((object)"Orgetorix Etched Runes v1.0.6 loaded (waiting for prefabs)."); } private void OnVanillaPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"Mod disabled in config – skipping registration."); return; } RichesRuneManager.RegisterAll(); LegendaryRuneManager.RegisterAll(); Log.LogInfo((object)"Etched Runes registration finished."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } public class RichesItemConfig { public string Label; public ConfigEntry<bool> Enabled; public ConfigEntry<string> Prefab; public ConfigEntry<string> Enchantment; public ConfigEntry<float> EnchantmentValue; public ConfigEntry<string> Rarity; public ConfigEntry<int> CoinsCost; public ConfigEntry<int> Stack; public ConfigEntry<bool> ApplyOnUse; public ConfigEntry<string> AllowedItemTypes; } public class LegendaryRuneDef { public string Key; public string SetName; public string Label; public ConfigEntry<bool> Enabled; public ConfigEntry<string> DisplayName; public ConfigEntry<string> LegendaryID; public ConfigEntry<string> AllowedItemTypes; public ConfigEntry<string> AllowedSkillTypes; public ConfigEntry<bool> RequireNoParryPower; public ConfigEntry<int> Price; public ConfigEntry<int> StackSize; public ConfigEntry<string> BasePrefab; public string PrefabName => "Orgetorix_LegRune_" + Key; } public static class ModConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<string> LogLevel; public static ConfigEntry<bool> RichesRunesEnabled; public static ConfigEntry<bool> LegendarySetRunesEnabled; public static ConfigEntry<bool> SetHeimdallEnabled; public static ConfigEntry<bool> SetRagnarEnabled; public static ConfigEntry<bool> SetGullveigEnabled; public static ConfigEntry<bool> SetHelEnabled; public static ConfigEntry<bool> SetUllrEnabled; public static ConfigEntry<bool> SetEirEnabled; public static ConfigEntry<bool> SetMimirEnabled; public static readonly List<RichesItemConfig> RichesItems = new List<RichesItemConfig>(); public static readonly List<LegendaryRuneDef> LegendaryRunes = new List<LegendaryRuneDef>(); public static void Bind(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Enable or disable the entire mod"); LogLevel = config.Bind<string>("General", "LogLevel", "Info", "Debug, Info, Warning, Error"); RichesRunesEnabled = config.Bind<bool>("General", "Riches Runes", true, "Enable all Riches etched runestones in Haldor's shop"); LegendarySetRunesEnabled = config.Bind<bool>("General", "Legendary Set Runes", true, "Enable all Legendary Set etched runes in Haldor's shop"); SetHeimdallEnabled = config.Bind<bool>("General", "Set Heimdall", true, "Enable Heimdall set runes"); SetRagnarEnabled = config.Bind<bool>("General", "Set Ragnar", true, "Enable Ragnar set runes"); SetGullveigEnabled = config.Bind<bool>("General", "Set Gullveig", true, "Enable Gullveig set runes (More Set Items)"); SetHelEnabled = config.Bind<bool>("General", "Set Hel", true, "Enable Hel set runes (More Set Items)"); SetUllrEnabled = config.Bind<bool>("General", "Set Ullr", true, "Enable Ullr set runes (More Set Items)"); SetEirEnabled = config.Bind<bool>("General", "Set Eir", true, "Enable Eir 2-piece runes (More Set Items)"); SetMimirEnabled = config.Bind<bool>("General", "Set Mimir", true, "Enable Mimir 2-piece runes (More Set Items)"); AddRiches(config, "01 Magic Runestone 10", "EtchedRunestoneMagic", "Riches", 10f, "Magic", 350, 1); AddRiches(config, "02 Magic Runestone 15", "EtchedRunestoneMagic", "Riches", 15f, "Magic", 500, 1); AddRiches(config, "03 Rare Runestone 20", "EtchedRunestoneRare", "Riches", 20f, "Rare", 800, 1); AddRiches(config, "04 Rare Runestone 25", "EtchedRunestoneRare", "Riches", 25f, "Rare", 1100, 1); AddRiches(config, "05 Epic Runestone 30", "EtchedRunestoneEpic", "Riches", 30f, "Epic", 1800, 1); AddRiches(config, "06 Epic Runestone 35", "EtchedRunestoneEpic", "Riches", 35f, "Epic", 2400, 1); AddRiches(config, "07 Legendary Runestone 40", "EtchedRunestoneLegendary", "Riches", 40f, "Legendary", 4000, 1); AddRiches(config, "08 Mythic Runestone 50", "EtchedRunestoneMythic", "Riches", 50f, "Mythic", 7500, 1); AddRiches(config, "09 Feather Fall Runestone", "EtchedRunestoneEpic", "FeatherFall", 1f, "Epic", 3500, 1); AddRiches(config, "10 Air Jump Runestone", "EtchedRunestoneEpic", "DoubleJump", 1f, "Epic", 3500, 1); AddLegendary(config, "01 Heimdall - Son of Nine Mothers", "Heimdall_SonOfNineMothers", "Heimdall", "Etched Rune: Son of Nine Mothers", "HeimdallHelmet", "Helmet", "", requireNoParry: false, 5000); AddLegendary(config, "02 Heimdall - Heart of the Bifrost", "Heimdall_HeartOfTheBifrost", "Heimdall", "Etched Rune: Heart of the Bifrost", "HeimdallChest", "Chest", "", requireNoParry: false, 5000); AddLegendary(config, "03 Heimdall - Stride of the Aesir", "Heimdall_StrideOfTheAesir", "Heimdall", "Etched Rune: Stride of the Aesir", "HeimdallLegs", "Legs", "", requireNoParry: false, 5000); AddLegendary(config, "04 Heimdall - Guardian of the Gods", "Heimdall_GuardianOfTheGods", "Heimdall", "Etched Rune: Guardian of the Gods", "HeimdallTowerShield", "Shield", "", requireNoParry: true, 5000); AddLegendary(config, "05 Ragnar - Serpentsbane", "Ragnar_Serpentsbane", "Ragnar", "Etched Rune: Serpentsbane", "RagnarBattleAxe", "TwoHandedWeapon", "Axes", requireNoParry: false, 5000); AddLegendary(config, "06 Ragnar - Ragnars White Shirt", "Ragnar_WhiteShirt", "Ragnar", "Etched Rune: Ragnar's White Shirt", "RagnarChest", "Chest", "", requireNoParry: false, 5000); AddLegendary(config, "07 Ragnar - Ragnars Ironsides", "Ragnar_Ironsides", "Ragnar", "Etched Rune: Ragnar's Ironsides", "RagnarLegs", "Legs", "", requireNoParry: false, 5000); AddLegendary(config, "08 Ragnar - Ragnars Boneless Wrap", "Ragnar_BonelessWrap", "Ragnar", "Etched Rune: Ragnar's Boneless Wrap", "RagnarCape", "Shoulder", "", requireNoParry: false, 5000); AddLegendary(config, "09 Gullveig - Staff of Three Winters", "Gullveig_Staff", "Gullveig", "Etched Rune: Staff of Three Winters", "GullveigStaff", "TwoHandedWeapon,TwoHandedWeaponLeft", "ElementalMagic", requireNoParry: false, 5000); AddLegendary(config, "10 Gullveig - Circlet of Cinders", "Gullveig_Helmet", "Gullveig", "Etched Rune: Circlet of Cinders", "GullveigHelmet", "Helmet", "", requireNoParry: false, 5000); AddLegendary(config, "11 Gullveig - Robe of the Wildfire", "Gullveig_Chest", "Gullveig", "Etched Rune: Robe of the Wildfire", "GullveigChest", "Chest", "", requireNoParry: false, 5000); AddLegendary(config, "12 Gullveig - Sash of the Storm", "Gullveig_Cape", "Gullveig", "Etched Rune: Sash of the Storm", "GullveigCape", "Shoulder", "", requireNoParry: false, 5000); AddLegendary(config, "13 Hel - Crook of the Dead", "Hel_Staff", "Hel", "Etched Rune: Crook of the Dead", "HelStaff", "TwoHandedWeapon,TwoHandedWeaponLeft", "BloodMagic", requireNoParry: false, 5000); AddLegendary(config, "14 Hel - Mask of the Barrow", "Hel_Helmet", "Hel", "Etched Rune: Mask of the Barrow", "HelHelmet", "Helmet", "", requireNoParry: false, 5000); AddLegendary(config, "15 Hel - Shroud of Helheim", "Hel_Chest", "Hel", "Etched Rune: Shroud of Helheim", "HelChest", "Chest", "", requireNoParry: false, 5000); AddLegendary(config, "16 Hel - Bindings of the Grave", "Hel_Legs", "Hel", "Etched Rune: Bindings of the Grave", "HelLegs", "Legs", "", requireNoParry: false, 5000); AddLegendary(config, "17 Ullr - Yew of Ullr", "Ullr_Bow", "Ullr", "Etched Rune: Yew of Ullr", "UllrBow", "Bow,Crossbow", "Bows,Crossbows", requireNoParry: false, 5000); AddLegendary(config, "18 Ullr - Hunters Hood", "Ullr_Helmet", "Ullr", "Etched Rune: Hunter's Hood", "UllrHelmet", "Helmet", "", requireNoParry: false, 5000); AddLegendary(config, "19 Ullr - Quiet Mail", "Ullr_Chest", "Ullr", "Etched Rune: Quiet Mail", "UllrChest", "Chest", "", requireNoParry: false, 5000); AddLegendary(config, "20 Ullr - Cloak of the Hunt", "Ullr_Cape", "Ullr", "Etched Rune: Cloak of the Hunt", "UllrCape", "Shoulder", "", requireNoParry: false, 5000); AddLegendary(config, "21 Eir - Eirs Mercy", "Eir_Mercy", "Eir", "Etched Rune: Eir's Mercy", "EirCharm", "Utility", "", requireNoParry: false, 2500); AddLegendary(config, "22 Eir - Eirs Reminder", "Eir_Reminder", "Eir", "Etched Rune: Eir's Reminder", "EirTrinket", "Utility", "", requireNoParry: false, 2500); AddLegendary(config, "23 Mimir - Mimirs Wellspring", "Mimir_Wellspring", "Mimir", "Etched Rune: Mimir's Wellspring", "MimirCharm", "Utility", "", requireNoParry: false, 2500); AddLegendary(config, "24 Mimir - Mimirs Debt", "Mimir_Debt", "Mimir", "Etched Rune: Mimir's Debt", "MimirTrinket", "Utility", "", requireNoParry: false, 2500); } private static void AddRiches(ConfigFile config, string label, string prefab, string enchant, float value, string rarity, int cost, int stack) { AddRiches(config, label, prefab, enchant, value, rarity, cost, stack, applyOnUse: false, ""); } private static void AddRiches(ConfigFile config, string label, string prefab, string enchant, float value, string rarity, int cost, int stack, bool applyOnUse, string allowedTypes) { string text = label + " - "; RichesItemConfig richesItemConfig = new RichesItemConfig(); richesItemConfig.Label = label; richesItemConfig.Enabled = config.Bind<bool>("Riches Runes", text + "Enabled", true, "Enable this runestone in Haldor's shop"); richesItemConfig.Prefab = config.Bind<string>("Riches Runes", text + "Prefab", prefab, "Prefab to clone"); richesItemConfig.Enchantment = config.Bind<string>("Riches Runes", text + "Enchantment", enchant, "Magic effect type"); richesItemConfig.EnchantmentValue = config.Bind<float>("Riches Runes", text + "Enchantment Value", value, "Effect strength"); richesItemConfig.Rarity = config.Bind<string>("Riches Runes", text + "Rarity", rarity, "Magic, Rare, Epic, Legendary, Mythic"); richesItemConfig.CoinsCost = config.Bind<int>("Riches Runes", text + "Coins Cost", cost, "Coin price"); richesItemConfig.Stack = config.Bind<int>("Riches Runes", text + "Stack", stack, "Stack per purchase"); richesItemConfig.ApplyOnUse = config.Bind<bool>("Riches Runes", text + "ApplyOnUse", applyOnUse, "If true, use on inventory slot 1 instead of being a pre-etched item"); richesItemConfig.AllowedItemTypes = config.Bind<string>("Riches Runes", text + "AllowedItemTypes", allowedTypes, "Allowed item types when ApplyOnUse is true"); RichesItems.Add(richesItemConfig); } private static void AddLegendary(ConfigFile config, string label, string key, string setName, string displayName, string legendaryId, string allowedTypes, string allowedSkills, bool requireNoParry, int price) { string text = label + " - "; LegendaryRuneDef legendaryRuneDef = new LegendaryRuneDef(); legendaryRuneDef.Key = key; legendaryRuneDef.SetName = setName; legendaryRuneDef.Label = label; legendaryRuneDef.Enabled = config.Bind<bool>("Legendary Sets", text + "Enabled", true, "Enable this rune in Haldor's shop"); legendaryRuneDef.DisplayName = config.Bind<string>("Legendary Sets", text + "DisplayName", displayName, "In-game display name"); legendaryRuneDef.LegendaryID = config.Bind<string>("Legendary Sets", text + "LegendaryID", legendaryId, "Epic Loot Legendary ID"); legendaryRuneDef.AllowedItemTypes = config.Bind<string>("Legendary Sets", text + "AllowedItemTypes", allowedTypes, "Allowed item types"); legendaryRuneDef.AllowedSkillTypes = config.Bind<string>("Legendary Sets", text + "AllowedSkillTypes", allowedSkills, "Allowed skill types"); legendaryRuneDef.RequireNoParryPower = config.Bind<bool>("Legendary Sets", text + "RequireNoParryPower", requireNoParry, "Tower shield only (no parry)"); legendaryRuneDef.Price = config.Bind<int>("Legendary Sets", text + "Price", price, "Coin price at Haldor"); legendaryRuneDef.StackSize = config.Bind<int>("Legendary Sets", text + "StackSize", 1, "Stack size"); legendaryRuneDef.BasePrefab = config.Bind<string>("Legendary Sets", text + "BasePrefab", "EtchedRunestoneLegendary", "Prefab to clone"); LegendaryRunes.Add(legendaryRuneDef); } public static bool IsRichesEnabled(RichesItemConfig c) { if (Enabled.Value && RichesRunesEnabled.Value) { return c.Enabled.Value; } return false; } public static bool IsLegendaryEnabled(LegendaryRuneDef def) { if (!Enabled.Value || !LegendarySetRunesEnabled.Value || !def.Enabled.Value) { return false; } if (def.SetName == "Heimdall" && !SetHeimdallEnabled.Value) { return false; } if (def.SetName == "Ragnar" && !SetRagnarEnabled.Value) { return false; } if (def.SetName == "Gullveig" && !SetGullveigEnabled.Value) { return false; } if (def.SetName == "Hel" && !SetHelEnabled.Value) { return false; } if (def.SetName == "Ullr" && !SetUllrEnabled.Value) { return false; } if (def.SetName == "Eir" && !SetEirEnabled.Value) { return false; } if (def.SetName == "Mimir" && !SetMimirEnabled.Value) { return false; } return true; } } public static class RichesRuneManager { public static readonly Dictionary<string, RichesItemConfig> Registered = new Dictionary<string, RichesItemConfig>(); private static ManualLogSource Logger => EtchedRunesPlugin.Log; public static void RegisterAll() { int num = 0; foreach (RichesItemConfig richesItem in ModConfig.RichesItems) { if (ModConfig.IsRichesEnabled(richesItem)) { num++; try { RegisterOne(richesItem, num); } catch (Exception ex) { Logger.LogError((object)("Riches rune register failed (" + richesItem.Label + "): " + ex)); } } } } private static void RegisterOne(RichesItemConfig cfg, int index) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown string text = cfg.Prefab.Value; GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab == (Object)null) { string[] array = new string[5] { "EtchedRunestoneMagic", "EtchedRunestoneRare", "EtchedRunestoneEpic", "EtchedRunestoneLegendary", "EtchedRunestoneMythic" }; for (int i = 0; i < array.Length; i++) { prefab = PrefabManager.Instance.GetPrefab(array[i]); if ((Object)(object)prefab != (Object)null) { Logger.LogWarning((object)("Riches base prefab '" + text + "' missing, fallback: " + array[i])); text = array[i]; break; } } } if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)("No base prefab for Riches item " + cfg.Label + " – skipped.")); return; } string text2 = text + "_Orge_" + index; string text3 = DisplayEffectName(cfg.Enchantment.Value); ItemConfig val = new ItemConfig(); val.Description = "Pre-etched: " + text3 + (IsNumericEffect(cfg.Enchantment.Value) ? (" " + cfg.EnchantmentValue.Value) : "") + " [" + cfg.Rarity.Value + "]. Use at the Enchanting Table."; CustomItem val2 = new CustomItem(text2, text, val); ItemManager.Instance.AddItem(val2); Registered[text2] = cfg; Logger.LogInfo((object)("Registered etched runestone: " + text2 + " -> " + text3 + " " + cfg.EnchantmentValue.Value)); GameObject prefab2 = PrefabManager.Instance.GetPrefab(text2); if ((Object)(object)prefab2 != (Object)null) { ItemDrop component = prefab2.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null && component.m_itemData != null) { component.m_itemData.m_dropPrefab = prefab2; ApplyEtchedMagic(component.m_itemData, cfg); } } } public static void TryApplyMagicData(ItemData item) { if (item == null) { return; } if (ShouldStripIllegalMagic(item)) { StripMagic(item); } else if (IsOurShopRune(item)) { RichesItemConfig richesItemConfig = FindConfig(item); if (richesItemConfig != null && !AlreadyHasEtchedEffect(item, richesItemConfig)) { ApplyEtchedMagic(item, richesItemConfig); } } } public static bool IsOurShopRune(ItemData item) { string prefabName = GetPrefabName(item); if (string.IsNullOrEmpty(prefabName)) { return false; } if (prefabName.IndexOf("_Orge_", StringComparison.OrdinalIgnoreCase) < 0) { return false; } return Registered.ContainsKey(prefabName); } private static string GetPrefabName(ItemData item) { if (item == null) { return null; } string text = null; if ((Object)(object)item.m_dropPrefab != (Object)null) { text = ((Object)item.m_dropPrefab).name; } if (string.IsNullOrEmpty(text) && item.m_shared != null) { text = item.m_shared.m_name; } if (string.IsNullOrEmpty(text)) { return null; } return text.Replace("(Clone)", "").Trim(); } private static bool ShouldStripIllegalMagic(ItemData item) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 string prefabName = GetPrefabName(item); if (string.IsNullOrEmpty(prefabName)) { return false; } if (prefabName.IndexOf("_Orge_", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (prefabName.IndexOf("Orgetorix_LegRune", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (prefabName.IndexOf("Runestone", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (prefabName.IndexOf("EtchedRune", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } bool flag = prefabName.Equals("Stone", StringComparison.OrdinalIgnoreCase) || prefabName.Equals("$item_stone", StringComparison.OrdinalIgnoreCase); bool flag2 = item.m_shared != null && (int)item.m_shared.m_itemType == 1; if (!flag && !flag2) { return false; } return ItemLooksMagic(item); } private static bool ItemLooksMagic(ItemData item) { try { Type type = FindType("EpicLoot.API"); if (type == null) { return false; } MethodInfo methodInfo = type.GetMethod("IsMagicItem", BindingFlags.Static | BindingFlags.Public) ?? type.GetMethod("IsEpicLootItem", BindingFlags.Static | BindingFlags.Public); if (methodInfo != null) { object obj = methodInfo.Invoke(null, new object[1] { item }); if (obj is bool && (bool)obj) { return true; } } MethodInfo method = type.GetMethod("GetMagicItemJson", BindingFlags.Static | BindingFlags.Public); if (method != null) { string text = method.Invoke(null, new object[1] { item }) as string; if (!string.IsNullOrEmpty(text) && text.IndexOf("EffectType", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } catch { } return false; } private static void StripMagic(ItemData item) { try { Type type = FindType("EpicLoot.ItemDataExtensions"); if (type != null) { string[] array = new string[4] { "RemoveMagicItem", "ClearMagicItem", "DeleteMagicItem", "MakeNonMagic" }; for (int i = 0; i < array.Length; i++) { MethodInfo method = type.GetMethod(array[i], BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(method == null)) { try { method.Invoke(null, new object[1] { item }); Logger.LogInfo((object)("Stripped illegal magic via " + array[i] + " from " + GetPrefabName(item))); return; } catch { } } } MethodInfo method2 = type.GetMethod("SaveMagicItem", BindingFlags.Static | BindingFlags.Public); if (method2 != null) { try { method2.Invoke(null, new object[2] { item, null }); Logger.LogInfo((object)("Stripped illegal magic via SaveMagicItem(null) from " + GetPrefabName(item))); return; } catch { } } } Type type2 = FindType("EpicLoot.API"); if (type2 != null) { MethodInfo method3 = type2.GetMethod("ApplyMagicItemJson", BindingFlags.Static | BindingFlags.Public); if (method3 != null) { method3.Invoke(null, new object[2] { item, "" }); Logger.LogInfo((object)("Stripped illegal magic via empty JSON from " + GetPrefabName(item))); } } } catch (Exception ex) { Logger.LogWarning((object)("StripMagic failed: " + ex.Message)); } } private static bool AlreadyHasEtchedEffect(ItemData item, RichesItemConfig cfg) { string text = ResolveEffectType(cfg.Enchantment.Value); try { Type type = FindType("EpicLoot.API"); if (type == null) { return false; } MethodInfo method = type.GetMethod("ItemHasMagicEffect", BindingFlags.Static | BindingFlags.Public); if (method != null) { object obj = method.Invoke(null, new object[3] { item, text, true }); if (obj is bool && (bool)obj) { return true; } } MethodInfo method2 = type.GetMethod("GetMagicItemJson", BindingFlags.Static | BindingFlags.Public); if (method2 != null) { string text2 = method2.Invoke(null, new object[1] { item }) as string; if (!string.IsNullOrEmpty(text2) && text2.IndexOf("\"EffectType\":\"" + text + "\"") >= 0) { return true; } } } catch { } return false; } private static RichesItemConfig FindConfig(ItemData item) { string[] array = new string[2]; if ((Object)(object)item.m_dropPrefab != (Object)null) { array[0] = ((Object)item.m_dropPrefab).name; } if (item.m_shared != null) { array[1] = item.m_shared.m_name; } for (int i = 0; i < array.Length; i++) { string text = array[i]; if (!string.IsNullOrEmpty(text)) { text = text.Replace("(Clone)", "").Trim(); if (Registered.TryGetValue(text, out var value)) { return value; } } } return null; } private static void ApplyEtchedMagic(ItemData item, RichesItemConfig cfg) { try { string text = ResolveEffectType(cfg.Enchantment.Value); float value = cfg.EnchantmentValue.Value; string value2 = cfg.Rarity.Value; if (!TryApplyViaApiJson(item, text, value, value2) && !TryApplyMagicToItemData(item, text, value, value2) && !TrySaveMagicItem(item, text, value, value2)) { Logger.LogWarning((object)("Could not apply etched magic for " + text + " / " + cfg.Label)); } } catch (Exception ex) { Logger.LogWarning((object)("ApplyEtchedMagic failed: " + ex.Message)); } } private static bool TryApplyViaApiJson(ItemData item, string effectType, float value, string rarityName) { Type type = FindType("EpicLoot.API"); if (type == null) { return false; } MethodInfo method = type.GetMethod("ApplyMagicItemJson", BindingFlags.Static | BindingFlags.Public); if (method == null) { return false; } int num = RarityToInt(rarityName); string text = "{\"Version\":3,\"Rarity\":" + num + ",\"Effects\":[{\"Version\":1,\"EffectValue\":" + value.ToString(CultureInfo.InvariantCulture) + ",\"EffectType\":\"" + effectType + "\"}],\"TypeNameOverride\":null,\"LegendaryID\":null,\"SetID\":null,\"IsUnidentified\":false,\"SocketCount\":0,\"Sockets\":[]}"; object obj = method.Invoke(null, new object[2] { item, text }); bool flag = !(obj is bool) || (bool)obj; if (!flag) { Logger.LogWarning((object)("ApplyMagicItemJson returned false for " + effectType)); } return flag; } private static int RarityToInt(string rarity) { if (string.IsNullOrEmpty(rarity)) { return 0; } return rarity.Trim().ToLowerInvariant() switch { "rare" => 1, "epic" => 2, "legendary" => 3, "mythic" => 4, _ => 0, }; } private static bool TryApplyMagicToItemData(ItemData item, string effectType, float value, string rarityName) { Type type = FindType("EpicLoot.ItemDataExtensions"); if (type == null) { return false; } MethodInfo method = type.GetMethod("ApplyMagicToItemData", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } ParameterInfo[] parameters = method.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; string text = ((parameters[i].Name != null) ? parameters[i].Name.ToLowerInvariant() : ""); if (parameterType.Name.IndexOf("ItemData") >= 0) { array[i] = item; } else if (parameterType == typeof(string) && (text.IndexOf("effect") >= 0 || text.IndexOf("type") >= 0)) { array[i] = effectType; } else if (parameterType == typeof(string) && text.IndexOf("rarity") >= 0) { array[i] = rarityName; } else if (parameterType == typeof(float) || parameterType == typeof(double) || parameterType == typeof(int)) { if (parameterType == typeof(int)) { array[i] = Mathf.RoundToInt(value); } else if (parameterType == typeof(double)) { array[i] = (double)value; } else { array[i] = value; } } else if (parameterType.IsEnum && parameterType.Name.IndexOf("Rarity") >= 0) { array[i] = ParseEnum(parameterType, rarityName); } else if (parameterType.IsEnum) { array[i] = ParseEnum(parameterType, effectType); } else { array[i] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null); } } method.Invoke(null, array); Logger.LogInfo((object)("ApplyMagicToItemData OK: " + effectType)); return true; } private static bool TrySaveMagicItem(ItemData item, string effectType, float value, string rarityName) { Type type = FindType("EpicLoot.ItemDataExtensions"); Type type2 = FindType("EpicLoot.MagicItem"); Type effectClrType = FindType("EpicLoot.MagicItemEffect"); if (type == null || type2 == null) { return false; } MethodInfo method = type.GetMethod("GetMagicItem", BindingFlags.Static | BindingFlags.Public); MethodInfo method2 = type.GetMethod("SaveMagicItem", BindingFlags.Static | BindingFlags.Public); MethodInfo method3 = type.GetMethod("SetNumericEffectValue", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); object obj = null; if (method != null) { try { obj = method.Invoke(null, new object[1] { item }); } catch { } } if (obj == null) { obj = Activator.CreateInstance(type2); } PropertyInfo property = type2.GetProperty("Rarity"); if (property != null) { object obj3 = ParseEnum(property.PropertyType, rarityName); if (obj3 != null) { property.SetValue(obj, obj3, null); } } EnsureEffectOnMagicItem(obj, effectClrType, effectType, value); if (method3 != null && IsNumericEffect(effectType)) { try { method3.Invoke(null, new object[3] { item, effectType, value }); } catch { try { method3.Invoke(null, new object[3] { obj, effectType, value }); } catch { } } } if (method2 != null) { method2.Invoke(null, new object[2] { item, obj }); Logger.LogInfo((object)("SaveMagicItem OK: " + effectType)); return true; } return false; } private static void EnsureEffectOnMagicItem(object magicItem, Type effectClrType, string effectType, float value) { if (magicItem == null) { return; } PropertyInfo property = magicItem.GetType().GetProperty("Effects"); if (property == null) { return; } object value2 = property.GetValue(magicItem, null); if (value2 == null) { return; } PropertyInfo property2 = value2.GetType().GetProperty("Count"); int num = 0; if (property2 != null) { num = (int)property2.GetValue(value2, null); } MethodInfo method = value2.GetType().GetMethod("get_Item", new Type[1] { typeof(int) }); if (method != null) { for (int i = 0; i < num; i++) { object obj = method.Invoke(value2, new object[1] { i }); if (obj != null) { string effectTypeName = GetEffectTypeName(obj); if (effectTypeName == effectType) { SetEffectValue(obj, value); return; } } } } object obj2 = CreateMagicItemEffect(effectClrType, effectType, value); if (obj2 != null) { MethodInfo method2 = value2.GetType().GetMethod("Add"); if (method2 != null) { method2.Invoke(value2, new object[1] { obj2 }); } } } private static object CreateMagicItemEffect(Type effectClrType, string effectType, float value) { if (effectClrType == null) { effectClrType = FindType("EpicLoot.MagicItemEffect"); } if (effectClrType == null) { return null; } object obj = null; try { obj = Activator.CreateInstance(effectClrType); } catch { return null; } PropertyInfo property = effectClrType.GetProperty("EffectType"); if (property != null) { if (property.PropertyType == typeof(string)) { property.SetValue(obj, effectType, null); } else if (property.PropertyType.IsEnum) { object obj3 = ParseEnum(property.PropertyType, effectType); if (obj3 != null) { property.SetValue(obj, obj3, null); } } } FieldInfo field = effectClrType.GetField("EffectType"); if (field != null && field.FieldType == typeof(string)) { field.SetValue(obj, effectType); } SetEffectValue(obj, value); return obj; } private static void SetEffectValue(object effect, float value) { if (effect == null) { return; } PropertyInfo property = effect.GetType().GetProperty("EffectValue"); if (property != null && property.CanWrite) { if (property.PropertyType == typeof(float)) { property.SetValue(effect, value, null); } else if (property.PropertyType == typeof(double)) { property.SetValue(effect, (double)value, null); } else if (property.PropertyType == typeof(int)) { property.SetValue(effect, Mathf.RoundToInt(value), null); } } FieldInfo field = effect.GetType().GetField("EffectValue"); if (field != null) { if (field.FieldType == typeof(float)) { field.SetValue(effect, value); } else if (field.FieldType == typeof(double)) { field.SetValue(effect, (double)value); } } } private static string GetEffectTypeName(object effect) { if (effect == null) { return null; } PropertyInfo property = effect.GetType().GetProperty("EffectType"); if (property != null) { object value = property.GetValue(effect, null); if (value != null) { return value.ToString(); } } FieldInfo field = effect.GetType().GetField("EffectType"); if (field != null) { object value2 = field.GetValue(effect); if (value2 != null) { return value2.ToString(); } } return null; } private static string ResolveEffectType(string configured) { if (string.IsNullOrEmpty(configured)) { return "Riches"; } string text = configured.Trim(); if (text.Equals("Air Jump", StringComparison.OrdinalIgnoreCase) || text.Equals("AirJump", StringComparison.OrdinalIgnoreCase)) { return "DoubleJump"; } if (text.Equals("Feather Fall", StringComparison.OrdinalIgnoreCase)) { return "FeatherFall"; } return text; } private static string DisplayEffectName(string effectType) { string text = ResolveEffectType(effectType); if (text == "DoubleJump") { return "Air Jump"; } if (text == "FeatherFall") { return "Feather Fall"; } return text; } private static bool IsNumericEffect(string effectType) { string text = ResolveEffectType(effectType); return text == "Riches"; } private static Type FindType(string fullName) { Type type = Type.GetType(fullName + ", EpicLoot"); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { try { if (!(assemblies[i].GetName().Name != "EpicLoot")) { type = assemblies[i].GetType(fullName); if (type != null) { return type; } } } catch { } } return null; } private static object ParseEnum(Type enumType, string name) { if (enumType == null || !enumType.IsEnum || string.IsNullOrEmpty(name)) { return null; } try { return Enum.Parse(enumType, name, ignoreCase: true); } catch { return null; } } } public static class LegendaryRuneManager { private static readonly Dictionary<string, LegendaryRuneDef> PrefabToRune = new Dictionary<string, LegendaryRuneDef>(); private static ManualLogSource Logger => EtchedRunesPlugin.Log; public static void RegisterAll() { if (!ModConfig.Enabled.Value) { return; } foreach (LegendaryRuneDef legendaryRune in ModConfig.LegendaryRunes) { if (ModConfig.IsLegendaryEnabled(legendaryRune)) { try { RegisterSingleRune(legendaryRune); } catch (Exception ex) { Logger.LogError((object)("Failed to register rune " + legendaryRune.Key + ": " + ex)); } } } } private static void RegisterSingleRune(LegendaryRuneDef def) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown string text = def.BasePrefab.Value; if (string.IsNullOrEmpty(text)) { text = "EtchedRunestoneLegendary"; } GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab == (Object)null) { string[] array = new string[5] { "EtchedRunestoneLegendary", "EtchedRunestoneEpic", "EtchedRunestoneRare", "EtchedRunestoneMagic", "SwordBronze" }; for (int i = 0; i < array.Length; i++) { prefab = PrefabManager.Instance.GetPrefab(array[i]); if ((Object)(object)prefab != (Object)null) { text = array[i]; Logger.LogWarning((object)("Base prefab missing, using fallback: " + text + " for " + def.Key)); break; } } } if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)("No base prefab found for legendary rune " + def.Key + " – skipped.")); return; } ItemConfig val = new ItemConfig(); val.Name = def.DisplayName.Value; val.Description = "Apply this rune to a matching item to turn it into the Legendary Set piece.\nLegendary ID: " + def.LegendaryID.Value; CustomItem val2 = new CustomItem(def.PrefabName, text, val); ItemManager.Instance.AddItem(val2); PrefabToRune[def.PrefabName] = def; Logger.LogInfo((object)("Registered etched rune: " + def.DisplayName.Value + " (" + def.PrefabName + ") -> " + def.LegendaryID.Value)); } public static LegendaryRuneDef GetRuneByPrefab(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } if (PrefabToRune.TryGetValue(prefabName, out var value)) { return value; } return null; } public static LegendaryRuneDef GetRuneByItemData(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return null; } return GetRuneByPrefab(((Object)item.m_dropPrefab).name); } public static bool IsEtchedRune(ItemData item) { return GetRuneByItemData(item) != null; } public static bool CanApplyTo(LegendaryRuneDef rune, ItemData target) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (rune == null || target == null || target.m_shared == null) { return false; } SharedData shared = target.m_shared; string text = rune.AllowedItemTypes.Value; if (text == null) { text = ""; } if (!string.IsNullOrEmpty(text)) { string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); bool flag = false; for (int i = 0; i < array.Length; i++) { string value = array[i].Trim(); if (Enum.TryParse<ItemType>(value, ignoreCase: true, out ItemType result) && shared.m_itemType == result) { flag = true; break; } } if (!flag) { return false; } } string text2 = rune.AllowedSkillTypes.Value; if (text2 == null) { text2 = ""; } if (!string.IsNullOrEmpty(text2)) { string[] array2 = text2.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); bool flag2 = false; for (int j = 0; j < array2.Length; j++) { string value2 = array2[j].Trim(); if (Enum.TryParse<SkillType>(value2, ignoreCase: true, out SkillType result2) && shared.m_skillType == result2) { flag2 = true; break; } } if (!flag2) { return false; } } if (rune.RequireNoParryPower.Value && shared.m_timedBlockBonus > 1.01f) { return false; } return true; } public static bool TryApplyRune(LegendaryRuneDef rune, ItemData target, out string message) { message = ""; if (!CanApplyTo(rune, target)) { message = "This rune cannot be applied to that item."; return false; } string value = rune.LegendaryID.Value; if (string.IsNullOrEmpty(value)) { message = "Rune has no LegendaryID configured."; return false; } try { if (ApplyLegendaryViaReflection(target, value)) { message = "Successfully etched: " + rune.DisplayName.Value; Logger.LogInfo((object)("Applied " + value + " to " + target.m_shared.m_name)); return true; } message = "Epic Loot refused to create the legendary item (requirements not met or API not found)."; Logger.LogWarning((object)("ApplyLegendary failed for " + value)); return false; } catch (Exception ex) { message = "Error while applying rune: " + ex.Message; Logger.LogError((object)ex.ToString()); return false; } } private static bool ApplyLegendaryViaReflection(ItemData item, string legendaryId) { Assembly assembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { try { if (assemblies[i].GetName().Name == "EpicLoot") { assembly = assemblies[i]; break; } } catch { } } if (assembly == null) { Logger.LogError((object)"EpicLoot assembly not found."); return false; } Type type = assembly.GetType("EpicLoot.API"); if (type == null) { Logger.LogError((object)"EpicLoot.API type not found."); return false; } MethodInfo method = type.GetMethod("GetMagicItemJson", BindingFlags.Static | BindingFlags.Public); MethodInfo method2 = type.GetMethod("ApplyMagicItemJson", BindingFlags.Static | BindingFlags.Public); MethodInfo method3 = type.GetMethod("GetLegendaryInfoJson", BindingFlags.Static | BindingFlags.Public); if (method != null && method2 != null) { string text = null; try { text = method.Invoke(null, new object[1] { item }) as string; } catch (Exception ex) { Logger.LogWarning((object)("GetMagicItemJson failed: " + ex.Message)); } string text2 = null; string setId = null; if (method3 != null) { try { string text3 = method3.Invoke(null, new object[1] { legendaryId }) as string; if (!string.IsNullOrEmpty(text3)) { Logger.LogInfo((object)("LegendaryInfoJson: " + text3)); text2 = ExtractJsonString(text3, "Name"); if (string.IsNullOrEmpty(text2)) { text2 = ExtractJsonString(text3, "name"); } if (IndexOfIgnoreCase(text3, "\"IsSetItem\":true") >= 0 || IndexOfIgnoreCase(text3, "\"IsSetItem\": true") >= 0) { setId = (legendaryId.StartsWith("Heimdall") ? "Heimdall" : ((!legendaryId.StartsWith("Ragnar")) ? legendaryId : "Ragnar")); } } } catch (Exception ex2) { Logger.LogWarning((object)("GetLegendaryInfoJson failed: " + ex2.Message)); } } text = ((!string.IsNullOrEmpty(text) && !(text == "null") && !(text == "{}")) ? InjectLegendaryIntoJson(text, legendaryId, text2, setId) : BuildMinimalMagicJson(legendaryId, text2, setId)); Logger.LogInfo((object)("Applying magic JSON (preserve effects): " + text)); try { if (!(method2.Invoke(null, new object[2] { item, text }) is bool result)) { return true; } return result; } catch (Exception ex3) { Logger.LogError((object)("ApplyMagicItemJson failed: " + ex3)); if (ex3.InnerException != null) { Logger.LogError((object)("Inner: " + ex3.InnerException)); } } } return ApplyLegendaryOnMagicItemObject(assembly, item, legendaryId); } private static bool ApplyLegendaryOnMagicItemObject(Assembly epicAsm, ItemData item, string legendaryId) { Type type = epicAsm.GetType("EpicLoot.ItemDataExtensions"); if (type == null) { Logger.LogError((object)"ItemDataExtensions not found."); return false; } MethodInfo method = type.GetMethod("GetMagicItem", BindingFlags.Static | BindingFlags.Public); MethodInfo method2 = type.GetMethod("SaveMagicItem", BindingFlags.Static | BindingFlags.Public); if (method == null || method2 == null) { Logger.LogError((object)"GetMagicItem/SaveMagicItem not found."); return false; } object obj = null; try { obj = method.Invoke(null, new object[1] { item }); } catch { } Type type2 = epicAsm.GetType("EpicLoot.MagicItem"); if (type2 == null) { type2 = epicAsm.GetType("EpicLoot.Magic.MagicItem"); } if (obj == null) { if (type2 == null) { Logger.LogError((object)"MagicItem type not found and item has no magic data."); return false; } obj = Activator.CreateInstance(type2); PropertyInfo property = type2.GetProperty("Rarity"); if (property != null) { Type propertyType = property.PropertyType; try { object value = Enum.Parse(propertyType, "Legendary", ignoreCase: true); property.SetValue(obj, value, null); } catch { } } } Type type3 = obj.GetType(); PropertyInfo[] properties = type3.GetProperties(BindingFlags.Instance | BindingFlags.Public); for (int i = 0; i < properties.Length; i++) { Logger.LogInfo((object)("MagicItem prop: " + properties[i].Name + " : " + properties[i].PropertyType.Name)); } SetStringProp(obj, "TypeNameOverride", "$mod_epicloot_l_" + legendaryId.ToLowerInvariant()); SetStringProp(obj, "LegendaryID", legendaryId); SetStringProp(obj, "LegendaryId", legendaryId); SetStringProp(obj, "LegendarySetItemID", legendaryId); SetStringProp(obj, "LegendarySetItemId", legendaryId); try { method2.Invoke(null, new object[2] { item, obj }); Logger.LogInfo((object)("SaveMagicItem OK for " + legendaryId)); return true; } catch (Exception ex) { Logger.LogError((object)("SaveMagicItem failed: " + ex)); return false; } } private static void SetStringProp(object obj, string name, string value) { if (obj != null && value != null) { PropertyInfo property = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite && property.PropertyType == typeof(string)) { property.SetValue(obj, value, null); Logger.LogInfo((object)("Set " + name + " = " + value)); } FieldInfo field = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == typeof(string)) { field.SetValue(obj, value); Logger.LogInfo((object)("Set field " + name + " = " + value)); } } } private static string ExtractJsonString(string json, string key) { if (string.IsNullOrEmpty(json) || string.IsNullOrEmpty(key)) { return null; } string text = "\"" + key + "\""; int num = json.IndexOf(text, StringComparison.OrdinalIgnoreCase); if (num < 0) { return null; } int num2 = json.IndexOf(':', num + text.Length); if (num2 < 0) { return null; } int num3 = json.IndexOf('"', num2 + 1); if (num3 < 0) { return null; } int num4 = json.IndexOf('"', num3 + 1); if (num4 < 0) { return null; } return json.Substring(num3 + 1, num4 - num3 - 1); } private static string BuildMinimalMagicJson(string legendaryId, string typeNameOverride, string setId) { if (string.IsNullOrEmpty(typeNameOverride)) { typeNameOverride = "$mod_epicloot_l_" + legendaryId.ToLowerInvariant(); } string text = ""; if (!string.IsNullOrEmpty(setId)) { text = ",\"SetID\":\"" + setId + "\""; } return "{\"Version\":3,\"Rarity\":3,\"Effects\":[],\"TypeNameOverride\":\"" + typeNameOverride + "\",\"LegendaryID\":\"" + legendaryId + "\"" + text + ",\"IsUnidentified\":false}"; } private static string InjectLegendaryIntoJson(string json, string legendaryId, string typeNameOverride, string setId) { if (string.IsNullOrEmpty(typeNameOverride)) { typeNameOverride = "$mod_epicloot_l_" + legendaryId.ToLowerInvariant(); } json = SetOrReplaceJsonString(json, "TypeNameOverride", typeNameOverride); json = SetOrReplaceJsonString(json, "LegendaryID", legendaryId); if (!string.IsNullOrEmpty(setId)) { json = SetOrReplaceJsonString(json, "SetID", setId); } return json; } private static string SetOrReplaceJsonString(string json, string key, string value) { if (string.IsNullOrEmpty(json)) { json = "{}"; } string text = value.Replace("\\", "\\\\").Replace("\"", "\\\""); string text2 = "\"" + key + "\":\"" + text + "\""; string text3 = "\"" + key + "\""; int num = IndexOfIgnoreCase(json, text3); if (num >= 0) { int num2 = json.IndexOf(':', num + text3.Length); if (num2 < 0) { return json; } int i; for (i = num2 + 1; i < json.Length && (json[i] == ' ' || json[i] == '\t'); i++) { } int j = i; if (i < json.Length && json[i] == '"') { for (j = i + 1; j < json.Length; j++) { if (json[j] == '"' && json[j - 1] != '\\') { j++; break; } } } else if (i + 4 <= json.Length && json.Substring(i, 4) == "null") { j = i + 4; } else { for (; j < json.Length && json[j] != ',' && json[j] != '}'; j++) { } } return json.Substring(0, num) + text2 + json.Substring(j); } string text4 = json.Trim(); if (text4.EndsWith("}")) { text4 = text4.Substring(0, text4.Length - 1).TrimEnd(new char[0]); } if (!text4.EndsWith("{") && !text4.EndsWith(",")) { text4 += ","; } return text4 + text2 + "}"; } private static int IndexOfIgnoreCase(string haystack, string needle) { return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase); } } } namespace Orgetorix.EtchedRunes.Patches { [HarmonyPatch(typeof(Trader), "GetAvailableItems")] public static class Trader_GetAvailableItems_Patch { [HarmonyPostfix] public static void Postfix(Trader __instance, ref List<TradeItem> __result) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown if (!ModConfig.Enabled.Value || (Object)(object)__instance == (Object)null || ((Object)__instance).name == null || (((Object)__instance).name.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) < 0 && (__instance.m_name == null || __instance.m_name.IndexOf("haldor", StringComparison.OrdinalIgnoreCase) < 0))) { return; } foreach (KeyValuePair<string, RichesItemConfig> item in RichesRuneManager.Registered) { string key = item.Key; RichesItemConfig value = item.Value; GameObject prefab = PrefabManager.Instance.GetPrefab(key); if (!((Object)(object)prefab == (Object)null)) { ItemDrop component = prefab.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && !AlreadyInList(__result, key)) { TradeItem val = new TradeItem(); val.m_prefab = component; val.m_stack = value.Stack.Value; val.m_price = value.CoinsCost.Value; __result.Add(val); } } } for (int i = 0; i < ModConfig.LegendaryRunes.Count; i++) { LegendaryRuneDef legendaryRuneDef = ModConfig.LegendaryRunes[i]; if (!ModConfig.IsLegendaryEnabled(legendaryRuneDef)) { continue; } GameObject prefab2 = PrefabManager.Instance.GetPrefab(legendaryRuneDef.PrefabName); if (!((Object)(object)prefab2 == (Object)null)) { ItemDrop component2 = prefab2.GetComponent<ItemDrop>(); if (!((Object)(object)component2 == (Object)null) && !AlreadyInList(__result, legendaryRuneDef.PrefabName)) { TradeItem val2 = new TradeItem(); val2.m_prefab = component2; val2.m_stack = legendaryRuneDef.StackSize.Value; val2.m_price = legendaryRuneDef.Price.Value; __result.Add(val2); } } } } private static bool AlreadyInList(List<TradeItem> list, string prefabName) { for (int i = 0; i < list.Count; i++) { if ((Object)(object)list[i].m_prefab != (Object)null && ((Object)list[i].m_prefab).name == prefabName) { return true; } } return false; } } [HarmonyPatch(typeof(Humanoid), "UseItem")] public static class Humanoid_UseItem_Patch { [HarmonyPrefix] public static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui) { if (!ModConfig.Enabled.Value) { return true; } if ((Object)(object)__instance == (Object)null || item == null) { return true; } LegendaryRuneDef runeByItemData = LegendaryRuneManager.GetRuneByItemData(item); if (runeByItemData == null) { return true; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null) { return false; } ItemData val2 = FindSlotOneItem(inventory, item); if (val2 == null) { ((Character)val).Message((MessageType)2, "Place the target item in inventory slot 1 (top-left).", 0, (Sprite)null); return false; } if (!LegendaryRuneManager.CanApplyTo(runeByItemData, val2)) { string text = runeByItemData.AllowedItemTypes.Value; if (string.IsNullOrEmpty(text)) { text = "matching item"; } if (runeByItemData.RequireNoParryPower.Value) { text += " (tower shield, no parry)"; } ((Character)val).Message((MessageType)2, "Slot 1 item is wrong type. Need: " + text, 0, (Sprite)null); return false; } if (LegendaryRuneManager.TryApplyRune(runeByItemData, val2, out var message)) { inventory.RemoveOneItem(item); ((Character)val).Message((MessageType)2, message, 0, (Sprite)null); } else { ((Character)val).Message((MessageType)2, message, 0, (Sprite)null); } return false; } private static ItemData FindSlotOneItem(Inventory inventory, ItemData runeItem) { if (inventory == null) { return null; } List<ItemData> allItems = inventory.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (val != null && val != runeItem && val.m_gridPos.x == 0 && val.m_gridPos.y == 0) { return val; } } return null; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] public static class Inventory_AddItem_Patch { [HarmonyPostfix] public static void Postfix(ItemData item) { if (ModConfig.Enabled.Value && item != null) { RichesRuneManager.TryApplyMagicData(item); } } } [HarmonyPatch(typeof(ItemData), "Clone")] public static class ItemData_Clone_Patch { [HarmonyPostfix] public static void Postfix(ItemData __instance, ItemData __result) { if (ModConfig.Enabled.Value && __result != null) { if ((Object)(object)__result.m_dropPrefab == (Object)null && __instance != null) { __result.m_dropPrefab = __instance.m_dropPrefab; } RichesRuneManager.TryApplyMagicData(__result); } } } [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDrop_Awake_Patch { [HarmonyPostfix] public static void Postfix(ItemDrop __instance) { if (ModConfig.Enabled.Value && !((Object)(object)__instance == (Object)null) && __instance.m_itemData != null) { RichesRuneManager.TryApplyMagicData(__instance.m_itemData); } } } }