Decompiled source of RPGEquipment v0.2.9

BepInEx/plugins/RPGEquipment/RPGEquipment.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "Coded with the assistance of ChatGPT 6.0; packaged with OpenAI Codex.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RPGEquipment;

internal static class Accessories
{
	internal struct WornItems
	{
		internal struct Enumerator
		{
			internal WornItems Data;

			internal int Index;

			public ItemData Current => Data.Items[Index];

			public bool MoveNext()
			{
				if (Data.Items == null)
				{
					return false;
				}
				while (++Index < Data.Items.Count)
				{
					ItemData val = Data.Items[Index];
					if (val.m_equipped && IsAccessory(val) && !object.ReferenceEquals(val, Data.UtilityItem) && !object.ReferenceEquals(val, Data.TrinketItem))
					{
						return true;
					}
				}
				return false;
			}
		}

		internal List<ItemData> Items;

		internal ItemData UtilityItem;

		internal ItemData TrinketItem;

		public Enumerator GetEnumerator()
		{
			return new Enumerator
			{
				Data = this,
				Index = -1
			};
		}
	}

	internal static readonly FieldInfo Utility = AccessTools.Field(typeof(Humanoid), "m_utilityItem");

	internal static readonly FieldInfo Trinket = AccessTools.Field(typeof(Humanoid), "m_trinketItem");

	private static readonly Func<Humanoid, ItemData, bool> hasSet = (Func<Humanoid, ItemData, bool>)Delegate.CreateDelegate(typeof(Func<Humanoid, ItemData, bool>), AccessTools.Method(typeof(Humanoid), "HaveSetEffect", (Type[])null, (Type[])null));

	private static readonly Action<Humanoid, ItemData, float> drain = (Action<Humanoid, ItemData, float>)Delegate.CreateDelegate(typeof(Action<Humanoid, ItemData, float>), AccessTools.Method(typeof(Humanoid), "DrainEquipedItemDurability", (Type[])null, (Type[])null));

