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 BetterTraders v1.0.2
BetterTraders.dll
Decompiled 14 hours agousing 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.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ConditionalConfigSync; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [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("BetterTraders")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetterTraders")] [assembly: AssemblyTitle("BetterTraders")] [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 BetterTraders { [BepInPlugin("com.dreich.bettertraders", "Better Traders", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class BetterTradersPlugin : BaseUnityPlugin { public const string Guid = "com.dreich.bettertraders"; public const string Name = "Better Traders"; public const string Version = "1.0.2"; private const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync"; private static bool ConfigSyncAvailable; internal static ManualLogSource Log; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<string> TraderName; internal static ConfigEntry<bool> BuyEnabled; internal static ConfigEntry<float> BuyMultiplier; internal static ConfigEntry<int> BuyStackSize; internal static ConfigEntry<bool> SellsRefined; internal static ConfigEntry<bool> SellsCraftedMaterials; internal static ConfigEntry<bool> SellsFood; internal static ConfigEntry<bool> SellsGear; internal static ConfigEntry<string> ExtraWares; internal static ConfigEntry<string> ExcludedItems; internal static ConfigEntry<bool> ExcludeKeys; internal static ConfigEntry<bool> BuysCrafted; internal static ConfigEntry<bool> BuysProcessed; internal static ConfigEntry<string> ExtraPurchases; internal static ConfigEntry<bool> SellEnabled; internal static ConfigEntry<string> SellLabel; internal static ConfigEntry<string> FlavorText; internal static ConfigEntry<string> SellTitle; internal static ConfigEntry<float> SellPanelGap; internal static ConfigEntry<float> SellPanelOffsetX; internal static ConfigEntry<float> SellPanelOffsetY; internal static ConfigEntry<float> SellMultiplier; internal static ConfigEntry<bool> ValuablesAtFullValue; internal static ConfigEntry<string> TierPrices; internal static ConfigEntry<float> CraftMarkup; internal static ConfigEntry<float> ConversionMarkup; internal static ConfigEntry<float> FoodValue; internal static ConfigEntry<string> ValueOverrides; internal static ConfigEntry<string> BiomeOverrides; internal static ConfigEntry<string> BossPrefabs; internal static ConfigEntry<bool> LogPrices; internal static ConfigEntry<bool> WitchSellsIdols; internal static ConfigEntry<string> WitchName; internal static ConfigEntry<string> IdolPrices; internal static ConfigEntry<string> Idols; internal static ConfigEntry<bool> HildirBuysChests; internal static ConfigEntry<string> HildirName; internal static ConfigEntry<string> HildirChestPrices; private void Awake() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Expected O, but got Unknown //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Expected O, but got Unknown //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Expected O, but got Unknown //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Expected O, but got Unknown //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Expected O, but got Unknown //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Expected O, but got Unknown //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Expected O, but got Unknown //IL_060d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ConfigSyncAvailable = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync"); if (ConfigSyncAvailable) { ConfigSyncCompat.Initialize("com.dreich.bettertraders", "Better Traders", "1.0.2"); } ConfigEntry<bool> entry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only. Requires ConditionalConfigSync."); if (ConfigSyncAvailable) { ConfigSyncCompat.AddLockingConfigEntry(entry); } ModEnabled = BindShared("General", "Enabled", defaultValue: true, "Lets Haldor buy crafted goods from you and sell refined goods once you have beaten the boss of the biome they come from."); TraderName = BindShared("General", "TraderName", "Haldor", "Prefab name of Haldor. Several can be listed, separated by commas."); BuyEnabled = BindShared("Buying", "Enabled", defaultValue: true, "Add items to Haldor's shop. Each item only appears once the boss of the biome it comes from has been defeated on the world."); BuyMultiplier = BindShared("Buying", "PriceMultiplier", 4f, new ConfigDescription("Haldor's selling price is an item's value times this. Higher makes buying more expensive.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 100f), Array.Empty<object>())); BuyStackSize = BindShared("Buying", "StackSize", 10, new ConfigDescription("How many of a stackable item one purchase gives, capped at the item's stack size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); SellsRefined = BindShared("Buying", "SellsRefined", defaultValue: true, "Haldor sells what comes out of a smelter, blast furnace, kiln, eitr refinery, spinning wheel or windmill: metal bars, coal, refined eitr, linen thread and flour. Never the ore or raw material that goes in."); SellsCraftedMaterials = BindShared("Buying", "SellsCraftedMaterials", defaultValue: true, "Haldor sells crafted materials such as bronze, iron nails and chains."); SellsFood = BindShared("Buying", "SellsFood", defaultValue: true, "Haldor sells cooked and prepared food and meads."); SellsGear = BindShared("Buying", "SellsGear", defaultValue: false, "Haldor also sells crafted weapons, armour and tools."); ExtraWares = BindShared("Buying", "ExtraItems", "", "Comma separated item prefab names Haldor also sells, on top of the groups above. They still unlock with their biome's boss."); ExcludedItems = BindShared("Buying", "ExcludedItems", "Coins,CryptKey,Wishbone,DvergrKey,TrophyEikthyr,TrophyTheElder,TrophyBonemass,TrophyDragonQueen,TrophyGoblinKing,TrophySeekerQueen,TrophyFader", "Comma separated item prefab names Haldor never sells, even if they belong to a group above."); ExcludeKeys = BindShared("Buying", "ExcludeKeys", defaultValue: true, "Haldor never sells keys: any item that opens a door, or whose name contains \"key\"."); SellEnabled = BindShared("Selling", "Enabled", defaultValue: true, "Let Haldor buy crafted and processed goods and valuables from you. A sell panel next to his shop lists everything you carry that he'll buy."); SellLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Selling", "ButtonLabel", "Sell", "Text on the sell panel's button."); FlavorText = ((BaseUnityPlugin)this).Config.Bind<string>("Selling", "FlavorText", "Valuable to the right person.", "Line added under the description of every item Haldor would buy, when you hover over it. Leave empty to turn it off."); SellTitle = ((BaseUnityPlugin)this).Config.Bind<string>("Selling", "PanelTitle", "Sell", "Title of the sell panel, in place of the shop's title."); SellPanelGap = ((BaseUnityPlugin)this).Config.Bind<float>("Selling", "PanelGap", 8f, new ConfigDescription("Space in pixels between Haldor's shop and the sell panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-500f, 500f), Array.Empty<object>())); SellPanelOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Selling", "PanelOffsetX", 20f, new ConfigDescription("Moves the sell panel right (positive) or left (negative) from its place next to the shop.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1000f, 1000f), Array.Empty<object>())); SellPanelOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Selling", "PanelOffsetY", 0f, new ConfigDescription("Moves the sell panel up (positive) or down (negative).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1000f, 1000f), Array.Empty<object>())); BuysCrafted = BindShared("Selling", "BuysCrafted", defaultValue: true, "Haldor buys anything made at a workbench, forge or other crafting station: gear, tools, food and crafted materials."); BuysProcessed = BindShared("Selling", "BuysProcessed", defaultValue: true, "Haldor buys smelted, cooked and fermented goods: metal bars, coal, cooked meat, meads and the like."); ExtraPurchases = BindShared("Selling", "ExtraItems", "Sap,Softtissue", "Comma separated item prefab names Haldor also buys, for rare gathered goods a trader would want. He never buys raw materials such as wood, stone or ore unless they are listed here."); SellMultiplier = BindShared("Selling", "PriceMultiplier", 0.05f, new ConfigDescription("Haldor pays an item's value times this. Lower means he pays less.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); ValuablesAtFullValue = BindShared("Selling", "ValuablesAtFullValue", defaultValue: true, "Valuables like amber, rubies and silver necklaces still sell for their full vanilla value."); TierPrices = BindShared("Pricing", "BiomeValues", "Meadows=1,BlackForest=2,Swamp=10,Ocean=10,Mountain=16,Plains=25,Mistlands=35,AshLands=45,DeepNorth=60", "Value of one raw material from each biome, before stack size is taken into account. Crafted, smelted and cooked items are worth what goes into them, and items Haldor already sells keep his price as their value."); CraftMarkup = BindShared("Pricing", "CraftMarkup", 1.25f, new ConfigDescription("A crafted item is worth its ingredients times this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); ConversionMarkup = BindShared("Pricing", "ConversionMarkup", 1.2f, new ConfigDescription("A smelted, cooked or fermented item is worth what goes in times this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); FoodValue = BindShared("Pricing", "FoodValue", 0.05f, new ConfigDescription("Food is valued by what it gives you instead of its ingredients: health, stamina and eitr added up, times this. Food that lasts longer than usual is worth a bit more.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); ValueOverrides = BindShared("Pricing", "ValueOverrides", "", "Comma separated ItemPrefab=value pairs that replace the worked out value of one item, for example Wood=2,Iron=40."); BiomeOverrides = BindShared("Pricing", "BiomeOverrides", "IronScrap=Swamp,SurtlingCore=BlackForest,AncientSeed=BlackForest,WitheredBone=Swamp,Crystal=Mountain,DragonEgg=Mountain,BlackMetalScrap=Plains,BugMeat=Mistlands,Carapace=Mistlands,BlackCore=Mistlands,Softtissue=Mistlands,Sap=Mistlands,RoyalJelly=Mistlands,DvergrNeedle=Mistlands", "Comma separated ItemPrefab=Biome pairs for items whose biome can't be worked out, mostly loot from dungeons. Biomes: Meadows, BlackForest, Swamp, Ocean, Mountain, Plains, Mistlands, AshLands, DeepNorth."); BossPrefabs = BindShared("Pricing", "BossPrefabs", "Meadows=Eikthyr,BlackForest=gd_king,Swamp=Bonemass,Ocean=Bonemass,Mountain=Dragon,Plains=GoblinKing,Mistlands=SeekerQueen,AshLands=Fader,DeepNorth=FrozenKing", "Comma separated Biome=BossPrefab pairs. Items from a biome are sold once that boss has been defeated on the world."); WitchSellsIdols = BindShared("Bog Witch", "SellsIdols", defaultValue: true, "The Bog Witch sells the idols used to upgrade gear at the Forge of Potential. Each idol only appears once the boss of its biome has been defeated."); WitchName = BindShared("Bog Witch", "TraderName", "BogWitch", "Prefab name of the Bog Witch. Several can be listed, separated by commas."); Idols = BindShared("Bog Witch", "Idols", "Upgrader0Armor=Meadows,Upgrader0Weapon=Meadows,Upgrader1Armor=BlackForest,Upgrader1Weapon=BlackForest,Upgrader2Armor=Swamp,Upgrader2Weapon=Swamp,Upgrader3Armor=Mountain,Upgrader3Weapon=Mountain,Upgrader4Armor=Plains,Upgrader4Weapon=Plains,Upgrader5Armor=Mistlands,Upgrader5Weapon=Mistlands,Upgrader6Armor=AshLands,Upgrader6Weapon=AshLands,Upgrader7Armor=DeepNorth,Upgrader7Weapon=DeepNorth", "Comma separated IdolPrefab=Biome pairs: the idols the Bog Witch sells and the biome whose boss unlocks each. If a biome's boss can't be found, the idol unlocks with the boss before it."); IdolPrices = BindShared("Bog Witch", "IdolPrices", "Meadows=500,BlackForest=1000,Swamp=1500,Ocean=1500,Mountain=2500,Plains=3500,Mistlands=5000,AshLands=7000,DeepNorth=9000", "Comma separated Biome=coins pairs: what one idol from each biome costs."); HildirBuysChests = BindShared("Hildir", "BuysExtraChests", defaultValue: true, "Once you have returned one of Hildir's chests, she buys any more of that chest you bring her. Use the chest on her as you would to return it."); HildirName = BindShared("Hildir", "TraderName", "Hildir", "Prefab name of Hildir. Several can be listed, separated by commas."); HildirChestPrices = BindShared("Hildir", "ChestPrices", "chest_hildir1=100,chest_hildir2=200,chest_hildir3=300", "Comma separated ChestPrefab=coins pairs. A chest that isn't listed sells for 100 coins."); LogPrices = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogPrices", false, "Write every item's biome, value and prices to the log the first time Haldor's shop opens."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { PriceTable.Clear(); }; new Harmony("com.dreich.bettertraders").PatchAll(); } private ConfigEntry<T> BindShared<T>(string section, string key, T defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return BindShared(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } private ConfigEntry<T> BindShared<T>(string section, string key, T defaultValue, ConfigDescription description) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description); if (ConfigSyncAvailable) { ConfigSyncCompat.AddConfigEntry<T>(val); } return val; } internal static bool Matches(Trader trader, string names) { if ((Object)(object)trader == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)trader).gameObject); string[] array = (names ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && (trader.m_name == text || string.Equals(prefabName, text, StringComparison.OrdinalIgnoreCase))) { return true; } } return false; } internal static bool IsHaldor(Trader trader) { if (ModEnabled.Value) { return Matches(trader, TraderName.Value); } return false; } } internal static class ConfigSyncCompat { private static object configSync; [MethodImpl(MethodImplOptions.NoInlining)] internal static void Initialize(string guid, string name, string version) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown configSync = (object)new ConfigSync(guid) { DisplayName = name, CurrentVersion = version, MinimumRequiredVersion = version, ModRequired = true }; } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddLockingConfigEntry(ConfigEntry<bool> entry) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((ConditionalConfigSync)(ConfigSync)configSync).AddLockingConfigEntry<bool>(entry); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddConfigEntry<T>(ConfigEntry<T> entry) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((ConditionalConfigSync)(ConfigSync)configSync).AddConfigEntry<T>(entry, (ConfigSyncMode)0); } } internal static class PriceTable { internal enum Source { Raw, Valuable, Crafted, Refined, Cooked } internal sealed class Entry { internal ItemDrop Item; internal Source Source; internal float Value; internal bool HasTier; internal int Tier; internal string BossKey; } private sealed class TierScan { internal readonly Dictionary<string, int> Narrow = new Dictionary<string, int>(StringComparer.Ordinal); internal readonly Dictionary<string, int> Broad = new Dictionary<string, int>(StringComparer.Ordinal); internal readonly Dictionary<string, string> NarrowFrom = new Dictionary<string, string>(StringComparer.Ordinal); internal readonly Dictionary<string, string> BroadFrom = new Dictionary<string, string>(StringComparer.Ordinal); internal readonly HashSet<GameObject> Visited = new HashSet<GameObject>(); internal int Rank; internal bool IsBroad; internal string Origin; } private struct Conversion { internal ItemDrop From; internal ItemDrop To; internal int Amount; internal Source Kind; } private static readonly Biome[] BiomeOrder; private static readonly Dictionary<string, Entry> entries; private static readonly List<TradeItem> wares; private static readonly Dictionary<TradeItem, Entry> wareEntries; private static ObjectDB builtFor; private static Trader builtTrader; private static ObjectDB tiersFor; private static Dictionary<string, int> tierCache; private static Dictionary<int, string> bossKeyCache; private static readonly List<TradeItem> idols; private static ObjectDB idolsFor; private static Trader prefabTrader; private static Dictionary<string, string> tierOrigins; private static List<Conversion> conversions; private static HashSet<string> purchases; private static Dictionary<string, Recipe> recipeByItem; internal static void Clear() { purchases = null; tiersFor = null; tierCache = null; bossKeyCache = null; idolsFor = null; idols.Clear(); builtFor = null; builtTrader = null; entries.Clear(); wares.Clear(); wareEntries.Clear(); } private static int Rank(Biome biome) { //IL_0004: 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) for (int i = 0; i < BiomeOrder.Length; i++) { if ((biome & BiomeOrder[i]) != 0) { return i; } } return -1; } private static bool TryParseBiome(string text, out Biome biome) { if (Enum.TryParse<Biome>(text.Trim(), ignoreCase: true, out biome)) { return (int)biome != 0; } return false; } private static Dictionary<string, string> ParsePairs(string raw) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string[] array = (raw ?? "").Split(new char[1] { ',' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 1).Trim(); if (text2.Length > 0 && text3.Length > 0) { dictionary[text2] = text3; } } } return dictionary; } private static float ParseFloat(string text, float fallback) { if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } internal static bool WouldBuy(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } if (entries.Count == 0 || (Object)(object)builtFor != (Object)(object)ObjectDB.instance) { if ((Object)(object)prefabTrader == (Object)null) { string[] array = (BetterTradersPlugin.TraderName.Value ?? "").Split(new char[1] { ',' }); foreach (string text in array) { GameObject val = ((text.Trim().Length > 0) ? ZNetScene.instance.GetPrefab(text.Trim()) : null); prefabTrader = (((Object)(object)val != (Object)null) ? val.GetComponent<Trader>() : null); if ((Object)(object)prefabTrader != (Object)null) { break; } } } EnsureBuilt(((Object)(object)builtTrader != (Object)null) ? builtTrader : prefabTrader); } return SellPrice(item) > 0; } internal static void EnsureBuilt(Trader trader) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ((Object)(object)builtFor == (Object)(object)instance && (Object)(object)builtTrader == (Object)(object)trader && entries.Count > 0)) { return; } Clear(); builtFor = instance; builtTrader = trader; EnsureTiers(instance); Dictionary<string, int> dictionary = tierCache; Dictionary<string, Source> sources; Dictionary<string, float> dictionary2 = FindValues(instance, trader, dictionary, out sources); Dictionary<int, string> dictionary3 = bossKeyCache; foreach (GameObject item in instance.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null)) { float value; Source value2; Entry entry = new Entry { Item = val, Value = (dictionary2.TryGetValue(((Object)item).name, out value) ? value : 0f), Source = (sources.TryGetValue(((Object)item).name, out value2) ? value2 : Source.Raw) }; if (dictionary.TryGetValue(((Object)item).name, out var value3)) { entry.HasTier = true; entry.Tier = value3; dictionary3.TryGetValue(value3, out entry.BossKey); } entries[((Object)item).name] = entry; } } BuildWares(instance); if (BetterTradersPlugin.LogPrices.Value) { LogTable(); } BetterTradersPlugin.Log.LogInfo((object)("Priced " + entries.Count + " items; Haldor can sell " + wares.Count + " of them.")); } private static void EnsureTiers(ObjectDB db) { if (!((Object)(object)tiersFor == (Object)(object)db) || tierCache == null) { tiersFor = db; tierCache = FindTiers(db); bossKeyCache = FindBossKeys(); } } internal static void AppendIdols(List<TradeItem> list) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return; } if ((Object)(object)idolsFor != (Object)(object)instance) { idolsFor = instance; idols.Clear(); BuildIdols(instance); } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (TradeItem item in list) { if (item != null && (Object)(object)item.m_prefab != (Object)null) { hashSet.Add(((Object)item.m_prefab).name); } } foreach (TradeItem idol in idols) { if (!hashSet.Contains(((Object)idol.m_prefab).name) && ZoneSystem.instance.GetGlobalKey(idol.m_requiredGlobalKey)) { list.Add(idol); } } } private static void BuildIdols(ObjectDB db) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Expected O, but got Unknown EnsureTiers(db); Dictionary<int, int> dictionary = new Dictionary<int, int>(); foreach (KeyValuePair<string, string> item in ParsePairs(BetterTradersPlugin.IdolPrices.Value)) { if (TryParseBiome(item.Key, out var biome) && int.TryParse(item.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result > 0) { dictionary[Rank(biome)] = result; } } List<KeyValuePair<int, ItemDrop>> list = new List<KeyValuePair<int, ItemDrop>>(); foreach (KeyValuePair<string, string> item2 in ParsePairs(BetterTradersPlugin.Idols.Value)) { if (!TryParseBiome(item2.Value, out var biome2)) { BetterTradersPlugin.Log.LogWarning((object)("Unknown biome '" + item2.Value + "' for the idol '" + item2.Key + "'.")); continue; } GameObject itemPrefab = db.GetItemPrefab(item2.Key); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { BetterTradersPlugin.Log.LogWarning((object)("The idol '" + item2.Key + "' was not found and won't be sold.")); continue; } int num = Rank(biome2); if (num >= 0 && dictionary.ContainsKey(num) && KeyFor(num) != null) { list.Add(new KeyValuePair<int, ItemDrop>(num, val)); } } list.Sort((KeyValuePair<int, ItemDrop> a, KeyValuePair<int, ItemDrop> b) => (a.Key == b.Key) ? string.Compare(Localize(a.Value.m_itemData.m_shared.m_name), Localize(b.Value.m_itemData.m_shared.m_name), StringComparison.CurrentCulture) : a.Key.CompareTo(b.Key)); foreach (KeyValuePair<int, ItemDrop> item3 in list) { idols.Add(new TradeItem { m_prefab = item3.Value, m_stack = 1, m_price = dictionary[item3.Key], m_requiredGlobalKey = KeyFor(item3.Key), m_buyPlayerEffects = new EffectList(), m_name = "", m_tooltip = "" }); } BetterTradersPlugin.Log.LogInfo((object)("The Bog Witch can sell " + idols.Count + " idols.")); } private static string KeyFor(int tier) { for (int num = tier; num >= 0; num--) { if (bossKeyCache.TryGetValue(num, out var value) && !string.IsNullOrEmpty(value)) { return value; } } return null; } private unsafe static Dictionary<int, string> FindBossKeys() { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) Dictionary<int, string> dictionary = new Dictionary<int, string>(); foreach (KeyValuePair<string, string> item in ParsePairs(BetterTradersPlugin.BossPrefabs.Value)) { if (TryParseBiome(item.Key, out var biome)) { GameObject prefab = ZNetScene.instance.GetPrefab(item.Value); Character val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Character>() : null); if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.m_defeatSetGlobalKey)) { BetterTradersPlugin.Log.LogWarning((object)("Boss '" + item.Value + "' for " + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString() + " wasn't found or sets no key; Haldor won't sell items from there.")); } else { dictionary[Rank(biome)] = val.m_defeatSetGlobalKey; } } } return dictionary; } private static int BiomeCount(Biome biome) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = 0; Biome[] biomeOrder = BiomeOrder; foreach (Biome val in biomeOrder) { if ((biome & val) != 0) { num++; } } return num; } private static int HighestRank(Biome biome) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) for (int num = BiomeOrder.Length - 1; num >= 0; num--) { if ((biome & BiomeOrder[num]) != 0) { return num; } } return -1; } private static void Begin(TierScan scan, Biome biome, string origin) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) scan.IsBroad = BiomeCount(biome) > 2; scan.Rank = (scan.IsBroad ? HighestRank(biome) : Rank(biome)); scan.Origin = origin; scan.Visited.Clear(); } private static void AddTier(TierScan scan, GameObject prefab) { if (!((Object)(object)prefab == (Object)null) && scan.Rank >= 0 && !((Object)(object)prefab.GetComponent<ItemDrop>() == (Object)null)) { string name = ((Object)prefab).name; Dictionary<string, int> dictionary = (scan.IsBroad ? scan.Broad : scan.Narrow); Dictionary<string, string> dictionary2 = (scan.IsBroad ? scan.BroadFrom : scan.NarrowFrom); if (!dictionary.TryGetValue(name, out var value) || scan.Rank < value) { dictionary[name] = scan.Rank; dictionary2[name] = scan.Origin; } } } private static void AddDropTable(TierScan scan, DropTable table, int depth) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (table == null || table.m_drops == null) { return; } foreach (DropData drop in table.m_drops) { AddSource(scan, drop.m_item, depth + 1); } } private static void AddSource(TierScan scan, GameObject prefab, int depth) { if ((Object)(object)prefab == (Object)null || scan.Rank < 0 || depth > 4 || !scan.Visited.Add(prefab)) { return; } AddTier(scan, prefab); Pickable component = prefab.GetComponent<Pickable>(); if ((Object)(object)component != (Object)null) { AddTier(scan, component.m_itemPrefab); AddDropTable(scan, component.m_extraDrops, depth); } DropOnDestroyed component2 = prefab.GetComponent<DropOnDestroyed>(); if ((Object)(object)component2 != (Object)null) { AddDropTable(scan, component2.m_dropWhenDestroyed, depth); } MineRock component3 = prefab.GetComponent<MineRock>(); if ((Object)(object)component3 != (Object)null) { AddDropTable(scan, component3.m_dropItems, depth); } MineRock5 component4 = prefab.GetComponent<MineRock5>(); if ((Object)(object)component4 != (Object)null) { AddDropTable(scan, component4.m_dropItems, depth); } TreeBase component5 = prefab.GetComponent<TreeBase>(); if ((Object)(object)component5 != (Object)null) { AddDropTable(scan, component5.m_dropWhenDestroyed, depth); AddSource(scan, component5.m_logPrefab, depth + 1); } TreeLog component6 = prefab.GetComponent<TreeLog>(); if ((Object)(object)component6 != (Object)null) { AddDropTable(scan, component6.m_dropWhenDestroyed, depth); AddSource(scan, component6.m_subLogPrefab, depth + 1); } Destructible component7 = prefab.GetComponent<Destructible>(); if ((Object)(object)component7 != (Object)null) { AddSource(scan, component7.m_spawnWhenDestroyed, depth + 1); } CharacterDrop component8 = prefab.GetComponent<CharacterDrop>(); if (!((Object)(object)component8 != (Object)null) || component8.m_drops == null) { return; } foreach (Drop drop in component8.m_drops) { AddTier(scan, drop.m_prefab); } } private static Dictionary<string, int> FindTiers(ObjectDB db) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) TierScan tierScan = new TierScan(); if ((Object)(object)ZoneSystem.instance != (Object)null) { foreach (ZoneVegetation item in ZoneSystem.instance.m_vegetation) { if (item != null && item.m_enable && !((Object)(object)item.m_prefab == (Object)null)) { Begin(tierScan, item.m_biome, "vegetation " + ((Object)item.m_prefab).name); AddSource(tierScan, item.m_prefab, 0); } } } foreach (SpawnSystem item2 in SpawnSystems()) { foreach (SpawnSystemList spawnList in item2.m_spawnLists) { if ((Object)(object)spawnList == (Object)null) { continue; } foreach (SpawnData spawner in spawnList.m_spawners) { if (spawner != null && spawner.m_enabled && !((Object)(object)spawner.m_prefab == (Object)null)) { Begin(tierScan, spawner.m_biome, "creature " + ((Object)spawner.m_prefab).name); AddSource(tierScan, spawner.m_prefab, 0); } } } } foreach (KeyValuePair<string, string> item3 in ParsePairs(BetterTradersPlugin.BossPrefabs.Value)) { if (TryParseBiome(item3.Key, out var biome)) { Begin(tierScan, biome, "boss " + item3.Value); AddSource(tierScan, ZNetScene.instance.GetPrefab(item3.Value), 0); } } Dictionary<string, int> dictionary = new Dictionary<string, int>(tierScan.Narrow, StringComparer.Ordinal); Dictionary<string, string> dictionary2 = new Dictionary<string, string>(tierScan.NarrowFrom, StringComparer.Ordinal); foreach (KeyValuePair<string, int> item4 in tierScan.Broad) { if (!dictionary.ContainsKey(item4.Key)) { dictionary[item4.Key] = item4.Value; dictionary2[item4.Key] = tierScan.BroadFrom[item4.Key] + " (many biomes)"; } } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (KeyValuePair<string, string> item5 in ParsePairs(BetterTradersPlugin.BiomeOverrides.Value)) { if (TryParseBiome(item5.Value, out var biome2)) { dictionary[item5.Key] = Rank(biome2); dictionary2[item5.Key] = "BiomeOverrides"; hashSet.Add(item5.Key); } } HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal); foreach (Conversion item6 in Conversions()) { if ((Object)(object)item6.To != (Object)null && !hashSet.Contains(((Object)item6.To).name)) { hashSet2.Add(((Object)item6.To).name); } } foreach (Recipe recipe in db.m_recipes) { if (Usable(recipe) && !hashSet.Contains(((Object)recipe.m_item).name)) { hashSet2.Add(((Object)recipe.m_item).name); } } foreach (string item7 in hashSet2) { dictionary.Remove(item7); dictionary2.Remove(item7); } bool flag = true; for (int i = 0; i < 20 && flag; i++) { flag = false; Dictionary<string, int> dictionary3 = new Dictionary<string, int>(StringComparer.Ordinal); Dictionary<string, string> dictionary4 = new Dictionary<string, string>(StringComparer.Ordinal); foreach (Conversion item8 in Conversions()) { if (!((Object)(object)item8.From == (Object)null) && !((Object)(object)item8.To == (Object)null) && hashSet2.Contains(((Object)item8.To).name) && dictionary.TryGetValue(((Object)item8.From).name, out var value) && (!dictionary3.TryGetValue(((Object)item8.To).name, out var value2) || value < value2)) { dictionary3[((Object)item8.To).name] = value; dictionary4[((Object)item8.To).name] = "made from " + ((Object)item8.From).name; } } foreach (Recipe recipe2 in db.m_recipes) { if (!Usable(recipe2) || !hashSet2.Contains(((Object)recipe2.m_item).name)) { continue; } int num = -1; string text = null; bool flag2 = true; Requirement[] resources = recipe2.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.GetAmount(1) > 0) { if (!dictionary.TryGetValue(((Object)val.m_resItem).name, out var value3)) { flag2 = false; break; } if (value3 > num) { num = value3; text = ((Object)val.m_resItem).name; } } } if (flag2 && num >= 0 && (!dictionary3.TryGetValue(((Object)recipe2.m_item).name, out var value4) || num < value4)) { dictionary3[((Object)recipe2.m_item).name] = num; dictionary4[((Object)recipe2.m_item).name] = "crafted from " + text; } } foreach (KeyValuePair<string, int> item9 in dictionary3) { if (!dictionary.TryGetValue(item9.Key, out var value5) || value5 != item9.Value) { dictionary[item9.Key] = item9.Value; dictionary2[item9.Key] = dictionary4[item9.Key]; flag = true; } } } tierOrigins = dictionary2; return dictionary; } private static HashSet<string> FindKeys(ObjectDB db) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Door[] componentsInChildren = prefab.GetComponentsInChildren<Door>(true); foreach (Door val in componentsInChildren) { if ((Object)(object)val.m_keyItem != (Object)null) { hashSet.Add(((Object)val.m_keyItem).name); } } } foreach (GameObject item in db.m_items) { ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (!((Object)(object)val2 == (Object)null)) { string text = val2.m_itemData.m_shared.m_name ?? ""; if (((Object)item).name.IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0 || Localize(text).IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0) { hashSet.Add(((Object)item).name); } } } return hashSet; } private static bool Usable(Recipe recipe) { if ((Object)(object)recipe != (Object)null && recipe.m_enabled && (Object)(object)recipe.m_item != (Object)null && recipe.m_resources != null) { return recipe.m_resources.Length != 0; } return false; } private static IEnumerable<SpawnSystem> SpawnSystems() { HashSet<SpawnSystem> seen = new HashSet<SpawnSystem>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { SpawnSystem val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<SpawnSystem>() : null); if ((Object)(object)val != (Object)null && seen.Add(val)) { yield return val; } } if (!(AccessTools.Field(typeof(SpawnSystem), "m_instances")?.GetValue(null) is List<SpawnSystem> list)) { yield break; } foreach (SpawnSystem item in list) { if ((Object)(object)item != (Object)null && seen.Add(item)) { yield return item; } } } private static List<Conversion> Conversions() { if (conversions != null) { return conversions; } conversions = new List<Conversion>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Smelter component = prefab.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null && component.m_conversion != null) { foreach (ItemConversion item in component.m_conversion) { conversions.Add(new Conversion { From = item.m_from, To = item.m_to, Amount = 1, Kind = Source.Refined }); } } CookingStation component2 = prefab.GetComponent<CookingStation>(); if ((Object)(object)component2 != (Object)null && component2.m_conversion != null) { foreach (ItemConversion item2 in component2.m_conversion) { conversions.Add(new Conversion { From = item2.m_from, To = item2.m_to, Amount = 1, Kind = Source.Cooked }); } } Fermenter component3 = prefab.GetComponent<Fermenter>(); if (!((Object)(object)component3 != (Object)null) || component3.m_conversion == null) { continue; } foreach (ItemConversion item3 in component3.m_conversion) { conversions.Add(new Conversion { From = item3.m_from, To = item3.m_to, Amount = Mathf.Max(1, item3.m_producedItems), Kind = Source.Cooked }); } } return conversions; } private static Dictionary<string, float> FindValues(ObjectDB db, Trader trader, Dictionary<string, int> tiers, out Dictionary<string, Source> sources) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) conversions = null; Dictionary<string, float> values = new Dictionary<string, float>(StringComparer.Ordinal); Dictionary<string, Source> found = new Dictionary<string, Source>(StringComparer.Ordinal); sources = found; Dictionary<string, string> overrides = ParsePairs(BetterTradersPlugin.ValueOverrides.Value); float[] tierValues = new float[BiomeOrder.Length]; for (int i = 0; i < tierValues.Length; i++) { tierValues[i] = 1f + (float)i * 5f; } foreach (KeyValuePair<string, string> item in ParsePairs(BetterTradersPlugin.TierPrices.Value)) { if (TryParseBiome(item.Key, out var biome)) { int num = Rank(biome); if (num >= 0) { tierValues[num] = Mathf.Max(0f, ParseFloat(item.Value, tierValues[num])); } } } Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>(StringComparer.Ordinal); foreach (Recipe recipe in db.m_recipes) { if (Usable(recipe) && !recipes.ContainsKey(((Object)recipe.m_item).name)) { recipes[((Object)recipe.m_item).name] = recipe; } } recipeByItem = recipes; Dictionary<string, Conversion> converted = new Dictionary<string, Conversion>(StringComparer.Ordinal); foreach (Conversion item2 in Conversions()) { if ((Object)(object)item2.From != (Object)null && (Object)(object)item2.To != (Object)null && !converted.ContainsKey(((Object)item2.To).name)) { converted[((Object)item2.To).name] = item2; } } Dictionary<string, float> traderPrices = new Dictionary<string, float>(StringComparer.Ordinal); if ((Object)(object)trader != (Object)null && trader.m_items != null) { foreach (TradeItem item3 in trader.m_items) { if (item3 != null && (Object)(object)item3.m_prefab != (Object)null && item3.m_price > 0) { traderPrices[((Object)item3.m_prefab).name] = (float)item3.m_price / (float)Mathf.Max(1, item3.m_stack); } } } HashSet<string> visiting = new HashSet<string>(); foreach (GameObject item4 in db.m_items) { ItemDrop val = (((Object)(object)item4 != (Object)null) ? item4.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null) { ValueOf(val); } } return values; float ValueOf(ItemDrop drop) { if ((Object)(object)drop == (Object)null) { return 0f; } string name = ((Object)drop).name; if (values.TryGetValue(name, out var value)) { return value; } if (!visiting.Add(name)) { return 0f; } SharedData shared = drop.m_itemData.m_shared; Conversion value2; if (shared.m_value > 0) { found[name] = Source.Valuable; } else if (recipes.ContainsKey(name)) { found[name] = Source.Crafted; } else if (converted.TryGetValue(name, out value2)) { found[name] = value2.Kind; } else { found[name] = Source.Raw; } float num2; float value4; Recipe value5; Conversion value6; if (overrides.TryGetValue(name, out var value3)) { num2 = Mathf.Max(0f, ParseFloat(value3, 0f)); } else if (shared.m_value > 0) { num2 = shared.m_value; } else if (traderPrices.TryGetValue(name, out value4)) { num2 = value4; } else if (FoodPoints(shared) > 0f) { num2 = FoodPoints(shared) * Mathf.Clamp(shared.m_foodBurnTime / 1500f, 0.5f, 2f) * BetterTradersPlugin.FoodValue.Value; } else if (recipes.TryGetValue(name, out value5)) { float num3 = 0f; Requirement[] resources = value5.m_resources; foreach (Requirement val2 in resources) { if (val2 != null && !((Object)(object)val2.m_resItem == (Object)null)) { num3 += ValueOf(val2.m_resItem) * (float)val2.GetAmount(1); } } num2 = num3 / (float)Mathf.Max(1, value5.m_amount) * BetterTradersPlugin.CraftMarkup.Value; } else if (converted.TryGetValue(name, out value6)) { num2 = ValueOf(value6.From) / (float)value6.Amount * BetterTradersPlugin.ConversionMarkup.Value; } else { int value7; int num4 = (tiers.TryGetValue(name, out value7) ? value7 : 0); float num5 = Mathf.Clamp(50f / (float)Mathf.Max(1, shared.m_maxStackSize), 0.5f, 5f); num2 = tierValues[Mathf.Clamp(num4, 0, tierValues.Length - 1)] * num5; } visiting.Remove(name); values[name] = num2; return num2; } } private static float FoodPoints(SharedData shared) { return Mathf.Max(0f, shared.m_food) + Mathf.Max(0f, shared.m_foodStamina) + Mathf.Max(0f, shared.m_foodEitr); } private static void BuildWares(ObjectDB db) { //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Expected O, but got Unknown if (!BetterTradersPlugin.BuyEnabled.Value) { return; } HashSet<string> hashSet = NameSet(BetterTradersPlugin.ExtraWares.Value); HashSet<string> hashSet2 = NameSet(BetterTradersPlugin.ExcludedItems.Value); if (BetterTradersPlugin.ExcludeKeys.Value) { hashSet2.UnionWith(FindKeys(db)); } List<Entry> list = new List<Entry>(); foreach (KeyValuePair<string, Entry> entry in entries) { Entry value = entry.Value; SharedData shared = value.Item.m_itemData.m_shared; if (value.HasTier && !string.IsNullOrEmpty(value.BossKey) && !(value.Value <= 0f) && !hashSet2.Contains(entry.Key) && (hashSet.Contains(entry.Key) || Sells(value)) && shared.m_icons != null && shared.m_icons.Length != 0 && !((Object)(object)shared.m_icons[0] == (Object)null)) { list.Add(value); } } list.Sort(delegate(Entry a, Entry b) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) int num2 = a.Tier.CompareTo(b.Tier); if (num2 != 0) { return num2; } ref ItemType itemType = ref a.Item.m_itemData.m_shared.m_itemType; object target = b.Item.m_itemData.m_shared.m_itemType; int num3 = ((Enum)Unsafe.As<ItemType, ItemType>(ref itemType)/*cast due to .constrained prefix*/).CompareTo(target); return (num3 != 0) ? num3 : string.Compare(Localize(a.Item.m_itemData.m_shared.m_name), Localize(b.Item.m_itemData.m_shared.m_name), StringComparison.CurrentCulture); }); foreach (Entry item in list) { int num = Mathf.Clamp(BetterTradersPlugin.BuyStackSize.Value, 1, Mathf.Max(1, item.Item.m_itemData.m_shared.m_maxStackSize)); TradeItem val = new TradeItem { m_prefab = item.Item, m_stack = num, m_price = Mathf.Max(1, Mathf.RoundToInt(item.Value * (float)num * BetterTradersPlugin.BuyMultiplier.Value)), m_requiredGlobalKey = item.BossKey, m_buyPlayerEffects = new EffectList(), m_name = "", m_tooltip = "" }; wares.Add(val); wareEntries[val] = item; } } private static HashSet<string> NameSet(string raw) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = (raw ?? "").Split(new char[1] { ',' }); foreach (string text in array) { if (text.Trim().Length > 0) { hashSet.Add(text.Trim()); } } return hashSet; } private static bool IsFood(SharedData shared) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)shared.m_itemType == 2; } private static bool IsMaterial(SharedData shared) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 return (int)shared.m_itemType == 1; } private static bool Sells(Entry entry) { SharedData shared = entry.Item.m_itemData.m_shared; switch (entry.Source) { case Source.Refined: return BetterTradersPlugin.SellsRefined.Value; case Source.Cooked: return BetterTradersPlugin.SellsFood.Value; case Source.Crafted: if (IsFood(shared)) { return BetterTradersPlugin.SellsFood.Value; } if (IsMaterial(shared)) { return BetterTradersPlugin.SellsCraftedMaterials.Value; } return BetterTradersPlugin.SellsGear.Value; default: return false; } } private static float UpgradeValue(string prefab, int quality) { if (quality <= 1 || !recipeByItem.TryGetValue(prefab, out var value)) { return 0f; } float num = 0f; for (int i = 2; i <= quality; i++) { Requirement[] resources = value.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null) && !val.m_upgraderResource) { int amount = val.GetAmount(i); if (amount > 0 && entries.TryGetValue(((Object)val.m_resItem).name, out var value2)) { num += value2.Value * (float)amount; } } } } return num * BetterTradersPlugin.CraftMarkup.Value; } private static bool Buys(string prefab, Entry entry) { if (purchases == null) { purchases = NameSet(BetterTradersPlugin.ExtraPurchases.Value); } if (purchases.Contains(prefab)) { return true; } switch (entry.Source) { case Source.Valuable: return true; case Source.Crafted: return BetterTradersPlugin.BuysCrafted.Value; case Source.Refined: case Source.Cooked: return BetterTradersPlugin.BuysProcessed.Value; default: return false; } } private static string Localize(string token) { if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } internal static void AppendWares(List<TradeItem> list) { if ((Object)(object)ZoneSystem.instance == (Object)null) { return; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (TradeItem item in list) { if (item != null && (Object)(object)item.m_prefab != (Object)null) { hashSet.Add(((Object)item.m_prefab).name); } } foreach (TradeItem ware in wares) { if (!hashSet.Contains(((Object)ware.m_prefab).name) && ZoneSystem.instance.GetGlobalKey(ware.m_requiredGlobalKey)) { list.Add(ware); } } } internal static int SellPrice(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return 0; } if (!entries.TryGetValue(((Object)item.m_dropPrefab).name, out var value) || !Buys(((Object)item.m_dropPrefab).name, value)) { return 0; } SharedData shared = item.m_shared; if (shared.m_value > 0 && BetterTradersPlugin.ValuablesAtFullValue.Value) { return shared.m_value * item.m_stack; } if (value.Value <= 0f) { return 0; } float num = UpgradeValue(((Object)item.m_dropPrefab).name, item.m_quality); if (num <= 0f && item.m_quality > 1) { num = value.Value * 0.5f * (float)(item.m_quality - 1); } float num2 = (value.Value + num) * (float)item.m_stack * BetterTradersPlugin.SellMultiplier.Value; if (!(num2 <= 0f)) { return Mathf.Max(1, Mathf.FloorToInt(num2)); } return 0; } private static void LogTable() { List<string> list = new List<string>(); foreach (KeyValuePair<string, Entry> entry in entries) { Entry value = entry.Value; string text = (value.HasTier ? ((object)Unsafe.As<Biome, Biome>(ref BiomeOrder[value.Tier])/*cast due to .constrained prefix*/).ToString() : "unknown"); list.Add(entry.Key + ": " + text + (tierOrigins.TryGetValue(entry.Key, out var value2) ? (" (" + value2 + ")") : "") + ", " + value.Source.ToString() + ", value " + value.Value.ToString("0.##", CultureInfo.InvariantCulture) + ((value.BossKey != null) ? (", unlocked by " + value.BossKey) : "")); } list.Sort(StringComparer.Ordinal); BetterTradersPlugin.Log.LogInfo((object)("Haldor's price table:\n" + string.Join("\n", list.ToArray()))); } static PriceTable() { Biome[] array = new Biome[9]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); BiomeOrder = (Biome[])(object)array; entries = new Dictionary<string, Entry>(); wares = new List<TradeItem>(); wareEntries = new Dictionary<TradeItem, Entry>(); idols = new List<TradeItem>(); tierOrigins = new Dictionary<string, string>(StringComparer.Ordinal); recipeByItem = new Dictionary<string, Recipe>(StringComparer.Ordinal); } } internal static class SellPanel { private sealed class Offer { internal ItemData Item; internal int Price; internal GameObject Element; } [CompilerGenerated] private static class <>O { public static Action <0>__OnInventoryChanged; public static UnityAction <1>__SellSelected; } private static readonly FieldRef<StoreGui, Trader> TraderRef = AccessTools.FieldRefAccess<StoreGui, Trader>("m_trader"); private static StoreGui owner; private static GameObject root; private static readonly FieldRef<StoreGui, float> ItemListBaseSizeRef = AccessTools.FieldRefAccess<StoreGui, float>("m_itemlistBaseSize"); private static RectTransform listRoot; private static Button sellButton; private static TMP_Text coinText; private static float listBaseSize; private static Inventory watched; private static bool dirty; private static readonly List<Offer> offers = new List<Offer>(); private static int selected = -1; private static bool IsOpen { get { if ((Object)(object)root != (Object)null) { return root.activeSelf; } return false; } } private static float ItemListBaseSize(StoreGui gui) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) float num = 0f; try { num = ItemListBaseSizeRef.Invoke(gui); } catch { } if (!(num > 0f)) { Rect rect = gui.m_listRoot.rect; return ((Rect)(ref rect)).height; } return num; } internal static Trader CurrentTrader(StoreGui gui) { if (!((Object)(object)gui != (Object)null)) { return null; } return TraderRef.Invoke(gui); } internal static void Open(StoreGui gui) { if (!BetterTradersPlugin.SellEnabled.Value) { return; } try { if (Ensure(gui)) { root.SetActive(true); root.transform.SetAsLastSibling(); PositionNextToStore(gui); selected = -1; Watch(((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); Refresh(); } } catch (Exception ex) { BetterTradersPlugin.Log.LogError((object)("Opening the sell panel failed: " + ex)); } } internal static void Close() { Watch(null); SellTooltip.HideAll(); if ((Object)(object)root != (Object)null) { root.SetActive(false); } } internal static void Tick(StoreGui gui) { if (!IsOpen) { return; } SellTooltip.Follow(); if ((Object)(object)gui == (Object)null || (Object)(object)gui != (Object)(object)owner || (Object)(object)gui.m_rootPanel == (Object)null || !gui.m_rootPanel.activeSelf || (Object)(object)Player.m_localPlayer == (Object)null || !BetterTradersPlugin.IsHaldor(CurrentTrader(gui))) { Close(); return; } PositionNextToStore(gui); if (dirty) { Refresh(); } if ((Object)(object)sellButton != (Object)null) { ((Selectable)sellButton).interactable = selected >= 0 && selected < offers.Count; } } private static void Watch(Inventory inventory) { if (watched != null) { Inventory obj = watched; obj.m_onChanged = (Action)Delegate.Remove(obj.m_onChanged, new Action(OnInventoryChanged)); } watched = inventory; if (watched != null) { Inventory obj2 = watched; obj2.m_onChanged = (Action)Delegate.Combine(obj2.m_onChanged, new Action(OnInventoryChanged)); } } private static void OnInventoryChanged() { dirty = true; } private static string PathFrom(Transform from, Transform target) { if ((Object)(object)target == (Object)null || ((Object)(object)target != (Object)(object)from && !target.IsChildOf(from))) { return null; } List<string> list = new List<string>(); Transform val = target; while ((Object)(object)val != (Object)(object)from) { list.Insert(0, ((Object)val).name); val = val.parent; } return string.Join("/", list.ToArray()); } private static Transform Twin(Transform copy, Transform original, Transform target) { string text = PathFrom(original, target); if (text == null) { return null; } if (text.Length != 0) { return copy.Find(text); } return copy; } private static bool Ensure(StoreGui gui) { //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Expected O, but got Unknown if ((Object)(object)root != (Object)null && (Object)(object)owner == (Object)(object)gui) { return true; } if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); } root = null; if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_rootPanel == (Object)null || (Object)(object)gui.m_listRoot == (Object)null || (Object)(object)gui.m_buyButton == (Object)null || (Object)(object)gui.m_listElement == (Object)null) { return false; } Transform transform = gui.m_rootPanel.transform; root = Object.Instantiate<GameObject>(gui.m_rootPanel, transform.parent, false); ((Object)root).name = "BetterTraders_SellPanel"; owner = gui; Transform transform2 = root.transform; Transform obj = Twin(transform2, transform, (Transform)(object)gui.m_listRoot); listRoot = (RectTransform)(object)((obj is RectTransform) ? obj : null); Transform val = Twin(transform2, transform, ((Component)gui.m_buyButton).transform); Transform val2 = (((Object)(object)gui.m_sellButton != (Object)null) ? Twin(transform2, transform, ((Component)gui.m_sellButton).transform) : null); Transform val3 = (((Object)(object)gui.m_coinText != (Object)null) ? Twin(transform2, transform, gui.m_coinText.transform) : null); if ((Object)(object)listRoot == (Object)null || (Object)(object)val == (Object)null) { BetterTradersPlugin.Log.LogWarning((object)"Couldn't copy the parts of Haldor's shop; the sell panel is unavailable."); Object.Destroy((Object)(object)root); root = null; return false; } for (int num = ((Transform)listRoot).childCount - 1; num >= 0; num--) { GameObject gameObject = ((Component)((Transform)listRoot).GetChild(num)).gameObject; if (!(((Object)gameObject).name == ((Object)gui.m_listElement).name) || gameObject.activeSelf) { gameObject.SetActive(false); Object.Destroy((Object)(object)gameObject); } } UIGamePad[] componentsInChildren = root.GetComponentsInChildren<UIGamePad>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } Localize[] componentsInChildren2 = root.GetComponentsInChildren<Localize>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } sellButton = ((Component)val).GetComponent<Button>(); for (int j = 0; j < ((UnityEventBase)sellButton.onClick).GetPersistentEventCount(); j++) { ((UnityEventBase)sellButton.onClick).SetPersistentListenerState(j, (UnityEventCallState)0); } ((UnityEventBase)sellButton.onClick).RemoveAllListeners(); ButtonClickedEvent onClick = sellButton.onClick; object obj2 = <>O.<1>__SellSelected; if (obj2 == null) { UnityAction val4 = SellSelected; <>O.<1>__SellSelected = val4; obj2 = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); UITooltip component = ((Component)sellButton).GetComponent<UITooltip>(); if ((Object)(object)component != (Object)null) { component.m_text = ""; } TMP_Text componentInChildren = ((Component)sellButton).GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = BetterTradersPlugin.SellLabel.Value; } if ((Object)(object)val2 != (Object)null) { ((Component)(((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)transform2 && ((Component)val2.parent).GetComponentsInChildren<Button>(true).Length == 1) ? val2.parent : val2)).gameObject.SetActive(false); } coinText = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<TMP_Text>() : null); if ((Object)(object)val3 != (Object)null) { Transform parent = val3.parent; ((Component)(((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)transform2 && !((Transform)listRoot).IsChildOf(parent) && ((Component)parent).GetComponentsInChildren<Button>(true).Length == 0 && ((Component)parent).GetComponentsInChildren<TMP_Text>(true).Length == 1) ? parent : val3)).gameObject.SetActive(false); } TMP_Text val5 = null; TMP_Text[] componentsInChildren3 = root.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val6 in componentsInChildren3) { if (!((Object)(object)val6 == (Object)(object)coinText) && !val6.transform.IsChildOf((Transform)(object)listRoot) && !((Object)(object)((Component)val6).GetComponentInParent<Button>() != (Object)null) && ((Object)(object)val5 == (Object)null || val6.fontSize > val5.fontSize)) { val5 = val6; } } if ((Object)(object)val5 != (Object)null) { val5.text = BetterTradersPlugin.SellTitle.Value; } listBaseSize = ItemListBaseSize(gui); listRoot.SetSizeWithCurrentAnchors((Axis)1, listBaseSize); root.SetActive(false); return true; } private static void PositionNextToStore(StoreGui store) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)root == (Object)null) && !((Object)(object)store == (Object)null) && !((Object)(object)store.m_rootPanel == (Object)null)) { RectTransform val = (RectTransform)root.transform; RectTransform val2 = (RectTransform)store.m_rootPanel.transform; RectTransform obj = VisiblePanel(val2); Vector3[] array = (Vector3[])(object)new Vector3[4]; obj.GetWorldCorners(array); float num = array[2].x - array[1].x; Vector3 lossyScale = ((Transform)val).lossyScale; float num2 = BetterTradersPlugin.SellPanelGap.Value * lossyScale.x; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(BetterTradersPlugin.SellPanelOffsetX.Value * lossyScale.x, BetterTradersPlugin.SellPanelOffsetY.Value * lossyScale.y, 0f); Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(num + num2, 0f, 0f); if (array[2].x + num + num2 > (float)Screen.width) { ((Vector3)(ref val4))..ctor(0f - num - num2, 0f, 0f); } ((Transform)val).position = ((Transform)val2).position + val4 + val3; } } private static RectTransform VisiblePanel(RectTransform rootRect) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) RectTransform result = rootRect; float num = 0f; Image[] componentsInChildren = ((Component)rootRect).GetComponentsInChildren<Image>(true); for (int i = 0; i < componentsInChildren.Length; i++) { RectTransform rectTransform = ((Graphic)componentsInChildren[i]).rectTransform; Rect rect = rectTransform.rect; float width = ((Rect)(ref rect)).width; rect = rectTransform.rect; float num2 = width * ((Rect)(ref rect)).height; rect = rectTransform.rect; if (!(((Rect)(ref rect)).width < 200f)) { rect = rectTransform.rect; if (!(((Rect)(ref rect)).height < 200f) && num2 > num) { result = rectTransform; num = num2; } } } return result; } private static void BuildOffers() { offers.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)owner == (Object)null) { return; } string text = (((Object)(object)owner.m_coinPrefab != (Object)null) ? owner.m_coinPrefab.m_itemData.m_shared.m_name : "$item_coins"); List<ItemData> list = new List<ItemData>(((Humanoid)localPlayer).GetInventory().GetAllItems()); list.Sort(delegate(ItemData a, ItemData b) { int num2 = a.m_gridPos.y.CompareTo(b.m_gridPos.y); return (num2 == 0) ? a.m_gridPos.x.CompareTo(b.m_gridPos.x) : num2; }); foreach (ItemData item in list) { if (item != null && !item.m_equipped && !(item.m_shared.m_name == text)) { int num = PriceTable.SellPrice(item); if (num > 0) { offers.Add(new Offer { Item = item, Price = num }); } } } } private static void Refresh() { dirty = false; if ((Object)(object)root == (Object)null || (Object)(object)listRoot == (Object)null || (Object)(object)owner == (Object)null) { return; } SellTooltip.HideAll(); ItemData val = ((selected >= 0 && selected < offers.Count) ? offers[selected].Item : null); foreach (Offer offer in offers) { if ((Object)(object)offer.Element != (Object)null) { Object.Destroy((Object)(object)offer.Element); } } BuildOffers(); float itemSpacing = owner.m_itemSpacing; listRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(listBaseSize, (float)offers.Count * itemSpacing)); selected = -1; for (int i = 0; i < offers.Count; i++) { if (offers[i].Item == val) { selected = i; } BuildRow(offers[i], i, itemSpacing); } if (selected < 0 && offers.Count > 0) { selected = 0; } Highlight(); } private static void BuildRow(Offer offer, int index, float spacing) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Expected O, but got Unknown //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(owner.m_listElement, (Transform)(object)listRoot); ((Object)val).name = "Offer_" + index; val.SetActive(true); offer.Element = val; RectTransform val2 = (RectTransform)val.transform; Rect rect = listRoot.rect; float width = ((Rect)(ref rect)).width; rect = val2.rect; float num = (width - ((Rect)(ref rect)).width) / 2f; val2.anchoredPosition = new Vector2(num, (float)index * (0f - spacing) - num); SharedData shared = offer.Item.m_shared; Transform val3 = val.transform.Find("icon"); Image val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Image>() : null); if ((Object)(object)val4 != (Object)null) { val4.sprite = offer.Item.GetIcon(); ((Graphic)val4).color = Color.white; } string text = Localization.instance.Localize(shared.m_name); if (offer.Item.m_quality > 1) { text = text + " ★" + offer.Item.m_quality; } if (offer.Item.m_stack > 1) { text = text + " x" + offer.Item.m_stack; } Transform val5 = val.transform.Find("name"); TMP_Text val6 = (((Object)(object)val5 != (Object)null) ? ((Component)val5).GetComponent<TMP_Text>() : null); if ((Object)(object)val6 != (Object)null) { val6.text = text; ((Graphic)val6).color = Color.white; } Transform val7 = Utils.FindChild(val.transform, "price", (IterativeSearchType)0); TMP_Text val8 = (((Object)(object)val7 != (Object)null) ? ((Component)val7).GetComponent<TMP_Text>() : null); if ((Object)(object)val8 != (Object)null) { val8.text = offer.Price.ToString(); ((Graphic)val8).color = Color.white; } UITooltip component = val.GetComponent<UITooltip>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } SellTooltip sellTooltip = val.AddComponent<SellTooltip>(); sellTooltip.Topic = text; sellTooltip.Item = offer.Item; Canvas componentInParent = root.GetComponentInParent<Canvas>(); sellTooltip.Canvas = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent.rootCanvas).transform : root.transform.root); Button component2 = val.GetComponent<Button>(); if ((Object)(object)component2 != (Object)null) { component2.onClick = new ButtonClickedEvent(); ((UnityEvent)component2.onClick).AddListener((UnityAction)delegate { Select(index); }); } } private static void Select(int index) { selected = index; Highlight(); } private static void Highlight() { for (int i = 0; i < offers.Count; i++) { Transform val = (((Object)(object)offers[i].Element != (Object)null) ? offers[i].Element.transform.Find("selected") : null); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(i == selected); } } } private static void SellSelected() { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)owner == (Object)null || selected < 0 || selected >= offers.Count) { return; } ItemData item = offers[selected].Item; Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (!inventory.ContainsItem(item)) { Refresh(); return; } int num = PriceTable.SellPrice(item); if (num > 0) { bool flag = inventory.ItemCheated(item.m_shared.m_name, -1, true); string text = ((item.m_stack > 1) ? (item.m_stack + "x" + item.m_shared.m_name) : item.m_shared.m_name); Sprite icon = item.GetIcon(); inventory.RemoveItem(item); ItemDrop coinPrefab = owner.m_coinPrefab; inventory.AddItem(((Object)((Component)coinPrefab).gameObject).name, num, coinPrefab.m_itemData.m_quality, coinPrefab.m_itemData.m_variant, 0L, "", flag, false); owner.m_sellEffects.Create(((Component)owner).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); ((Character)localPlayer).Message((MessageType)1, Localization.instance.Localize("$msg_sold", new string[2] { text, num.ToString() }), 0, icon, false); Trader val = CurrentTrader(owner); if ((Object)(object)val != (Object)null) { val.OnSold(); } Refresh(); } } } internal class SellTooltip : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { private const float Delay = 0.5f; private const float Gap = 18f; private static GameObject tooltip; private static GameObject prefab; private static SellTooltip owner; private static float showAt; public string Topic; public ItemData Item; public Transform Canvas; public void OnPointerEnter(PointerEventData eventData) { owner = this; showAt = Time.time + 0.5f; if ((Object)(object)tooltip != (Object)null) { tooltip.SetActive(false); } } public void OnPointerExit(PointerEventData eventData) { if ((Object)(object)owner == (Object)(object)this) { HideAll(); } } private void OnDisable() { if ((Object)(object)owner == (Object)(object)this) { HideAll(); } } internal static void HideAll() { owner = null; if ((Object)(object)tooltip != (Object)null) { tooltip.SetActive(false); } } private static GameObject Prefab() { if ((Object)(object)prefab != (Object)null) { return prefab; } StoreGui instance = StoreGui.instance; UITooltip val = (((Object)(object)instance != (Object)null && (Object)(object)instance.m_listElement != (Object)null) ? instance.m_listElement.GetComponent<UITooltip>() : null); if ((Object)(object)val != (Object)null && (Object)(object)val.m_tooltipPrefab != (Object)null) { return prefab = val.m_tooltipPrefab; } UITooltip[] array = Resources.FindObjectsOfTypeAll<UITooltip>(); foreach (UITooltip val2 in array) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_tooltipPrefab != (Object)null) { return prefab = val2.m_tooltipPrefab; } } return null; } private static void SetText(string childName, string value) { Transform val = Utils.FindChild(tooltip.transform, childName, (IterativeSearchType)0); TMP_Text val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : null); if ((Object)(object)val2 != (Object)null) { val2.text = value ?? ""; } } internal static void Follow() { //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)owner == (Object)null) { return; } if (!((Component)owner).gameObject.activeInHierarchy) { HideAll(); } else { if (Time.time < showAt) { return; } Transform val = (((Object)(object)owner.Canvas != (Object)null) ? owner.Canvas : ((Component)owner).transform.root); if ((Object)(object)tooltip == (Object)null || (Object)(object)tooltip.transform.parent != (Object)(object)val) { GameObject val2 = Prefab(); if ((Object)(object)val2 == (Object)null) { return; } if ((Object)(object)tooltip != (Object)null) { Object.Destroy((Object)(object)tooltip); } tooltip = Object.Instantiate<GameObject>(val2, val); ((Object)tooltip).name = "BetterTraders_Tooltip"; CanvasGroup val3 = tooltip.GetComponent<CanvasGroup>(); if ((Object)(object)val3 == (Object)null) { val3 = tooltip.AddComponent<CanvasGroup>(); } val3.blocksRaycasts = false; val3.interactable = false; Graphic[] componentsInChildren = tooltip.GetComponentsInChildren<Graphic>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].raycastTarget = false; } tooltip.SetActive(false); } if (!tooltip.activeSelf) { SetText("Topic", Localization.instance.Localize(owner.Topic)); SetText("Text", (owner.Item != null) ? Localization.instance.Localize(owner.Item.GetTooltip(-1)) : ""); tooltip.SetActive(true); tooltip.transform.SetAsLastSibling(); } Vector3 pointerPosition = ZInput.pointerPosition; tooltip.transform.position = pointerPosition; RectTransform val4 = (RectTransform)((tooltip.transform.childCount > 0) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val4 == (Object)null)) { Vector3[] array = (Vector3[])(object)new Vector3[4]; val4.GetWorldCorners(array); float num = array[2].x - array[1].x; float num2 = array[1].y - array[0].y; Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(pointerPosition.x - 18f - array[3].x, pointerPosition.y + 18f - array[3].y, 0f); if (pointerPosition.x - 18f - num < 0f) { val5.x = pointerPosition.x + 18f - array[0].x; } if (pointerPosition.y + 18f + num2 > (float)Screen.height) { val5.y = pointerPosition.y - 18f - array[1].y; } Transform transform = tooltip.transform; transform.position += val5; } } } } [HarmonyPatch(typeof(Trader), "UseItem")] internal static class HildirChestPatch { private static readonly Action<Trader, List<string>, string> Say = AccessTools.MethodDelegate<Action<Trader, List<string>, string>>(AccessTools.Method(typeof(Trader), "Say", new Type[2] { typeof(List<string>), typeof(string) }, (Type[])null), (object)null, true); private static bool Prefix(Trader __instance, Humanoid user, ItemData item, ref bool __result) { //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) if (!BetterTradersPlugin.ModEnabled.Value || !BetterTradersPlugin.HildirBuysChests.Value) { return true; } if (!BetterTradersPlugin.Matches(__instance, BetterTradersPlugin.HildirName.Value)) { return true; } if (item == null || (Object)(object)user == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer || (Object)(object)ZoneSystem.instance == (Object)null) { return true; } foreach (TraderUseItem useItem in __instance.m_useItems) { if (useItem == null || (Object)(object)useItem.m_prefab == (Object)null || !useItem.m_removesItem || item.m_shared.m_name != useItem.m_prefab.m_itemData.m_shared.m_name) { continue; } if (string.IsNullOrEmpty(useItem.m_setsGlobalKey) || !ZoneSystem.instance.GetGlobalKey(useItem.m_setsGlobalKey)) { return true; } int num = ChestPrice(((Object)useItem.m_prefab).name); if (num <= 0) { return true; } Inventory inventory = user.GetInventory(); bool flag = inventory.ItemCheated(item.m_shared.m_name, -1, true); inventory.RemoveItem(item, 1); ItemDrop val = (((Object)(object)StoreGui.instance != (Object)null) ? StoreGui.instance.m_coinPrefab : null); string text = (((Object)(object)val != (Object)null) ? ((Object)((Component)val).gameObject).name : "Coins"); inventory.AddItem(text, num, 1, 0, 0L, "", flag, false); Sprite val2 = ((item.m_shared.m_icons != null && item.m_shared.m_icons.Length != 0) ? item.m_shared.m_icons[0] : null); ((Character)user).Message((MessageType)1, Localization.instance.Localize("$msg_sold", new string[2] { item.m_shared.m_name, num.ToString() }), 0, val2, false); try { if (__instance.m_randomSell != null && __instance.m_randomSell.Count > 0) { Say(__instance, __instance.m_randomSell, "Sell"); } __instance.m_randomSellFX.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } catch (Exception ex) { BetterTradersPlugin.Log.LogWarning((object)("Hildir couldn't react to the sale: " + ex.Message)); } __result = true; return false; } return true; } private static int ChestPrice(string prefab) { string[] array = BetterTradersPlugin.HildirChestPrices.Value.Split(new char[1] { ',' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0 && string.Equals(text.Substring(0, num).Trim(), prefab, StringComparison.OrdinalIgnoreCase)) { if (!int.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return 100; } return result; } } return 100; } } [HarmonyPatch] internal static class SellableTooltipPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[6] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) }, (Type[])null); } private static bool Prepare() { return TargetMethod() != null; } private static void Postfix(ItemData item, bool crafting, bool appending, ref string __result) { if (crafting || appending || item == null || __result == null || !BetterTradersPlugin.ModEnabled.Value || !BetterTradersPlugin.SellEnabled.Value) { return; } string value = BetterTradersPlugin.FlavorText.Value; if (string.IsNullOrEmpty(value)) { return; } try { if (!PriceTable.WouldBuy(item)) { return; } } catch (Exception) { return; } string text = item.m_shared.m_description ?? ""; string text2 = "\n<color=#C8A464><i>" + value + "</i></color>"; if (text.Length > 0 && __result.StartsWith(text, StringComparison.Ordinal)) { __result = __result.Insert(text.Length, text2); } else { __result = text2.Substring(1) + "\n" + __result; } } } [HarmonyPatch(typeof(Trader), "GetAvailableItems")] internal static class TraderAvailableItemsPatch { private static void Postfix(Trader __instance, ref List<TradeItem> __result) { if (BetterTradersPlugin.ModEnabled.Value && BetterTradersPlugin.WitchSellsIdols.Value && BetterTradersPlugin.Matches(__instance, BetterTradersPlugin.WitchName.Value)) { try { PriceTable.AppendIdols(__result); return; } catch (Exception ex) { BetterTradersPlugin.Log.LogError((object)("Building the Bog Witch's idols failed: " + ex)); return; } } if (!BetterTradersPlugin.IsHaldor(__instance)) { return; } try { PriceTable.EnsureBuilt(__instance); PriceTable.AppendWares(__result); } catch (Exception ex2) { BetterTradersPlugin.Log.LogError((object)("Building Haldor's shop failed: " + ex2)); } } } [HarmonyPatch(typeof(StoreGui), "Show")] internal static class StoreShowPatch { internal static GameObject SellButtonHolder(StoreGui gui) { if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_sellButton == (Object)null) { return null; } Transform parent = ((Component)gui.m_sellButton).transform.parent; if (!((Object)(object)parent != (Object)null) || !((Object)(object)gui.m_rootPanel != (Object)null) || !((Object)(object)parent != (Object)(object)gui.m_rootPanel.transform)) { return ((Component)gui.m_sellButton).gameObject; } return ((Component)parent).gameObject; } private static void Prefix(Trader trader) { if (!BetterTradersPlugin.IsHaldor(trader)) { return; } try { PriceTable.EnsureBuilt(trader); } catch (Exception ex) { BetterTradersPlugin.Log.LogError((object)("Pricing Haldor's items failed: " + ex)); } } private static void Postfix(StoreGui __instance, Trader trader) { bool flag = BetterTradersPlugin.IsHaldor(trader); GameObject obj = SellButtonHolder(__instance); if (obj != null) { obj.SetActive(!flag || !BetterTradersPlugin.SellEnabled.Value); } if (flag) { SellPanel.Open(__instance); } else { SellPanel.Close(); } } } [HarmonyPatch(typeof(StoreGui), "Hide")] internal static class StoreHidePatch { private static void Postfix(StoreGui __instance) { SellPanel.Close(); GameObject obj = StoreShowPatch.SellButtonHolder(__instance); if (obj != null) { obj.SetActive(true); } } } [HarmonyPatch(typeof(StoreGui), "Update")] internal static class StoreUpdatePatch { private static void Postfix(StoreGui __instance) { SellPanel.Tick(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyPatch { private static void Postfix() { PriceTable.Clear(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix() { PriceTable.Clear(); } } }