Decompiled source of MoreSpellSlots v1.1.4

plugins/MoreSpellSlots.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MoreSpellSlots")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a9352b86c54d6fad225c6e20c794c2fa03c16fff")]
[assembly: AssemblyProduct("MoreSpellSlots")]
[assembly: AssemblyTitle("MoreSpellSlots")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MoreSpellSlots
{
	internal static class HostConfig
	{
		private static ConfigFile cfg;

		private static string messageName;

		private static string[] personal;

		private static Dictionary<string, string> whenHostLacksMod;

		private static Func<bool> active;

		private static HandleNamedMessageDelegate handler;

		private static IntPtr registeredOn;

		private static float nextSend;

		private static float joinedAt;

		private static string lastSent;

		private static string lastApplied;

		private static bool overriding;

		private static bool heardFromHost;

		private static bool warnedMissing;

		private static bool savedFlag;

		private static bool savingPersonal;

		private static readonly Dictionary<ConfigEntryBase, string> originals = new Dictionary<ConfigEntryBase, string>();

		internal static bool FromHost
		{
			get
			{
				if (overriding)
				{
					return heardFromHost;
				}
				return false;
			}
		}

		internal static void Init(BasePlugin plugin, string guid, string[] personalKeys, Dictionary<string, string> offWithoutHost, Func<bool> isActive = null)
		{
			cfg = plugin.Config;
			messageName = guid + ".HostConfig";
			personal = personalKeys ?? Array.Empty<string>();
			whenHostLacksMod = offWithoutHost ?? new Dictionary<string, string>();
			active = isActive;
			cfg.SettingChanged += OnSettingChanged;
			plugin.AddComponent<HostConfigRunner>();
		}

		private static void OnSettingChanged(object sender, SettingChangedEventArgs e)
		{
			try
			{
				if (overriding && !savingPersonal && IsPersonal(e.ChangedSetting.Definition))
				{
					SavePersonal();
				}
			}
			catch
			{
			}
		}

		private static string Id(ConfigDefinition d)
		{
			return d.Section + "." + d.Key;
		}

		private static bool IsPersonal(ConfigDefinition d)
		{
			string[] array = personal;
			foreach (string text in array)
			{
				if (text.EndsWith(".*") ? (d.Section == text.Substring(0, text.Length - 2)) : (Id(d) == text))
				{
					return true;
				}
			}
			return false;
		}

		internal static void Tick()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				bool flag = (Object)(object)singleton != (Object)null && singleton.IsListening;
				if (!flag || singleton.IsServer || (active != null && !active()))
				{
					if (overriding)
					{
						Restore();
					}
					if (flag && singleton.IsServer)
					{
						HostTick(singleton);
					}
					if (!flag)
					{
						registeredOn = IntPtr.Zero;
					}
				}
				else
				{
					ClientTick(singleton);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag2 = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(15, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Host settings: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}

		private static void HostTick(NetworkManager nm)
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < nextSend || nm.CustomMessagingManager == null)
			{
				return;
			}
			nextSend = Time.unscaledTime + 1.5f;
			List<string> list = new List<string>();
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in cfg)
			{
				if (!IsPersonal(item.Key))
				{
					list.Add(item.Key.Section + "\u001f" + item.Key.Key + "\u001f" + item.Value.GetSerializedValue());
				}
			}
			string text = string.Join("\u001e", list);
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(text.Length * 2 + 64, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe(text, false);
				nm.CustomMessagingManager.SendNamedMessageToAll(messageName, val, (NetworkDelivery)4);
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
			if (text != lastSent)
			{
				lastSent = text;
				Plugin.Log.LogInfo((object)"Sending this game's settings to all players.");
			}
		}

		private static void ClientTick(NetworkManager nm)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = nm.CustomMessagingManager;
			if (customMessagingManager != null && registeredOn != ((Il2CppObjectBase)customMessagingManager).Pointer)
			{
				if (handler == null)
				{
					handler = DelegateSupport.ConvertDelegate<HandleNamedMessageDelegate>((Delegate)new Action<ulong, FastBufferReader>(OnReceived));
				}
				customMessagingManager.RegisterNamedMessageHandler(messageName, handler);
				registeredOn = ((Il2CppObjectBase)customMessagingManager).Pointer;
			}
			if (!overriding)
			{
				Begin();
				joinedAt = Time.unscaledTime;
				foreach (KeyValuePair<string, string> item in whenHostLacksMod)
				{
					Set(item.Key, item.Value);
				}
			}
			if (!heardFromHost && !warnedMissing && Time.unscaledTime - joinedAt > 15f)
			{
				warnedMissing = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(88, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No settings from the host: the host doesn't seem to have ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("MoreSpellSlots");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", so it stays off in this game.");
				}
				log.LogWarning(val);
			}
		}

		private static void OnReceived(ulong sender, FastBufferReader reader)
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				string text = default(string);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
				if (!overriding)
				{
					Begin();
				}
				heardFromHost = true;
				if (text == lastApplied)
				{
					return;
				}
				lastApplied = text;
				int num = 0;
				string[] array = text.Split('\u001e');
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split('\u001f');
					if (array2.Length == 3)
					{
						ConfigDefinition d = new ConfigDefinition(array2[0], array2[1]);
						if (!IsPersonal(d) && Set(Id(d), array2[2]))
						{
							num++;
						}
					}
				}
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Using the host's settings (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" values).");
				}
				log.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Host settings (receive): ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log2.LogError(val2);
			}
		}

		private static void Begin()
		{
			overriding = true;
			heardFromHost = false;
			warnedMissing = false;
			lastApplied = null;
			savedFlag = cfg.SaveOnConfigSet;
			cfg.SaveOnConfigSet = false;
		}

		private static bool Set(string id, string value)
		{
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in cfg)
			{
				if (!(Id(item.Key) != id))
				{
					ConfigEntryBase value2 = item.Value;
					if (!originals.ContainsKey(value2))
					{
						originals[value2] = value2.GetSerializedValue();
					}
					if (value2.GetSerializedValue() != value)
					{
						value2.SetSerializedValue(value);
					}
					return true;
				}
			}
			return false;
		}

		private static void SavePersonal()
		{
			savingPersonal = true;
			Dictionary<ConfigEntryBase, string> dictionary = new Dictionary<ConfigEntryBase, string>();
			try
			{
				foreach (KeyValuePair<ConfigEntryBase, string> original in originals)
				{
					dictionary[original.Key] = original.Key.GetSerializedValue();
					original.Key.SetSerializedValue(original.Value);
				}
				cfg.Save();
			}
			finally
			{
				foreach (KeyValuePair<ConfigEntryBase, string> item in dictionary)
				{
					try
					{
						item.Key.SetSerializedValue(item.Value);
					}
					catch
					{
					}
				}
				savingPersonal = false;
			}
		}

		private static void Restore()
		{
			foreach (KeyValuePair<ConfigEntryBase, string> original in originals)
			{
				try
				{
					original.Key.SetSerializedValue(original.Value);
				}
				catch
				{
				}
			}
			originals.Clear();
			overriding = false;
			heardFromHost = false;
			lastApplied = null;
			cfg.SaveOnConfigSet = savedFlag;
			try
			{
				cfg.Save();
			}
			catch
			{
			}
			Plugin.Log.LogInfo((object)"Left the game; back to this computer's own settings.");
		}
	}
	public class HostConfigRunner : MonoBehaviour
	{
		public HostConfigRunner(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			HostConfig.Tick();
		}
	}
	[HarmonyPatch]
	internal static class HostSettings
	{
		private const string MessageName = "girthy_mods.MoreSpellSlots.Settings";

		private static HandleNamedMessageDelegate handler;

		private static Dictionary<string, string> synced;

		internal static bool Enabled
		{
			get
			{
				if (synced == null || !synced.TryGetValue("Enabled", out var value) || !bool.TryParse(value, out var result))
				{
					return Plugin.Enabled.Value;
				}
				return result;
			}
		}

		internal static int ExtraSlots
		{
			get
			{
				if (!Enabled)
				{
					return 0;
				}
				return Math.Clamp(Int("ExtraSlots", Plugin.ExtraSlots.Value), 0, 6);
			}
		}

		internal static int LevelsBetween => Math.Max(1, Int("LevelsBetween", Plugin.LevelsBetween.Value));

		internal static int FirstExtraLevel => Math.Max(0, Int("FirstExtraLevel", Plugin.FirstExtraLevel.Value));

		private static int Int(string key, int local)
		{
			if (synced == null || !synced.TryGetValue(key, out var value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return local;
			}
			return result;
		}

		[HarmonyPatch(typeof(RunManager), "OnNetworkSpawn")]
		[HarmonyPostfix]
		private static void Listen()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && !singleton.IsServer && singleton.CustomMessagingManager != null)
				{
					if (handler == null)
					{
						handler = DelegateSupport.ConvertDelegate<HandleNamedMessageDelegate>((Delegate)new Action<ulong, FastBufferReader>(OnReceived));
					}
					singleton.CustomMessagingManager.RegisterNamedMessageHandler("girthy_mods.MoreSpellSlots.Settings", handler);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Host settings (listen): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private static void OnReceived(ulong sender, FastBufferReader reader)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				string text = default(string);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				string[] array = text.Split(';');
				foreach (string text2 in array)
				{
					int num = text2.IndexOf('=');
					if (num > 0)
					{
						dictionary[text2.Substring(0, num)] = text2.Substring(num + 1);
					}
				}
				synced = dictionary;
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(38, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Using the host's spell slot settings: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				}
				log.LogInfo(val);
				HudPatches.RefreshAll();
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Host settings (receive): ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
		}

		[HarmonyPatch(typeof(RunManager), "StartRunOnServerRpc")]
		[HarmonyPrefix]
		private static void StartRun_Prefix(RunManager __instance, out bool __state)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			__state = false;
			try
			{
				__state = (int)((NetworkBehaviour)__instance).__rpc_exec_stage == 1;
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(RunManager), "StartRunOnServerRpc")]
		[HarmonyPostfix]
		private static void StartRun_Postfix(bool __state)
		{
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (!__state)
			{
				return;
			}
			bool value = default(bool);
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer || singleton.CustomMessagingManager == null)
				{
					return;
				}
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				string[] array = new string[4];
				value = Plugin.Enabled.Value;
				array[0] = "Enabled=" + value;
				array[1] = "ExtraSlots=" + Plugin.ExtraSlots.Value.ToString(invariantCulture);
				array[2] = "LevelsBetween=" + Plugin.LevelsBetween.Value.ToString(invariantCulture);
				array[3] = "FirstExtraLevel=" + Plugin.FirstExtraLevel.Value.ToString(invariantCulture);
				string text = string.Join(";", array);
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(Encoding.UTF8.GetByteCount(text) * 2 + 64, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(text, false);
					singleton.CustomMessagingManager.SendNamedMessageToAll("girthy_mods.MoreSpellSlots.Settings", val, (NetworkDelivery)4);
				}
				finally
				{
					((FastBufferWriter)(ref val)).Dispose();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref value);
				if (value)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Host settings (send): ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log.LogError(val2);
			}
		}

		[HarmonyPatch(typeof(RunManager), "OnDestroy")]
		[HarmonyPostfix]
		private static void Clear()
		{
			synced = null;
		}
	}
	[HarmonyPatch]
	internal static class HudPatches
	{
		private sealed class State
		{
			public GameObject Template;

			public int BaseCount;

			public float Step;

			public float Y;

			public readonly List<Vector2> BasePos = new List<Vector2>();

			public RectTransform Avoid;

			public Vector2 AvoidSize;

			public int LaidOutFor = -1;
		}

		private const float MaxRowWidth = 1600f;

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

		private static float nextErrorLog;

		private static bool Alive(Object o)
		{
			if (o != null && !((Il2CppObjectBase)o).WasCollected)
			{
				return o != (Object)null;
			}
			return false;
		}

		[HarmonyPatch(typeof(SpellSlotsDisplay), "SetSlotsForMaxAmountOfSpells")]
		[HarmonyPostfix]
		private static void SetSlots_Postfix(SpellSlotsDisplay __instance)
		{
			Ensure(__instance);
		}

		[HarmonyPatch(typeof(SpellSlotsDisplay), "OnSpellEquipped")]
		[HarmonyPrefix]
		private static void SpellEquipped_Prefix(SpellSlotsDisplay __instance)
		{
			Ensure(__instance);
		}

		[HarmonyPatch(typeof(SpellSlotsDisplay), "AssureSpellsEarlierGrantedIsShown")]
		[HarmonyPostfix]
		private static void EarlierGranted_Postfix(SpellSlotsDisplay __instance)
		{
			Ensure(__instance);
		}

		internal static void RefreshAll()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			try
			{
				foreach (SpellSlotsDisplay item in Object.FindObjectsOfType<SpellSlotsDisplay>())
				{
					if (Alive((Object)(object)item))
					{
						Ensure(item, reshow: true);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(19, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Spell bar refresh: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private static void Ensure(SpellSlotsDisplay display, bool reshow = false)
		{
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Expected O, but got Unknown
			try
			{
				if (!Alive((Object)(object)display))
				{
					return;
				}
				SpellSlotLayout activeLayout = display.activeLayout;
				if (!Alive((Object)(object)activeLayout))
				{
					return;
				}
				List<SpellSlot> slots = activeLayout.slots;
				if (slots == null || slots.Count == 0)
				{
					return;
				}
				if (!states.TryGetValue(((Il2CppObjectBase)activeLayout).Pointer, out var value) || !Alive((Object)(object)value.Template))
				{
					if (slots.Count < 2)
					{
						return;
					}
					value = Capture(activeLayout, slots);
					if (value == null)
					{
						return;
					}
					states[((Il2CppObjectBase)activeLayout).Pointer] = value;
				}
				int num = 0;
				try
				{
					num = display.GetEquippedSpells()?.Count ?? 0;
				}
				catch
				{
				}
				int num2 = ((value.BaseCount >= 4 && StorePatches.NormalSpellCount() >= 4) ? HostSettings.ExtraSlots : 0);
				int num3 = Math.Max(value.BaseCount + num2, Math.Min(num, value.BaseCount + 6));
				bool flag = false;
				while (slots.Count < num3)
				{
					GameObject val = Object.Instantiate<GameObject>(value.Template, value.Template.transform.parent);
					((Object)val).name = $"SpellSlot{slots.Count + 1}";
					val.SetActive(true);
					SpellSlot component = val.GetComponent<SpellSlot>();
					if ((Object)(object)component == (Object)null)
					{
						Object.Destroy((Object)(object)val);
						break;
					}
					try
					{
						component.isStatApplicableChecker = slots[0].isStatApplicableChecker;
					}
					catch
					{
					}
					slots.Add(component);
					flag = true;
				}
				while (slots.Count > num3 && slots.Count > value.BaseCount)
				{
					SpellSlot val2 = slots[slots.Count - 1];
					slots.RemoveAt(slots.Count - 1);
					if (Alive((Object)(object)val2))
					{
						Object.Destroy((Object)(object)((Component)val2).gameObject);
					}
					flag = true;
				}
				if (flag || value.LaidOutFor != slots.Count)
				{
					Arrange(value, slots);
				}
				Label(value, slots, num);
				if (!(flag || reshow) || num <= 0)
				{
					return;
				}
				try
				{
					display.ShowSpells(display.GetEquippedSpells());
				}
				catch
				{
				}
			}
			catch (Exception ex)
			{
				if (!(Time.unscaledTime < nextErrorLog))
				{
					nextErrorLog = Time.unscaledTime + 10f;
					ManualLogSource log = Plugin.Log;
					bool flag2 = default(bool);
					BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(11, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Spell bar: ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
					}
					log.LogError(val3);
				}
			}
		}

		private static State Capture(SpellSlotLayout layout, List<SpellSlot> slots)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			State state = new State
			{
				BaseCount = slots.Count
			};
			for (int i = 0; i < slots.Count; i++)
			{
				RectTransform component = ((Component)slots[i]).GetComponent<RectTransform>();
				if ((Object)(object)component == (Object)null)
				{
					return null;
				}
				state.BasePos.Add(component.anchoredPosition);
			}
			state.Step = Math.Abs(state.BasePos[state.BaseCount - 1].x - state.BasePos[state.BaseCount - 2].x);
			if (state.Step < 50f)
			{
				state.Step = 228f;
			}
			state.Y = state.BasePos[state.BaseCount - 1].y;
			GameObject gameObject = ((Component)slots[state.BaseCount - 1]).gameObject;
			state.Template = Object.Instantiate<GameObject>(gameObject, gameObject.transform.parent);
			state.Template.SetActive(false);
			((Object)state.Template).name = "MoreSpellSlots_Template";
			Transform val = ((Component)layout).transform.Find("AvoidanceRect");
			if ((Object)(object)val != (Object)null)
			{
				state.Avoid = ((Component)val).GetComponent<RectTransform>();
				if ((Object)(object)state.Avoid != (Object)null)
				{
					state.AvoidSize = state.Avoid.sizeDelta;
				}
			}
			try
			{
				TMP_Text spellSlotLevelText = slots[state.BaseCount - 1].spellSlotLevelText;
				if ((Object)(object)spellSlotLevelText != (Object)null && int.TryParse(spellSlotLevelText.text?.Trim(), out var result) && result > 0)
				{
					StorePatches.HudHint = result;
				}
			}
			catch
			{
			}
			return state;
		}

		private static void Arrange(State st, List<SpellSlot> slots)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			int num = (st.LaidOutFor = slots.Count);
			if (num <= st.BaseCount)
			{
				for (int i = 0; i < num && i < st.BasePos.Count; i++)
				{
					RectTransform component = ((Component)slots[i]).GetComponent<RectTransform>();
					component.anchoredPosition = st.BasePos[i];
					((Transform)component).localScale = Vector3.one;
				}
				if ((Object)(object)st.Avoid != (Object)null)
				{
					st.Avoid.sizeDelta = st.AvoidSize;
				}
				return;
			}
			float num2 = Mathf.Min(1f, 1600f / ((float)num * st.Step));
			float num3 = st.Step * num2;
			for (int j = 0; j < num; j++)
			{
				RectTransform component2 = ((Component)slots[j]).GetComponent<RectTransform>();
				component2.anchoredPosition = new Vector2(((float)j - (float)(num - 1) / 2f) * num3, st.Y);
				((Transform)component2).localScale = new Vector3(num2, num2, 1f);
			}
			if ((Object)(object)st.Avoid != (Object)null)
			{
				st.Avoid.sizeDelta = new Vector2(st.AvoidSize.x * ((float)num * num3) / ((float)st.BaseCount * st.Step), st.AvoidSize.y);
			}
		}

		private static void Label(State st, List<SpellSlot> slots, int equipped)
		{
			if (slots.Count <= st.BaseCount)
			{
				return;
			}
			try
			{
				TMP_Text spellSlotLevelText = slots[st.BaseCount - 1].spellSlotLevelText;
				if ((Object)(object)spellSlotLevelText != (Object)null && int.TryParse(spellSlotLevelText.text?.Trim(), out var result) && result > 0)
				{
					StorePatches.HudHint = result;
				}
			}
			catch
			{
			}
			List<int> list = StorePatches.ExtraLevels();
			for (int i = st.BaseCount; i < slots.Count; i++)
			{
				if (i < equipped)
				{
					continue;
				}
				int num = i - st.BaseCount;
				try
				{
					TMP_Text spellSlotLevelText2 = slots[i].spellSlotLevelText;
					if (!((Object)(object)spellSlotLevelText2 == (Object)null))
					{
						string text = ((num < list.Count) ? list[num].ToString() : "");
						if (spellSlotLevelText2.text != text)
						{
							spellSlotLevelText2.SetText(text);
						}
					}
				}
				catch
				{
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Owed
	{
		private const string MessageName = "girthy_mods.MoreSpellSlots.Owed";

		private static HandleNamedMessageDelegate handler;

		private static IntPtr registeredOn;

		private static List<ulong> hostOwed;

		private static bool storeSeenOpen;

		private static float offeredAt;

		private static float nextCheck;

		private static float runSeenAt = -1f;

		private static int lastLevel;

		private static float armedUntil;

		private static float levelChangedAt;

		private static float nextLevelLook;

		private static IntPtr runPtr;

		private static readonly Dictionary<ulong, (int count, float since)> stable = new Dictionary<ulong, (int, float)>();

		private static HashSet<ulong> local;

		private static bool localWaitingShown;

		private static float localSince;

		internal const string SpecialStoreFlag = "girthy_mods.SpecialStore";

		private static StoreManager store;

		private static StoreManager Store
		{
			get
			{
				if (!Alive((Object)(object)store))
				{
					store = Object.FindObjectOfType<StoreManager>();
				}
				return store;
			}
		}

		internal static bool ForceSpellShop
		{
			get
			{
				if (local != null)
				{
					return local.Contains(Me());
				}
				return false;
			}
		}

		private static void SetFlag(bool on)
		{
			try
			{
				AppDomain.CurrentDomain.SetData("girthy_mods.SpecialStore", on ? ((object)Time.realtimeSinceStartup) : null);
			}
			catch
			{
			}
		}

		private static bool FlagSet()
		{
			try
			{
				return AppDomain.CurrentDomain.GetData("girthy_mods.SpecialStore") is float num && Time.realtimeSinceStartup - num < 180f;
			}
			catch
			{
				return false;
			}
		}

		private static bool Alive(Object o)
		{
			if (o != null && !((Il2CppObjectBase)o).WasCollected)
			{
				return o != (Object)null;
			}
			return false;
		}

		private static ulong Me()
		{
			try
			{
				return NetworkManager.Singleton.LocalClientId;
			}
			catch
			{
				return ulong.MaxValue;
			}
		}

		internal static void Tick()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Listen();
			LocalTick();
			try
			{
				HostTick();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(13, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Owed spells: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
				nextCheck = Time.unscaledTime + 10f;
			}
		}

		private static bool StoreBusy(StoreManager s)
		{
			try
			{
				return s.showStoresCoroutine != null || s.IsShopPanelActive || s.IsExitingStore;
			}
			catch
			{
				return true;
			}
		}

		private static void HostTick()
		{
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening || !singleton.IsServer || !HostSettings.Enabled)
			{
				hostOwed = null;
				return;
			}
			StoreManager val = Store;
			if ((Object)(object)val == (Object)null)
			{
				hostOwed = null;
				return;
			}
			if (((Il2CppObjectBase)val).Pointer != runPtr)
			{
				runPtr = ((Il2CppObjectBase)val).Pointer;
				runSeenAt = Time.unscaledTime;
				stable.Clear();
				hostOwed = null;
				SetFlag(on: false);
				lastLevel = 0;
				armedUntil = 0f;
			}
			WatchLevel();
			if (hostOwed != null)
			{
				if (StoreBusy(val))
				{
					storeSeenOpen = true;
				}
				else if (storeSeenOpen || Time.unscaledTime - offeredAt > 20f)
				{
					hostOwed = null;
					SetFlag(on: false);
					Announce(null);
					nextCheck = Time.unscaledTime + 2f;
				}
			}
			else
			{
				if (Time.unscaledTime >= armedUntil || Time.unscaledTime < nextCheck)
				{
					return;
				}
				nextCheck = Time.unscaledTime + 2f;
				if (Time.unscaledTime - levelChangedAt < 10f || Time.unscaledTime - runSeenAt < 20f || StoreBusy(val) || Time.timeScale <= 0.01f || FlagSet())
				{
					return;
				}
				PartyLevelManager val2 = Object.FindObjectOfType<PartyLevelManager>();
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				if (StorePatches.Checker == null)
				{
					try
					{
						ISpellStoreAvailabilityChecker spellStoreAvailabilityChecker = val.spellStoreAvailabilityChecker;
						StorePatches.Checker = ((spellStoreAvailabilityChecker != null) ? ((Il2CppObjectBase)spellStoreAvailabilityChecker).TryCast<SpellStoreAvailabilityChecker>() : null);
					}
					catch
					{
					}
				}
				int num = StorePatches.SpellsEarnedAt(val2.level);
				if (num <= 1)
				{
					return;
				}
				List<ulong> list = new List<ulong>();
				int num2 = 0;
				foreach (GameplayPlayerIdentity item in Object.FindObjectsOfType<GameplayPlayerIdentity>())
				{
					if (!((Object)(object)item == (Object)null) && ((NetworkBehaviour)item).IsSpawned)
					{
						int valueOrDefault;
						try
						{
							SpellEquipper spellEquipper = item.spellEquipper;
							valueOrDefault = ((spellEquipper == null) ? ((int?)null) : spellEquipper.equippedSpells?.Count).GetValueOrDefault();
						}
						catch
						{
							continue;
						}
						(int, float) value;
						if (valueOrDefault <= 0)
						{
							num2++;
						}
						else if (!stable.TryGetValue(((NetworkBehaviour)item).OwnerClientId, out value) || value.Item1 != valueOrDefault)
						{
							stable[((NetworkBehaviour)item).OwnerClientId] = (valueOrDefault, Time.unscaledTime);
							num2++;
						}
						else if (Time.unscaledTime - value.Item2 < 8f)
						{
							num2++;
						}
						else if (valueOrDefault < num)
						{
							list.Add(((NetworkBehaviour)item).OwnerClientId);
						}
					}
				}
				if (list.Count == 0)
				{
					if (num2 == 0 && stable.Count > 0)
					{
						armedUntil = 0f;
						Plugin.Log.LogInfo((object)"Everyone has the spells their level has earned.");
					}
					return;
				}
				hostOwed = list;
				SetFlag(on: true);
				storeSeenOpen = false;
				offeredAt = Time.unscaledTime;
				Announce(list);
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(62, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Owed spell shop for ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(list.Count);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" player(s) (party level ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(val2.level);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" spells earned).");
				}
				log.LogInfo(val3);
				val.OfferStoreToAllPlayers((StoreType)0);
			}
		}

		private static void WatchLevel()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			if (Time.unscaledTime < nextLevelLook)
			{
				return;
			}
			nextLevelLook = Time.unscaledTime + 0.5f;
			PartyLevelManager val = Object.FindObjectOfType<PartyLevelManager>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int level = val.level;
			if (level == lastLevel)
			{
				return;
			}
			if (lastLevel > 0 && level - lastLevel >= 2)
			{
				armedUntil = Time.unscaledTime + 300f;
				stable.Clear();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(71, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Party level jumped ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(lastLevel);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" -> ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(level);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (resumed save): checking for spells nobody got.");
				}
				log.LogInfo(val2);
			}
			lastLevel = level;
			levelChangedAt = Time.unscaledTime;
		}

		[HarmonyPatch(typeof(StoreManager), "PrepareChoosingPlayers")]
		[HarmonyPostfix]
		private static void PrepareChoosing_Postfix(StoreManager __instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			List<ulong> list = hostOwed;
			if (list == null)
			{
				return;
			}
			try
			{
				__instance.SetChoosingPlayersRpc(new Il2CppStructArray<ulong>(list.ToArray()));
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Owed spells (choosers): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}

		[HarmonyPatch(typeof(StoreManager), "StartCountdown")]
		[HarmonyPrefix]
		private static bool StartCountdown_Prefix()
		{
			if (hostOwed == null)
			{
				return local == null;
			}
			return false;
		}

		[HarmonyPatch(typeof(StoreManager), "KickPlayer")]
		[HarmonyPrefix]
		private static bool Kick_Prefix()
		{
			if (hostOwed == null)
			{
				return local == null;
			}
			return false;
		}

		[HarmonyPatch(typeof(StoreManager), "ChooseShopItem")]
		[HarmonyPrefix]
		private static bool Choose_Prefix()
		{
			if (local != null)
			{
				return local.Contains(Me());
			}
			return true;
		}

		[HarmonyPatch(typeof(StoreManager), "Reroll")]
		[HarmonyPrefix]
		private static bool Reroll_Prefix()
		{
			if (local != null)
			{
				return local.Contains(Me());
			}
			return true;
		}

		private static void LocalTick()
		{
			if (local == null)
			{
				return;
			}
			if (Time.unscaledTime - localSince > 120f)
			{
				local = null;
				return;
			}
			StoreManager val = Store;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool flag = false;
			try
			{
				flag = val.IsShopPanelActive;
			}
			catch
			{
			}
			if (!flag || localWaitingShown || local.Contains(Me()))
			{
				return;
			}
			localWaitingShown = true;
			try
			{
				StorePanel storePanel = val.storePanel;
				if (storePanel != null)
				{
					storePanel.SetAsWaitingForOtherPlayers();
				}
			}
			catch
			{
			}
		}

		private static void Listen()
		{
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.IsServer || singleton.CustomMessagingManager == null)
				{
					if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
					{
						registeredOn = IntPtr.Zero;
					}
					return;
				}
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				if (!(registeredOn == ((Il2CppObjectBase)customMessagingManager).Pointer))
				{
					if (handler == null)
					{
						handler = DelegateSupport.ConvertDelegate<HandleNamedMessageDelegate>((Delegate)new Action<ulong, FastBufferReader>(OnMessage));
					}
					customMessagingManager.RegisterNamedMessageHandler("girthy_mods.MoreSpellSlots.Owed", handler);
					registeredOn = ((Il2CppObjectBase)customMessagingManager).Pointer;
				}
			}
			catch
			{
			}
		}

		private static void Announce(List<ulong> ids)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			SetLocal(ids);
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer || singleton.CustomMessagingManager == null)
				{
					return;
				}
				string text = ((ids == null) ? "end" : string.Join(",", ids.ConvertAll((ulong i) => i.ToString(CultureInfo.InvariantCulture))));
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(text.Length * 2 + 64, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(text, false);
					singleton.CustomMessagingManager.SendNamedMessageToAll("girthy_mods.MoreSpellSlots.Owed", val, (NetworkDelivery)4);
				}
				finally
				{
					((FastBufferWriter)(ref val)).Dispose();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(20, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Owed spells (send): ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val2);
			}
		}

		private static void OnMessage(ulong sender, FastBufferReader reader)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			try
			{
				string text = default(string);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
				if (text == "end")
				{
					SetLocal(null);
					return;
				}
				List<ulong> list = new List<ulong>();
				string[] array = text.Split(',');
				for (int i = 0; i < array.Length; i++)
				{
					if (ulong.TryParse(array[i], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
					{
						list.Add(result);
					}
				}
				SetLocal(list);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(23, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Owed spells (receive): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}

		private static void SetLocal(List<ulong> ids)
		{
			local = ((ids == null) ? null : new HashSet<ulong>(ids));
			localWaitingShown = false;
			localSince = Time.unscaledTime;
		}
	}
	public class Runner : MonoBehaviour
	{
		public Runner(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			Owed.Tick();
		}
	}
	[BepInPlugin("girthy_mods.MoreSpellSlots", "MoreSpellSlots", "1.1.4")]
	public class Plugin : BasePlugin
	{
		public const string Guid = "girthy_mods.MoreSpellSlots";

		public const string Name = "MoreSpellSlots";

		public const string Version = "1.1.4";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> ExtraSlots;

		internal static ConfigEntry<int> LevelsBetween;

		internal static ConfigEntry<int> FirstExtraLevel;

		public override void Load()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			HostConfig.Init((BasePlugin)(object)this, "girthy_mods.MoreSpellSlots", Array.Empty<string>(), new Dictionary<string, string> { ["Spell Slots.Enabled"] = "false" });
			Enabled = ((BasePlugin)this).Config.Bind<bool>("Spell Slots", "Enabled", true, "Add extra spell slots.");
			ExtraSlots = ((BasePlugin)this).Config.Bind<int>("Spell Slots", "ExtraSlots", 2, new ConfigDescription("How many spells you can have on top of the normal 4.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			LevelsBetween = ((BasePlugin)this).Config.Bind<int>("Spell Slots", "LevelsBetweenExtraSpells", 6, new ConfigDescription("Party levels between each extra spell shop.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			FirstExtraLevel = ((BasePlugin)this).Config.Bind<int>("Spell Slots", "FirstExtraSpellLevel", 0, new ConfigDescription("Party level of the first extra spell shop. 0 = the last normal spell level + LevelsBetweenExtraSpells.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			Harmony val = new Harmony("girthy_mods.MoreSpellSlots");
			val.PatchAll(typeof(StorePatches));
			val.PatchAll(typeof(FifthSpellRarity));
			val.PatchAll(typeof(HudPatches));
			val.PatchAll(typeof(HostSettings));
			val.PatchAll(typeof(Owed));
			((BasePlugin)this).AddComponent<Runner>();
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(8, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("MoreSpellSlots");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.1.4");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ready.");
			}
			log.LogInfo(val2);
		}
	}
	[HarmonyPatch]
	internal static class StorePatches
	{
		private static SpellStoreAvailabilityChecker checker;

		private static int lastNormalLevel;

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

		internal static int HudHint;

		internal static SpellStoreAvailabilityChecker Checker
		{
			get
			{
				return checker;
			}
			set
			{
				checker = value;
			}
		}

		[HarmonyPatch(typeof(SpellStoreAvailabilityChecker), "SpellStoreShouldBeOffered")]
		[HarmonyPostfix]
		private static void ShouldBeOffered_Postfix(SpellStoreAvailabilityChecker __instance, int partyLevel, ref bool __result)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				checker = __instance;
				if (Owed.ForceSpellShop)
				{
					__result = true;
				}
				else
				{
					if (__result || HostSettings.ExtraSlots <= 0 || NormalSpellCount() < 4)
					{
						return;
					}
					List<int> list = ExtraLevels();
					int num = list.IndexOf(partyLevel);
					if (num < 0)
					{
						return;
					}
					__result = true;
					if (logged.Add(partyLevel))
					{
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Extra spell shop at party level ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(partyLevel);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (extra slot ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num + 1);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
						}
						log.LogInfo(val);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(18, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Spell shop check: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
		}

		[HarmonyPatch(typeof(RunManager), "OnDestroy")]
		[HarmonyPostfix]
		private static void RunEnded()
		{
			checker = null;
			lastNormalLevel = 0;
			logged.Clear();
		}

		internal static int NormalSpellCount()
		{
			try
			{
				SpellStoreAvailabilityChecker val = checker;
				if (val != null && !((Il2CppObjectBase)val).WasCollected && val.spellAmountProvider != null)
				{
					return val.spellAmountProvider.GetAmountOfSpellsForRun();
				}
			}
			catch
			{
			}
			return 4;
		}

		internal static int LastNormalLevel(int fromHud)
		{
			try
			{
				SpellStoreAvailabilityChecker val = checker;
				if (val != null && !((Il2CppObjectBase)val).WasCollected)
				{
					Il2CppStructArray<int> val2 = (val.ShouldUseAdjustedSpellLevels() ? val.adjustedLevels : val.baseLevels);
					int num = Math.Min(((Il2CppArrayBase<int>)(object)val2)?.Length ?? 0, NormalSpellCount() - 1);
					if (val2 != null && num > 0)
					{
						int num2 = 0;
						for (int i = 0; i < num; i++)
						{
							num2 = Math.Max(num2, ((Il2CppArrayBase<int>)(object)val2)[i]);
						}
						if (num2 > 0)
						{
							lastNormalLevel = num2;
						}
					}
				}
			}
			catch
			{
			}
			if (lastNormalLevel > 0)
			{
				return lastNormalLevel;
			}
			if (fromHud <= 0)
			{
				return 19;
			}
			return fromHud;
		}

		internal static int SpellsEarnedAt(int partyLevel)
		{
			int num = 1;
			try
			{
				SpellStoreAvailabilityChecker val = checker;
				if (val == null || ((Il2CppObjectBase)val).WasCollected)
				{
					return 0;
				}
				Il2CppStructArray<int> val2 = (val.ShouldUseAdjustedSpellLevels() ? val.adjustedLevels : val.baseLevels);
				int num2 = Math.Min(((Il2CppArrayBase<int>)(object)val2)?.Length ?? 0, NormalSpellCount() - 1);
				for (int i = 0; i < num2; i++)
				{
					if (((Il2CppArrayBase<int>)(object)val2)[i] <= partyLevel)
					{
						num++;
					}
				}
			}
			catch
			{
				return 0;
			}
			foreach (int item in ExtraLevels())
			{
				if (item <= partyLevel)
				{
					num++;
				}
			}
			return num;
		}

		internal static List<int> ExtraLevels()
		{
			int num = ((NormalSpellCount() >= 4) ? HostSettings.ExtraSlots : 0);
			int levelsBetween = HostSettings.LevelsBetween;
			int num2 = HostSettings.FirstExtraLevel;
			int num3 = LastNormalLevel(HudHint);
			if (num2 <= num3)
			{
				num2 = num3 + levelsBetween;
			}
			List<int> list = new List<int>(num);
			for (int i = 0; i < num; i++)
			{
				list.Add(num2 + i * levelsBetween);
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal static class FifthSpellRarity
	{
		[HarmonyPatch(typeof(CatchUpImprovementInventoryGenerator), "TryIncreaseMinimumRarityForNewlyEquippedSpell")]
		[HarmonyPrefix]
		private static void Rarity_Prefix(CatchUpImprovementInventoryGenerator __instance)
		{
			Trim(__instance);
		}

		[HarmonyPatch(typeof(CatchUpImprovementInventoryGenerator), "FilterForSpellImprovementAfterEquippingNewSpell")]
		[HarmonyPrefix]
		private static void Filter_Prefix(CatchUpImprovementInventoryGenerator __instance)
		{
			Trim(__instance);
		}

		private static void Trim(CatchUpImprovementInventoryGenerator g)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			try
			{
				List<SpellType> spellsThatHaveBeenOfferedAnImprovement = g.spellsThatHaveBeenOfferedAnImprovement;
				if (spellsThatHaveBeenOfferedAnImprovement != null)
				{
					int num = (g.shouldOfferImprovementForNewlyEquippedSpell ? 4 : 3);
					while (spellsThatHaveBeenOfferedAnImprovement.Count > num)
					{
						spellsThatHaveBeenOfferedAnImprovement.RemoveAt(0);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(20, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Spell bonus rarity: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}
	}
}