	internal static bool IsAccessory(ItemData item)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Invalid comparison between Unknown and I4
		if (item != null)
		{
			if ((int)item.m_shared.m_itemType != 18)
			{
				return (int)item.m_shared.m_itemType == 24;
			}
			return true;
		}
		return false;
	}

	internal static WornItems All(Humanoid h)
	{
		return new WornItems
		{
			Items = ((!Plugin.Applies(h) || h.GetInventory() == null) ? null : h.GetInventory().GetAllItems())
		};
	}

	internal static WornItems Extra(Humanoid h)
	{
		WornItems result = All(h);
		if (result.Items != null)
		{
			object? value = Utility.GetValue(h);
			result.UtilityItem = (ItemData)((value is ItemData) ? value : null);
			object? value2 = Trinket.GetValue(h);
			result.TrinketItem = (ItemData)((value2 is ItemData) ? value2 : null);
		}
		return result;
	}

	internal static void KeepPrevious(Humanoid h, ItemData previous, bool effects)
	{
		if (!Plugin.Applies(h))
		{
			h.UnequipItem(previous, effects);
		}
	}

	internal static void AddEffects(Humanoid h, HashSet<StatusEffect> desired)
	{
		WornItems.Enumerator enumerator = All(h).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			if ((Object)(object)current.m_shared.m_equipStatusEffect != (Object)null)
			{
				desired.Add(current.m_shared.m_equipStatusEffect);
			}
			if ((Object)(object)current.m_shared.m_setStatusEffect != (Object)null && hasSet(h, current))
			{
				desired.Add(current.m_shared.m_setStatusEffect);
			}
		}
	}

	internal static void Drain(Humanoid h, float delta)
	{
		WornItems wornItems = Extra(h);
		if (wornItems.Items == null)
		{
			return;
		}
		for (int num = wornItems.Items.Count - 1; num >= 0; num--)
		{
			ItemData val = wornItems.Items[num];
			if (val.m_equipped && IsAccessory(val) && val.m_shared.m_useDurability && !object.ReferenceEquals(val, wornItems.UtilityItem) && !object.ReferenceEquals(val, wornItems.TrinketItem))
			{
				drain(h, val, delta);
			}
		}
	}

	internal static void AddArmor(SEMan seman, ref float armor, Player player)
	{
		if ((Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.UseExtraArmourPoints.Value)
		{
			WornItems.Enumerator enumerator = All((Humanoid)(object)player).GetEnumerator();
			while (enumerator.MoveNext())
			{
				ItemData current = enumerator.Current;
				armor += current.GetArmor();
			}
		}
		seman.ApplyArmorMods(ref armor);
	}

	internal static void Reequip(Player player)
	{
		ItemData[] array = ((Humanoid)player).GetInventory().GetEquippedItems().ToArray();
		ItemData[] array2 = array;
		foreach (ItemData val in array2)
		{
			val.m_equipped = false;
		}
		int num = 0;
		ItemData[] array3 = array;
		foreach (ItemData val2 in array3)
		{
			if (((Humanoid)player).EquipItem(val2, false))
			{
				num++;
			}
			else
			{
				Plugin.Log("Saved equipment remains in backpack (could not equip): " + Plugin.Prefab(val2));
			}
		}
		Plugin.Log("Restored equipped items " + num + "/" + array.Length + "; no item was dropped by re-equipping.");
	}

	internal static void UnequipAccessories(Humanoid h)
	{
		WornItems.Enumerator enumerator = All(h).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			h.UnequipItem(current, false);
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "EquipItem")]
internal static class EquipPatch
{
	private static bool Prefix(Humanoid __instance, ItemData __0, ref bool __result)
	{
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Invalid comparison between Unknown and I4
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.Applies(__instance) || !Accessories.IsAccessory(__0))
		{
			return true;
		}
		int num = 0;
		bool flag = false;
		ItemData objB = EquipmentActions.ReplacementFor(__instance, __0);
		Accessories.WornItems.Enumerator enumerator = Accessories.All(__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			if (object.ReferenceEquals(current, __0))
			{
				__result = true;
				return false;
			}
			if (!object.ReferenceEquals(current, objB) && current.m_shared.m_itemType == __0.m_shared.m_itemType)
			{
				num++;
				if (Plugin.Prefab(current) == Plugin.Prefab(__0))
				{
					flag = true;
				}
			}
		}
		int limit = (((int)__0.m_shared.m_itemType == 18) ? Plugin.Instance.UtilitySlots.Value : Plugin.Instance.TrinketSlots.Value);
		if (!Rules.MayEquip(num, limit, flag, Plugin.Instance.DuplicateItems.Value))
		{
			__result = false;
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Message(flag ? "That accessory is already worn." : "All slots of this type are occupied. Unequip one first.");
			}
			return false;
		}
		return true;
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = instructions.ToList();
		MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "UnequipItem", (Type[])null, (Type[])null);
		int num = 0;
		for (int i = 2; i < list.Count; i++)
		{
			if (CodeInstructionExtensions.Calls(list[i], methodInfo) && list[i - 2].opcode == OpCodes.Ldfld && (object.Equals(list[i - 2].operand, Accessories.Utility) || object.Equals(list[i - 2].operand, Accessories.Trinket)))
			{
				list[i].opcode = OpCodes.Call;
				list[i].operand = AccessTools.Method(typeof(Accessories), "KeepPrevious", (Type[])null, (Type[])null);
				num++;
			}
		}
		if (num != 2)
		{
			throw new InvalidOperationException("Expected exactly two native accessory replacement calls.");
		}
		return list;
	}
}
[HarmonyPatch(typeof(Humanoid), "IsItemEquiped")]
internal static class EquippedPatch
{
	private static void Postfix(Humanoid __instance, ItemData __0, ref bool __result)
	{
		if (Plugin.Applies(__instance) && Accessories.IsAccessory(__0) && __0.m_equipped && __instance.GetInventory().ContainsItem(__0))
		{
			__result = true;
		}
	}
}
[HarmonyPatch(typeof(Player), "EquipInventoryItems")]
internal static class ReequipPatch
{
	private static bool Prefix(Player __instance)
	{
		if (!Plugin.Applies((Humanoid)(object)__instance))
		{
			return true;
		}
		Accessories.Reequip(__instance);
		return false;
	}
}
[HarmonyPatch(typeof(Humanoid), "UpdateEquipmentStatusEffects")]
internal static class EffectsPatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Expected O, but got Unknown
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Expected O, but got Unknown
		List<CodeInstruction> list = instructions.ToList();
		FieldInfo tracked = AccessTools.Field(typeof(Humanoid), "m_equipmentStatusEffects");
		int num = list.FindIndex((CodeInstruction i) => i.opcode == OpCodes.Ldfld && object.Equals(i.operand, tracked));
		if (num < 1 || list[num - 1].opcode != OpCodes.Ldarg_0)
		{
			throw new InvalidOperationException("Unsupported equipment effect reconciliation layout.");
		}
		CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
		val.labels.AddRange(list[num - 1].labels);
		list[num - 1].labels.Clear();
		list.InsertRange(num - 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
		{
			val,
			new CodeInstruction(OpCodes.Ldloc_0, (object)null),
			new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Accessories), "AddEffects", (Type[])null, (Type[])null))
		});
		return list;
	}
}
[HarmonyPatch(typeof(Humanoid), "GetSetCount")]
internal static class SetCountPatch
{
	private static void Postfix(Humanoid __instance, string __0, ref int __result)
	{
		Accessories.WornItems.Enumerator enumerator = Accessories.Extra(__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			if (current.m_shared.m_setName == __0)
			{
				__result++;
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdateModifiers")]
internal static class ModifiersPatch
{
	private static void Postfix(Player __instance, FieldInfo[] ___s_equipmentModifierSourceFields, float[] ___m_equipmentModifierValues)
	{
		if (!Plugin.Applies((Humanoid)(object)__instance) || ___s_equipmentModifierSourceFields == null)
		{
			return;
		}
		Accessories.WornItems.Enumerator enumerator = Accessories.Extra((Humanoid)(object)__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			for (int i = 0; i < Math.Min(___s_equipmentModifierSourceFields.Length, ___m_equipmentModifierValues.Length); i++)
			{
				___m_equipmentModifierValues[i] += (float)___s_equipmentModifierSourceFields[i].GetValue(current.m_shared);
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "GetEquipmentEitrRegenModifier")]
internal static class EitrPatch
{
	private static void Postfix(Player __instance, ref float __result)
	{
		object value = Accessories.Utility.GetValue(__instance);
		Accessories.WornItems.Enumerator enumerator = Accessories.All((Humanoid)(object)__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			if (!object.ReferenceEquals(current, value))
			{
				__result += current.m_shared.m_eitrRegenModifier;
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "ApplyArmorDamageMods")]
internal static class ResistPatch
{
	private static void Postfix(Player __instance, ref DamageModifiers __0)
	{
		Accessories.WornItems.Enumerator enumerator = Accessories.All((Humanoid)(object)__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			((DamageModifiers)(ref __0)).Apply(current.m_shared.m_damageModifiers);
		}
	}
}
[HarmonyPatch(typeof(Player), "GetBodyArmor")]
internal static class ArmorPatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>();
		int num = 0;
		foreach (CodeInstruction instruction in instructions)
		{
			if (CodeInstructionExtensions.Calls(instruction, AccessTools.Method(typeof(SEMan), "ApplyArmorMods", (Type[])null, (Type[])null)))
			{
				CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
				val.labels.AddRange(instruction.labels);
				instruction.labels.Clear();
				list.Add(val);
				instruction.opcode = OpCodes.Call;
				instruction.operand = AccessTools.Method(typeof(Accessories), "AddArmor", (Type[])null, (Type[])null);
				num++;
			}
			list.Add(instruction);
		}
		if (num != 1)
		{
			throw new InvalidOperationException("Unsupported armor calculation layout.");
		}
		return list;
	}
}
[HarmonyPatch(typeof(Humanoid), "GetEquipmentWeight")]
internal static class WeightPatch
{
	private static void Postfix(Humanoid __instance, ref float __result)
	{
		Accessories.WornItems.Enumerator enumerator = Accessories.Extra(__instance).GetEnumerator();
		while (enumerator.MoveNext())
		{
			ItemData current = enumerator.Current;
			__result += current.m_shared.m_weight;
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "UpdateEquipment")]
internal static class DurabilityPatch
{
	private static void Postfix(Humanoid __instance, float __0)
	{
		Accessories.Drain(__instance, __0);
	}
}
[HarmonyPatch(typeof(Humanoid), "UnequipAllItems")]
internal static class UnequipAllPatch
{
	private static void Postfix(Humanoid __instance)
	{
		Accessories.UnequipAccessories(__instance);
	}
}
[HarmonyPatch(typeof(Player), "UnequipDeathDropItems")]
internal static class DeathPatch
{
	private static void Postfix(Player __instance)
	{
		Accessories.UnequipAccessories((Humanoid)(object)__instance);
	}
}
internal static class AutoShield
{
	internal const string PreferenceKey = "au.tyvalheim.rpgequipment.preferredShield";

	private static Player pendingPlayer;

	private static ItemData pendingWeapon;

	private static bool hotbarActive;

	private static bool queueActive;

	private static bool applying;

	private static bool Enabled(Player p)
	{
		if (Plugin.AutoShieldEnabled && (Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer && !WeaponSets.Conflict)
		{
			return !WeaponSets.Switching;
		}
		return false;
	}

	internal static void Cancel()
	{
		pendingPlayer = null;
		pendingWeapon = null;
		hotbarActive = false;
		queueActive = false;
	}

	internal static ItemData Preferred(Player p)
	{
		if (!((Object)(object)p != (Object)null) || !p.m_customData.TryGetValue("au.tyvalheim.rpgequipment.preferredShield", out var value))
		{
			return null;
		}
		return WeaponSetRules.Unique(((Humanoid)p).GetInventory().GetAllItems(), WeaponSets.Identity, value);
	}

	internal static void Remember(Player p, ItemData shield)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Invalid comparison between Unknown and I4
		if (Enabled(p) && shield != null && (int)shield.m_shared.m_itemType == 5 && ((Humanoid)p).GetInventory().ContainsItem(shield))
		{
			string text = WeaponSets.EnsureIdentity(p, shield);
			if (!p.m_customData.TryGetValue("au.tyvalheim.rpgequipment.preferredShield", out var value) || !(value == text))
			{
				p.m_customData["au.tyvalheim.rpgequipment.preferredShield"] = text;
				InventorySafety.Changed(((Humanoid)p).GetInventory());
			}
		}
	}

	internal static void BeginHotbar(Player p, int index)
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Invalid comparison between Unknown and I4
		if ((Object)(object)p != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		Cancel();
		if (Enabled(p) && Plugin.SetInputAllowed(p) && index >= 1 && index <= 8)
		{
			if (!p.m_customData.ContainsKey("au.tyvalheim.rpgequipment.preferredShield"))
			{
				Remember(p, ((Humanoid)p).LeftItem);
			}
			ItemData itemAt = ((Humanoid)p).GetInventory().GetItemAt(index - 1, 0);
			if (itemAt != null && (int)itemAt.m_shared.m_itemType == 3 && !itemAt.m_equipped && !p.IsEquipActionQueued(itemAt) && WeaponSets.Usable(p, itemAt))
			{
				pendingPlayer = p;
				pendingWeapon = itemAt;
				hotbarActive = true;
			}
		}
	}

	internal static void EndHotbar(Player p, bool failed)
	{
		if (!((Object)(object)p != (Object)(object)pendingPlayer))
		{
			hotbarActive = false;
			if (failed || !p.IsEquipActionQueued(pendingWeapon))
			{
				Cancel();
			}
		}
	}

	internal static void BeginQueue(Player p)
	{
		if (!((Object)(object)p != (Object)(object)pendingPlayer))
		{
			if (!Enabled(p) || !Plugin.SetInputAllowed(p) || !p.IsEquipActionQueued(pendingWeapon))
			{
				Cancel();
			}
			else
			{
				queueActive = true;
			}
		}
	}

	internal static void EndQueue(Player p)
	{
		if (!((Object)(object)p != (Object)(object)pendingPlayer))
		{
			queueActive = false;
			if (!p.IsEquipActionQueued(pendingWeapon))
			{
				Cancel();
			}
		}
	}

	internal static void Equipped(Player p, ItemData item, bool success)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Invalid comparison between Unknown and I4
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Invalid comparison between Unknown and I4
		if (applying || !Enabled(p) || item == null)
		{
			return;
		}
		if (success && object.ReferenceEquals(((Humanoid)p).LeftItem, item))
		{
			Remember(p, item);
		}
		if ((Object)(object)p != (Object)(object)pendingPlayer || !object.ReferenceEquals(item, pendingWeapon) || (!hotbarActive && !queueActive))
		{
			return;
		}
		Cancel();
		if (!success || !object.ReferenceEquals(((Humanoid)p).RightItem, item) || !item.m_equipped || (int)item.m_shared.m_itemType != 3 || !Plugin.SetInputAllowed(p) || ((Character)p).InAttack() || ((Character)p).InDodge() || (((Character)p).IsSwimming() && !((Character)p).IsOnGround()))
		{
			return;
		}
		ItemData val = Preferred(p);
		if (val == null || (int)val.m_shared.m_itemType != 5 || !WeaponSets.Usable(p, val) || object.ReferenceEquals(((Humanoid)p).LeftItem, val))
		{
			return;
		}
		applying = true;
		try
		{
			if (!((Humanoid)p).EquipItem(val, true))
			{
				Plugin.Log("Preferred shield was rejected by native equip; selected weapon retained.");
			}
		}
		catch (Exception ex)
		{
			Plugin.Log("Preferred shield equip failed: " + ex.Message);
		}
		finally
		{
			applying = false;
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "EquipItem")]
internal static class AutoShieldEquipPatch
{
	[HarmonyPriority(0)]
	private static void Postfix(Humanoid __instance, ItemData __0, bool __result)
	{
		AutoShield.Equipped((Player)(object)((__instance is Player) ? __instance : null), __0, __result);
	}
}
[HarmonyPatch(typeof(Player), "UpdateActionQueue")]
internal static class AutoShieldQueuePatch
{
	private static void Prefix(Player __instance)
	{
		AutoShield.BeginQueue(__instance);
	}

	private static void Finalizer(Player __instance)
	{
		AutoShield.EndQueue(__instance);
	}
}
[HarmonyPatch(typeof(Humanoid), "HideHandItems")]
internal static class AutoShieldStowPatch
{
	private static void Prefix(Humanoid __instance)
	{
		if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
		{
			AutoShield.Cancel();
		}
	}
}
[HarmonyPatch(typeof(Player), "RemoveEquipAction")]
internal static class AutoShieldCancelPatch
{
	private static void Prefix(Player __instance)
	{
		if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
		{
			AutoShield.Cancel();
		}
	}
}
[HarmonyPatch(typeof(Player), "ClearActionQueue")]
internal static class AutoShieldClearPatch
{
	private static void Prefix(Player __instance)
	{
		if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
		{
			AutoShield.Cancel();
		}
	}
}
internal static class EquipmentActions
{
	private static Player replacingPlayer;

	private static ItemData replacingIncoming;

	private static ItemData replacingOutgoing;

	internal static ItemData ReplacementFor(Humanoid player, ItemData incoming)
	{
		if (!object.ReferenceEquals(player, replacingPlayer) || !object.ReferenceEquals(incoming, replacingIncoming))
		{
			return null;
		}
		return replacingOutgoing;
	}

	private static bool CanChange(Player player)
	{
		if ((Object)(object)player != (Object)null && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InAttack() && !((Character)player).InDodge())
		{
			if (((Character)player).IsSwimming())
			{
				return ((Character)player).IsOnGround();
			}
			return true;
		}
		return false;
	}

	private static void ClearQueue(Player player, ItemType type)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
		{
			if (allItem.m_shared.m_itemType == type)
			{
				((Humanoid)player).RemoveEquipAction(allItem);
			}
		}
	}

	internal static bool Equip(Player player, ItemData incoming, ItemData outgoing, ItemType type)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		if (incoming == null || incoming.m_shared.m_itemType != type)
		{
			Plugin.Message("That item does not match this equipment slot.");
			return false;
		}
		if (!CanChange(player))
		{
			Plugin.Message("Cannot change equipment during this action.");
			return false;
		}
		if (!((Humanoid)player).GetInventory().ContainsItem(incoming))
		{
			return false;
		}
		if (outgoing != null && (!((Humanoid)player).GetInventory().ContainsItem(outgoing) || !outgoing.m_equipped || outgoing.m_shared.m_itemType != type))
		{
			outgoing = null;
		}
		ClearQueue(player, type);
		Player val = replacingPlayer;
		ItemData val2 = replacingIncoming;
		ItemData val3 = replacingOutgoing;
		replacingPlayer = player;
		replacingIncoming = incoming;
		replacingOutgoing = outgoing;
		bool flag;
		try
		{
			flag = Rules.CommitReplacement(incoming.m_equipped, object.ReferenceEquals(incoming, outgoing), () => ((Humanoid)player).EquipItem(incoming, true), delegate
			{
				if (outgoing != null && outgoing.m_equipped)
				{
					((Humanoid)player).UnequipItem(outgoing, false);
				}
			});
		}
		finally
		{
			replacingPlayer = val;
			replacingIncoming = val2;
			replacingOutgoing = val3;
		}
		if (!flag)
		{
			Plugin.Message("Could not equip that item. Check durability and the game's equipment restrictions.");
		}
		return flag;
	}

	internal static bool Unequip(Player player, ItemData item)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		if (!CanChange(player))
		{
			Plugin.Message("Cannot change equipment during this action.");
			return false;
		}
		if (item == null || !((Humanoid)player).GetInventory().ContainsItem(item) || !item.m_equipped)
		{
			return false;
		}
		ClearQueue(player, item.m_shared.m_itemType);
		((Humanoid)player).UnequipItem(item, true);
		return !item.m_equipped;
	}
}
public sealed class PanelDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IEventSystemHandler
{
	internal RectTransform Target;

	internal Plugin Plugin;

	private Vector2 start;

	private Vector2 mouse;

	public void OnBeginDrag(PointerEventData data)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		start = Target.anchoredPosition;
		mouse = data.position;
	}

	public void OnDrag(PointerEventData data)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		Canvas componentInParent = ((Component)Target).GetComponentInParent<Canvas>();
		Target.anchoredPosition = start + (data.position - mouse) / (((Object)(object)componentInParent == (Object)null) ? 1f : componentInParent.scaleFactor);
	}

	public void OnEndDrag(PointerEventData data)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		Plugin.PanelX.Value = Target.anchoredPosition.x;
		Plugin.PanelY.Value = 0f - Target.anchoredPosition.y;
	}
}
internal sealed class EquipmentPanel : IDisposable
{
	private sealed class Slot
	{
		internal ItemType Type;

