Decompiled source of HaldorOverhaul v1.0.5

HaldorOverhaul.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Haldor Overhaul")]
[assembly: AssemblyDescription("Custom buy/sell trading for Haldor")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HaldorOverhaul")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b7e4f347-ccbb-4fa9-9a20-b39679b6d0f7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[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 HaldorOverhaul
{
	public static class ConfigLoader
	{
		private static string BuyFile => Path.Combine(Paths.ConfigPath, "HaldorOverhaul.haldor.buy.json");

		private static string SellFile => Path.Combine(Paths.ConfigPath, "HaldorOverhaul.haldor.sell.json");

		public static List<TradeEntry> BuyEntries { get; private set; } = new List<TradeEntry>();


		public static List<TradeEntry> SellEntries { get; private set; } = new List<TradeEntry>();


		public static void Initialize()
		{
			EnsureConfigFilesExist();
			LoadBuyConfig();
			LoadSellConfig();
			ValidateAndLogStats();
		}

		private static void ValidateAndLogStats()
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			foreach (TradeEntry item in BuyEntries.ToList())
			{
				if (!ValidateEntry(item, "BUY"))
				{
					BuyEntries.Remove(item);
					num2++;
				}
				else
				{
					num++;
				}
			}
			foreach (TradeEntry item2 in SellEntries.ToList())
			{
				if (!ValidateEntry(item2, "SELL"))
				{
					SellEntries.Remove(item2);
					num4++;
				}
				else
				{
					num3++;
				}
			}
			if (num2 > 0 || num4 > 0)
			{
				HaldorOverhaul.Log.LogWarning((object)string.Format("{0} Removed {1} invalid BUY entries and {2} invalid SELL entries.", "[ConfigLoader]", num2, num4));
			}
			HaldorOverhaul.Log.LogInfo((object)string.Format("{0} Config validated: {1} BUY entries, {2} SELL entries.", "[ConfigLoader]", num, num3));
		}

		private static bool ValidateEntry(TradeEntry entry, string type)
		{
			if (entry == null)
			{
				HaldorOverhaul.Log.LogWarning((object)("[ConfigLoader] " + type + " entry is null, skipping."));
				return false;
			}
			if (string.IsNullOrWhiteSpace(entry.prefab))
			{
				HaldorOverhaul.Log.LogWarning((object)("[ConfigLoader] " + type + " entry has empty prefab name, skipping."));
				return false;
			}
			if (entry.price < 0)
			{
				HaldorOverhaul.Log.LogWarning((object)string.Format("{0} {1} entry '{2}' has negative price ({3}), setting to 0.", "[ConfigLoader]", type, entry.prefab, entry.price));
				entry.price = 0;
			}
			if (entry.stack <= 0)
			{
				HaldorOverhaul.Log.LogWarning((object)string.Format("{0} {1} entry '{2}' has invalid stack ({3}), setting to 1.", "[ConfigLoader]", type, entry.prefab, entry.stack));
				entry.stack = 1;
			}
			return true;
		}

		private static void EnsureConfigFilesExist()
		{
			if (!File.Exists(BuyFile))
			{
				File.WriteAllText(BuyFile, DefaultBuyJson());
				HaldorOverhaul.Log.LogInfo((object)"[ConfigLoader] Created default BUY config.");
			}
			if (!File.Exists(SellFile))
			{
				File.WriteAllText(SellFile, DefaultSellJson());
				HaldorOverhaul.Log.LogInfo((object)"[ConfigLoader] Created default SELL config.");
			}
		}

		private static void LoadBuyConfig()
		{
			try
			{
				BuyEntries = JsonConvert.DeserializeObject<List<TradeEntry>>(File.ReadAllText(BuyFile)) ?? new List<TradeEntry>();
				HaldorOverhaul.Log.LogInfo((object)$"[ConfigLoader] Loaded {BuyEntries.Count} BUY entries.");
			}
			catch (Exception arg)
			{
				HaldorOverhaul.Log.LogError((object)$"[ConfigLoader] Error loading BUY config: {arg}");
				BuyEntries = new List<TradeEntry>();
			}
		}

		private static void LoadSellConfig()
		{
			try
			{
				SellEntries = JsonConvert.DeserializeObject<List<TradeEntry>>(File.ReadAllText(SellFile)) ?? new List<TradeEntry>();
				HaldorOverhaul.Log.LogInfo((object)$"[ConfigLoader] Loaded {SellEntries.Count} SELL entries.");
			}
			catch (Exception arg)
			{
				HaldorOverhaul.Log.LogError((object)$"[ConfigLoader] Error loading SELL config: {arg}");
				SellEntries = new List<TradeEntry>();
			}
		}

		private static string DefaultBuyJson()
		{
			return JsonConvert.SerializeObject((object)new List<TradeEntry>
			{
				new TradeEntry
				{
					prefab = "Wood",
					stack = 50,
					price = 25,
					requiredGlobalKey = "defeated_eikthyr"
				}
			}, (Formatting)1);
		}

		private static string DefaultSellJson()
		{
			return JsonConvert.SerializeObject((object)new List<TradeEntry>
			{
				new TradeEntry
				{
					prefab = "Wood",
					stack = 1,
					price = 1
				}
			}, (Formatting)1);
		}
	}
	public class TradeEntry
	{
		[JsonProperty("item_prefab")]
		public string prefab = "";

		[JsonProperty("item_quantity")]
		public int stack = 1;

		[JsonProperty("item_price")]
		public int price = 1;

		[JsonProperty("must_defeated_boss")]
		public string requiredGlobalKey = "";
	}
	public static class Constants
	{
		public static class UIElements
		{
			public const string Selected = "selected";

			public const string Icon = "icon";

			public const string Name = "name";

			public const string Price = "price";

			public const string Stack = "stack";

			public const string CoinBackground = "coin_bkg";

			public const string Quality = "quality";

			public const string ItemList = "ItemList";

			public const string Items = "Items";

			public const string ListRoot = "ListRoot";

			public const string ItemElement = "ItemElement";

			public const string Topic = "topic";

			public const string Coins = "coins";

			public const string Border = "border (1)";

			public const string BuyButton = "BuyButton";

			public const string SellPanel = "SellPanel";

			public const string Background = "bkg";

			public const string Text = "Text";
		}

		public const float BuyPanelPositionOffset = 35f;

		public const float SellPanelHorizontalOffset = 250f;

		public const float DefaultItemListBaseSize = 300f;

		public const float DefaultViewportHeight = 300f;

		public static readonly Color CategoryHeaderBackground = new Color(0.3f, 0.25f, 0.15f, 0.85f);

		public static readonly Color CategoryHeaderTextColor = new Color(1f, 0.9f, 0.5f, 1f);

		public static readonly Color CategoryIconTint = new Color(1f, 0.9f, 0.6f, 1f);

		public const float CategoryHeaderFontSizeMultiplier = 1.2f;

		public static readonly Color AffordableItemColor = Color.white;

		public static readonly Color UnaffordableItemColor = new Color(1f, 0f, 1f, 1f);

		public const float GamepadHintVerticalOffset = -30f;

		public const float GamepadHintFontSizeReduction = 2f;

		public const float MinGamepadHintFontSize = 14f;

		public const float InputDebounceTime = 0.15f;

		public const int HashMultiplier = 397;

		public const string LogPrefixUIManager = "[UIManager]";

		public const string LogPrefixPatches = "[StoreGuiPatches]";

		public const string LogPrefixConfig = "[ConfigLoader]";

		public static readonly string[] CategoryBuckets = new string[10] { "Weapons", "Armor", "Shields", "Ammo", "Consumables", "Materials", "Utility", "Trophies", "Crafting", "Misc" };

		public static string GetCategoryDisplayName(string category)
		{
			if (string.IsNullOrEmpty(category))
			{
				return "Misc";
			}
			return category;
		}
	}
	public static class UIElementFinder
	{
		public static Transform FindChild(Transform parent, string name, bool recursive = false)
		{
			if ((Object)(object)parent == (Object)null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			if (!recursive)
			{
				return null;
			}
			return FindChildRecursive(parent, name);
		}

		public static Transform FindChildRecursive(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (string.Equals(((Object)child).name, name, StringComparison.OrdinalIgnoreCase))
				{
					return child;
				}
				Transform val = FindChildRecursive(child, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		public static Image GetIcon(Transform parent)
		{
			Transform val = FindChild(parent, "icon");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).GetComponent<Image>();
			}
			Image[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Image>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return null;
			}
			return componentsInChildren[0];
		}

		public static TMP_Text GetText(Transform parent, string childName)
		{
			Transform val = FindChild(parent, childName);
			if ((Object)(object)val != (Object)null)
			{
				TMP_Text component = ((Component)val).GetComponent<TMP_Text>();
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
				return (TMP_Text)(object)((Component)val).GetComponent<TextMeshProUGUI>();
			}
			TMP_Text[] componentsInChildren = ((Component)parent).GetComponentsInChildren<TMP_Text>(true);
			if (componentsInChildren != null)
			{
				TMP_Text[] array = componentsInChildren;
				foreach (TMP_Text val2 in array)
				{
					if ((Object)(object)val2 != (Object)null && string.Equals(((Object)((Component)val2).gameObject).name, childName, StringComparison.OrdinalIgnoreCase))
					{
						return val2;
					}
				}
			}
			return null;
		}

		public static TMP_Text GetNameText(Transform parent)
		{
			return GetText(parent, "name");
		}

		public static TMP_Text GetPriceText(Transform parent)
		{
			TMP_Text text = GetText(parent, "price");
			if ((Object)(object)text != (Object)null)
			{
				return text;
			}
			Transform val = FindChild(parent, "coin_bkg");
			if ((Object)(object)val != (Object)null)
			{
				return GetText(val, "price");
			}
			return null;
		}

		public static TMP_Text GetStackText(Transform parent)
		{
			return GetText(parent, "stack");
		}

		public static Transform GetSelectedIndicator(Transform parent)
		{
			return FindChild(parent, "selected");
		}

		public static void SetSelected(Transform parent, bool selected)
		{
			Transform selectedIndicator = GetSelectedIndicator(parent);
			if ((Object)(object)selectedIndicator != (Object)null)
			{
				((Component)selectedIndicator).gameObject.SetActive(selected);
			}
		}

		public static Button GetButton(GameObject go)
		{
			if (go == null)
			{
				return null;
			}
			return go.GetComponent<Button>();
		}

		public static void DestroyChild(Transform parent, string name)
		{
			if (!((Object)(object)parent == (Object)null) && !string.IsNullOrEmpty(name))
			{
				Transform val = parent.Find(name);
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
		}

		public static T GetOrAddComponent<T>(GameObject go) where T : Component
		{
			if ((Object)(object)go == (Object)null)
			{
				return default(T);
			}
			T component = go.GetComponent<T>();
			if (!((Object)(object)component != (Object)null))
			{
				return go.AddComponent<T>();
			}
			return component;
		}
	}
	public static class GamepadInputHandler
	{
		private static readonly object _lock = new object();

		private static readonly Dictionary<string, float> _lastInputTime = new Dictionary<string, float>();

		private static readonly float _debounceTime = 0.15f;

		public static void Reset()
		{
			lock (_lock)
			{
				_lastInputTime.Clear();
			}
		}

		private static bool GetButtonDownDebounced(string buttonName)
		{
			if (string.IsNullOrEmpty(buttonName))
			{
				return false;
			}
			if (!ZInput.GetButtonDown(buttonName))
			{
				return false;
			}
			float unscaledTime = Time.unscaledTime;
			lock (_lock)
			{
				if (_lastInputTime.TryGetValue(buttonName, out var value) && unscaledTime - value < _debounceTime)
				{
					return false;
				}
				_lastInputTime[buttonName] = unscaledTime;
			}
			return true;
		}

		public static bool GetLeftBumper()
		{
			if (!GetButtonDownDebounced("JoyLB") && !GetButtonDownDebounced("JoyLBumper") && !GetButtonDownDebounced("JoyButtonLB"))
			{
				return GetButtonDownDebounced("JoyL1");
			}
			return true;
		}

		public static bool GetRightBumper()
		{
			if (!GetButtonDownDebounced("JoyRB") && !GetButtonDownDebounced("JoyRBumper") && !GetButtonDownDebounced("JoyButtonRB"))
			{
				return GetButtonDownDebounced("JoyR1");
			}
			return true;
		}

		public static bool GetMoveDown()
		{
			if (!GetButtonDownDebounced("JoyLStickDown"))
			{
				return GetButtonDownDebounced("JoyDPadDown");
			}
			return true;
		}

		public static bool GetMoveUp()
		{
			if (!GetButtonDownDebounced("JoyLStickUp"))
			{
				return GetButtonDownDebounced("JoyDPadUp");
			}
			return true;
		}

		public static bool GetMoveLeft()
		{
			if (!GetButtonDownDebounced("JoyDPadLeft"))
			{
				return GetButtonDownDebounced("JoyRStickLeft");
			}
			return true;
		}

		public static bool GetMoveRight()
		{
			if (!GetButtonDownDebounced("JoyDPadRight"))
			{
				return GetButtonDownDebounced("JoyRStickRight");
			}
			return true;
		}

		public static bool GetButtonX()
		{
			return GetButtonDownDebounced("JoyButtonX");
		}

		public static bool GetButtonA()
		{
			return GetButtonDownDebounced("JoyButtonA");
		}

		public static bool IsGamepadActive()
		{
			return ZInput.IsGamepadActive();
		}
	}
	[BepInPlugin("com.haldor.overhaul", "Haldor Overhaul", "1.0.0")]
	public class HaldorOverhaul : BaseUnityPlugin
	{
		public const string PluginGUID = "com.haldor.overhaul";

		public const string PluginName = "Haldor Overhaul";

		public const string PluginVersion = "1.0.0";

		private static Harmony _harmony;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Haldor Overhaul v1.0.0 loading...");
			ConfigLoader.Initialize();
			_harmony = new Harmony("com.haldor.overhaul");
			_harmony.PatchAll(typeof(StoreGuiPatches));
			Log.LogInfo((object)"Haldor Overhaul loaded successfully!");
		}

		private void OnDestroy()
		{
			UIManager.ClearAllCaches();
			GamepadInputHandler.Reset();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log.LogInfo((object)"Haldor Overhaul unloaded.");
		}
	}
	[HarmonyPatch]
	public static class StoreGuiPatches
	{
		private static readonly object _reflectionLock = new object();

		private static FieldInfo _itemListField;

		private static FieldInfo _traderField;

		private static FieldInfo _itemsField;

		private static FieldInfo _listRootField;

		private static FieldInfo _selectedItemField;

		private static MethodInfo _getPlayerCoinsMethod;

		private static MethodInfo _selectItemMethod;

		private static MethodInfo _buySelectedItemMethod;

		private static volatile bool _reflectionCached;

		internal static bool SuppressSellDeselect = false;

		private static volatile bool _fullyInitialized = false;

		private static string _pendingBuyItemName;

		private static int _pendingBuyPrice;

		private static int _pendingBuyStack;

		private static Sprite _pendingBuyIcon;

		private static int _pendingBuyCoins = -1;

		private static bool _buyAttempted = false;

		internal static bool SuppressNextBuyMessage = false;

		[HarmonyPatch(typeof(Chat), "HasFocus")]
		[HarmonyPostfix]
		private static void Chat_HasFocus_Postfix(ref bool __result)
		{
			if (!__result && UIManager.IsOpen() && UIManager.IsSearchInputFocused)
			{
				__result = true;
			}
		}

		[HarmonyPatch(typeof(StoreGui), "Show")]
		[HarmonyPostfix]
		private static void StoreGui_Show_Postfix(StoreGui __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					CacheReflection();
					Trader trader = GetTrader(__instance);
					UIManager.OnStoreOpened(__instance);
				}
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogError((object)("[StoreGuiPatches] Show error: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(StoreGui), "Hide")]
		[HarmonyPostfix]
		private static void StoreGui_Hide_Postfix()
		{
			UIManager.OnStoreClosed();
		}

		[HarmonyPatch(typeof(StoreGui), "Update")]
		[HarmonyPostfix]
		private static void StoreGui_Update_Postfix(StoreGui __instance)
		{
			if (UIManager.IsOpen())
			{
				UIManager.UpdateCoinsDisplay(__instance);
				UIManager.RefreshSellListIfInventoryChanged();
				UIManager.UpdateGamepadHints(__instance);
				UIManager.UpdateSearchFocusState();
			}
		}

		[HarmonyPatch(typeof(StoreGui), "GetSelectedItemIndex")]
		[HarmonyPrefix]
		private static bool StoreGui_GetSelectedItemIndex_Prefix(StoreGui __instance, ref int __result)
		{
			if (!UIManager.IsOpen())
			{
				return true;
			}
			List<GameObject> itemList = GetItemList(__instance);
			if (itemList == null)
			{
				return true;
			}
			__result = -1;
			for (int i = 0; i < itemList.Count; i++)
			{
				if (UIManager.IsBuyIndexVisible(i, itemList.Count) && !((Object)(object)itemList[i] == (Object)null))
				{
					Transform val = itemList[i].transform.Find("selected");
					if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
					{
						__result = i;
						break;
					}
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(StoreGui), "SelectItem")]
		[HarmonyPrefix]
		private static void StoreGui_SelectItem_Prefix(StoreGui __instance, ref int index, ref bool center)
		{
			if (!UIManager.IsOpen())
			{
				return;
			}
			List<GameObject> itemList = GetItemList(__instance);
			if (itemList == null)
			{
				return;
			}
			if (index >= 0)
			{
				if (itemList.Count == 0)
				{
					index = -1;
				}
				else
				{
					index = Mathf.Clamp(index, 0, itemList.Count - 1);
					index = UIManager.FindNearestVisibleBuyIndex(index, itemList.Count);
				}
				center = center || index == 0;
				if (index >= 0 && !SuppressSellDeselect)
				{
					UIManager.DeselectSellSide();
				}
			}
			UIManager.OnBuyItemSelected(index);
		}

		[HarmonyPatch(typeof(StoreGui), "UpdateRecipeGamepadInput")]
		[HarmonyPrefix]
		private static bool StoreGui_UpdateRecipeGamepadInput_Prefix(StoreGui __instance)
		{
			if (!UIManager.IsOpen())
			{
				return true;
			}
			List<GameObject> itemList = GetItemList(__instance);
			if (itemList == null)
			{
				return true;
			}
			UIManager.EnsureTabFocus(__instance, itemList);
			if (GamepadInputHandler.GetLeftBumper())
			{
				UIManager.SwitchToBuyTab(__instance, itemList, centerOnSelect: true);
				return false;
			}
			if (GamepadInputHandler.GetRightBumper())
			{
				UIManager.SwitchToSellTab(centerOnSelect: true);
				return false;
			}
			if (GamepadInputHandler.GetMoveDown())
			{
				UIManager.MoveActiveFocus(__instance, itemList, 1);
				return false;
			}
			if (GamepadInputHandler.GetMoveUp())
			{
				UIManager.MoveActiveFocus(__instance, itemList, -1);
				return false;
			}
			if (GamepadInputHandler.GetMoveLeft())
			{
				UIManager.SwitchToBuyTab(__instance, itemList, centerOnSelect: true);
				return false;
			}
			if (GamepadInputHandler.GetMoveRight())
			{
				UIManager.SwitchToSellTab(centerOnSelect: true);
				return false;
			}
			if (GamepadInputHandler.GetButtonX())
			{
				UIManager.ToggleFocusedCategory(__instance, itemList);
				return false;
			}
			if (GamepadInputHandler.GetButtonA())
			{
				UIManager.ActivateFocused(__instance);
				return false;
			}
			return false;
		}

		private static void ManualFillList(StoreGui instance, List<TradeItem> items, List<GameObject> itemList, RectTransform listRoot)
		{
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_053a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0544: Expected O, but got Unknown
			if ((Object)(object)instance == (Object)null || items == null || itemList == null)
			{
				return;
			}
			if (items.Count == 0)
			{
				for (int i = 0; i < itemList.Count; i++)
				{
					if ((Object)(object)itemList[i] != (Object)null)
					{
						itemList[i].SetActive(false);
					}
				}
			}
			else
			{
				if (itemList.Count == 0)
				{
					return;
				}
				int num = Mathf.Min(items.Count, itemList.Count);
				int playerCoins = GetPlayerCoins(instance);
				for (int j = 0; j < itemList.Count; j++)
				{
					if (!((Object)(object)itemList[j] == (Object)null))
					{
						Transform val = itemList[j].transform.Find("selected");
						if ((Object)(object)val != (Object)null)
						{
							((Component)val).gameObject.SetActive(false);
						}
					}
				}
				for (int k = 0; k < num && k < items.Count && k < itemList.Count; k++)
				{
					TradeItem val2 = items[k];
					GameObject val3 = itemList[k];
					if (val2 == null || (Object)(object)val3 == (Object)null)
					{
						continue;
					}
					if (!string.IsNullOrEmpty(val2.m_requiredGlobalKey) && (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGlobalKey(val2.m_requiredGlobalKey)))
					{
						val3.SetActive(false);
						continue;
					}
					try
					{
						val3.SetActive(true);
						Transform transform = val3.transform;
						RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
						if ((Object)(object)val4 != (Object)null && (Object)(object)listRoot != (Object)null && (Object)(object)((Transform)val4).parent != (Object)(object)listRoot)
						{
							((Transform)val4).SetParent((Transform)(object)listRoot, false);
						}
						Image val5 = null;
						Transform val6 = val3.transform.Find("icon");
						if ((Object)(object)val6 != (Object)null)
						{
							val5 = ((Component)val6).GetComponent<Image>();
						}
						if ((Object)(object)val5 == (Object)null)
						{
							Image[] componentsInChildren = val3.GetComponentsInChildren<Image>(true);
							if (componentsInChildren != null && componentsInChildren.Length != 0)
							{
								val5 = componentsInChildren[0];
							}
						}
						if ((Object)(object)val5 != (Object)null && (Object)(object)val2.m_prefab != (Object)null && val2.m_prefab.m_itemData != null)
						{
							Sprite icon = val2.m_prefab.m_itemData.GetIcon();
							if ((Object)(object)icon != (Object)null)
							{
								val5.sprite = icon;
								((Graphic)val5).color = Color.white;
							}
						}
						TextMeshProUGUI val7 = null;
						Transform val8 = val3.transform.Find("name");
						if ((Object)(object)val8 != (Object)null)
						{
							val7 = ((Component)val8).GetComponent<TextMeshProUGUI>();
						}
						if ((Object)(object)val7 == (Object)null)
						{
							TextMeshProUGUI[] componentsInChildren2 = val3.GetComponentsInChildren<TextMeshProUGUI>(true);
							if (componentsInChildren2 != null)
							{
								TextMeshProUGUI[] array = componentsInChildren2;
								foreach (TextMeshProUGUI val9 in array)
								{
									if ((Object)(object)val9 != (Object)null && ((Object)((Component)val9).gameObject).name == "name")
									{
										val7 = val9;
										break;
									}
								}
							}
						}
						if ((Object)(object)val7 != (Object)null && (Object)(object)val2.m_prefab != (Object)null && val2.m_prefab.m_itemData != null)
						{
							string text = UIManager.Localize(val2.m_prefab.m_itemData.m_shared.m_name);
							if (val2.m_stack > 1)
							{
								text = text + " x" + val2.m_stack;
							}
							((TMP_Text)val7).text = text;
						}
						TextMeshProUGUI val10 = null;
						Transform val11 = val3.transform.Find("price");
						if ((Object)(object)val11 != (Object)null)
						{
							val10 = ((Component)val11).GetComponent<TextMeshProUGUI>();
						}
						if ((Object)(object)val10 == (Object)null)
						{
							TextMeshProUGUI[] componentsInChildren3 = val3.GetComponentsInChildren<TextMeshProUGUI>(true);
							if (componentsInChildren3 != null)
							{
								TextMeshProUGUI[] array2 = componentsInChildren3;
								foreach (TextMeshProUGUI val12 in array2)
								{
									if ((Object)(object)val12 != (Object)null && ((Object)((Component)val12).gameObject).name == "price")
									{
										val10 = val12;
										break;
									}
								}
							}
						}
						if ((Object)(object)val10 != (Object)null)
						{
							((TMP_Text)val10).text = val2.m_price.ToString();
							((Graphic)val10).color = ((playerCoins >= val2.m_price) ? Constants.AffordableItemColor : Constants.UnaffordableItemColor);
						}
						TextMeshProUGUI val13 = null;
						Transform val14 = val3.transform.Find("stack");
						if ((Object)(object)val14 != (Object)null)
						{
							val13 = ((Component)val14).GetComponent<TextMeshProUGUI>();
						}
						if ((Object)(object)val13 == (Object)null)
						{
							TextMeshProUGUI[] componentsInChildren4 = val3.GetComponentsInChildren<TextMeshProUGUI>(true);
							if (componentsInChildren4 != null)
							{
								TextMeshProUGUI[] array3 = componentsInChildren4;
								foreach (TextMeshProUGUI val15 in array3)
								{
									if ((Object)(object)val15 != (Object)null && ((Object)((Component)val15).gameObject).name == "stack")
									{
										val13 = val15;
										break;
									}
								}
							}
						}
						if ((Object)(object)val13 != (Object)null)
						{
							if (val2.m_stack > 1)
							{
								((Component)val13).gameObject.SetActive(true);
								((TMP_Text)val13).text = val2.m_stack.ToString();
							}
							else
							{
								((Component)val13).gameObject.SetActive(false);
							}
						}
						Transform val16 = val3.transform.Find("selected");
						if ((Object)(object)val16 != (Object)null)
						{
							((Component)val16).gameObject.SetActive(false);
						}
						Button component = val3.GetComponent<Button>();
						if ((Object)(object)component != (Object)null)
						{
							((UnityEventBase)component.onClick).RemoveAllListeners();
							int capturedIndex = k;
							((UnityEvent)component.onClick).AddListener((UnityAction)delegate
							{
								InvokeSelectItem(instance, capturedIndex, center: false);
							});
						}
						Component component2 = val3.GetComponent("UITooltip");
						if ((Object)(object)component2 != (Object)null && (Object)(object)val2.m_prefab != (Object)null && val2.m_prefab.m_itemData != null)
						{
							ItemData itemData = val2.m_prefab.m_itemData;
							string value = UIManager.Localize(itemData.m_shared.m_name);
							string value2 = UIManager.Localize(itemData.m_shared.m_description);
							Type type = ((object)component2).GetType();
							FieldInfo field = type.GetField("m_topic", BindingFlags.Instance | BindingFlags.Public);
							FieldInfo field2 = type.GetField("m_text", BindingFlags.Instance | BindingFlags.Public);
							field?.SetValue(component2, value);
							field2?.SetValue(component2, value2);
						}
					}
					catch (Exception ex)
					{
						HaldorOverhaul.Log.LogWarning((object)string.Format("{0} ManualFillList item {1} failed: {2}", "[StoreGuiPatches]", k, ex.Message));
					}
				}
				for (int num2 = num; num2 < itemList.Count; num2++)
				{
					try
					{
						if ((Object)(object)itemList[num2] != (Object)null)
						{
							itemList[num2].SetActive(false);
						}
					}
					catch (Exception ex2)
					{
						HaldorOverhaul.Log.LogWarning((object)string.Format("{0} ManualFillList cleanup {1} failed: {2}", "[StoreGuiPatches]", num2, ex2.Message));
					}
				}
			}
		}

		[HarmonyPatch(typeof(StoreGui), "FillList")]
		[HarmonyPrefix]
		private static bool StoreGui_FillList_Prefix(StoreGui __instance)
		{
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CacheReflection();
				List<TradeItem> list = GetTradeItems(__instance);
				List<GameObject> list2 = GetItemList(__instance);
				RectTransform val = GetListRoot(__instance);
				Trader trader = GetTrader(__instance);
				if (list == null)
				{
					list = new List<TradeItem>();
					if (_itemsField != null)
					{
						_itemsField.SetValue(__instance, list);
					}
				}
				if (list2 == null)
				{
					list2 = new List<GameObject>();
					if (_itemListField != null)
					{
						_itemListField.SetValue(__instance, list2);
					}
				}
				if ((Object)(object)val == (Object)null && (Object)(object)__instance != (Object)null)
				{
					Transform val2 = ((Component)__instance).transform.Find("ItemList/Items/ListRoot");
					RectTransform val3 = (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = ((IEnumerable<RectTransform>)((Component)__instance).GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform r) => string.Equals(((Object)r).name, "ListRoot", StringComparison.OrdinalIgnoreCase)));
					}
					if ((Object)(object)val3 == (Object)null && (Object)(object)__instance.m_listElement != (Object)null)
					{
						Transform parent = __instance.m_listElement.transform.parent;
						val3 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
					}
					if ((Object)(object)val3 == (Object)null)
					{
						Transform val4 = ((Component)__instance).transform.Find("ItemList/Items");
						if ((Object)(object)val4 == (Object)null)
						{
							val4 = ((Component)__instance).transform.Find("ItemList");
						}
						GameObject val5 = new GameObject("ListRoot", new Type[1] { typeof(RectTransform) });
						RectTransform component = val5.GetComponent<RectTransform>();
						val5.transform.SetParent(((Object)(object)val4 != (Object)null) ? val4 : ((Component)__instance).transform, false);
						component.anchorMin = new Vector2(0f, 1f);
						component.anchorMax = new Vector2(1f, 1f);
						component.pivot = new Vector2(0.5f, 1f);
						val3 = component;
					}
					if ((Object)(object)val3 != (Object)null)
					{
						val = val3;
						if (_listRootField != null)
						{
							_listRootField.SetValue(__instance, val3);
						}
					}
				}
				int count = list.Count;
				int count2 = list2.Count;
				if ((Object)(object)val == (Object)null)
				{
					GameObject val6 = new GameObject("ListRoot_Fallback", new Type[1] { typeof(RectTransform) });
					RectTransform component2 = val6.GetComponent<RectTransform>();
					val6.transform.SetParent(((Component)__instance).transform, false);
					component2.anchorMin = new Vector2(0f, 1f);
					component2.anchorMax = new Vector2(1f, 1f);
					component2.pivot = new Vector2(0.5f, 1f);
					val = component2;
					if (_listRootField != null)
					{
						_listRootField.SetValue(__instance, component2);
					}
				}
				if (count2 < count)
				{
					int num = count - count2;
					GameObject val7 = __instance.m_listElement;
					Transform val8 = (Transform)(object)__instance.m_listRoot;
					if ((Object)(object)val7 == (Object)null && list2.Count > 0)
					{
						val7 = list2[0];
					}
					if ((Object)(object)val8 == (Object)null)
					{
						val8 = (Transform)(object)val;
					}
					if ((Object)(object)val8 == (Object)null && (Object)(object)val7 != (Object)null)
					{
						val8 = val7.transform.parent;
					}
					if ((Object)(object)val7 != (Object)null && (Object)(object)val8 != (Object)null)
					{
						int count3 = list2.Count;
						for (int i = 0; i < num; i++)
						{
							try
							{
								GameObject val9 = Object.Instantiate<GameObject>(val7, val8);
								((Object)val9).name = $"StoreElement_Clone_{count3 + i}";
								val9.SetActive(false);
								Transform val10 = val9.transform.Find("selected");
								if ((Object)(object)val10 != (Object)null)
								{
									((Component)val10).gameObject.SetActive(false);
								}
								list2.Add(val9);
							}
							catch (Exception ex)
							{
								HaldorOverhaul.Log.LogError((object)$"[StoreGuiPatches] Failed to clone element {i}: {ex.Message}");
								break;
							}
						}
						count2 = list2.Count;
						if (_itemListField != null)
						{
							_itemListField.SetValue(__instance, list2);
							List<GameObject> itemList = GetItemList(__instance);
							if (itemList == null || itemList.Count != count2)
							{
								HaldorOverhaul.Log.LogWarning((object)$"[StoreGuiPatches] Pool expanded but reflection update failed (local={count2}, actual={itemList?.Count ?? (-1)})");
								list2 = itemList ?? list2;
								count2 = list2.Count;
							}
						}
						else
						{
							HaldorOverhaul.Log.LogWarning((object)"[StoreGuiPatches] Pool expanded locally but _itemListField is null, cannot update StoreGui");
						}
					}
					else
					{
						HaldorOverhaul.Log.LogError((object)$"[StoreGuiPatches] CANNOT EXPAND POOL (template={(Object)(object)val7 != (Object)null}, parent={(Object)(object)val8 != (Object)null}). Will display first {count2} of {count} items.");
					}
				}
				List<GameObject> list3 = GetItemList(__instance);
				RectTransform listRoot = GetListRoot(__instance);
				int num2 = list3?.Count ?? 0;
				HaldorOverhaul.Log.LogInfo((object)string.Format("[StoreGuiPatches] FillList_Prefix final state: trader={0}, items={1}, itemList={2}, root={3}, initialized={4}", trader?.m_name ?? "NULL", count, num2, ((listRoot != null) ? ((Object)listRoot).name : null) ?? "NULL", _fullyInitialized));
				if (list3 != list2)
				{
					HaldorOverhaul.Log.LogWarning((object)$"[StoreGuiPatches] List reference mismatch! local={list2?.Count ?? (-1)}, fromReflection={num2}");
					list3 = list2;
					num2 = list2?.Count ?? 0;
				}
				ManualFillList(__instance, list ?? new List<TradeItem>(), list3 ?? new List<GameObject>(), listRoot);
				return false;
			}
			catch (Exception ex2)
			{
				HaldorOverhaul.Log.LogError((object)("[StoreGuiPatches] FillList_Prefix failed: " + ex2.Message + "\n" + ex2.StackTrace));
				return true;
			}
		}

		[HarmonyPatch(typeof(StoreGui), "FillList")]
		[HarmonyPostfix]
		private static void StoreGui_FillList_Postfix(StoreGui __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				CacheReflection();
				List<GameObject> itemList = GetItemList(__instance);
				if (itemList == null)
				{
					return;
				}
				List<TradeItem> tradeItems = GetTradeItems(__instance);
				for (int i = 0; i < itemList.Count; i++)
				{
					if (tradeItems == null)
					{
						break;
					}
					if (i >= tradeItems.Count)
					{
						break;
					}
					GameObject val = itemList[i];
					if (!((Object)(object)val == (Object)null))
					{
						Component component = val.GetComponent("UITooltip");
						TradeItem val2 = tradeItems[i];
						if ((Object)(object)component != (Object)null && val2?.m_prefab?.m_itemData != null)
						{
							ItemData itemData = val2.m_prefab.m_itemData;
							string value = UIManager.Localize(itemData.m_shared.m_name);
							string value2 = UIManager.Localize(itemData.m_shared.m_description);
							Type type = ((object)component).GetType();
							FieldInfo field = type.GetField("m_topic", BindingFlags.Instance | BindingFlags.Public);
							FieldInfo field2 = type.GetField("m_text", BindingFlags.Instance | BindingFlags.Public);
							field?.SetValue(component, value);
							field2?.SetValue(component, value2);
						}
					}
				}
				if (_fullyInitialized)
				{
					RectTransform listRoot = GetListRoot(__instance);
					Vector2? buyScrollPosition = UIManager.GetBuyScrollPosition(__instance);
					float? buyScrollNormalized = UIManager.GetBuyScrollNormalized(__instance);
					UIManager.ApplyBuyCategories(__instance, itemList, tradeItems, listRoot);
					if (buyScrollPosition.HasValue || buyScrollNormalized.HasValue)
					{
						UIManager.RestoreBuyScroll(__instance, buyScrollPosition, buyScrollNormalized);
					}
				}
				if (_fullyInitialized && UIManager.IsOpen())
				{
					UIManager.FillSellableList();
				}
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogError((object)("[StoreGuiPatches] FillList error: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(StoreGui), "FillList")]
		[HarmonyFinalizer]
		private static Exception StoreGui_FillList_Finalizer(StoreGui __instance, Exception __exception)
		{
			if (__exception != null)
			{
				List<TradeItem> tradeItems = GetTradeItems(__instance);
				List<GameObject> itemList = GetItemList(__instance);
				RectTransform listRoot = GetListRoot(__instance);
				Trader trader = GetTrader(__instance);
				HaldorOverhaul.Log.LogError((object)string.Format("[StoreGuiPatches] FillList exception: trader={0}, items={1}, itemList={2}, root={3}, message={4}", trader?.m_name ?? "NULL", tradeItems?.Count ?? (-1), itemList?.Count ?? (-1), ((listRoot != null) ? ((Object)listRoot).name : null) ?? "NULL", __exception.Message));
				HaldorOverhaul.Log.LogError((object)__exception.StackTrace);
				return null;
			}
			return null;
		}

		internal static void ResetInitialization()
		{
			_fullyInitialized = false;
		}

		internal static void MarkInitialized()
		{
			_fullyInitialized = true;
		}

		internal static bool IsInitialized()
		{
			return _fullyInitialized;
		}

		private static void CacheReflection()
		{
			if (_reflectionCached)
			{
				return;
			}
			lock (_reflectionLock)
			{
				if (_reflectionCached)
				{
					return;
				}
				try
				{
					Type typeFromHandle = typeof(StoreGui);
					BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
					_itemListField = typeFromHandle.GetField("m_itemList", bindingFlags);
					_traderField = typeFromHandle.GetField("m_trader", bindingFlags);
					_itemsField = typeFromHandle.GetField("m_items", bindingFlags);
					_listRootField = typeFromHandle.GetField("m_listRoot", bindingFlags);
					_selectedItemField = typeFromHandle.GetField("m_selectedItem", bindingFlags);
					_getPlayerCoinsMethod = typeFromHandle.GetMethod("GetPlayerCoins", bindingFlags);
					_selectItemMethod = typeFromHandle.GetMethod("SelectItem", bindingFlags, null, new Type[2]
					{
						typeof(int),
						typeof(bool)
					}, null);
					_buySelectedItemMethod = typeFromHandle.GetMethod("BuySelectedItem", bindingFlags);
					if (_itemsField == null)
					{
						_itemsField = FindFieldByType(typeFromHandle, typeof(List<TradeItem>), bindingFlags);
					}
					if (_itemListField == null)
					{
						_itemListField = FindFieldByType(typeFromHandle, typeof(List<GameObject>), bindingFlags);
					}
					if (_listRootField == null)
					{
						_listRootField = FindFieldByType(typeFromHandle, typeof(RectTransform), bindingFlags);
					}
					if (_buySelectedItemMethod == null)
					{
						_buySelectedItemMethod = typeFromHandle.GetMethods(bindingFlags).FirstOrDefault((MethodInfo m) => m.Name.IndexOf("BuySelected", StringComparison.OrdinalIgnoreCase) >= 0 && m.GetParameters().Length == 0);
					}
					_reflectionCached = true;
				}
				catch (Exception ex)
				{
					HaldorOverhaul.Log.LogError((object)("[StoreGuiPatches] Reflection cache failed: " + ex.Message));
					_reflectionCached = true;
				}
			}
		}

		private static FieldInfo FindFieldByType(Type type, Type targetType, BindingFlags flags)
		{
			try
			{
				return type.GetFields(flags).FirstOrDefault((FieldInfo f) => targetType.IsAssignableFrom(f.FieldType));
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] FindFieldByType failed for " + targetType.Name + ": " + ex.Message));
				return null;
			}
		}

		internal static List<GameObject> GetItemList(StoreGui gui)
		{
			if (_itemListField == null || (Object)(object)gui == (Object)null)
			{
				return null;
			}
			try
			{
				return _itemListField.GetValue(gui) as List<GameObject>;
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetItemList failed: " + ex.Message));
				return null;
			}
		}

		internal static List<TradeItem> GetTradeItems(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return null;
			}
			CacheReflection();
			List<TradeItem> list = null;
			if (_itemsField != null)
			{
				try
				{
					list = _itemsField.GetValue(gui) as List<TradeItem>;
				}
				catch (Exception ex)
				{
					HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetTradeItems reflection failed: " + ex.Message));
				}
			}
			if (list == null || list.Count == 0)
			{
				Trader trader = GetTrader(gui);
				if ((Object)(object)trader != (Object)null)
				{
					try
					{
						List<TradeItem> availableItems = trader.GetAvailableItems();
						if (availableItems != null && availableItems.Count > 0)
						{
							list = availableItems;
							_itemsField?.SetValue(gui, availableItems);
						}
					}
					catch (Exception ex2)
					{
						HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetTradeItems fallback failed: " + ex2.Message));
					}
				}
			}
			return list;
		}

		internal static Trader GetTrader(StoreGui gui)
		{
			if (_traderField == null || (Object)(object)gui == (Object)null)
			{
				return null;
			}
			try
			{
				object? value = _traderField.GetValue(gui);
				return (Trader)((value is Trader) ? value : null);
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetTrader failed: " + ex.Message));
				return null;
			}
		}

		internal static RectTransform GetListRoot(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return null;
			}
			CacheReflection();
			RectTransform val = null;
			if (_listRootField != null)
			{
				try
				{
					object? value = _listRootField.GetValue(gui);
					val = (RectTransform)((value is RectTransform) ? value : null);
				}
				catch (Exception ex)
				{
					HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetListRoot reflection failed: " + ex.Message));
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Transform val2 = ((Component)gui).transform.Find("ItemList/Items/ListRoot");
				RectTransform val3 = (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
				if (val3 != null)
				{
					val = val3;
					_listRootField?.SetValue(gui, val3);
				}
			}
			return val;
		}

		internal static int GetPlayerCoins(StoreGui gui)
		{
			if (_getPlayerCoinsMethod == null || (Object)(object)gui == (Object)null)
			{
				return 0;
			}
			try
			{
				return (int)_getPlayerCoinsMethod.Invoke(gui, null);
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetPlayerCoins failed: " + ex.Message));
				return 0;
			}
		}

		internal static void InvokeSelectItem(StoreGui gui, int index, bool center)
		{
			if (_selectItemMethod == null || (Object)(object)gui == (Object)null)
			{
				return;
			}
			SuppressSellDeselect = true;
			try
			{
				_selectItemMethod.Invoke(gui, new object[2] { index, center });
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] InvokeSelectItem failed: " + ex.Message));
			}
			finally
			{
				SuppressSellDeselect = false;
			}
		}

		internal static void InvokeBuySelectedItem(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return;
			}
			CacheReflection();
			if (!(_buySelectedItemMethod != null))
			{
				return;
			}
			try
			{
				_buySelectedItemMethod.Invoke(gui, null);
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] InvokeBuySelectedItem failed: " + ex.Message));
			}
		}

		internal static int GetSelectedItemIndex(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return -1;
			}
			CacheReflection();
			if (_selectedItemField != null)
			{
				try
				{
					return (int)_selectedItemField.GetValue(gui);
				}
				catch (Exception ex)
				{
					HaldorOverhaul.Log.LogWarning((object)("[StoreGuiPatches] GetSelectedItemIndex failed: " + ex.Message));
				}
			}
			return -1;
		}

		[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
		[HarmonyPostfix]
		private static void Trader_GetAvailableItems_Postfix(Trader __instance, List<TradeItem> __result)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			try
			{
				if ((Object)(object)__instance == (Object)null || __result == null || (Object)(object)ObjectDB.instance == (Object)null)
				{
					return;
				}
				string text = __instance.m_name ?? "";
				if ((text.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("$npc_haldor", StringComparison.OrdinalIgnoreCase) < 0) || ConfigLoader.BuyEntries == null || ConfigLoader.BuyEntries.Count == 0)
				{
					return;
				}
				List<TradeItem> list = new List<TradeItem>();
				int num = 0;
				foreach (TradeEntry buyEntry in ConfigLoader.BuyEntries)
				{
					if (buyEntry == null || string.IsNullOrEmpty(buyEntry.prefab))
					{
						continue;
					}
					if (!string.IsNullOrEmpty(buyEntry.requiredGlobalKey) && (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGlobalKey(buyEntry.requiredGlobalKey)))
					{
						num++;
						continue;
					}
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(buyEntry.prefab);
					if (!((Object)(object)itemPrefab == (Object)null))
					{
						ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
						if (!((Object)(object)component == (Object)null) && component.m_itemData != null)
						{
							TradeItem item = new TradeItem
							{
								m_prefab = component,
								m_price = buyEntry.price,
								m_stack = buyEntry.stack,
								m_requiredGlobalKey = ""
							};
							list.Add(item);
						}
					}
				}
				if (list.Count > 0)
				{
					__result.Clear();
					__result.AddRange(list);
				}
				else
				{
					HaldorOverhaul.Log.LogWarning((object)$"[GetAvailableItems] No items to add (skippedByKey={num}), using vanilla items ({__result.Count}) for trader={text}");
				}
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogError((object)("[StoreGuiPatches] GetAvailableItems error: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(StoreGui), "SellItem")]
		[HarmonyPrefix]
		private static bool StoreGui_SellItem_Prefix(StoreGui __instance)
		{
			if (UIManager.IsOpen())
			{
				UIManager.SellSelectedItem(__instance);
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(StoreGui), "OnSelectedItem")]
		[HarmonyPostfix]
		private static void StoreGui_OnSelectedItem_Postfix()
		{
			if (!SuppressSellDeselect && UIManager.IsOpen())
			{
				UIManager.DeselectSellSide();
			}
		}

		private static int CountPlayerCoins(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_coinPrefab == (Object)null)
			{
				return -1;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return -1;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory == null)
			{
				return -1;
			}
			string text = gui.m_coinPrefab.m_itemData?.m_shared?.m_name;
			if (string.IsNullOrEmpty(text))
			{
				return -1;
			}
			return inventory.CountItems(text, -1, true);
		}

		[HarmonyPatch(typeof(Character), "Message")]
		[HarmonyPrefix]
		private static bool Character_Message_Prefix(Character __instance)
		{
			if (SuppressNextBuyMessage && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				SuppressNextBuyMessage = false;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(StoreGui), "BuySelectedItem")]
		[HarmonyPrefix]
		private static void StoreGui_BuySelectedItem_Prefix(StoreGui __instance)
		{
			_pendingBuyItemName = null;
			_pendingBuyPrice = 0;
			_pendingBuyStack = 0;
			_pendingBuyIcon = null;
			_pendingBuyCoins = -1;
			_buyAttempted = false;
			SuppressNextBuyMessage = false;
			try
			{
				_pendingBuyCoins = CountPlayerCoins(__instance);
				List<TradeItem> tradeItems = GetTradeItems(__instance);
				if (tradeItems == null || tradeItems.Count == 0)
				{
					HaldorOverhaul.Log.LogWarning((object)"[Buy_Prefix] No trade items");
					return;
				}
				int selectedItemIndex = GetSelectedItemIndex(__instance);
				if (selectedItemIndex < 0 || selectedItemIndex >= tradeItems.Count)
				{
					HaldorOverhaul.Log.LogWarning((object)$"[Buy_Prefix] Invalid index: {selectedItemIndex}, items: {tradeItems.Count}");
					return;
				}
				TradeItem val = tradeItems[selectedItemIndex];
				if (val?.m_prefab?.m_itemData?.m_shared == null)
				{
					HaldorOverhaul.Log.LogWarning((object)"[Buy_Prefix] Invalid item data");
					return;
				}
				_pendingBuyItemName = UIManager.Localize(val.m_prefab.m_itemData.m_shared.m_name);
				_pendingBuyPrice = val.m_price;
				_pendingBuyStack = val.m_stack;
				_buyAttempted = true;
				SuppressNextBuyMessage = true;
				try
				{
					_pendingBuyIcon = val.m_prefab.m_itemData.GetIcon();
				}
				catch
				{
					_pendingBuyIcon = null;
				}
				HaldorOverhaul.Log.LogInfo((object)$"[Buy_Prefix] Attempting: {_pendingBuyItemName} x{_pendingBuyStack} for {_pendingBuyPrice}, coins before: {_pendingBuyCoins}");
			}
			catch (Exception ex)
			{
				SuppressNextBuyMessage = false;
				HaldorOverhaul.Log.LogError((object)("[Buy_Prefix] Error: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(StoreGui), "BuySelectedItem")]
		[HarmonyPostfix]
		private static void StoreGui_BuySelectedItem_Postfix(StoreGui __instance)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!_buyAttempted || string.IsNullOrEmpty(_pendingBuyItemName))
				{
					HaldorOverhaul.Log.LogWarning((object)"[Buy_Postfix] No buy was attempted");
					return;
				}
				int num = CountPlayerCoins(__instance);
				bool flag = false;
				if (_pendingBuyCoins >= 0 && num >= 0)
				{
					int pendingBuyPrice = _pendingBuyPrice;
					int num2 = _pendingBuyCoins - num;
					flag = num2 >= pendingBuyPrice;
					HaldorOverhaul.Log.LogInfo((object)$"[Buy_Postfix] Coins: {_pendingBuyCoins} -> {num} (expected -{pendingBuyPrice}, actual -{num2})");
				}
				else
				{
					flag = true;
					HaldorOverhaul.Log.LogWarning((object)"[Buy_Postfix] Could not verify coins, assuming success");
				}
				if (flag)
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer != (Object)null)
					{
						bool flag2 = false;
						try
						{
							if (__instance.m_sellEffects != null && __instance.m_sellEffects.m_effectPrefabs != null && __instance.m_sellEffects.m_effectPrefabs.Length != 0)
							{
								__instance.m_sellEffects.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
								flag2 = true;
								HaldorOverhaul.Log.LogInfo((object)"[Buy_Postfix] Played m_sellEffects");
							}
							else
							{
								HaldorOverhaul.Log.LogWarning((object)"[Buy_Postfix] m_sellEffects is null or empty");
							}
						}
						catch (Exception ex)
						{
							HaldorOverhaul.Log.LogError((object)("[Buy_Postfix] Sound error: " + ex.Message));
						}
						string arg = ((_pendingBuyStack > 1) ? $"{_pendingBuyStack} {_pendingBuyItemName}" : _pendingBuyItemName);
						string text = $"Bought {arg} from Haldor for {_pendingBuyPrice} coins";
						((Character)localPlayer).Message((MessageType)1, text, 0, _pendingBuyIcon);
						HaldorOverhaul.Log.LogInfo((object)$"[Buy_Postfix] Purchase complete: {arg}, sound={flag2}");
					}
				}
				else
				{
					HaldorOverhaul.Log.LogWarning((object)"[Buy_Postfix] Purchase failed or insufficient funds");
				}
			}
			catch (Exception ex2)
			{
				HaldorOverhaul.Log.LogError((object)("[Buy_Postfix] Error: " + ex2.Message + "\n" + ex2.StackTrace));
			}
			finally
			{
				_pendingBuyItemName = null;
				_pendingBuyIcon = null;
				_buyAttempted = false;
			}
			if (UIManager.IsOpen())
			{
				UIManager.FillSellableList();
			}
		}
	}
	internal static class UIManager
	{
		private enum ActiveTab
		{
			Buy,
			Sell
		}

		internal sealed class SellRow
		{
			public ItemData Item;

			public int TotalPrice;

			public int Stack;

			public int ConfigStack;

			public GameObject RowObject;

			public string Category;
		}

		private sealed class SellCandidate
		{
			public ItemData Item;

			public int Price;

			public int ConfigStack;

			public string Category;
		}

		private sealed class NavigationEntry
		{
			public string Category;

			public int Index;

			public bool IsHeader;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnSellButtonClicked;

			public static UnityAction<string> <1>__OnBuySearchChanged;

			public static UnityAction<string> <2>__OnSellSearchChanged;
		}

		private static readonly float PositionDelta = 35f;

		private static readonly float SellPanelOffset = 250f;

		private static readonly HashSet<int> AdjustedStores = new HashSet<int>();

		private static GameObject _sellPanel;

		private static Button _sellButton;

		private static RectTransform _sellListRoot;

		private static GameObject _sellListElementPrefab;

		private static ScrollRectEnsureVisible _sellItemEnsureVisible;

		private static TMP_Text _playerCoinsText;

		private static TMP_Text _gamepadHintText;

		private static StoreGui _currentStore;

		private static TMP_InputField _buySearchInput;

		private static TMP_InputField _sellSearchInput;

		private static string _buySearchFilter = "";

		private static string _sellSearchFilter = "";

		internal static bool IsSearchInputFocused = false;

		private static float _itemSpacing;

		private static float _itemListBaseSize;

		private static int _lastInventoryHash = -1;

		internal static readonly List<GameObject> SellItemList = new List<GameObject>();

		internal static readonly List<SellRow> SellRows = new List<SellRow>();

		private static readonly List<GameObject> _sellCategoryHeaders = new List<GameObject>();

		private static readonly List<string> _sellCategoryOrder = new List<string>();

		private static readonly Dictionary<string, GameObject> _sellHeaderLookup = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, bool> _sellCategoryCollapsed = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

		private static int _selectedSellIndex = -1;

		private static bool _sellInProgress = false;

		private static readonly List<GameObject> _buyCategoryHeaders = new List<GameObject>();

		private static readonly List<string> _buyCategoryOrder = new List<string>();

		private static readonly Dictionary<string, GameObject> _buyHeaderLookup = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, bool> _buyCategoryCollapsed = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<int> _hiddenBuyIndices = new HashSet<int>();

		private static readonly List<string> _buyIndexCategories = new List<string>();

		private static bool _buyInProgress = false;

		private static readonly string[] _categoryBuckets = Constants.CategoryBuckets;

		private static readonly Dictionary<string, string[]> _categoryIconPrefabs = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"Weapons",
				new string[5] { "SwordBronze", "SwordIron", "AxeBronze", "Bow", "Club" }
			},
			{
				"Armor",
				new string[4] { "ArmorBronzeChest", "ArmorIronChest", "HelmetBronze", "ArmorLeatherChest" }
			},
			{
				"Shields",
				new string[4] { "ShieldWood", "ShieldBronzeBuckler", "ShieldIronSquare", "ShieldBanded" }
			},
			{
				"Ammo",
				new string[4] { "ArrowWood", "ArrowFire", "ArrowFlint", "ArrowBronze" }
			},
			{
				"Consumables",
				new string[4] { "MeadHealthMinor", "MeadStaminaMinor", "Honey", "Raspberry" }
			},
			{
				"Materials",
				new string[5] { "Wood", "Stone", "Coal", "Bronze", "Iron" }
			},
			{
				"Utility",
				new string[4] { "Hammer", "Hoe", "FishingRod", "Torch" }
			},
			{
				"Trophies",
				new string[4] { "TrophyBoar", "TrophyDeer", "TrophyNeck", "TrophyGreydwarf" }
			},
			{
				"Crafting",
				new string[4] { "Hammer", "SurtlingCore", "GreydwarfEye", "Resin" }
			},
			{
				"Misc",
				new string[4] { "Coins", "Ruby", "Amber", "AmberPearl" }
			}
		};

		private static readonly Dictionary<string, Sprite> _categoryIconCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		private static ActiveTab _activeTab = ActiveTab.Buy;

		private static string _focusedBuyHeader;

		private static int _focusedBuyIndex = -1;

		private static string _focusedSellHeader;

		private static MethodInfo _localizeMethod;

		private static object _localizationInstance;

		private static bool _localizationCached;

		private static void ClearCategoryHeaders(List<GameObject> headers, Dictionary<string, GameObject> lookup)
		{
			if (headers != null)
			{
				foreach (GameObject header in headers)
				{
					if ((Object)(object)header != (Object)null)
					{
						Object.Destroy((Object)(object)header);
					}
				}
				headers.Clear();
			}
			lookup?.Clear();
		}

		private static string GetItemCategory(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return "Misc";
			}
			string text = ((object)(ItemType)(ref item.m_shared.m_itemType)).ToString();
			if (string.IsNullOrEmpty(text))
			{
				return "Misc";
			}
			string text2 = text switch
			{
				"OneHandedWeapon" => "Weapons", 
				"TwoHandedWeapon" => "Weapons", 
				"Bow" => "Weapons", 
				"Tool" => "Utility", 
				"Shield" => "Shields", 
				"Helmet" => "Armor", 
				"Chest" => "Armor", 
				"Legs" => "Armor", 
				"Shoulder" => "Armor", 
				"Utility" => "Utility", 
				"Ammo" => "Ammo", 
				"Consumable" => "Consumables", 
				"Trophie" => "Trophies", 
				_ => text, 
			};
			if (text2.IndexOf("Weapon", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Weapons";
			}
			else if (text2.IndexOf("Armor", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Armor";
			}
			else if (text2.IndexOf("Shield", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Shields";
			}
			else if (text2.IndexOf("Ammo", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Ammo";
			}
			else if (text2.IndexOf("Consum", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Food", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Consumables";
			}
			else if (text2.IndexOf("Material", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Materials";
			}
			else if (text2.IndexOf("Utility", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Tool", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Utility";
			}
			else if (text2.IndexOf("Troph", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				text2 = "Trophies";
			}
			string[] categoryBuckets = _categoryBuckets;
			foreach (string text3 in categoryBuckets)
			{
				if (string.Equals(text2, text3, StringComparison.OrdinalIgnoreCase))
				{
					return text3;
				}
			}
			return "Misc";
		}

		private static string GetCategoryHeaderLabel(string category, bool collapsed)
		{
			string categoryDisplayName = Constants.GetCategoryDisplayName(category);
			return (collapsed ? "[+] " : "[-] ") + categoryDisplayName;
		}

		private static Sprite GetCategoryIcon(string category)
		{
			if (string.IsNullOrEmpty(category))
			{
				return null;
			}
			if (_categoryIconCache.TryGetValue(category, out var value))
			{
				return value;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			if (_categoryIconPrefabs.TryGetValue(category, out var value2))
			{
				string[] array = value2;
				foreach (string text in array)
				{
					try
					{
						GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
						if ((Object)(object)itemPrefab == (Object)null)
						{
							continue;
						}
						ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
						if (component?.m_itemData != null)
						{
							Sprite icon = component.m_itemData.GetIcon();
							if ((Object)(object)icon != (Object)null)
							{
								_categoryIconCache[category] = icon;
								return icon;
							}
						}
					}
					catch (Exception ex)
					{
						HaldorOverhaul.Log.LogWarning((object)("[UIManager] GetCategoryIcon failed for " + text + ": " + ex.Message));
					}
				}
			}
			return null;
		}

		private static GameObject CreateCategoryHeader(GameObject prefab, Transform parent, string category, bool collapsed, bool isSell)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			if ((Object)(object)prefab == (Object)null || (Object)(object)parent == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, parent);
			val.SetActive(true);
			((Object)val).name = (isSell ? "SellCategory_" : "BuyCategory_") + category;
			Image val2 = val.GetComponent<Image>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.AddComponent<Image>();
			}
			((Graphic)val2).color = Constants.CategoryHeaderBackground;
			Transform val3 = val.transform.Find("icon");
			if ((Object)(object)val3 != (Object)null)
			{
				Sprite categoryIcon = GetCategoryIcon(category);
				if ((Object)(object)categoryIcon != (Object)null)
				{
					((Component)val3).gameObject.SetActive(true);
					Image component = ((Component)val3).GetComponent<Image>();
					if ((Object)(object)component != (Object)null)
					{
						component.sprite = categoryIcon;
						((Graphic)component).color = Constants.CategoryIconTint;
					}
				}
				else
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
			Transform val4 = val.transform.Find("coin_bkg");
			if ((Object)(object)val4 != (Object)null)
			{
				((Component)val4).gameObject.SetActive(false);
			}
			Transform val5 = val.transform.Find("quality");
			if ((Object)(object)val5 != (Object)null)
			{
				((Component)val5).gameObject.SetActive(false);
			}
			Transform val6 = val.transform.Find("selected");
			if ((Object)(object)val6 != (Object)null)
			{
				((Component)val6).gameObject.SetActive(false);
			}
			Transform obj = val.transform.Find("name");
			TMP_Text val7 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			if ((Object)(object)val7 != (Object)null)
			{
				val7.text = GetCategoryHeaderLabel(category, collapsed);
				((Graphic)val7).color = Constants.CategoryHeaderTextColor;
				val7.fontStyle = (FontStyles)1;
				val7.fontSize *= 1.2f;
			}
			else
			{
				HaldorOverhaul.Log.LogWarning((object)("[UIManager] CreateCategoryHeader: name text missing for " + category));
			}
			Button component2 = val.GetComponent<Button>();
			if ((Object)(object)component2 != (Object)null)
			{
				((UnityEventBase)component2.onClick).RemoveAllListeners();
				if (isSell)
				{
					((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
					{
						ToggleSellCategory(category);
					});
				}
				else
				{
					((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
					{
						ToggleBuyCategory(category);
					});
				}
				((Selectable)component2).interactable = true;
			}
			return val;
		}

		private static void UpdateHeaderLabel(GameObject header, string category, bool collapsed)
		{
			object obj;
			if (header == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = header.transform.Find("name");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
			}
			TMP_Text val = (TMP_Text)obj;
			if ((Object)(object)val != (Object)null)
			{
				val.text = GetCategoryHeaderLabel(category, collapsed);
			}
		}

		private static void PositionRow(RectTransform rect, float offset, int visualIndex)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rect == (Object)null))
			{
				rect.anchoredPosition = new Vector2(offset, (float)visualIndex * (0f - _itemSpacing) - offset);
			}
		}

		private static void MarkHeaderSelected(Dictionary<string, GameObject> lookup, string category)
		{
			if (lookup == null)
			{
				return;
			}
			foreach (KeyValuePair<string, GameObject> item in lookup)
			{
				GameObject value = item.Value;
				if (!((Object)(object)value == (Object)null))
				{
					Transform val = value.transform.Find("selected");
					if ((Object)(object)val != (Object)null)
					{
						bool active = !string.IsNullOrEmpty(category) && string.Equals(category, item.Key, StringComparison.OrdinalIgnoreCase);
						((Component)val).gameObject.SetActive(active);
					}
				}
			}
		}

		private static void ToggleSellCategory(string category)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(category))
			{
				return;
			}
			bool value;
			bool flag = _sellCategoryCollapsed.TryGetValue(category, out value) && value;
			_sellCategoryCollapsed[category] = !flag;
			SetActiveTab(ActiveTab.Sell);
			_selectedSellIndex = -1;
			_focusedSellHeader = category;
			MarkHeaderSelected(_sellHeaderLookup, category);
			RelayoutSellList(rebuildHeaders: false);
			GameObject sellPanel = _sellPanel;
			object obj;
			if (sellPanel == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = sellPanel.transform.Find("ItemList/Items");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<ScrollRect>() : null);
			}
			ScrollRect val = (ScrollRect)obj;
			if ((Object)(object)val != (Object)null && (Object)(object)val.content != (Object)null && _sellHeaderLookup.TryGetValue(category, out var value2) && (Object)(object)value2 != (Object)null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(val.content);
				Canvas.ForceUpdateCanvases();
				Transform transform = value2.transform;
				RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				Rect rect = val.content.rect;
				float height = ((Rect)(ref rect)).height;
				float num;
				if (!((Object)(object)val.viewport != (Object)null))
				{
					num = 300f;
				}
				else
				{
					rect = val.viewport.rect;
					num = ((Rect)(ref rect)).height;
				}
				float num2 = num;
				if (height > num2 && (Object)(object)val2 != (Object)null)
				{
					float num3 = Mathf.Abs(val2.anchoredPosition.y);
					float num4 = height - num2;
					num3 = Mathf.Clamp(num3, 0f, num4);
					float num5 = 1f - num3 / num4;
					val.verticalNormalizedPosition = Mathf.Clamp01(num5);
				}
				else if (height <= num2)
				{
					val.verticalNormalizedPosition = 1f;
				}
				val.velocity = Vector2.zero;
			}
		}

		private static void ToggleBuyCategory(string category)
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(category) || (Object)(object)_currentStore == (Object)null)
			{
				return;
			}
			bool value;
			bool flag = _buyCategoryCollapsed.TryGetValue(category, out value) && value;
			_buyCategoryCollapsed[category] = !flag;
			SetActiveTab(ActiveTab.Buy);
			_focusedBuyHeader = category;
			_focusedBuyIndex = -1;
			List<GameObject> itemList = StoreGuiPatches.GetItemList(_currentStore);
			List<TradeItem> tradeItems = StoreGuiPatches.GetTradeItems(_currentStore);
			MarkHeaderSelected(_buyHeaderLookup, category);
			ClearBuyItemSelection(itemList);
			ApplyBuyCategories(_currentStore, itemList, tradeItems);
			GameObject rootPanel = _currentStore.m_rootPanel;
			object obj;
			if (rootPanel == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = rootPanel.transform.Find("ItemList/Items");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<ScrollRect>() : null);
			}
			ScrollRect val = (ScrollRect)obj;
			if ((Object)(object)val != (Object)null && (Object)(object)val.content != (Object)null && _buyHeaderLookup.TryGetValue(category, out var value2) && (Object)(object)value2 != (Object)null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(val.content);
				Canvas.ForceUpdateCanvases();
				Transform transform = value2.transform;
				RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				Rect rect = val.content.rect;
				float height = ((Rect)(ref rect)).height;
				float num;
				if (!((Object)(object)val.viewport != (Object)null))
				{
					num = 300f;
				}
				else
				{
					rect = val.viewport.rect;
					num = ((Rect)(ref rect)).height;
				}
				float num2 = num;
				if (height > num2 && (Object)(object)val2 != (Object)null)
				{
					float num3 = Mathf.Abs(val2.anchoredPosition.y);
					float num4 = height - num2;
					num3 = Mathf.Clamp(num3, 0f, num4);
					float num5 = 1f - num3 / num4;
					val.verticalNormalizedPosition = Mathf.Clamp01(num5);
				}
				else if (height <= num2)
				{
					val.verticalNormalizedPosition = 1f;
				}
				val.velocity = Vector2.zero;
			}
		}

		private static string GetBuyCategoryForIndex(int index)
		{
			if (index < 0 || !(index < _buyIndexCategories?.Count))
			{
				return null;
			}
			return _buyIndexCategories[index];
		}

		internal static bool IsBuyIndexVisible(int index, int totalCount)
		{
			if (index >= 0 && index < totalCount)
			{
				return !_hiddenBuyIndices.Contains(index);
			}
			return false;
		}

		internal static int FindNearestVisibleBuyIndex(int index, int totalCount)
		{
			if (totalCount <= 0)
			{
				return -1;
			}
			index = Mathf.Clamp(index, 0, totalCount - 1);
			if (!_hiddenBuyIndices.Contains(index))
			{
				return index;
			}
			for (int i = 1; i < totalCount; i++)
			{
				int num = index + i;
				if (num < totalCount && !_hiddenBuyIndices.Contains(num))
				{
					return num;
				}
				int num2 = index - i;
				if (num2 >= 0 && !_hiddenBuyIndices.Contains(num2))
				{
					return num2;
				}
			}
			return -1;
		}

		internal static int GetNextVisibleBuyIndex(int index, int direction, int totalCount)
		{
			if (totalCount <= 0)
			{
				return -1;
			}
			if (direction == 0)
			{
				direction = 1;
			}
			int num = index;
			int num2 = Math.Sign(direction);
			if (num < 0)
			{
				num = ((num2 > 0) ? (-1) : totalCount);
			}
			for (int i = num + num2; i >= 0 && i < totalCount; i += num2)
			{
				if (!_hiddenBuyIndices.Contains(i))
				{
					return i;
				}
			}
			return -1;
		}

		internal static void RefreshBuyCategories(StoreGui gui)
		{
			if (!((Object)(object)gui == (Object)null))
			{
				List<GameObject> itemList = StoreGuiPatches.GetItemList(gui);
				List<TradeItem> tradeItems = StoreGuiPatches.GetTradeItems(gui);
				ApplyBuyCategories(gui, itemList, tradeItems);
			}
		}

		internal static void ApplyBuyCategories(StoreGui gui, List<GameObject> buyList, List<TradeItem> tradeItems, RectTransform explicitListRoot = null)
		{
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0911: Unknown result type (might be due to invalid IL or missing references)
			//IL_0916: Unknown result type (might be due to invalid IL or missing references)
			//IL_091f: Unknown result type (might be due to invalid IL or missing references)
			//IL_098d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)gui == (Object)null)
			{
				return;
			}
			if (buyList == null || buyList.Count == 0)
			{
				HaldorOverhaul.Log.LogWarning((object)"[UIManager] ApplyBuyCategories skipped: buyList empty");
				return;
			}
			if (_itemSpacing <= 0f)
			{
				_itemSpacing = gui.m_itemSpacing;
				if (_itemSpacing <= 0f)
				{
					HaldorOverhaul.Log.LogWarning((object)"[UIManager] Buy category build skipped: itemSpacing is 0");
					return;
				}
			}
			RectTransform val = explicitListRoot ?? gui.m_listRoot;
			if ((Object)(object)val == (Object)null)
			{
				GameObject obj = buyList[0];
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					Transform transform = obj.transform;
					obj2 = ((transform != null) ? transform.parent : null);
				}
				Transform val2 = (Transform)obj2;
				val = (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				HaldorOverhaul.Log.LogWarning((object)"[UIManager] Buy category build skipped: no list root found.");
				return;
			}
			if (tradeItems == null || tradeItems.Count != buyList.Count)
			{
				Trader trader = StoreGuiPatches.GetTrader(gui);
				if ((Object)(object)trader != (Object)null)
				{
					try
					{
						List<TradeItem> availableItems = trader.GetAvailableItems();
						if (availableItems != null && availableItems.Count > 0)
						{
							tradeItems = availableItems;
						}
					}
					catch (Exception ex)
					{
						HaldorOverhaul.Log.LogWarning((object)("[UIManager] Failed to fetch fallback trade items: " + ex.Message));
					}
				}
			}
			VerticalLayoutGroup component = ((Component)val).GetComponent<VerticalLayoutGroup>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			ContentSizeFitter component2 = ((Component)val).GetComponent<ContentSizeFitter>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Behaviour)component2).enabled = false;
			}
			Transform parent = ((Transform)val).parent;
			if ((Object)(object)parent != (Object)null)
			{
				VerticalLayoutGroup component3 = ((Component)parent).GetComponent<VerticalLayoutGroup>();
				if ((Object)(object)component3 != (Object)null)
				{
					((Behaviour)component3).enabled = false;
				}
				ContentSizeFitter component4 = ((Component)parent).GetComponent<ContentSizeFitter>();
				if ((Object)(object)component4 != (Object)null)
				{
					((Behaviour)component4).enabled = false;
				}
			}
			ClearCategoryHeaders(_buyCategoryHeaders, _buyHeaderLookup);
			_buyCategoryOrder.Clear();
			_hiddenBuyIndices.Clear();
			int num = tradeItems?.Count ?? buyList.Count;
			string[] array = new string[num];
			string[] array2 = new string[num];
			string[] categoryBuckets = _categoryBuckets;
			foreach (string text in categoryBuckets)
			{
				if (!_buyCategoryCollapsed.ContainsKey(text))
				{
					_buyCategoryCollapsed[text] = true;
				}
				_buyCategoryOrder.Add(text);
			}
			for (int j = 0; j < num; j++)
			{
				ItemData val3 = ((tradeItems == null || j >= tradeItems.Count) ? null : tradeItems[j]?.m_prefab?.m_itemData);
				string key = (array[j] = GetItemCategory(val3));
				array2[j] = ((val3?.m_shared != null) ? Localize(val3.m_shared.m_name) : "");
				if (!_buyCategoryCollapsed.ContainsKey(key))
				{
					_buyCategoryCollapsed[key] = true;
				}
			}
			_buyIndexCategories.Clear();
			_buyIndexCategories.AddRange(array);
			Rect rect = val.rect;
			float width = ((Rect)(ref rect)).width;
			GameObject val4 = (((Object)(object)gui.m_listElement != (Object)null) ? gui.m_listElement : buyList[0]);
			RectTransform val5 = (((Object)(object)val4 != (Object)null) ? val4.GetComponent<RectTransform>() : null);
			float num2;
			if (!((Object)(object)val5 != (Object)null))
			{
				num2 = width;
			}
			else
			{
				rect = val5.rect;
				num2 = ((Rect)(ref rect)).width;
			}
			float num3 = num2;
			float offset = (width - num3) / 2f;
			LayoutElement val6 = (((Object)(object)val4 != (Object)null) ? val4.GetComponent<LayoutElement>() : null);
			bool flag = IsSearchActive(isBuy: true);
			if (!flag)
			{
				foreach (string item in _buyCategoryOrder)
				{
					bool value;
					bool collapsed = _buyCategoryCollapsed.TryGetValue(item, out value) && value;
					GameObject val7 = CreateCategoryHeader(val4, (Transform)(object)val, item, collapsed, isSell: false);
					if ((Object)(object)val7 != (Object)null)
					{
						if ((Object)(object)val6 != (Object)null)
						{
							LayoutElement val8 = val7.GetComponent<LayoutElement>() ?? val7.AddComponent<LayoutElement>();
							val8.minHeight = val6.minHeight;
							val8.preferredHeight = val6.preferredHeight;
							val8.flexibleHeight = val6.flexibleHeight;
							val8.minWidth = val6.minWidth;
							val8.preferredWidth = val6.preferredWidth;
							val8.flexibleWidth = val6.flexibleWidth;
							val8.ignoreLayout = true;
						}
						else
						{
							LayoutElement val9 = val7.GetComponent<LayoutElement>() ?? val7.AddComponent<LayoutElement>();
							val9.ignoreLayout = true;
						}
						_buyCategoryHeaders.Add(val7);
						_buyHeaderLookup[item] = val7;
					}
					else
					{
						HaldorOverhaul.Log.LogWarning((object)("[UIManager] Failed to create buy header for: " + item));
					}
				}
			}
			int num4 = FindSelectedBuyIndex(buyList);
			int num5 = 0;
			List<GameObject> list = new List<GameObject>();
			for (int k = 0; k < buyList.Count; k++)
			{
				if (!((Object)(object)buyList[k] == (Object)null))
				{
					Transform val10 = buyList[k].transform.Find("selected");
					if ((Object)(object)val10 != (Object)null)
					{
						((Component)val10).gameObject.SetActive(false);
					}
				}
			}
			if (flag)
			{
				for (int l = 0; l < buyList.Count; l++)
				{
					if (l >= num)
					{
						GameObject obj3 = buyList[l];
						if (obj3 != null)
						{
							obj3.SetActive(false);
						}
						continue;
					}
					GameObject val11 = buyList[l];
					if ((Object)(object)val11 == (Object)null)
					{
						continue;
					}
					LayoutElement val12 = val11.GetComponent<LayoutElement>() ?? val11.AddComponent<LayoutElement>();
					val12.ignoreLayout = true;
					bool flag2 = ItemMatchesSearch(array2[l], isBuy: true);
					val11.SetActive(flag2);
					Button component5 = val11.GetComponent<Button>();
					if ((Object)(object)component5 != (Object)null)
					{
						((Selectable)component5).interactable = flag2;
					}
					Transform val13 = val11.transform.Find("selected");
					if (!flag2)
					{
						if ((Object)(object)val13 != (Object)null)
						{
							((Component)val13).gameObject.SetActive(false);
						}
						_hiddenBuyIndices.Add(l);
					}
					else
					{
						if ((Object)(object)val13 != (Object)null)
						{
							((Component)val13).gameObject.SetActive(l == num4);
						}
						list.Add(val11);
					}
				}
			}
			else
			{
				foreach (string item2 in _buyCategoryOrder)
				{
					bool value2;
					bool flag3 = _buyCategoryCollapsed.TryGetValue(item2, out value2) && value2;
					if (_buyHeaderLookup.TryGetValue(item2, out var value3) && (Object)(object)value3 != (Object)null)
					{
						value3.SetActive(true);
						UpdateHeaderLabel(value3, item2, flag3);
						list.Add(value3);
					}
					for (int m = 0; m < buyList.Count; m++)
					{
						if (m >= num)
						{
							GameObject obj4 = buyList[m];
							if (obj4 != null)
							{
								obj4.SetActive(false);
							}
						}
						else
						{
							if (!string.Equals(array[m], item2, StringComparison.OrdinalIgnoreCase))
							{
								continue;
							}
							GameObject val14 = buyList[m];
							if ((Object)(object)val14 == (Object)null)
							{
								continue;
							}
							LayoutElement val15 = val14.GetComponent<LayoutElement>() ?? val14.AddComponent<LayoutElement>();
							val15.ignoreLayout = true;
							bool flag4 = !flag3;
							val14.SetActive(flag4);
							Button component6 = val14.GetComponent<Button>();
							if ((Object)(object)component6 != (Object)null)
							{
								((Selectable)component6).interactable = flag4;
							}
							Transform val16 = val14.transform.Find("selected");
							if (!flag4 && (Object)(object)val16 != (Object)null)
							{
								((Component)val16).gameObject.SetActive(false);
							}
							if (!flag4)
							{
								_hiddenBuyIndices.Add(m);
								continue;
							}
							if ((Object)(object)val16 != (Object)null)
							{
								((Component)val16).gameObject.SetActive(m == num4);
							}
							list.Add(val14);
						}
					}
				}
			}
			for (int n = 0; n < list.Count; n++)
			{
				GameObject val17 = list[n];
				if (!((Object)(object)val17 == (Object)null))
				{
					val17.transform.SetSiblingIndex(n);
					Transform transform2 = val17.transform;
					PositionRow((RectTransform)(object)((transform2 is RectTransform) ? transform2 : null), offset, n);
					val17.SetActive(true);
				}
			}
			num5 = list.Count;
			HashSet<GameObject> hashSet = new HashSet<GameObject>(list);
			for (int num6 = 0; num6 < ((Transform)val).childCount; num6++)
			{
				Transform child = ((Transform)val).GetChild(num6);
				if (!((Object)(object)child == (Object)null) && !hashSet.Contains(((Component)child).gameObject))
				{
					((Component)child).gameObject.SetActive(false);
					child.SetSiblingIndex(((Transform)val).childCount - 1);
				}
			}
			float num7 = (float)num5 * _itemSpacing + _itemSpacing * 0.1f;
			float num8 = Mathf.Max(_itemListBaseSize, num7);
			val.SetSizeWithCurrentAnchors((Axis)1, num8);
			LayoutRebuilder.ForceRebuildLayoutImmediate(val);
			Transform parent2 = ((Transform)val).parent;
			ScrollRect val18 = ((parent2 != null) ? ((Component)parent2).GetComponent<ScrollRect>() : null);
			if ((Object)(object)val18 != (Object)null)
			{
				val18.movementType = (MovementType)2;
				val18.vertical = true;
				val18.horizontal = false;
			}
			if (string.IsNullOrEmpty(_focusedBuyHeader))
			{
				EnsureBuySelectionVisible(gui, buyList);
				NormalizeBuySelection(buyList, _focusedBuyIndex);
				Transform parent3 = ((Transform)val).parent;
				ScrollRect val19 = ((parent3 != null) ? ((Component)parent3).GetComponent<ScrollRect>() : null);
				if ((Object)(object)val19 != (Object)null && (Object)(object)val19.content == (Object)(object)val)
				{
					Vector2 anchoredPosition = val19.content.anchoredPosition;
					val19.content.anchoredPosition = anchoredPosition;
				}
				NormalizeBuySelection(buyList, FindSelectedBuyIndex(buyList));
			}
			else
			{
				MarkHeaderSelected(_buyHeaderLookup, _focusedBuyHeader);
				ClearBuyItemSelection(buyList);
			}
			try
			{
				int childCount = ((Transform)val).childCount;
				int num9 = Math.Min(childCount, 15);
				for (int num10 = 0; num10 < num9; num10++)
				{
					Transform child2 = ((Transform)val).GetChild(num10);
					RectTransform val20 = (RectTransform)(object)((child2 is RectTransform) ? child2 : null);
					string text2 = (((Object)(object)val20 != (Object)null) ? $"pos={val20.anchoredPosition}" : "");
				}
			}
			catch (Exception ex2)
			{
				HaldorOverhaul.Log.LogWarning((object)("[UIManager] Failed to list buy children: " + ex2.Message));
			}
		}

		private static int FindSelectedBuyIndex(List<GameObject> buyList)
		{
			if (buyList == null)
			{
				return -1;
			}
			for (int i = 0; i < buyList.Count; i++)
			{
				GameObject obj = buyList[i];
				if (obj != null)
				{
					Transform obj2 = obj.transform.Find("selected");
					if (((obj2 != null) ? new bool?(((Component)obj2).gameObject.activeSelf) : null).GetValueOrDefault())
					{
						return i;
					}
				}
			}
			return -1;
		}

		private static void EnsureBuySelectionVisible(StoreGui gui, List<GameObject> buyList)
		{
			if ((Object)(object)gui == (Object)null || buyList == null)
			{
				return;
			}
			if (!string.IsNullOrEmpty(_focusedBuyHeader))
			{
				MarkHeaderSelected(_buyHeaderLookup, _focusedBuyHeader);
				ClearBuyItemSelection(buyList);
				return;
			}
			int num = FindSelectedBuyIndex(buyList);
			int num2 = FindNearestVisibleBuyIndex((num >= 0) ? num : 0, buyList.Count);
			if (_focusedBuyIndex >= 0 && IsBuyIndexVisible(_focusedBuyIndex, buyList.Count))
			{
				StoreGuiPatches.InvokeSelectItem(gui, _focusedBuyIndex, center: false);
				return;
			}
			if (num >= 0 && IsBuyIndexVisible(num, buyList.Count))
			{
				_focusedBuyIndex = num;
				return;
			}
			StoreGuiPatches.InvokeSelectItem(gui, num2, center: false);
			_focusedBuyIndex = num2;
		}

		private static void CacheLocalization()
		{
			if (_localizationCached)
			{
				return;
			}
			_localizationCached = true;
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					Type type = assembly.GetType("Localization");
					if (!(type == null))
					{
						_localizationInstance = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? type.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
						if (_localizationInstance != null)
						{
							_localizeMethod = type.GetMethod("Localize", new Type[1] { typeof(string) });
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				HaldorOverhaul.Log.LogWarning((object)("[UIManager] CacheLocalization failed: " + ex.Message));
			}
		}

		internal static string Localize(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return token;
			}
			CacheLocalization();
			if (_localizeMethod != null && _localizationInstance != null)
			{
				try
				{
					if (_localizeMethod.Invoke(_localizationInstance, new object[1] { token }) is string text && !string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
				catch (Exception ex)
				{
					HaldorOverhaul.Log.LogWarning((object)("[UIManager] Localize failed for '" + token + "': " + ex.Message));
				}
			}
			return (token.StartsWith("$") ? token.Substring(1) : token).Replace('_', ' ');
		}

		private static int CalculateInventoryHash(List<ItemData> items)
		{
			if (items == null || items.Count == 0)
			{
				return 0;
			}
			int num = items.Count;
			for (int i = 0; i < items.Count; i++)
			{
				ItemData val = items[i];
				if (val != null)
				{
					num = (num * 397) ^ val.m_stack.GetHashCode();
					num = (num * 397) ^ val.m_quality.GetHashCode();
					if ((Object)(object)val.m_dropPrefab != (Object)null)
					{
						num = (num * 397) ^ ((Object)val.m_dropPrefab).name.GetHashCode();
					}
					else if (val.m_shared != null && val.m_shared.m_name != null)
					{
						num = (num * 397) ^ val.m_shared.m_name.GetHashCode();
					}
				}
			}
			return num;
		}

		private static void DestroyChildSafe(Transform parent, string name)
		{
			Transform obj = parent.Find(name);
			Object.Destroy((Object)(object)((obj != null) ? ((Component)obj).gameObject : null));
		}

		private static void ClearBuyItemSelection(List<GameObject> buyList = null)
		{
			if (buyList == null)
			{
				buyList = (((Object)(object)_currentStore != (Object)null) ? StoreGuiPatches.GetItemList(_currentStore) : null);
			}
			if (buyList == null)
			{
				return;
			}
			foreach (GameObject buy in buyList)
			{
				if (buy != null)
				{
					Transform obj = buy.transform.Find("selected");
					if (obj != null)
					{
						((Component)obj).gameObject.SetActive(false);
					}
				}
			}
		}

		private static void NormalizeBuySelection(List<GameObject> buyList, int targetIndex = -1)
		{
			if (buyList == null)
			{
				return;
			}
			if (targetIndex < 0)
			{
				targetIndex = FindSelectedBuyIndex(buyList);
			}
			for (int i = 0; i < buyList.Count; i++)
			{
				GameObject obj = buyList[i];
				if (obj != null)
				{
					Transform obj2 = obj.transform.Find("selected");
					if (obj2 != null)
					{
						((Component)obj2).gameObject.SetActive(i == targetIndex);
					}
				}
			}
		}

		private static Transform FindChildRecursive(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (string.Equals(((Object)child).name, name, StringComparison.OrdinalIgnoreCase))
				{
					return child;
				}
				Transform val = FindChildRecursive(child, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		internal static void ResetBuyListScroll(StoreGui gui)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			ScrollRect buyScrollRect = GetBuyScrollRect(gui);
			if ((Object)(object)buyScrollRect != (Object)null)
			{
				buyScrollRect.velocity = Vector2.zero;
			}
		}

		internal static Vector2? GetBuyScrollPosition(StoreGui gui)
		{
			return GetScrollPosition(GetBuyScrollRect(gui));
		}

		internal static float? GetBuyScrollNormalized(StoreGui gui)
		{
			ScrollRect buyScrollRect = GetBuyScrollRect(gui);
			if (buyScrollRect == null)
			{
				return null;
			}
			return buyScrollRect.verticalNormalizedPosition;
		}

		internal static void RestoreBuyScroll(StoreGui gui, Vector2? anchored, float? normalized)
		{
			RestoreScroll(GetBuyScrollRect(gui), anchored, normalized);
		}

		private static ScrollRect GetBuyScrollRect(StoreGui gui)
		{
			if (gui == null)
			{
				return null;
			}
			GameObject rootPanel = gui.m_rootPanel;
			if (rootPanel == null)
			{
				return null;
			}
			Transform obj = rootPanel.transform.Find("ItemList/Items");
			if (obj == null)
			{
				return null;
			}
			return ((Component)obj).GetComponent<ScrollRect>();
		}

		private static ScrollRect GetSellScrollRect()
		{
			RectTransform sellListRoot = _sellListRoot;
			object obj;
			if (sellListRoot == null)
			{
				obj = null;
			}
			else
			{
				Transform parent = ((Transform)sellListRoot).parent;
				obj = ((parent != null) ? ((Component)parent).GetComponent<ScrollRect>() : null);
			}
			if (obj == null)
			{
				ScrollRectEnsureVisible sellItemEnsureVisible = _sellItemEnsureVisible;
				if (sellItemEnsureVisible == null)
				{
					return null;
				}
				obj = ((Component)sellItemEnsureVisible).GetComponent<ScrollRect>();
			}
			return (ScrollRect)obj;
		}

		private static Vector2? GetSellScrollPosition()
		{
			return GetScrollPosition(GetSellScrollRect());
		}

		private static float? GetSellScrollNormalized()
		{
			ScrollRect sellScrollRect = GetSellScrollRect();
			if (sellScrollRect == null)
			{
				return null;
			}
			return sellScrollRect.verticalNormalizedPosition;
		}

		private static void RestoreSellScroll(Vector2? anchored, float? normalized)
		{
			RestoreScroll(GetSellScrollRect(), anchored, normalized);
		}

		private static Vector2? GetScrollPosition(ScrollRect scroll)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (scroll == null)
			{
				return null;
			}
			RectTransform content = scroll.content;
			if (content == null)
			{
				return null;
			}
			return content.anchoredPosition;
		}

		private static void RestoreScroll(ScrollRect scroll, Vector2? anchored, float? normalized)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)scroll == (Object)null))
			{
				if (anchored.HasValue && (Object)(object)scroll.content != (Object)null)
				{
					scroll.content.anchoredPosition = anchored.Value;
				}
				if (normalized.HasValue)
				{
					scroll.verticalNormalizedPosition = normalized.Value;
				}
			}
		}

		internal static void EnsureBuyHeaderVisible(StoreGui gui, string category)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)gui == (Object)null || string.IsNullOrEmpty(category) || !_buyHeaderLookup.TryGetValue(category, out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			Transform transform = value.transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ScrollRect buyScrollRect = GetBuyScrollRect(gui);
			if (!((Object)(object)buyScrollRect == (Object)null) && !((Object)(object)buyScrollRect.content == (Object)null))
			{
				int siblingIndex = value.transform.GetSiblingIndex();
				float num = (float)siblingIndex * _itemSpacing;
				if ((Object)(object)buyScrollRect.viewport != (Object)null)
				{
					Rect rect = buyScrollRect.content.rect;
					float height = ((Rect)(ref rect)).height;
					rect = buyScrollRect.viewport.rect;
					float num2 = Mathf.Max(0f, height - ((Rect)(ref rect)).height);
					num = Mathf.Clamp(num, 0f, num2);
				}
				buyScrollRect.content.anchoredPosition = new Vector2(buyScrollRect.content.anchoredPosition.x, num);
				buyScrollRect.velocity = Vector2.zero;
			}
		}

		internal static void EnsureSellHeaderVisible(string category)
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(category) || !_sellHeaderLookup.TryGetValue(category, out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			Transform transform = value.transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ScrollRect sellScrollRect = GetSellScrollRect();
			if (!((Object)(object)sellScrollRect == (Object)null) && !((Object)(object)sellScrollRect.content == (Object)null))
			{
				int siblingIndex = value.transform.GetSiblingIndex();
				float num = (float)siblingIndex * _itemSpacing;
				if ((Object)(object)sellScrollRect.viewport != (Object)null)
				{
					Rect rect = sellScrollRect.content.rect;
					float height = ((Rect)(ref rect)).height;
					rect = sellScrollRect.viewport.rect;
					float num2 = Mathf.Max(0f, height - ((Rect)(ref rect)).height);
					num = Mathf.Clamp(num, 0f, num2);
				}
				sellScrollRect.content.anchoredPosition = new Vector2(sellScrollRect.content.anchoredPosition.x, num);
				sellScrollRect.velocity = Vector2.zero;
			}
		}

		internal static void UpdateGamepadHints(StoreGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return;
			}
			if (!UsingGamepad())
			{
				if ((Object)(object)_gamepadHintText != (Object)null)
				{
					((Component)_gamepadHintText).gameObject.SetActive(false);
				}
				return;
			}
			EnsureGamepadHint(gui);
			if (!((Object)(object)_gamepadHintText == (Object)null))
			{
				((Component)_gamepadHintText).gameObject.SetActive(true);
				string text = ((_activeTab == ActiveTab.Sell) ? "A: Sell" : "A: Buy");
				_gamepadHintText.text = "LB: Buy tab  RB: Sell tab  LS/D-Pad: Navigate  X: Toggle category  " + text;
			}
		}

		private static void EnsureGamepadHint(StoreGui gui)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_gamepadHintText != (Object)null) && !((Object)(object)gui == (Object)null) && !((Object)(object)gui.m_rootPanel == (Object)null))
			{
				Transform obj = gui.m_rootPanel.transform.Find("topic");
				TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val == (Object)null && (Object)(object)_sellPanel != (Object)null)
				{
					Transform obj2 = _sellPanel.transform.Find("topic");
					val = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
				}
				if (!((Object)(object)val == (Object)null))
				{
					_gamepadHintText = Object.Instantiate<TMP_Text>(val, gui.m_rootPanel.transform);
					((Object)_gamepadHintText).name = "GamepadHints";
					_gamepadHintText.text = "";
					RectTransform rectTransform = _gamepadHintText.rectTransform;
					rectTransform.anchorMin = new Vector2(0.5f, 0f);
					rectTransform.anchorMax = new Vector2(0.5f, 0f);
					rectTransform.pivot = new Vector2(0.5f, 0f);
					rectTransform.anchoredPosition = new Vector2(0f, -30f);
					_gamepadHintText.alignment = (TextAlignmentOptions)514;
					_gamepadHintText.fontSize = Mathf.Max(14f, val.fontSize - 2f);
				}
			}
		}

		private static List<NavigationEntry> BuildBuyNavigation(List<GameObject> buyList)
		{
			List<NavigationEntry> list = new List<NavigationEntry>();
			if (buyList == null || buyList.Count == 0)
			{
				return list;
			}
			foreach (string item in _buyCategoryOrder)
			{
				if (_buyHeaderLookup.TryGetValue(item, out var value) && (Object)(object)value != (Object)null)
				{
					list.Add(new NavigationEntry
					{
						Category = item,
						Index = -1,
						IsHeader = true
					});
				}
				if (_buyCategoryCollapsed.TryGetValue(item, out var value2) && value2)
				{
					continue;
				}
				for (int i = 0; i < buyList.Count; i++)
				{
					if (IsBuyIndexVisible(i, buyList.Count))
					{
						string buyCategoryForIndex = GetBuyCategoryForIndex(i);
						if (string.Equals(buyCategoryForIndex, item, StringComparison.OrdinalIgnoreCase))
						{
							list.Add(new NavigationEntry
							{
								Category = item,
								Index = i,
								IsHeader = false
							});
						}
					}
				}
			}
			return list;
		}

		private static List<NavigationEntry> BuildSellNavigation()
		{
			List<NavigationEntry> list = new List<NavigationEntry>();
			foreach (string item in _sellCategoryOrder)
			{
				if (_sellHeaderLookup.TryGetValue(item, out var value) && (Object)(object)value != (Object)null)
				{
					list.Add(new NavigationEntry
					{
						Category = item,
						Index = -1,
						IsHeader = true
					});
				}
				bool value2;
				bool flag = _sellCategoryCollapsed.TryGetValue(item, out value2) && value2;
				for (int i = 0; i < SellRows.Count; i++)
				{
					SellRow sellRow = SellRows[i];
					if (sellRow != null && str