using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("MG-HaldorSellPatch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MG-HaldorSellPatch")] [assembly: AssemblyTitle("MG-HaldorSellPatch")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 MG.HaldorSellPatch { [BepInPlugin("mg.haldorsellpatch", "MG Haldor Sell Patch", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class HaldorSellPatchPlugin : BaseUnityPlugin { private readonly struct ItemConfig { public string PrefabName { get; } public int SellPrice { get; } public int BuyQuantity { get; } public int BuyPrice { get; } public bool BuyOnly { get; } public bool HasBuy => BuyQuantity > 0; public ItemConfig(string prefabName, int sellPrice, int buyQuantity = 0, int buyPrice = 0, bool buyOnly = false) { PrefabName = prefabName; SellPrice = sellPrice; BuyQuantity = buyQuantity; BuyPrice = ((buyPrice > 0) ? buyPrice : (sellPrice * buyQuantity * 2)); BuyOnly = buyOnly; } } private sealed class BuyConfig { public ConfigEntry Quantity; public int FixedQuantity; public ConfigEntry Price; } private readonly struct BuyEntry { public string PrefabName { get; } public int Quantity { get; } public int Price { get; } public bool Remove { get; } public BuyEntry(string prefabName, int quantity, int price) { PrefabName = prefabName; Quantity = quantity; Price = price; Remove = false; } private BuyEntry(string prefabName) { PrefabName = prefabName; Quantity = 0; Price = 0; Remove = true; } public static BuyEntry Disabled(string prefabName) { return new BuyEntry(prefabName); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDBAwakePatch { private static void Postfix(ObjectDB __instance) { ApplySellValues(__instance); } } [HarmonyPatch(typeof(StoreGui), "Show")] private static class StoreGuiShowPatch { private static void Prefix(Trader trader) { ApplyBuyItems(trader); } } public const string ModGuid = "mg.haldorsellpatch"; public const string ModName = "MG Haldor Sell Patch"; public const string ModVersion = "1.2.1"; private const int TrophyItemType = 13; private static readonly List Items = new List(); private static readonly string[] RemovedOriginalBuyItems = new string[2] { "Ashwood", "CharredWood" }; private static readonly Dictionary> SellPrices = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary BuyItems = new Dictionary(StringComparer.OrdinalIgnoreCase); private static ConfigEntry EnableExtraBuyItemsConfig; private static ConfigEntry CustomBuyItemsConfig; private static ConfigEntry EnableExtraSellItemsConfig; private static ConfigEntry CustomSellItemsConfig; private static ConfigEntry EnableTrophySellingConfig; private static ConfigEntry DefaultTrophyPriceConfig; private static ConfigEntry TrophyPriceOverridesConfig; private static ManualLogSource Log; private Harmony harmony; private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BuildItemList(); BindConfig(); PatchHaldorExpansionSellLists(); harmony = new Harmony("mg.haldorsellpatch"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded configurable Haldor buy/sell list."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private static void BuildItemList() { Items.Clear(); Add("Stone", 1, 50); Add("Wood", 1, 50); Add("Resin", 1, 50); Add("Feathers", 1, 50); Add("BoneFragments", 1, 50); Add("LeatherScraps", 1, 50); Add("DeerHide", 1, 50); Add("RoundLog", 2, 50); Add("Grausten", 2, 50); Add("GreydwarfEye", 2, 50); Add("Needle", 2, 50); Add("Flint", 2, 30); Add("Coal", 2, 50); Add("TrollHide", 2, 20); Add("WolfPelt", 2, 50); Add("FreezeGland", 2, 50); Add("FineWood", 3, 50); Add("Guck", 3, 50); Add("LoxPelt", 3, 50); Add("ElderBark", 4, 50); Add("BlackMarble", 4, 50); Add("Copper", 4, 30); Add("JuteRed", 4, 50); Add("JuteBlue", 4, 50); Add("YggdrasilWood", 4, 50); Add("Chitin", 4, 50); Add("Root", 4, 50); Add("WolfFang", 4, 50); Add("Carapace", 4, 50); Add("BloodClot", 4, 50); Add("Obsidian", 5, 50); Add("Tin", 5, 30); Add("Tar", 5, 50); Add("Blackwood", 5, 50); Add("Crystal", 5, 50); Add("Chain", 5, 50); Add("Mandible", 5, 50); Add("Bilebag", 5, 50); Add("Bronze", 6, 30); Add("SoftTissue", 6, 40); Add("RoyalJelly", 6, 50); Add("Iron", 7, 30); Add("Silver", 7, 30); Add("RefinedEitr", 7, 30); Add("BlackMetal", 8, 30); Add("Flametal", 10, 30); Add("SurtlingCore", 30, 10); Add("BlackCore", 80, 20); Add("MoltenCore", 130, 20); AddUniqueBuy("BrisingamenRing", 1, 1600); AddUniqueBuy("CapeWoundedBeast", 1, 2500); AddUniqueBuy("CapeFracturedBreath", 1, 2500); AddUniqueBuy("CrossbowSilentHunt", 1, 2500); AddUniqueBuy("Bone_crushers", 1, 2500); AddUniqueBuy("ArmorDelayedDoomChest", 1, 4000); AddUniqueBuy("ArmorPitKingChest", 1, 4000); } private static void Add(string prefabName, int sellPrice, int buyQuantity = 0) { Items.Add(new ItemConfig(prefabName, sellPrice, buyQuantity)); } private static void AddUniqueBuy(string prefabName, int quantity, int price) { Items.Add(new ItemConfig(prefabName, 0, quantity, price, buyOnly: true)); } private void BindConfig() { EnableExtraBuyItemsConfig = ((BaseUnityPlugin)this).Config.Bind("1 - Buy - General", "Enable Extra Buy Items", true, "If false, this add-on removes all extra buy items it controls and leaves Haldor's normal vanilla shop alone."); CustomBuyItemsConfig = ((BaseUnityPlugin)this).Config.Bind("1 - Buy - General", "Custom Buy Items", "", "Extra items Haldor sells. Format: PrefabName:Quantity:Price. Example: Coal:50:100."); foreach (ItemConfig item in Items) { if (item.HasBuy) { BuyConfig buyConfig = new BuyConfig { FixedQuantity = item.BuyQuantity, Price = ((BaseUnityPlugin)this).Config.Bind("2 - Buy - Items", item.PrefabName + " - Price", item.BuyPrice, "Coin cost for buying " + item.PrefabName + ". Set to 0 to remove this item from Haldor's shop.") }; if (!item.BuyOnly) { buyConfig.Quantity = ((BaseUnityPlugin)this).Config.Bind("2 - Buy - Items", item.PrefabName + " - Quantity", item.BuyQuantity, "How many " + item.PrefabName + " Haldor sells at once."); } BuyItems[item.PrefabName] = buyConfig; } } EnableExtraSellItemsConfig = ((BaseUnityPlugin)this).Config.Bind("3 - Sell - General", "Enable Extra Sell Items", true, "If false, this add-on disables all extra non-trophy sell items it controls."); CustomSellItemsConfig = ((BaseUnityPlugin)this).Config.Bind("3 - Sell - General", "Custom Sell Items", "", "Extra items players can sell to Haldor. Format: PrefabName:Price,PrefabName:Price. Example: Coal:2,Flint:2. Set a price to 0 to disable selling that item."); foreach (ItemConfig item2 in Items) { if (!item2.BuyOnly) { SellPrices[item2.PrefabName] = ((BaseUnityPlugin)this).Config.Bind("4 - Sell - Items", item2.PrefabName + " - Price", item2.SellPrice, "Coins paid for selling one " + item2.PrefabName + ". Set to 0 to disable selling this item."); } } EnableTrophySellingConfig = ((BaseUnityPlugin)this).Config.Bind("5 - Sell - Trophies", "Enable Trophy Selling", true, "If false, all trophy sell values are set to 0."); DefaultTrophyPriceConfig = ((BaseUnityPlugin)this).Config.Bind("5 - Sell - Trophies", "Default Trophy Price", 10, "Sell price for trophy items not listed in Trophy Price Overrides."); TrophyPriceOverridesConfig = ((BaseUnityPlugin)this).Config.Bind("5 - Sell - Trophies", "Trophy Price Overrides", "TrophyDeer:15,TrophyBoar:15,TrophyNeck:25,TrophyEikthyr:70,TrophyGreydwarf:15,TrophySkeleton:15,TrophyGreydwarfShaman:20,TrophyGhost:25,TrophyGreydwarfBrute:20,TrophyBjorn:50,TrophyFrostTroll:50,TrophySkeletonPoison:50,TrophySkeletonHildir:80,TrophyTheElder:100,TrophySerpent:500,TrophyBonemawSerpent:500,TrophyBlob:15,TrophyDraugr:15,TrophyLeech:15,TrophySurtling:15,TrophyDraugrElite:30,TrophyWraith:35,TrophyAbomination:75,TrophyKvastur:80,TrophyBonemass:150,TrophyWolf:15,TrophyHatchling:15,TrophyUlv:20,TrophyFenring:25,TrophyCultist:40,TrophySGolem:70,TrophyCultist_Hildir:80,TrophyDragonQueen:200,TrophyDeathsquito:15,TrophyGoblin:15,TrophyGrowth:15,TrophyBjornUndead:50,TrophyLox:35,TrophyGoblinShaman:30,TrophyGoblinBrute:70,TrophyGoblinBruteBrosShaman:80,TrophyGoblinBruteBrosBrute:80,TrophyGoblinKing:350,TrophySeeker:20,TrophyTick:20,TrophyDvergr:20,TrophyHare:20,TrophyGjall:70,TrophySeekerBrute:80,TrophySeekerQueen:500,TrophyCharredArcher:20,TrophyVolture:20,TrophyAsksvin:20,TrophyCharredMage:25,TrophyCharredMelee:25,TrophyMorgen:100,TrophyFallenValkyrie:120,TrophyFader:1000", "Specific trophy prices. Format: TrophyPrefab:Price,TrophyPrefab:Price. Set a price to 0 to disable that trophy."); } private static void PatchHaldorExpansionSellLists() { PatchDictionary("ExtraSellableItems", GetConfiguredSellItems()); PatchDictionary("TrophyValueOverrides", ParsePriceList(TrophyPriceOverridesConfig.Value)); } private static void PatchDictionary(string fieldName, Dictionary values) { object obj = Type.GetType("HaldorExpansion.HaldorExpansionPlugin, HaldorExpansion")?.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); PropertyInfo propertyInfo = obj?.GetType().GetProperty("Item"); MethodInfo methodInfo = obj?.GetType().GetMethod("Remove", new Type[1] { typeof(string) }); if (propertyInfo == null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Could not find HaldorExpansion " + fieldName + "; direct ObjectDB patch will still run.")); } return; } foreach (KeyValuePair value in values) { if (value.Value > 0) { propertyInfo.SetValue(obj, value.Value, new object[1] { value.Key }); } else { methodInfo?.Invoke(obj, new object[1] { value.Key }); } } } internal static void ApplySellValues(ObjectDB db) { if ((Object)(object)db == (Object)null) { return; } PatchHaldorExpansionSellLists(); foreach (KeyValuePair configuredSellItem in GetConfiguredSellItems()) { SetItemValue(db, configuredSellItem.Key, configuredSellItem.Value); } ApplyTrophySellValues(db); } private static Dictionary GetConfiguredSellItems() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair> sellPrice in SellPrices) { dictionary[sellPrice.Key] = (EnableExtraSellItemsConfig.Value ? Math.Max(0, sellPrice.Value.Value) : 0); } if (EnableExtraSellItemsConfig.Value) { foreach (KeyValuePair item in ParsePriceList(CustomSellItemsConfig.Value)) { dictionary[item.Key] = item.Value; } } return dictionary; } private static Dictionary ParsePriceList(string value) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); string[] array2 = text.Split(new char[2] { ':', '=' }, 2); if (array2.Length != 2 || string.IsNullOrWhiteSpace(array2[0]) || !int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Ignored invalid sell config entry: " + text)); } } else { dictionary[array2[0].Trim()] = Math.Max(0, result); } } return dictionary; } private static IEnumerable GetConfiguredBuyItems() { foreach (KeyValuePair buyItem in BuyItems) { BuyConfig value = buyItem.Value; int num = ((value.Quantity != null) ? value.Quantity.Value : value.FixedQuantity); if (!EnableExtraBuyItemsConfig.Value || value.Price.Value <= 0 || num <= 0) { yield return BuyEntry.Disabled(buyItem.Key); } else { yield return new BuyEntry(buyItem.Key, num, value.Price.Value); } } if (!EnableExtraBuyItemsConfig.Value) { yield break; } foreach (BuyEntry item in ParseBuyList(CustomBuyItemsConfig.Value)) { yield return item; } } private static IEnumerable ParseBuyList(string value) { if (string.IsNullOrWhiteSpace(value)) { yield break; } string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length != 3 || string.IsNullOrWhiteSpace(array2[0]) || !int.TryParse(array2[2].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Ignored invalid buy config entry: " + text)); } continue; } int result2; if (array2[1].Trim().Equals("MaxStack", StringComparison.OrdinalIgnoreCase)) { result2 = 0; } else if (!int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result2)) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)("Ignored invalid buy quantity: " + text)); } continue; } yield return new BuyEntry(array2[0].Trim(), result2, Math.Max(0, result)); } } private static void ApplyTrophySellValues(ObjectDB db) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 Dictionary dictionary = ParsePriceList(TrophyPriceOverridesConfig.Value); foreach (GameObject item in db.m_items) { SharedData val = (((Object)(object)item != (Object)null) ? item.GetComponent() : null)?.m_itemData?.m_shared; if (val != null && (int)val.m_itemType == 13) { int val2 = 0; if (EnableTrophySellingConfig.Value) { val2 = (dictionary.TryGetValue(((Object)item).name, out var value) ? value : Math.Max(0, DefaultTrophyPriceConfig.Value)); } val.m_value = Math.Max(0, val2); } } } private static void SetItemValue(ObjectDB db, string prefabName, int price) { GameObject itemPrefab = db.GetItemPrefab(prefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if (val?.m_itemData?.m_shared == null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Could not find item prefab for sell value: " + prefabName)); } } else { val.m_itemData.m_shared.m_value = Math.Max(0, price); } } private static void ApplyBuyItems(Trader trader) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown if ((Object)(object)trader == (Object)null || !IsHaldor(trader)) { return; } if (trader.m_items == null) { trader.m_items = new List(); } foreach (BuyEntry configuredBuyItem in GetConfiguredBuyItems()) { RemoveTradeItem(trader, configuredBuyItem.PrefabName); if (configuredBuyItem.Remove || configuredBuyItem.Price <= 0) { continue; } ItemDrop itemDrop = GetItemDrop(configuredBuyItem.PrefabName); if ((Object)(object)itemDrop == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Could not find item prefab for buy list: " + configuredBuyItem.PrefabName)); } continue; } int num = ResolveQuantity(itemDrop, configuredBuyItem.Quantity); if (num > 0) { trader.m_items.Add(new TradeItem { m_prefab = itemDrop, m_stack = num, m_price = configuredBuyItem.Price, m_requiredGlobalKey = string.Empty }); } } string[] removedOriginalBuyItems = RemovedOriginalBuyItems; foreach (string prefabName in removedOriginalBuyItems) { RemoveTradeItem(trader, prefabName); } } private static bool IsHaldor(Trader trader) { if ((Object)(object)trader != (Object)null && (Object)(object)((Component)trader).gameObject != (Object)null) { return ((Object)((Component)trader).gameObject).name.StartsWith("Haldor", StringComparison.Ordinal); } return false; } private static ItemDrop GetItemDrop(string prefabName) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); if ((Object)(object)val != (Object)null) { return val.GetComponent(); } GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabName) : null); if (!((Object)(object)val2 != (Object)null)) { return null; } return val2.GetComponent(); } private static int ResolveQuantity(ItemDrop itemDrop, int configuredQuantity) { if (configuredQuantity > 0) { return configuredQuantity; } return Math.Max(1, (itemDrop.m_itemData?.m_shared?.m_maxStackSize).GetValueOrDefault(1)); } private static void RemoveTradeItem(Trader trader, string prefabName) { trader.m_items.RemoveAll((TradeItem item) => (Object)(object)item?.m_prefab != (Object)null && NormalizePrefabName(((Object)((Component)item.m_prefab).gameObject).name) == prefabName); } private static string NormalizePrefabName(string name) { if (!string.IsNullOrWhiteSpace(name)) { return name.Replace("(Clone)", string.Empty).Trim(); } return string.Empty; } } }