		internal int Index;

		internal int Quick = -1;

		internal int Set = -1;

		internal bool Offhand;

		internal bool Ammo;

		internal bool Ghost;

		internal string Label;

		internal Image Icon;

		internal TMP_Text Text;

		internal TMP_Text KeyText;

		internal InventoryElement Element;

		internal UITooltip Tooltip;

		internal ItemData Item;

		internal ItemData DrawnItem;

		internal int Stack = -1;

		internal int Quality = -1;

		internal int Variant = -1;

		internal bool Equipped;

		internal bool Hovered;

		internal float Durability = -1f;

		internal float TooltipDue;

		internal string Key = "";
	}

	private Plugin plugin;

	private RectTransform root;

	private RectTransform picker;

	private TMP_FontAsset font;

	private GameObject tooltipPrefab;

	private Image backgroundStyle;

	private InventoryElement nativeSlot;

	private Vector2 cellSize;

	private float cellPitch;

	private float panelWidth;

	private Vector3 nativeScale;

	private int dragSlot = -1;

	private int suppressClickFrame = -1;

	private ItemData dragItem;

	private Image dragIcon;

	private TMP_Text stats;

	private TMP_Text heading;

	private readonly TMP_Text[] setLabels = (TMP_Text[])(object)new TMP_Text[2];

	private Player player;

	private float nextUpdate;

	private float nextStats;

	private int lastRows = -1;

	private int lastKeys = -1;

	private int lastScreenWidth;

	private int lastScreenHeight;

	private Vector2 lastPosition;

	private readonly Slot[] quickSlots = new Slot[3];

	private readonly List<Slot> slots = new List<Slot>();

	private Slot selecting;

	private int page;

	private int bindingSlot = -1;

	private int keyPage;

	private bool ctrl;

	private bool alt;

	private bool shift;

	private string bindingMessage = "Choose a key with the mouse.";

	private static readonly Color Gold = new Color(0.85f, 0.7f, 0.4f);

	private static readonly Color Muted = new Color(0.85f, 0.8f, 0.68f);

	internal InventoryGui Gui { get; private set; }

	internal EquipmentPanel(InventoryGui gui, Plugin config)
	{
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: 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_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0232: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: 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_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0356: Unknown result type (might be due to invalid IL or missing references)
		//IL_039b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0690: Unknown result type (might be due to invalid IL or missing references)
		//IL_075b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0826: Unknown result type (might be due to invalid IL or missing references)
		//IL_084f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0886: Unknown result type (might be due to invalid IL or missing references)
		//IL_090f: Unknown result type (might be due to invalid IL or missing references)
		Gui = gui;
		plugin = config;
		font = gui.m_playerName.font;
		UITooltip val = ((IEnumerable<UITooltip>)((Component)gui).GetComponentsInChildren<UITooltip>(true)).FirstOrDefault((Func<UITooltip, bool>)((UITooltip t) => (Object)(object)t.m_tooltipPrefab != (Object)null));
		if ((Object)(object)val != (Object)null)
		{
			tooltipPrefab = val.m_tooltipPrefab;
		}
		Image[] componentsInChildren = ((Component)gui.m_player).GetComponentsInChildren<Image>(true);
		backgroundStyle = ((Component)gui.m_player).GetComponent<Image>();
		if ((Object)(object)backgroundStyle == (Object)null || (Object)(object)backgroundStyle.sprite == (Object)null)
		{
			backgroundStyle = ((IEnumerable<Image>)componentsInChildren).FirstOrDefault((Func<Image, bool>)((Image i) => (Object)(object)i.sprite != (Object)null && (((Object)i).name.ToLowerInvariant().Contains("bkg") || ((Object)i).name.ToLowerInvariant().Contains("background"))));
		}
		if ((Object)(object)backgroundStyle == (Object)null)
		{
			backgroundStyle = ((IEnumerable<Image>)componentsInChildren).FirstOrDefault((Func<Image, bool>)((Image i) => (Object)(object)i.sprite != (Object)null && (int)i.type == 1));
		}
		nativeSlot = gui.m_playerGrid.m_elementPrefab.GetComponent<InventoryElement>();
		if ((Object)(object)nativeSlot == (Object)null)
		{
			throw new InvalidOperationException("Native inventory slot prefab unavailable.");
		}
		Rect rect = ((RectTransform)((Component)nativeSlot).transform).rect;
		cellSize = ((Rect)(ref rect)).size;
		cellPitch = gui.m_playerGrid.m_elementSpace;
		if (cellSize.x <= 0f || cellSize.y <= 0f || cellPitch <= 0f)
		{
			throw new InvalidOperationException("Native slot dimensions unavailable.");
		}
		panelWidth = Math.Max(300f, 24f + cellPitch * 2f + cellSize.x);
		Vector3 lossyScale = ((Transform)gui.m_player).parent.lossyScale;
		Vector3 lossyScale2 = ((Transform)gui.m_playerGrid.m_gridRoot).lossyScale;
		nativeScale = new Vector3(lossyScale2.x / lossyScale.x, lossyScale2.y / lossyScale.y, 1f);
		Plugin.Log(string.Concat("Panel native slots: size=", cellSize, "; pitch=", cellPitch, "; background=", ((Object)(object)backgroundStyle == (Object)null) ? "brown fallback" : ((Object)backgroundStyle).name));
		root = Box(((Transform)gui.m_player).parent, "RPG Equipment", config.PanelX.Value, config.PanelY.Value, panelWidth, 600f, new Color(0.26f, 0.17f, 0.1f, 0.98f));
		Style(((Component)root).GetComponent<Image>(), backgroundStyle);
		((Transform)root).localScale = nativeScale;
		RectTransform val2 = Box((Transform)(object)root, "titlebar", 8f, 6f, panelWidth - 16f, 28f, new Color(0f, 0f, 0f, 0f));
		heading = Text((Transform)(object)val2, "Equipment", 6f, 1f, 150f, 25f, 20, Gold);
		stats = Text((Transform)(object)val2, "", panelWidth - 146f, 5f, 122f, 20f, 12, Muted);
		PanelDrag panelDrag = ((Component)val2).gameObject.AddComponent<PanelDrag>();
		panelDrag.Target = root;
		panelDrag.Plugin = plugin;
		for (int num = 0; num < 2; num++)
		{
			int set = num;
			Button val3 = Button((Transform)(object)root, "", 12f + (float)num * (panelWidth - 24f) / 2f, 38f, (panelWidth - 28f) / 2f, 28f, delegate
			{
				if ((Object)(object)player != (Object)null)
				{
					WeaponSets.Switch(player, set);
					RefreshNow();
				}
			});
			setLabels[num] = Text(((Component)val3).transform, "Equip set " + (num + 1), 4f, 3f, (panelWidth - 36f) / 2f, 23f, 12, Gold);
		}
		float num2 = 77f;
		float num3 = cellSize.y + 27f;
		AddSlot("Selected ammo", (ItemType)9, 0, 12f, num2);
		slots[slots.Count - 1].Ammo = true;
		AddSlot("Head", (ItemType)6, 0, 12f + cellPitch, num2);
		AddSlot("Cape", (ItemType)17, 0, 12f + cellPitch * 2f, num2);
		AddWeaponSlot("Set 1 primary", 0, offhand: false, 12f, num2 + num3);
		AddSlot("Chest", (ItemType)7, 0, 12f + cellPitch, num2 + num3);
		AddWeaponSlot("Set 1 off-hand", 0, offhand: true, 12f + cellPitch * 2f, num2 + num3);
		AddWeaponSlot("Set 2 primary", 1, offhand: false, 12f, num2 + num3 * 2f);
		AddSlot("Legs", (ItemType)11, 0, 12f + cellPitch, num2 + num3 * 2f);
		AddWeaponSlot("Set 2 off-hand", 1, offhand: true, 12f + cellPitch * 2f, num2 + num3 * 2f);
		float num4 = num2 + num3 * 3f;
		Text((Transform)(object)root, "Trinkets / Totems", 12f, num4, panelWidth - 24f, 18f, 13, Gold);
		for (int num5 = 0; num5 < plugin.TrinketSlots.Value; num5++)
		{
			AddSlot("Trinket " + (num5 + 1), (ItemType)24, num5, 12f + (float)(num5 % 3) * cellPitch, num4 + 22f + (float)(num5 / 3) * cellPitch);
		}
		float num6 = num4 + 22f + (float)Math.Ceiling((float)plugin.TrinketSlots.Value / 3f) * cellPitch + 5f;
		Text((Transform)(object)root, "Utilities", 12f, num6, panelWidth - 24f, 18f, 13, Gold);
		for (int num7 = 0; num7 < plugin.UtilitySlots.Value; num7++)
		{
			AddSlot("Utility " + (num7 + 1), (ItemType)18, num7, 12f + (float)(num7 % 3) * cellPitch, num6 + 22f + (float)(num7 / 3) * cellPitch);
		}
		float num8 = num6 + 22f + (float)Math.Ceiling((float)plugin.UtilitySlots.Value / 3f) * cellPitch + 7f;
		root.sizeDelta = new Vector2(panelWidth, num8 + 22f + cellSize.y + 28f);
		Text((Transform)(object)root, "Quick slots", 15f, num8, 130f, 18f, 13, Gold);
		Text((Transform)(object)root, "Right-click: set key", 135f, num8 + 2f, panelWidth - 147f, 16f, 10, Muted);
		for (int num9 = 0; num9 < 3; num9++)
		{
			AddSlot("Quick " + (num9 + 1), (ItemType)0, num9, 12f + (float)num9 * cellPitch, num8 + 22f, num9);
		}
		Text((Transform)(object)root, "Sets: click to equip / right-click to assign", 12f, num8 + 24f + cellSize.y, panelWidth - 24f, 18f, 10, Muted);
		((Component)root).gameObject.SetActive(false);
	}

	private RectTransform Box(Transform parent, string name, float x, float y, float w, float h, Color colour)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected O, but got Unknown
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name, new Type[3]
		{
			typeof(RectTransform),
			typeof(CanvasRenderer),
			typeof(Image)
		});
		RectTransform val2 = (RectTransform)val.transform;
		((Transform)val2).SetParent(parent, false);
		Vector2 val3 = (val2.pivot = new Vector2(0f, 1f));
		Vector2 anchorMin = (val2.anchorMax = val3);
		val2.anchorMin = anchorMin;
		val2.anchoredPosition = new Vector2(x, 0f - y);
		val2.sizeDelta = new Vector2(w, h);
		((Graphic)val.GetComponent<Image>()).color = colour;
		return val2;
	}

	private TMP_Text Text(Transform parent, string value, float x, float y, float w, float h, int size, Color colour)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: 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)
		GameObject val = new GameObject("Label", new Type[1] { typeof(RectTransform) });
		val.SetActive(false);
		RectTransform val2 = (RectTransform)val.transform;
		((Transform)val2).SetParent(parent, false);
		Vector2 val3 = (val2.pivot = new Vector2(0f, 1f));
		Vector2 anchorMin = (val2.anchorMax = val3);
		val2.anchorMin = anchorMin;
		val2.anchoredPosition = new Vector2(x, 0f - y);
		val2.sizeDelta = new Vector2(w, h);
		TextMeshProUGUI val6 = val.AddComponent<TextMeshProUGUI>();
		((TMP_Text)val6).font = font;
		((TMP_Text)val6).text = value;
		((TMP_Text)val6).fontSize = size;
		((Graphic)val6).color = colour;
		((Graphic)val6).raycastTarget = false;
		((TMP_Text)val6).overflowMode = (TextOverflowModes)1;
		val.SetActive(true);
		return (TMP_Text)(object)val6;
	}

	private static void Style(Image image, Image source)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)source == (Object)null) && !((Object)(object)source.sprite == (Object)null))
		{
			image.sprite = source.sprite;
			image.type = source.type;
			((Graphic)image).color = ((Graphic)source).color;
			((Graphic)image).material = ((Graphic)source).material;
			image.pixelsPerUnitMultiplier = source.pixelsPerUnitMultiplier;
		}
	}

	private Button Button(Transform parent, string label, float x, float y, float w, float h, Action action)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = Box(parent, label, x, y, w, h, Color.white);
		Button val2 = ((Component)val).gameObject.AddComponent<Button>();
		((Selectable)val2).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>();
		((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
		{
			action();
		});
		ColorBlock colors = ((Selectable)val2).colors;
		((ColorBlock)(ref colors)).normalColor = new Color(0.22f, 0.16f, 0.11f, 1f);
		((ColorBlock)(ref colors)).highlightedColor = new Color(0.36f, 0.27f, 0.17f, 1f);
		((ColorBlock)(ref colors)).pressedColor = new Color(0.13f, 0.09f, 0.06f, 1f);
		((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).highlightedColor;
		((ColorBlock)(ref colors)).disabledColor = new Color(0.12f, 0.1f, 0.08f, 1f);
		((ColorBlock)(ref colors)).colorMultiplier = 1f;
		((ColorBlock)(ref colors)).fadeDuration = 0.08f;
		((Selectable)val2).colors = colors;
		Navigation navigation = ((Selectable)val2).navigation;
		((Navigation)(ref navigation)).mode = (Mode)0;
		((Selectable)val2).navigation = navigation;
		if (label.Length > 0)
		{
			TMP_Text val3 = Text((Transform)(object)val, label, 4f, 3f, w - 8f, h - 6f, 13, Color.white);
			val3.alignment = (TextAlignmentOptions)514;
		}
		return val2;
	}

	private void AddSlot(string name, ItemType type, int index, float x, float y, int quick = -1)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: 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_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Expected O, but got Unknown
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Expected O, but got Unknown
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_036a: Invalid comparison between Unknown and I4
		//IL_0442: Unknown result type (might be due to invalid IL or missing references)
		//IL_036c: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Invalid comparison between Unknown and I4
		//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
		Slot slot = new Slot
		{
			Label = name,
			Type = type,
			Index = index,
			Quick = quick
		};
		GameObject val = new GameObject("Slot holder", new Type[1] { typeof(RectTransform) });
		val.SetActive(false);
		val.transform.SetParent((Transform)(object)root, false);
		GameObject val2 = Object.Instantiate<GameObject>(((Component)nativeSlot).gameObject, val.transform);
		RectTransform val3 = (RectTransform)val2.transform;
		Vector2 val4 = (val3.pivot = new Vector2(0f, 1f));
		Vector2 anchorMin = (val3.anchorMax = val4);
		val3.anchorMin = anchorMin;
		val3.anchoredPosition = new Vector2(x, 0f - y);
		val3.sizeDelta = cellSize;
		((Transform)val3).localScale = Vector3.one;
		UIInputHandler[] componentsInChildren = val2.GetComponentsInChildren<UIInputHandler>(true);
		foreach (UIInputHandler val7 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val7);
		}
		UIDragHandler[] componentsInChildren2 = val2.GetComponentsInChildren<UIDragHandler>(true);
		foreach (UIDragHandler val8 in componentsInChildren2)
		{
			Object.DestroyImmediate((Object)(object)val8);
		}
		InventoryElement component = val2.GetComponent<InventoryElement>();
		slot.Element = component;
		component.Initialize(index, 0);
		Button button = component.m_button;
		button.onClick = new ButtonClickedEvent();
		((UnityEvent)button.onClick).AddListener((UnityAction)delegate
		{
			Click(slot);
		});
		Navigation navigation = ((Selectable)button).navigation;
		((Navigation)(ref navigation)).mode = (Mode)0;
		((Selectable)button).navigation = navigation;
		Graphic[] componentsInChildren3 = val2.GetComponentsInChildren<Graphic>(true);
		foreach (Graphic val9 in componentsInChildren3)
		{
			val9.raycastTarget = false;
		}
		((Selectable)button).targetGraphic.raycastTarget = true;
		slot.Icon = component.m_icon;
		((Behaviour)slot.Icon).enabled = false;
		Image equiped = component.m_equiped;
		Image queued = component.m_queued;
		Image noteleport = component.m_noteleport;
		bool flag = (((Behaviour)component.m_food).enabled = false);
		bool flag3 = (((Behaviour)noteleport).enabled = flag);
		bool enabled = (((Behaviour)queued).enabled = flag3);
		((Behaviour)equiped).enabled = enabled;
		TMP_Text amount = component.m_amount;
		bool enabled2 = (((Behaviour)component.m_quality).enabled = false);
		((Behaviour)amount).enabled = enabled2;
		component.m_selected.SetActive(false);
		((Component)component.m_durability).gameObject.SetActive(false);
		Transform val10 = val2.transform.Find("binding");
		if ((Object)(object)val10 != (Object)null)
		{
			slot.KeyText = ((Component)val10).GetComponent<TMP_Text>();
			if ((Object)(object)slot.KeyText != (Object)null)
			{
				((Behaviour)slot.KeyText).enabled = quick >= 0;
				slot.KeyText.text = "";
				((Graphic)slot.KeyText).raycastTarget = false;
			}
			if ((Object)(object)slot.KeyText != (Object)null && quick >= 0)
			{
				slot.KeyText.enableAutoSizing = true;
				slot.KeyText.fontSizeMin = 8f;
				slot.KeyText.fontSizeMax = 18f;
			}
		}
		if (quick < 0 && (int)type != 18 && (int)type != 24)
		{
			slot.Text = Text((Transform)(object)root, name, x, y + cellSize.y + 1f, cellSize.x, 16f, 10, Muted);
			slot.Text.alignment = (TextAlignmentOptions)514;
		}
		slot.Tooltip = component.m_tooltip;
		slot.Tooltip.m_text = name;
		PanelSlotInput panelSlotInput = ((Component)button).gameObject.AddComponent<PanelSlotInput>();
		panelSlotInput.Panel = this;
		panelSlotInput.Slot = slots.Count;
		if (quick >= 0)
		{
			quickSlots[quick] = slot;
		}
		((Transform)val3).SetParent((Transform)(object)root, false);
		val3.anchoredPosition = new Vector2(x, 0f - y);
		Object.Destroy((Object)(object)val);
		slots.Add(slot);
	}

	private void AddWeaponSlot(string name, int set, bool offhand, float x, float y)
	{
		AddSlot(name, (ItemType)0, 0, x, y);
		Slot slot = slots[slots.Count - 1];
		slot.Set = set;
		slot.Offhand = offhand;
	}

	private UITooltip AddTooltip(GameObject target)
	{
		UITooltip val = target.AddComponent<UITooltip>();
		val.m_tooltipPrefab = tooltipPrefab;
		((Behaviour)val).enabled = (Object)(object)tooltipPrefab != (Object)null;
		return val;
	}

	private void Click(Slot slot)
	{
		if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || Time.frameCount <= suppressClickFrame || dragSlot >= 0)
		{
			return;
		}
		RefreshAssignments();
		if (NativeDrag.Item(Gui) != null)
		{
			AcceptInventoryDrag(slots.IndexOf(slot));
		}
		else if (slot.Set >= 0)
		{
			if (slot.Ghost)
			{
				Plugin.Message("Both hands are occupied by this set's primary weapon.");
				return;
			}
			if (slot.Item == null)
			{
				OpenPicker(slot);
			}
			else
			{
				WeaponSets.Switch(player, slot.Set);
			}
			RefreshNow();
		}
		else if (slot.Quick >= 0)
		{
			Plugin.UseQuick(player, slot.Quick);
			RefreshNow();
		}
		else if (slot.Item == null)
		{
			OpenPicker(slot);
		}
		else if (((Humanoid)player).GetInventory().ContainsItem(slot.Item))
		{
			EquipmentActions.Unequip(player, slot.Item);
			RefreshNow();
		}
	}

	internal void ContextSlot(int index)
	{
		if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead())
		{
			RefreshAssignments();
			Slot slot = slots[index];
			if (slot.Ghost)
			{
				Plugin.Message("Replace the primary weapon to unlock this off-hand slot.");
			}
			else if (slot.Quick >= 0)
			{
				OpenKeys(slot.Quick);
			}
			else
			{
				OpenPicker(slot);
			}
		}
	}

	private void OpenPicker(Slot slot)
	{
		if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead())
		{
			bindingSlot = -1;
			selecting = slot;
			page = 0;
			DrawPicker();
		}
	}

	private void DrawPicker()
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		NewPicker();
		Text((Transform)(object)picker, selecting.Label, 10f, 8f, 205f, 24f, 18, Gold);
		Button((Transform)(object)picker, "Close", 229f, 8f, 60f, 26f, ClosePicker);
		ItemData[] array = (from i in ((Humanoid)player).GetInventory().GetAllItems()
			where selecting.Quick >= 0 || ((selecting.Set < 0) ? ((!selecting.Ammo) ? (i.m_shared.m_itemType == selecting.Type && !i.m_equipped) : WeaponSetRules.Ammo((int)i.m_shared.m_itemType)) : WeaponSets.Accepts(player, selecting.Set, selecting.Offhand, i))
			orderby Localization.instance.Localize(i.m_shared.m_name)
			select i).ToArray();
		int num = Math.Max(1, (int)Math.Ceiling((float)array.Length / 5f));
		page = Math.Max(0, Math.Min(page, num - 1));
		int num2 = 0;
		foreach (ItemData item2 in array.Skip(page * 5).Take(5))
		{
			ItemData item = item2;
			string value = Localization.instance.Localize(item.m_shared.m_name) + ((item.m_stack > 1) ? (" x" + item.m_stack) : "");
			Button val = Button((Transform)(object)picker, "", 10f, 44 + num2 * 43, 280f, 40f, delegate
			{
				if (!((Humanoid)player).GetInventory().ContainsItem(item))
				{
					ClosePicker();
				}
				else if (AssignSlot(selecting, item))
				{
					ClosePicker();
					RefreshNow();
				}
			});
			Image component = ((Component)Box(((Component)val).transform, "icon", 2f, 2f, 36f, 36f, Color.white)).GetComponent<Image>();
			component.sprite = item.GetIcon();
			component.preserveAspect = true;
			((Graphic)component).raycastTarget = false;
			Text(((Component)val).transform, value, 44f, 6f, 230f, 30f, 13, Color.white);
			AddTooltip(((Component)val).gameObject).m_text = item.GetTooltip(item.m_quality);
			num2++;
		}
		if (array.Length == 0)
		{
			Text((Transform)(object)picker, "No matching items in your backpack.", 12f, 55f, 304f, 45f, 14, Muted);
		}
		Button((Transform)(object)picker, "<", 10f, 268f, 36f, 26f, delegate
		{
			page--;
			DrawPicker();
		});
		Text((Transform)(object)picker, page + 1 + " / " + num, 57f, 270f, 68f, 22f, 13, Muted);
		Button((Transform)(object)picker, ">", 127f, 268f, 36f, 26f, delegate
		{
			page++;
			DrawPicker();
		});
		if (selecting.Set >= 0)
		{
			Button((Transform)(object)picker, "Clear", 217f, 268f, 73f, 26f, delegate
			{
				WeaponSets.Assign(player, selecting.Set, selecting.Offhand, null);
				ClosePicker();
				RefreshNow();
			});
		}
		if (selecting.Quick >= 0)
		{
			Button((Transform)(object)picker, "Clear", 217f, 268f, 73f, 26f, delegate
			{
				Plugin.AssignQuick(player, selecting.Quick, null);
				ClosePicker();
			});
		}
	}

	private void NewPicker()
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)picker != (Object)null)
		{
			((Component)picker).gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)picker).gameObject);
		}
		CancelSlotDrag();
		picker = Box((Transform)(object)root, "Choose", 0f, 35f, panelWidth, root.sizeDelta.y - 41f, new Color(0.1f, 0.075f, 0.055f, 1f));
		Box((Transform)(object)picker, "accent", 0f, 0f, panelWidth, 2f, Gold);
	}

	internal void OpenKeys(int slot)
	{
		bindingSlot = slot;
		selecting = null;
		keyPage = 0;
		ctrl = (alt = (shift = false));
		bindingMessage = "Choose a key with the mouse.";
		DrawKeys();
	}

	private void DrawKeys()
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0306: Unknown result type (might be due to invalid IL or missing references)
		//IL_0397: Unknown result type (might be due to invalid IL or missing references)
		NewPicker();
		Text((Transform)(object)picker, "Quick " + (bindingSlot + 1) + " key", 10f, 8f, 208f, 25f, 18, Gold);
		Button((Transform)(object)picker, "Close", 229f, 8f, 60f, 26f, ClosePicker);
		Button((Transform)(object)picker, (ctrl ? "+ " : "") + "Ctrl", 10f, 41f, 88f, 26f, delegate
		{
			ctrl = !ctrl;
			DrawKeys();
		});
		Button((Transform)(object)picker, (alt ? "+ " : "") + "Alt", 106f, 41f, 88f, 26f, delegate
		{
			alt = !alt;
			DrawKeys();
		});
		Button((Transform)(object)picker, (shift ? "+ " : "") + "Shift", 202f, 41f, 88f, 26f, delegate
		{
			shift = !shift;
			DrawKeys();
		});
		int num = (int)Math.Ceiling((float)KeyBindings.Choices.Length / 16f);
		keyPage = Math.Max(0, Math.Min(keyPage, num - 1));
		int num2 = 0;
		foreach (KeyCode item in KeyBindings.Choices.Skip(keyPage * 16).Take(16))
		{
			KeyCode key = item;
			Button val = Button((Transform)(object)picker, ((object)key).ToString().Replace("Alpha", ""), 10 + num2 % 4 * 72, 77 + num2 / 4 * 32, 64f, 27f, delegate
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				List<KeyCode> list = new List<KeyCode>();
				if (ctrl)
				{
					list.Add((KeyCode)306);
				}
				if (alt)
				{
					list.Add((KeyCode)308);
				}
				if (shift)
				{
					list.Add((KeyCode)304);
				}
				string text = plugin.SetKey(bindingSlot, key, list.ToArray());
				if (text == null)
				{
					ClosePicker();
					nextUpdate = 0f;
				}
				else
				{
					bindingMessage = text;
					DrawKeys();
				}
			});
			AddTooltip(((Component)val).gameObject).m_text = ((object)key).ToString();
			num2++;
		}
		Text((Transform)(object)picker, bindingMessage, 10f, 208f, 280f, 39f, 12, Muted);
		Button((Transform)(object)picker, "<", 10f, 250f, 35f, 26f, delegate
		{
			keyPage--;
			DrawKeys();
		});
		Text((Transform)(object)picker, keyPage + 1 + "/" + num, 54f, 253f, 50f, 22f, 13, Muted);
		Button((Transform)(object)picker, ">", 106f, 250f, 35f, 26f, delegate
		{
			keyPage++;
			DrawKeys();
		});
		Button((Transform)(object)picker, "Unbind", 202f, 250f, 88f, 26f, delegate
		{
			plugin.SetKey(bindingSlot, (KeyCode)0, (KeyCode[])(object)new KeyCode[0]);
			ClosePicker();
			nextUpdate = 0f;
		});
		Text((Transform)(object)picker, "Other mods may also use these keys.", 10f, 285f, 280f, 18f, 10, Muted);
	}

	private void ClosePicker()
	{
		if ((Object)(object)picker != (Object)null)
		{
			((Component)picker).gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)picker).gameObject);
		}
		selecting = null;
		picker = null;
		bindingSlot = -1;
	}

	internal bool AcceptInventoryDrag(int slot)
	{
		if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || (Object)(object)picker != (Object)null || dragSlot >= 0)
		{
			return false;
		}
		ItemData val = NativeDrag.Item(Gui);
		if (val == null)
		{
			return false;
		}
		if (!object.ReferenceEquals(NativeDrag.Inventory(Gui), ((Humanoid)player).GetInventory()) || !((Humanoid)player).GetInventory().ContainsItem(val))
		{
			Plugin.Message("Move the item into your backpack before assigning it.");
			return false;
		}
		RefreshAssignments();
		if (!AssignSlot(slots[slot], val))
		{
			return false;
		}
		NativeDrag.Clear(Gui);
		suppressClickFrame = Time.frameCount + 1;
		RefreshNow();
		return true;
	}

	private bool AssignSlot(Slot slot, ItemData item)
	{
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		if (slot.Set >= 0)
		{
			if (slot.Ghost)
			{
				Plugin.Message("The off-hand is locked by this set's primary weapon.");
				return false;
			}
			return WeaponSets.Assign(player, slot.Set, slot.Offhand, item);
		}
		if (slot.Ammo)
		{
			return WeaponSets.SelectAmmo(player, item);
		}
		if (slot.Quick >= 0)
		{
			Plugin.AssignQuick(player, slot.Quick, item);
			return true;
		}
		if (!EquipmentActions.Equip(player, item, slot.Item, slot.Type))
		{
			return false;
		}
		foreach (Slot slot2 in slots)
		{
			if (slot2.Quick < 0 && object.ReferenceEquals(slot2.Item, item))
			{
				slot2.Item = null;
			}
		}
		slot.Item = item;
		return true;
	}

	internal void BeginSlotDrag(int slot, PointerEventData data)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: 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)
		if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead() && !((Object)(object)picker != (Object)null) && NativeDrag.Item(Gui) == null)
		{
			RefreshAssignments();
			ItemData item = slots[slot].Item;
			if (item != null && !slots[slot].Ghost)
			{
				CancelSlotDrag();
				dragSlot = slot;
				dragItem = item;
				Canvas rootCanvas = ((Component)root).GetComponentInParent<Canvas>().rootCanvas;
				RectTransform val = Box(((Component)rootCanvas).transform, "Equipment drag", 0f, 0f, cellSize.x, cellSize.y, Color.white);
				dragIcon = ((Component)val).GetComponent<Image>();
				dragIcon.sprite = item.GetIcon();
				((Graphic)dragIcon).raycastTarget = false;
				dragIcon.preserveAspect = true;
				((Transform)val).localScale = new Vector3(((Transform)root).lossyScale.x / ((Component)rootCanvas).transform.lossyScale.x, ((Transform)root).lossyScale.y / ((Component)rootCanvas).transform.lossyScale.y, 1f);
				MoveSlotDrag(data);
			}
		}
	}

	internal void MoveSlotDrag(PointerEventData data)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)dragIcon == (Object)null))
		{
			Canvas componentInParent = ((Component)dragIcon).GetComponentInParent<Canvas>();
			Vector2 val = default(Vector2);
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)((Component)componentInParent).transform, data.position, data.pressEventCamera, ref val))
			{
				((Component)dragIcon).transform.position = ((Component)componentInParent).transform.TransformPoint(Vector2.op_Implicit(val));
			}
		}
	}

	internal void EndSlotDrag(PointerEventData data)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (dragSlot < 0)
		{
			return;
		}
		try
		{
			RaycastResult pointerCurrentRaycast = data.pointerCurrentRaycast;
			GameObject gameObject = ((RaycastResult)(ref pointerCurrentRaycast)).gameObject;
			if ((Object)(object)player != (Object)null)
			{
				RefreshAssignments();
			}
			if (!((Object)(object)player != (Object)null) || ((Character)player).IsDead() || !object.ReferenceEquals(slots[dragSlot].Item, dragItem) || !((Object)(object)gameObject != (Object)null))
			{
				return;
			}
			if ((Object)(object)gameObject.GetComponentInParent<InventoryGrid>() == (Object)(object)Gui.m_playerGrid)
			{
				if (slots[dragSlot].Set >= 0)
				{
					WeaponSets.Assign(player, slots[dragSlot].Set, slots[dragSlot].Offhand, null);
				}
				else if (slots[dragSlot].Quick >= 0)
				{
					Plugin.AssignQuick(player, slots[dragSlot].Quick, null);
				}
				else
				{
					EquipmentActions.Unequip(player, dragItem);
				}
			}
			else
			{
				PanelSlotInput componentInParent = gameObject.GetComponentInParent<PanelSlotInput>();
				if ((Object)(object)componentInParent != (Object)null && componentInParent.Panel == this)
				{
					AssignSlot(slots[componentInParent.Slot], dragItem);
				}
			}
		}
		finally
		{
			CancelSlotDrag();
			RefreshNow();
		}
	}

	internal void CancelSlotDrag()
	{
		if (dragSlot >= 0)
		{
			suppressClickFrame = Time.frameCount + 1;
		}
		dragSlot = -1;
		dragItem = null;
		if ((Object)(object)dragIcon != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)dragIcon).gameObject);
			dragIcon = null;
		}
	}

	internal void Tick(Player current)
	{
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		if (!object.ReferenceEquals(player, current))
		{
			foreach (Slot slot in slots)
			{
				slot.Item = null;
				slot.Hovered = false;
			}
			ClosePicker();
			CancelSlotDrag();
			lastRows = -1;
			nextUpdate = 0f;
		}
		player = current;
		bool flag = (Object)(object)player != (Object)null && !((Character)player).IsDead() && InventoryGui.IsVisible() && plugin.ShowPanel.Value;
		if ((Object)(object)root == (Object)null)
		{
			return;
		}
		if (((Component)root).gameObject.activeSelf != flag)
		{
			((Component)root).gameObject.SetActive(flag);
			nextUpdate = (nextStats = 0f);
			lastRows = -1;
			if (!flag)
			{
				ClosePicker();
				CancelSlotDrag();
			}
		}
		if (flag && !(Time.unscaledTime < nextUpdate))
		{
			nextUpdate = Time.unscaledTime + 0.1f;
			RefreshAssignments();
			RefreshVisuals();
			Vector3 lossyScale = ((Transform)Gui.m_playerGrid.m_gridRoot).lossyScale;
			Vector3 lossyScale2 = ((Transform)root).parent.lossyScale;
			float num = Math.Min(1f, Math.Min(((float)Screen.height - 30f) / (root.sizeDelta.y * lossyScale.y), ((float)Screen.width - 30f) / (root.sizeDelta.x * lossyScale.x)));
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(lossyScale.x / lossyScale2.x * num, lossyScale.y / lossyScale2.y * num, 1f);
			if (((Transform)root).localScale != val || root.anchoredPosition != lastPosition || Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
			{
				((Transform)root).localScale = val;
				Utils.ClampUIToScreen(root);
				lastPosition = root.anchoredPosition;
				lastScreenWidth = Screen.width;
				lastScreenHeight = Screen.height;
			}
			int height = ((Humanoid)player).GetInventory().GetHeight();
			if (height != lastRows)
			{
				Gui.SetInventorySize(height);
				lastRows = height;
			}
		}
	}

	private void RefreshNow()
	{
		if (!((Object)(object)player == (Object)null) && !((Object)(object)root == (Object)null) && ((Component)root).gameObject.activeSelf)
		{
			nextStats = 0f;
			RefreshAssignments();
			RefreshVisuals();
		}
	}

	private void RefreshAssignments()
	{
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		foreach (Slot slot2 in slots)
		{
			if (slot2.Set >= 0 || slot2.Ammo)
			{
				slot2.Ghost = slot2.Set >= 0 && slot2.Offhand && WeaponSets.Locked(player, slot2.Set);
				slot2.Item = (slot2.Ammo ? ((Humanoid)player).GetAmmoItem() : WeaponSets.Get(player, slot2.Set, !slot2.Ghost && slot2.Offhand));
				if (slot2.Item != null && !inventory.ContainsItem(slot2.Item))
				{
					slot2.Item = null;
				}
			}
			else if (slot2.Quick >= 0 || (slot2.Item != null && (!slot2.Item.m_equipped || !inventory.ContainsItem(slot2.Item))))
			{
				slot2.Item = null;
			}
		}
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if (allItem.m_customData.TryGetValue("au.tyvalheim.rpgequipment.quick", out var value))
			{
				int num = value switch
				{
					"2" => 2, 
					"1" => 1, 
					"0" => 0, 
					_ => -1, 
				};
				if (num >= 0 && quickSlots[num].Item == null)
				{
					quickSlots[num].Item = allItem;
				}
			}
			if (!allItem.m_equipped)
			{
				continue;
			}
			bool flag = false;
			Slot slot = null;
			foreach (Slot slot3 in slots)
			{
				if (slot3.Set < 0 && !slot3.Ammo && slot3.Quick < 0 && slot3.Type == allItem.m_shared.m_itemType)
				{
					if (object.ReferenceEquals(slot3.Item, allItem))
					{
						flag = true;
						break;
					}
					if (slot3.Item == null && slot == null)
					{
						slot = slot3;
					}
				}
			}
			if (!flag && slot != null)
			{
				slot.Item = allItem;
			}
		}
	}

	private void RefreshVisuals()
	{
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		if (Time.unscaledTime >= nextStats)
		{
			nextStats = Time.unscaledTime + 1f;
			string text = "Armour " + ((Character)player).GetBodyArmor().ToString("0") + "  |  " + player.GetMaxCarryWeight().ToString("0");
			if (stats.text != text)
			{
				stats.text = text;
			}
		}
		if (lastKeys != plugin.KeyRevision)
		{
			lastKeys = plugin.KeyRevision;
			Slot[] array = quickSlots;
			foreach (Slot slot in array)
			{
				slot.Key = plugin.KeyLabel(slot.Quick);
				if ((Object)(object)slot.KeyText != (Object)null)
				{
					slot.KeyText.text = ((slot.Key == "Set key") ? "" : slot.Key.Replace("LeftControl", "Ctrl").Replace("LeftShift", "Shift").Replace("LeftAlt", "Alt"));
				}
				slot.TooltipDue = 0f;
			}
		}
		for (int j = 0; j < 2; j++)
		{
			setLabels[j].text = (WeaponSets.Matches(player, j) ? "Active " : "Equip ") + (j + 1) + " [" + ((object)plugin.SetKeys[j].Value/*cast due to .constrained prefix*/).ToString().Replace("LeftAlt", "Alt").Replace("LeftShift", "Shift")
				.Replace("LeftControl", "Ctrl")
				.Replace("Alpha", "") + "]";
		}
		foreach (Slot slot2 in slots)
		{
			ItemData item = slot2.Item;
			((Graphic)slot2.Icon).color = (Color)(slot2.Ghost ? new Color(1f, 1f, 1f, 0.28f) : Color.white);
			if (slot2.Set >= 0 && (Object)(object)slot2.Text != (Object)null)
			{
				slot2.Text.text = (slot2.Ghost ? "Both hands" : ((slot2.Item == null && WeaponSets.Saved(player, slot2.Set, slot2.Offhand) != "") ? "Missing - reassign" : slot2.Label));
			}
			InventoryElement element = slot2.Element;
			bool flag = !object.ReferenceEquals(item, slot2.DrawnItem);
			if (flag)
			{
				slot2.DrawnItem = item;
				((Behaviour)slot2.Icon).enabled = item != null;
				((Behaviour)element.m_amount).enabled = item != null && item.m_shared.m_maxStackSize > 1;
				((Behaviour)element.m_quality).enabled = item != null && item.m_shared.m_maxQuality > 1;
				((Component)element.m_durability).gameObject.SetActive(item?.m_shared.m_useDurability ?? false);
				slot2.Stack = (slot2.Quality = (slot2.Variant = -1));
				slot2.Durability = -1f;
				slot2.TooltipDue = 0f;
			}
			bool flag2 = !slot2.Ghost && item != null && item.m_equipped;
			if (flag || slot2.Equipped != flag2)
			{
				((Behaviour)element.m_equiped).enabled = flag2;
				slot2.Equipped = flag2;
				slot2.TooltipDue = 0f;
			}
			if (item != null)
			{
				if (slot2.Variant != item.m_variant)
				{
					slot2.Variant = item.m_variant;
					slot2.Icon.sprite = item.GetIcon();
				}
				if (slot2.Stack != item.m_stack)
				{
					slot2.Stack = item.m_stack;
					if (((Behaviour)element.m_amount).enabled)
					{
						element.m_amount.text = item.m_stack + "/" + item.m_shared.m_maxStackSize;
					}
				}
				if (slot2.Quality != item.m_quality)
				{
					slot2.Quality = item.m_quality;
					if (((Behaviour)element.m_quality).enabled)
					{
						element.m_quality.text = item.m_quality.ToString();
					}
				}
				if (item.m_shared.m_useDurability)
				{
					float durabilityPercentage = item.GetDurabilityPercentage();
					if (slot2.Durability != durabilityPercentage)
					{
						slot2.Durability = durabilityPercentage;
						element.m_durability.SetValue(durabilityPercentage);
					}
				}
			}
			if (slot2.Hovered && Time.unscaledTime >= slot2.TooltipDue)
			{
				UpdateTooltip(slot2);
			}
		}
	}

	internal void HoverSlot(int index, bool entered)
	{
		if (index >= 0 && index < slots.Count)
		{
			Slot slot = slots[index];
			slot.Hovered = entered;
			if (entered && (Object)(object)player != (Object)null)
			{
				RefreshAssignments();
				UpdateTooltip(slot);
			}
		}
	}

	private void UpdateTooltip(Slot slot)
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		slot.TooltipDue = Time.unscaledTime + 1f;
		string text = slot.Label + "\n";
		if (slot.Item != null)
		{
			text = text + slot.Item.GetTooltip(slot.Item.m_quality) + "\n";
		}
		if (slot.Set >= 0)
		{
			text += (slot.Ghost ? "Off-hand locked: this primary occupies both hands." : "Saved backpack reference, not extra storage.\nLeft-click: equip set | Right-click: choose / clear\nDrag from backpack: assign | Drag back: unassign");
			slot.Tooltip.Set("", text, (RectTransform)null, Vector2.zero);
		}
		else if (slot.Ammo)
		{
			slot.Tooltip.Set("", text + "Native selected ammo. Drag ammo here or right-click to choose.\nShared across both sets; normal game ammo fallback applies.", (RectTransform)null, Vector2.zero);
		}
		else
		{
			text += ((slot.Quick >= 0) ? ("Drag an item here. Drag back to backpack: unassign\nRight-click: set key | Key: " + plugin.KeyLabel(slot.Quick)) : "Drag matching equipment here to equip or replace.\nDrag back to backpack: unequip\nLeft-click: unequip / choose | Right-click: choose replacement");
			slot.Tooltip.Set("", text, (RectTransform)null, Vector2.zero);
		}
	}

	public void Dispose()
	{
		CancelSlotDrag();
		if ((Object)(object)root != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)root).gameObject);
		}
	}
}
internal static class HotkeyInput
{
	private static int lastTextFrame = -2;

	internal static bool Blocked()
	{
		bool flag = TextInput.IsVisible() || UnifiedPopup.WasVisibleThisFrame();
		TextInput instance = TextInput.instance;
		if ((Object)(object)instance != (Object)null)
		{
			flag |= ((Object)(object)instance.m_panel != (Object)null && instance.m_panel.activeInHierarchy) || ((Object)(object)instance.m_inputField != (Object)null && ((Behaviour)instance.m_inputField).isActiveAndEnabled && ((TMP_InputField)instance.m_inputField).isFocused);
		}
		EventSystem current = EventSystem.current;
		GameObject val = (((Object)(object)current == (Object)null) ? null : current.currentSelectedGameObject);
		if ((Object)(object)val != (Object)null && val.activeInHierarchy)
		{
			TMP_InputField componentInParent = val.GetComponentInParent<TMP_InputField>();
			InputField componentInParent2 = val.GetComponentInParent<InputField>();
			flag |= ((Object)(object)componentInParent != (Object)null && ((Behaviour)componentInParent).isActiveAndEnabled) || ((Object)(object)componentInParent2 != (Object)null && ((Behaviour)componentInParent2).isActiveAndEnabled);
		}
		if (flag)
		{
			lastTextFrame = Time.frameCount;
		}
		if (!flag)
		{
			return Time.frameCount <= lastTextFrame + 1;
		}
		return true;
	}
}
internal static class InventorySafety
{
	private sealed class State
	{
		internal Player Player;

		internal Container Grave;

		internal int BaseRows;

		internal int Loading;
	}

	private static readonly Dictionary<Inventory, State> states = new Dictionary<Inventory, State>();

	private static readonly MethodInfo changed = AccessTools.Method(typeof(Inventory), "Changed", new Type[2]
	{
		typeof(bool),
		typeof(bool)
	}, (Type[])null);

	private static bool resizing;

	internal static void Clear()
	{
		states.Clear();
	}

	internal static void Changed(Inventory inventory)
	{
		changed.Invoke(inventory, new object[2] { false, false });
	}

	internal static void Register(Player player)
	{
		if (Plugin.Ready && ((Humanoid)player).GetInventory() != null)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (!states.ContainsKey(inventory))
			{
				states[inventory] = new State
				{
					Player = player,
					BaseRows = Math.Max(1, inventory.GetHeight())
				};
			}
			Ensure(inventory, repair: false);
		}
	}

	internal static void Unregister(Player player)
	{
		if (((Humanoid)player).GetInventory() != null)
		{
			states.Remove(((Humanoid)player).GetInventory());
		}
	}

	internal static void RegisterGrave(Container container)
	{
		if (Plugin.Ready && !((Object)(object)((Component)container).GetComponent<TombStone>() == (Object)null) && container.GetInventory() != null)
		{
			KeyValuePair<Inventory, State>[] array = states.Where((KeyValuePair<Inventory, State> s) => (Object)(object)s.Value.Player == (Object)null && (Object)(object)s.Value.Grave == (Object)null).ToArray();
			foreach (KeyValuePair<Inventory, State> keyValuePair in array)
			{
				states.Remove(keyValuePair.Key);
			}
			Inventory inventory = container.GetInventory();
			if (!states.ContainsKey(inventory))
			{
				states[inventory] = new State
				{
					Grave = container,
					BaseRows = Math.Max(1, inventory.GetHeight())
				};
			}
		}
	}

	internal static void SetBase(Player player, int rows)
	{
		Register(player);
		if (states.TryGetValue(((Humanoid)player).GetInventory(), out var value))
		{
			value.BaseRows = Math.Max(1, Math.Min(9, rows));
		}
	}

	internal static int GuardHeight(Inventory inv, int proposed)
	{
		if (resizing || !states.TryGetValue(inv, out var value))
		{
			return proposed;
		}
		int val = Rules.Height(value.BaseRows, (!((Object)(object)value.Player == (Object)null)) ? Plugin.Instance.ExtraRows.Value : 0, from i in inv.GetAllItems()
			select new Cell(i.m_gridPos.x, i.m_gridPos.y));
		return Math.Max(proposed, Math.Max(val, (value.Loading <= 0) ? 1 : 64));
	}

	internal static void BeforeLoad(Inventory inv)
	{
		if (states.TryGetValue(inv, out var value))
		{
			value.Loading++;
			inv.SetHeight(Math.Max(64, inv.GetHeight()));
		}
	}

	internal static void AfterLoad(Inventory inv)
	{
		if (states.TryGetValue(inv, out var value))
		{
			value.Loading = Math.Max(0, value.Loading - 1);
			Ensure(inv, repair: true);
		}
	}

	internal static void Ensure(Inventory inv, bool repair)
	{
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		if (!states.TryGetValue(inv, out var value))
		{
			return;
		}
		if (repair)
		{
			List<ItemData> allItems = inv.GetAllItems();
			Cell[] array = Rules.Repair(inv.GetWidth(), allItems.Select((ItemData i) => new Cell(i.m_gridPos.x, i.m_gridPos.y)));
			int num = 0;
			for (int num2 = 0; num2 < allItems.Count; num2++)
			{
				if (array[num2].X != allItems[num2].m_gridPos.x || array[num2].Y != allItems[num2].m_gridPos.y)
				{
					num++;
				}
				allItems[num2].m_gridPos = new Vector2i(array[num2].X, array[num2].Y);
			}
			if (num > 0)
			{
				Plugin.Log("Recovered " + num + " invalid/overlapping saved item positions without dropping items.");
			}
		}
		int num3 = Rules.Height(value.BaseRows, (!((Object)(object)value.Player == (Object)null)) ? Plugin.Instance.ExtraRows.Value : 0, from i in inv.GetAllItems()
			select new Cell(i.m_gridPos.x, i.m_gridPos.y));
		if (value.Loading > 0)
		{
			num3 = Math.Max(num3, 64);
		}
		if (num3 != inv.GetHeight())
		{
			int height = inv.GetHeight();
			resizing = true;
			try
			{
				inv.SetHeight(num3);
			}
			finally
			{
				resizing = false;
			}
			Plugin.Log("Inventory resize " + height + " -> " + num3 + " rows; items=" + inv.GetAllItems().Count + "; player=" + ((Object)(object)value.Player != (Object)null));
		}
	}

	internal static void SavedItem(Inventory inv, ItemData item)
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		if (states.TryGetValue(inv, out var value) && value.Loading != 0 && item != null)
		{
			Cell incoming = new Cell(item.m_gridPos.x, item.m_gridPos.y);
			Cell cell = Rules.SavedCell(inv.GetWidth(), incoming, from i in inv.GetAllItems()
				select new Cell(i.m_gridPos.x, i.m_gridPos.y));
			item.m_gridPos = new Vector2i(cell.X, cell.Y);
			if (cell.X != incoming.X || cell.Y != incoming.Y)
			{
				Plugin.Log("Recovered saved item coordinate before native load: " + incoming.X + "," + incoming.Y + " -> " + cell.X + "," + cell.Y);
			}
			if (item.m_gridPos.y >= inv.GetHeight())
			{
				inv.SetHeight(item.m_gridPos.y + 1);
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
internal static class PlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		InventorySafety.Register(__instance);
	}
}
[HarmonyPatch(typeof(Player), "OnDestroy")]
internal static class PlayerDestroyPatch
{
	private static void Prefix(Player __instance)
	{
		InventorySafety.Unregister(__instance);
	}
}
[HarmonyPatch(typeof(Player), "Load")]
internal static class PlayerLoadPatch
{
	private static void Prefix(Player __instance)
	{
		InventorySafety.Register(__instance);
	}

	private static void Postfix(Player __instance)
	{
		InventorySafety.Ensure(((Humanoid)__instance).GetInventory(), repair: true);
		Plugin.Log("Player load complete: items=" + ((Humanoid)__instance).GetInventory().GetAllItems().Count + "; equipped=" + ((Humanoid)__instance).GetInventory().GetEquippedItems().Count + "; rows=" + ((Humanoid)__instance).GetInventory().GetHeight());
	}
}
[HarmonyPatch(typeof(Player), "SetInventorySize")]
internal static class PlayerSizePatch
{
	private static void Prefix(Player __instance, int __0)
	{
		InventorySafety.SetBase(__instance, __0);
	}
}
[HarmonyPatch(typeof(Inventory), "SetHeight")]
internal static class HeightPatch
{
	private static void Prefix(Inventory __instance, ref int __0)
	{
		__0 = InventorySafety.GuardHeight(__instance, __0);
	}
}
[HarmonyPatch(typeof(Humanoid), "DropInvalidItems")]
internal static class InvalidDropPatch
{
	private static void Prefix(Humanoid __instance)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Expected O, but got Unknown
		if (Plugin.Applies(__instance))
		{
			InventorySafety.Register((Player)__instance);
			InventorySafety.Ensure(__instance.GetInventory(), repair: true);
		}
	}
}
[HarmonyPatch(typeof(Inventory), "Load", new Type[]
{
	typeof(ZPackage),
	typeof(bool)
})]
internal static class InventoryLoadPatch
{
	private static void Prefix(Inventory __instance)
	{
		InventorySafety.BeforeLoad(__instance);
	}

	private static void Finalizer(Inventory __instance)
	{
		InventorySafety.AfterLoad(__instance);
	}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
{
	typeof(int),
	typeof(ItemData),
	typeof(bool)
})]
internal static class SavedItemPatch
{
	private static void Prefix(Inventory __instance, ItemData __1)
	{
		InventorySafety.SavedItem(__instance, __1);
	}
}
[HarmonyPatch(typeof(Container), "Load")]
internal static class GraveLoadPatch
{
	private static void Prefix(Container __instance)
	{
		InventorySafety.RegisterGrave(__instance);
	}
}
[HarmonyPatch(typeof(InventoryGui), "SetInventorySize")]
internal static class GuiSizePatch
{
	private static void Prefix(ref int __0)
	{
		if (Plugin.Ready && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			__0 = Math.Max(__0, ((Humanoid)Player.m_localPlayer).GetInventory().GetHeight());
		}
	}
}
internal static class KeyBindings
{
	internal static readonly KeyCode[] Choices = ((IEnumerable<KeyCode>)(object)new KeyCode[16]
	{
		(KeyCode)287,
		(KeyCode)288,
		(KeyCode)289,
		(KeyCode)290,
		(KeyCode)291,
		(KeyCode)292,
		(KeyCode)293,
		(KeyCode)57,
		(KeyCode)48,
		(KeyCode)277,
		(KeyCode)278,
		(KeyCode)279,
		(KeyCode)280,
		(KeyCode)281,
		(KeyCode)127,
		(KeyCode)96
	}).Concat(from k in Enumerable.Range(97, 26)
		select (KeyCode)k).ToArray();

	internal static string GameConflict(KeyCode key)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		if (ZInput.instance == null)
		{
			return "input settings unavailable";
		}
		FieldInfo fieldInfo = AccessTools.Field(typeof(ZInput), "m_buttons");
		IDictionary dictionary = ((fieldInfo == null) ? null : (fieldInfo.GetValue(ZInput.instance) as IDictionary));
		if (dictionary == null)
		{
			return "input settings unavailable";
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(ZInput), "KeyCodeToPath", new Type[2]
		{
			typeof(KeyCode),
			typeof(bool)
		}, (Type[])null);
		if (methodInfo == null)
		{
			return "input settings unavailable";
		}
		string text = methodInfo.Invoke(null, new object[2] { key, false }) as string;
		if (string.IsNullOrEmpty(text))
		{
			return "unsupported key";
		}
		foreach (DictionaryEntry item in dictionary)
		{
			PropertyInfo propertyInfo = AccessTools.Property(item.Value.GetType(), "ButtonAction");
			InputAction val = (InputAction)((propertyInfo == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if (val == null)
			{
				continue;
			}
			Enumerator<InputBinding> enumerator = val.bindings.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					InputBinding current = enumerator.Current;
					if (string.Equals(((InputBinding)(ref current)).effectivePath, text, StringComparison.OrdinalIgnoreCase))
					{
						return item.Key.ToString();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}
		return null;
	}
}
[BepInIncompatibility("aedenthorn.ExtendedPlayerInventory")]
[BepInPlugin("au.tyvalheim.rpgequipment", "RPG Equipment", "0.2.9")]
[BepInIncompatibility("aedenthorn.EquipMultipleUtilityItems")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Id = "au.tyvalheim.rpgequipment";

	internal const string QuickKey = "au.tyvalheim.rpgequipment.quick";

	internal static Plugin Instance;

	internal static bool Ready;

	internal ConfigEntry<int> ExtraRows;

	internal ConfigEntry<int> UtilitySlots;

	internal ConfigEntry<int> TrinketSlots;

	internal ConfigEntry<string> PreferredUtilityVisual;

	internal ConfigEntry<string> BeltVisualPrefabs;

	internal ConfigEntry<bool> DuplicateItems;

	internal ConfigEntry<bool> ShowPanel;

	internal ConfigEntry<bool> Diagnostics;

	internal ConfigEntry<bool> UseExtraArmourPoints;

	internal ConfigEntry<bool> HalveDualTrinketAdrenalineCost;

	internal ConfigEntry<bool> DivideTrinketAdrenalineCostByCount;

	internal ConfigEntry<float> TrinketAdrenalineCostMultiplier;

	internal ConfigEntry<bool> AutoEquipShieldWithOneHandedWeapon;

	internal ConfigEntry<float> PanelX;

	internal ConfigEntry<float> PanelY;

	internal ConfigEntry<float> PanelScale;

	private ConfigEntry<KeyboardShortcut>[] keys;

	internal ConfigEntry<KeyboardShortcut>[] SetKeys;

	private int lastSetFrame = -1;

	private static readonly MethodInfo takeInput = AccessTools.Method(typeof(Player), "TakeInput", Type.EmptyTypes, (Type[])null);

	internal int NativeHotbarFrame = -1;

	private Harmony harmony;

	private EquipmentPanel panel;

	private bool uiFaulted;

	internal int KeyRevision;

	internal static bool AutoShieldEnabled
	{
		get
		{
			if (Ready && (Object)(object)Instance != (Object)null)
			{
				return Instance.AutoEquipShieldWithOneHandedWeapon.Value;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Expected O, but got Unknown
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Expected O, but got Unknown
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Expected O, but got Unknown
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0379: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Expected O, but got Unknown
		//IL_035b: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		ExtraRows = ((BaseUnityPlugin)this).Config.Bind<int>("Inventory", "ExtraRows", 2, new ConfigDescription("Extra ordinary backpack rows. Occupied rows are retained if this is reduced. Restart after edits.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), new object[0]));
		UtilitySlots = ((BaseUnityPlugin)this).Config.Bind<int>("Equipment", "UtilitySlots", 5, new ConfigDescription("Simultaneously worn utility items.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), new object[0]));
		PreferredUtilityVisual = ((BaseUnityPlugin)this).Config.Bind<string>("Equipment", "PreferredUtilityVisual", "", "Optional belt prefab to prefer when the selected utility is also a belt in BeltVisualPrefabs. Never overrides an unrelated primary utility or helmet. Empty keeps native selection. Restart after edits.");
		BeltVisualPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Equipment", "BeltVisualPrefabs", "BeltStrength,UB_UsainsBelt", "Comma-separated belt prefabs sharing the same visual space. PreferredUtilityVisual only resolves conflicts within this list. Does not add extra utility render slots. Restart after edits.");
		TrinketSlots = ((BaseUnityPlugin)this).Config.Bind<int>("Equipment", "TrinketSlots", 2, new ConfigDescription("Simultaneously worn items whose game type is Trinket, including wearable totems.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), new object[0]));
		UseExtraArmourPoints = ((BaseUnityPlugin)this).Config.Bind<bool>("Equipment", "UseExtraArmourPoints", true, "Use Extra Armour Points: add the armour values of all equipped utilities and trinkets to body armour. Many accessories contribute 10 points even when their tooltip shows no armour. Default true preserves this bonus. False excludes these item armour values; normal worn armour and status effects still apply. Restart after edits.");
		HalveDualTrinketAdrenalineCost = ((BaseUnityPlugin)this).Config.Bind<bool>("Equipment", "HalveDualTrinketAdrenalineCost", false, "Legacy option: when exactly two trinkets are equipped, halve their combined positive adrenaline threshold contribution. Ignored when DivideTrinketAdrenalineCostByCount is true. Other equipment and base adrenaline are unchanged. Default false.");
		DivideTrinketAdrenalineCostByCount = ((BaseUnityPlugin)this).Config.Bind<bool>("Equipment", "DivideTrinketAdrenalineCostByCount", false, "Divide the combined positive adrenaline threshold contribution of equipped trinkets by their equipped count. Empty slots and backpack items do not count. Other equipment and base adrenaline are unchanged. Takes precedence over HalveDualTrinketAdrenalineCost; reductions never stack. Default false preserves existing settings.");
		DuplicateItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Equipment", "AllowDuplicatePrefabs", false, "Allow two copies of the same accessory. Identical status effects still use native non-stacking rules.");
		TrinketAdrenalineCostMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Equipment", "TrinketAdrenalineCostMultiplier", 1f, new ConfigDescription("Multiplier for equipped trinkets' combined positive adrenaline requirement, applied AFTER any enabled divide-by-count or legacy halving reduction. 0.1 = 10%, 1 = 100%, 3.5 = 350%; 0 removes the positive trinket contribution. Applies to one or more trinkets. Other equipment, negative contributions and base adrenaline are unchanged. Default 1 preserves existing behaviour. Range 0 to 3.5 (0% to 350%). Restart after edits.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3.5f), new object[0]));
		ShowPanel = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowCharacterPanel", true, "Show character equipment controls while inventory is open.");
		PanelX = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "PanelX", 650f, "Horizontal offset from the left edge of the inventory canvas. Drag the title bar to save a new position.");
		PanelY = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "PanelY", 110f, "Vertical offset from the top edge of the inventory canvas.");
		PanelScale = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "PanelScale", 1f, new ConfigDescription("Legacy setting, ignored from 0.1.2: equipment slots now match the native inventory size and scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 1.4f), new object[0]));
		Diagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "LogPersistence", true, "Log load/resize/re-equip summaries and repaired legacy item coordinates.");
		keys = new ConfigEntry<KeyboardShortcut>[3];
		for (int i = 0; i < 3; i++)
		{
			keys[i] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("QuickSlots", "Slot" + (i + 1), new KeyboardShortcut((KeyCode)0, (KeyCode[])(object)new KeyCode[0]), "Optional shortcut. None by default: no V/B/N or other game bindings are replaced.");
			keys[i].SettingChanged += delegate
			{
				KeyRevision++;
			};
		}
		SetKeys = new ConfigEntry<KeyboardShortcut>[2];
		AutoEquipShieldWithOneHandedWeapon = ((BaseUnityPlugin)this).Config.Bind<bool>("WeaponSets", "AutoEquipShieldWithOneHandedWeapon", false, "Optional hotbar shield: remember the last shield manually equipped or assigned to an off-hand set slot, then equip it after a successful one-handed weapon selection with normal hotbar controls (1-8). Two-handed weapons, tools, stowing and explicit weapon sets retain their normal behaviour. The exact shield must be usable and in your backpack. Default false. Restart after editing.");
		for (int num = 0; num < 2; num++)
		{
			SetKeys[num] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("WeaponSets", "Set" + (num + 1), new KeyboardShortcut((KeyCode)((num == 0) ? 49 : 50), (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Toggle set shortcut: equip, then stow on repeat. Default LeftAlt+1/2. Configurable Unity KeyCode, e.g. F6 or Alpha1 + LeftShift. Unmodified 1-8 are always reserved for Valheim. Set None to disable. Do not overlap other game or mod shortcuts. Restart after editing.");
		}
		try
		{
			harmony = new Harmony("au.tyvalheim.rpgequipment");
			harmony.PatchAll(typeof(Plugin).Assembly);
			Ready = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("RPG Equipment 0.2.9 loaded; built against Valheim 1.0.16. Extra rows=" + ExtraRows.Value + ", utility slots=" + UtilitySlots.Value + ", trinket slots=" + TrinketSlots.Value + ", extra armour points=" + UseExtraArmourPoints.Value + ", trinket adrenaline multiplier=" + TrinketAdrenalineCostMultiplier.Value + ". Quick keys are optional."));
		}
		catch (Exception ex)
		{
			Ready = false;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("RPG Equipment could not install its complete patch set. Do not load an expanded character until this is resolved: " + ex));
		}
	}

	internal static bool Applies(Humanoid human)
	{
		if (Ready)
		{
			return human is Player;
		}
		return false;
	}

	internal static void Log(string text)
	{
		if ((Object)(object)Instance != (Object)null && Instance.Diagnostics.Value)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)text);
		}
	}

	internal static string Prefab(ItemData item)
	{
		if (item != null && !((Object)(object)item.m_dropPrefab == (Object)null))
		{
			return ((Object)item.m_dropPrefab).name.Replace("(Clone)", "");
		}
		return "";
	}

	internal static void Message(string text)
	{
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			((Character)Player.m_localPlayer).Message((MessageType)1, "RPG Equipment: " + text, 0, (Sprite)null, false);
		}
	}

	internal static ItemData QuickItem(Player player, int slot)
	{
		return ((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_customData.ContainsKey("au.tyvalheim.rpgequipment.quick") && i.m_customData["au.tyvalheim.rpgequipment.quick"] == slot.ToString()));
	}

	internal static void AssignQuick(Player player, int slot, ItemData item)
	{
		if ((item == null || ((Humanoid)player).GetInventory().ContainsItem(item)) && Rules.AssignShortcut(((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).Select((Func<ItemData, IDictionary<string, string>>)((ItemData i) => i.m_customData)), "au.tyvalheim.rpgequipment.quick", slot, item?.m_customData))
		{
			InventorySafety.Changed(((Humanoid)player).GetInventory());
		}
	}

	internal static void UseQuick(Player player, int slot)
	{
		ItemData val = QuickItem(player, slot);
		if (val != null && !((Character)player).IsDead())
		{
			((Humanoid)player).UseItem(((Humanoid)player).GetInventory(), val, false);
		}
	}

	internal string KeyLabel(int slot)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = keys[slot].Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
		{
			return ((object)keys[slot].Value/*cast due to .constrained prefix*/).ToString();
		}
		return "Set key";
	}

	internal string SetKey(int slot, KeyCode key, KeyCode[] modifiers)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		if ((int)key != 0)
		{
			string text = KeyBindings.GameConflict(key);
			if (text != null)
			{
				return "Already used by Valheim: " + text;
			}
			for (int i = 0; i < keys.Length; i++)
			{
				if (i == slot)
				{
					continue;
				}
				KeyboardShortcut value = keys[i].Value;
				if (((KeyboardShortcut)(ref value)).MainKey == key)
				{
					KeyboardShortcut value2 = keys[i].Value;
					if (((KeyboardShortcut)(ref value2)).Modifiers.OrderBy((KeyCode k) => (int)k).SequenceEqual(modifiers.OrderBy((KeyCode k) => (int)k)))
					{
						return "Already assigned to quick slot " + (i + 1);
					}
				}
			}
		}
		keys[slot].Value = new KeyboardShortcut(key, modifiers);
		((BaseUnityPlugin)this).Config.Save();
		return null;
	}

	private void Update()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		if (!Ready)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (SetInputAllowed(localPlayer))
		{
			for (int i = 0; i < keys.Length; i++)
			{
				KeyboardShortcut value = keys[i].Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					KeyboardShortcut value2 = keys[i].Value;
					if (((KeyboardShortcut)(ref value2)).IsDown())
					{
						UseQuick(localPlayer, i);
					}
				}
			}
		}
		HandleSetKeys(localPlayer);
		if (uiFaulted)
		{
			return;
		}
		try
		{
			if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_player != (Object)null && (Object)(object)InventoryGui.instance.m_playerName != (Object)null && (Object)(object)InventoryGui.instance.m_playerGrid != (Object)null && (Object)(object)InventoryGui.instance.m_playerGrid.m_elementPrefab != (Object)null && (Object)(object)InventoryGui.instance.m_playerName.font != (Object)null && (panel == null || (Object)(object)panel.Gui != (Object)(object)InventoryGui.instance))
			{
				if (panel != null)
				{
					panel.Dispose();
				}
				panel = new EquipmentPanel(InventoryGui.instance, this);
			}
			if (panel != null)
			{
				panel.Tick(localPlayer);
			}
		}
		catch (Exception ex)
		{
			uiFaulted = true;
			if (panel != null)
			{
				panel.Dispose();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Character panel disabled after a UI error; inventory persistence patches remain active: " + ex));
		}
	}

	internal static bool SetInputAllowed(Player player)
	{
		if ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.