Decompiled source of TerminalLoadouts v1.1.4

BepInEx/plugins/TerminalLoadouts/TerminalLoadouts.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using TerminalLoadouts.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TerminalLoadouts")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.4.0")]
[assembly: AssemblyInformationalVersion("1.1.4")]
[assembly: AssemblyProduct("TerminalLoadouts")]
[assembly: AssemblyTitle("TerminalLoadouts")]
[assembly: AssemblyVersion("1.1.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TerminalLoadouts
{
	internal static class BrutalV1Compatibility
	{
		internal const string PluginId = "com.potpot.brutalv1";

		private static Action<NewMovement> original;

		private static MethodInfo update;

		private static HarmonyMethod originalPatch;

		private static string owner;

		internal static void Install(Harmony harmony)
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_014d: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: 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_01b1: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("com.potpot.brutalv1", out var value))
			{
				return;
			}
			try
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("NewMovementUpdatePatch");
				MethodInfo method = ((type == null) ? null : AccessTools.DeclaredMethod(type, "Postfix", new Type[1] { typeof(NewMovement) }, (Type[])null));
				if (method == null || !method.IsStatic || method.ReturnType != typeof(void))
				{
					throw new InvalidOperationException("Unsupported BrutalV1 movement patch signature.");
				}
				update = AccessTools.DeclaredMethod(typeof(NewMovement), "Update", (Type[])null, (Type[])null);
				Patch val = ((IEnumerable<Patch>)Harmony.GetPatchInfo((MethodBase)update)?.Postfixes).SingleOrDefault((Func<Patch, bool>)((Patch p) => p.PatchMethod == method));
				if (val == null)
				{
					throw new InvalidOperationException("BrutalV1 movement callback is not registered.");
				}
				original = (Action<NewMovement>)Delegate.CreateDelegate(typeof(Action<NewMovement>), method);
				originalPatch = new HarmonyMethod(method)
				{
					priority = val.priority,
					before = val.before,
					after = val.after
				};
				owner = val.owner;
				harmony.Unpatch((MethodBase)update, method);
				try
				{
					harmony.Patch((MethodBase)update, (HarmonyMethod)null, new HarmonyMethod(typeof(BrutalV1Compatibility), "MovementPostfix", (Type[])null)
					{
						priority = val.priority,
						before = val.before,
						after = val.after
					}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				catch
				{
					Restore();
					throw;
				}
				Plugin.Log.LogInfo((object)"BrutalV1 movement guard enabled for loadout dialogs.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not guard BrutalV1 during loadout dialogs: " + ex));
			}
		}

		private static void MovementPostfix(NewMovement __instance)
		{
			if (!LoadoutDialog.IsOpen)
			{
				original?.Invoke(__instance);
			}
		}

		internal static void Restore()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (originalPatch != null)
			{
				new Harmony(owner).Patch((MethodBase)update, (HarmonyMethod)null, originalPatch, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				originalPatch = null;
			}
		}
	}
	internal sealed class EquipmentIcons
	{
		private readonly ShopZone shop;

		private readonly Dictionary<int, Sprite> sprites = new Dictionary<int, Sprite>();

		private readonly HashSet<int> warned = new HashSet<int>();

		internal EquipmentIcons(ShopZone shop)
		{
			this.shop = shop;
		}

		internal Sprite Get(int index, int selection)
		{
			int num = index * 3 + selection;
			if (sprites.TryGetValue(num, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			try
			{
				Sprite val = null;
				if (index < 15)
				{
					GunSetter instance = MonoSingleton<GunSetter>.Instance;
					if (!Object.op_Implicit((Object)(object)instance))
					{
						return null;
					}
					AssetReference[] array = (new AssetReference[15][]
					{
						instance.revolverPierce, instance.revolverTwirl, instance.revolverRicochet, instance.shotgunGrenade, instance.shotgunPump, instance.shotgunRed, instance.nailMagnet, instance.nailOverheat, instance.nailRed, instance.railCannon,
						instance.railHarpoon, instance.railMalicious, instance.rocketBlue, instance.rocketGreen, instance.rocketRed
					})[index];
					int num2 = selection - 1;
					if (array != null && num2 >= 0 && num2 < array.Length)
					{
						GameObject val2 = AddressablesExtensions.ToAsset(array[num2]);
						WeaponIcon val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<WeaponIcon>() : null);
						if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.weaponDescriptor))
						{
							val = val3.weaponDescriptor.icon;
						}
					}
				}
				else
				{
					VariationInfo val4 = ((IEnumerable<VariationInfo>)((Component)shop).GetComponentsInChildren<VariationInfo>(true)).FirstOrDefault((Func<VariationInfo, bool>)((VariationInfo item) => item.weaponName == Catalog.Keys[index]));
					if (Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)val4.icon))
					{
						val = val4.icon.sprite;
					}
				}
				if (Object.op_Implicit((Object)(object)val))
				{
					sprites[num] = val;
				}
				return val;
			}
			catch (Exception ex)
			{
				if (warned.Add(num))
				{
					Plugin.Log.LogWarning((object)("Icon unavailable for " + Catalog.Keys[index] + ": " + ex.Message));
				}
				return null;
			}
		}

		internal static Color ColorFor(int index)
		{
			//IL_0050: 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)
			int num = ((index < 15) ? (index % 3) : (index - 15));
			switch (index)
			{
			case 1:
				num = 2;
				break;
			case 2:
				num = 1;
				break;
			case 16:
				num = 2;
				break;
			case 17:
				num = 1;
				break;
			}
			ColorBlindSettings instance = MonoSingleton<ColorBlindSettings>.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || instance.variationColors == null || num >= instance.variationColors.Length)
			{
				return Color.white;
			}
			return instance.variationColors[num];
		}
	}
	internal sealed class GameEquipment : IEquipmentRuntime
	{
		private readonly PrefsManager prefs;

		private readonly GunSetter setter;

		private readonly FistControl fists;

		private readonly GunControl guns;

		private string selectedName;

		private int selectedSlot;

		private bool wasActivated;

		private readonly GrenadeLauncherCompatibility grenades;

		public bool Restricted
		{
			get
			{
				if (setter.forcedLoadout == null)
				{
					return fists.forcedLoadout != null;
				}
				return true;
			}
		}

		public GameEquipment()
		{
			prefs = MonoSingleton<PrefsManager>.Instance;
			setter = MonoSingleton<GunSetter>.Instance;
			fists = MonoSingleton<FistControl>.Instance;
			guns = MonoSingleton<GunControl>.Instance;
			if (!Object.op_Implicit((Object)(object)prefs) || !Object.op_Implicit((Object)(object)setter) || !Object.op_Implicit((Object)(object)fists) || !Object.op_Implicit((Object)(object)guns) || guns.slots.Count < 5)
			{
				throw new InvalidOperationException("Player equipment is not ready yet.");
			}
			grenades = new GrenadeLauncherCompatibility();
		}

		public int GetInt(string key, int fallback)
		{
			return prefs.GetInt(key, fallback);
		}

		public string GetString(string key, string fallback)
		{
			return prefs.GetString(key, fallback);
		}

		public bool HasKey(string key)
		{
			return prefs.HasKey(key);
		}

		public void SetInt(string key, int value)
		{
			prefs.SetInt(key, value);
		}

		public void SetString(string key, string value)
		{
			prefs.SetString(key, value);
		}

		public void DeleteKey(string key)
		{
			prefs.DeleteKey(key);
		}

		public int Gear(string id)
		{
			return GameProgressSaver.CheckGear(id);
		}

		public bool[] CaptureGrenadeModes()
		{
			return grenades.Capture();
		}

		public void SetGrenadeModes(bool[] modes)
		{
			grenades.Apply(modes);
		}

		public void RememberSelection()
		{
			selectedName = (Object.op_Implicit((Object)(object)guns.currentWeapon) ? ((Object)guns.currentWeapon).name : null);
			selectedSlot = guns.currentSlotIndex - 1;
			wasActivated = guns.activated;
		}

		public void ResetWeapons()
		{
			setter.ResetWeapons(false);
		}

		public void ResetFists()
		{
			fists.ResetFists();
		}

		public void RestoreSelection()
		{
			GameObject target = guns.slots.SelectMany((List<GameObject> s) => s).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w) && ((Object)w).name == selectedName));
			if (!Object.op_Implicit((Object)(object)target) && selectedSlot >= 0 && selectedSlot < guns.slots.Count)
			{
				target = ((IEnumerable<GameObject>)guns.slots[selectedSlot]).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w)));
			}
			if (!Object.op_Implicit((Object)(object)target))
			{
				target = guns.slots.SelectMany((List<GameObject> s) => s).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w)));
			}
			if (Object.op_Implicit((Object)(object)guns.currentWeapon))
			{
				guns.currentWeapon.SetActive(false);
			}
			guns.currentWeapon = null;
			foreach (GameObject item in guns.slots.SelectMany((List<GameObject> s) => s))
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					item.SetActive(false);
				}
			}
			if (Object.op_Implicit((Object)(object)target))
			{
				int num = guns.slots.FindIndex((List<GameObject> s) => s.Contains(target));
				guns.SwitchWeapon(num + 1, (int?)guns.slots[num].IndexOf(target), false, false, false);
				if (!wasActivated)
				{
					guns.NoWeapon();
				}
			}
			else
			{
				guns.currentSlotIndex = 1;
				guns.currentVariationIndex = 0;
				guns.noWeapons = true;
			}
			guns.activated = wasActivated;
		}
	}
	internal sealed class GrenadeLauncherCompatibility
	{
		internal const string PluginId = "docvalentyne.ultrakill.grenadelauncher";

		private readonly BaseUnityPlugin instance;

		private readonly MethodInfo get;

		private readonly MethodInfo set;

		internal static bool IsLoaded
		{
			get
			{
				if (Chainloader.PluginInfos.TryGetValue("docvalentyne.ultrakill.grenadelauncher", out var value) && Object.op_Implicit((Object)(object)value.Instance))
				{
					return ((Behaviour)value.Instance).isActiveAndEnabled;
				}
				return false;
			}
		}

		internal GrenadeLauncherCompatibility()
		{
			if (Chainloader.PluginInfos.TryGetValue("docvalentyne.ultrakill.grenadelauncher", out var value) && Object.op_Implicit((Object)(object)value.Instance) && ((Behaviour)value.Instance).isActiveAndEnabled)
			{
				instance = value.Instance;
				Type type = ((object)instance).GetType();
				get = type.GetMethod("IsGrenadeModeEnabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
				set = type.GetMethod("SetGrenadeModeEnabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
				{
					typeof(int),
					typeof(bool)
				}, null);
				if (get == null || get.ReturnType != typeof(bool) || set == null || set.ReturnType != typeof(void))
				{
					throw new InvalidOperationException("This Grenade Launcher version is unsupported. Loadouts were not changed; compatibility was verified with 2.0.2.");
				}
			}
		}

		internal bool[] Capture()
		{
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			bool[] array = new bool[3];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = (bool)Invoke(get, i);
			}
			return array;
		}

		internal void Apply(bool[] modes)
		{
			if (!Object.op_Implicit((Object)(object)instance))
			{
				throw new InvalidOperationException("Grenade Launcher is no longer available.");
			}
			if (modes == null || modes.Length != 3)
			{
				throw new ArgumentException("Expected three grenade modes.");
			}
			for (int i = 0; i < modes.Length; i++)
			{
				Invoke(set, i, modes[i]);
			}
			for (int j = 0; j < modes.Length; j++)
			{
				if ((bool)Invoke(get, j) != modes[j])
				{
					throw new InvalidOperationException("Grenade Launcher did not accept the saved selection.");
				}
			}
		}

		private object Invoke(MethodInfo method, params object[] args)
		{
			try
			{
				return method.Invoke(instance, args);
			}
			catch (TargetInvocationException ex)
			{
				throw new InvalidOperationException("Grenade Launcher selection failed: " + (ex.InnerException ?? ex).Message, ex.InnerException ?? ex);
			}
		}
	}
	internal sealed class LoadoutDialog : MonoBehaviour
	{
		private static LoadoutDialog current;

		private const string StateKey = "local.terminal-loadouts.dialog";

		private readonly List<EventSystem> suspendedSystems = new List<EventSystem>();

		private EventSystem previousSystem;

		private EventSystem modalSystem;

		private GameObject previousSelection;

		private CursorLockMode previousLock;

		private bool previousVisible;

		private bool closed;

		private TMP_Text template;

		private TMP_Text notice;

		private TMP_InputField input;

		private RectTransform panel;

		private Action<string> accept;

		private bool colorMode;

		private Image sample;

		private Slider[] channels;

		private TMP_Text[] channelLabels;

		private Button save;

		private int openedFrame;

		private ActionSuspension<InputAction> gameplayInput;

		internal static bool IsOpen => (Object)(object)current != (Object)null;

		private static LoadoutDialog Create(TMP_Text template, string title, int height, Action<string> accept)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			if (IsOpen)
			{
				throw new InvalidOperationException("A loadout dialog is already open.");
			}
			GameObject val = new GameObject("TerminalLoadouts Dialog", new Type[1] { typeof(RectTransform) });
			val.SetActive(false);
			LoadoutDialog loadoutDialog = val.AddComponent<LoadoutDialog>();
			try
			{
				current = loadoutDialog;
				loadoutDialog.template = template;
				loadoutDialog.accept = accept;
				loadoutDialog.openedFrame = Time.frameCount;
				loadoutDialog.previousSystem = EventSystem.current;
				loadoutDialog.previousSelection = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null);
				loadoutDialog.previousLock = Cursor.lockState;
				loadoutDialog.previousVisible = Cursor.visible;
				Canvas obj = val.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 30000;
				CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
				obj2.uiScaleMode = (ScaleMode)1;
				obj2.referenceResolution = new Vector2(960f, 540f);
				obj2.matchWidthOrHeight = 0.5f;
				val.AddComponent<GraphicRaycaster>();
				((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.85f);
				loadoutDialog.panel = TerminalUi.Rect("Dialog", val.transform, 0f, 0f, 540f, height);
				RectTransform obj3 = loadoutDialog.panel;
				RectTransform obj4 = loadoutDialog.panel;
				Vector2 val2 = (loadoutDialog.panel.pivot = new Vector2(0.5f, 0.5f));
				Vector2 anchorMin = (obj4.anchorMax = val2);
				obj3.anchorMin = anchorMin;
				((Graphic)((Component)loadoutDialog.panel).gameObject.AddComponent<Image>()).color = LoadoutTheme.Panel;
				((Graphic)loadoutDialog.Text((Transform)(object)loadoutDialog.panel, title, 20f, 12f, 500f, 35f, 26)).color = LoadoutTheme.Accent;
				EventSystem[] array = Object.FindObjectsOfType<EventSystem>();
				foreach (EventSystem val5 in array)
				{
					if (((Behaviour)val5).enabled)
					{
						loadoutDialog.suspendedSystems.Add(val5);
						((Behaviour)val5).enabled = false;
					}
				}
				GameObject val6 = new GameObject("Dialog Input");
				val6.transform.SetParent(val.transform, false);
				loadoutDialog.modalSystem = val6.AddComponent<EventSystem>();
				val6.AddComponent<InputSystemUIInputModule>().AssignDefaultActions();
				GameStateManager.Instance.RegisterState(new GameState("local.terminal-loadouts.dialog", val)
				{
					playerInputLock = (LockMode)1,
					cameraInputLock = (LockMode)1,
					cursorLock = (LockMode)2,
					priority = 100
				});
				return loadoutDialog;
			}
			catch
			{
				loadoutDialog.Close();
				throw;
			}
		}

		internal static LoadoutDialog ShowRename(TMP_Text template, string value, Action<string> accept)
		{
			LoadoutDialog dialog = Create(template, "RENAME LOADOUT", 230, accept);
			try
			{
				dialog.Text((Transform)(object)dialog.panel, "Up to 32 characters. Enter saves; Escape cancels.", 20f, 52f, 500f, 25f, 16);
				dialog.input = dialog.Field("Name", 20f, 92f, 500f, 32, value);
				((UnityEvent<string>)(object)dialog.input.onSubmit).AddListener((UnityAction<string>)delegate
				{
					dialog.Submit();
				});
				dialog.AddButtons(168);
				dialog.Activate(focusText: true);
				return dialog;
			}
			catch
			{
				dialog.Close();
				throw;
			}
		}

		internal static LoadoutDialog ShowColor(TMP_Text template, string value, Action<string> accept)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			LoadoutDialog dialog = Create(template, "LOADOUT SLOT COLOR", 430, accept);
			try
			{
				dialog.colorMode = true;
				dialog.Text((Transform)(object)dialog.panel, "Choose a palette color, adjust RGB, or enter #RRGGBB.", 20f, 50f, 500f, 25f, 16);
				Color val = default(Color);
				for (int i = 0; i < Catalog.Palette.Length; i++)
				{
					string hex = Catalog.Palette[i];
					ColorUtility.TryParseHtmlString("#" + hex, ref val);
					Button obj = dialog.Button((Transform)(object)dialog.panel, "", 20 + i % 10 * 50, 82 + i / 10 * 43, 42f, 35f, delegate
					{
						dialog.SetColor(hex);
					});
					ColorBlock colors = ((Selectable)obj).colors;
					((ColorBlock)(ref colors)).normalColor = val;
					Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = Color.Lerp(val, Color.white, 0.25f));
					((ColorBlock)(ref colors)).highlightedColor = highlightedColor;
					((ColorBlock)(ref colors)).pressedColor = Color.Lerp(val, Color.black, 0.25f);
					((Selectable)obj).colors = colors;
				}
				dialog.sample = ((Component)TerminalUi.Rect("Preview", (Transform)(object)dialog.panel, 20f, 181f, 95f, 114f)).gameObject.AddComponent<Image>();
				dialog.Text((Transform)(object)dialog.panel, "PREVIEW", 20f, 296f, 95f, 20f, 12).alignment = (TextAlignmentOptions)514;
				dialog.channels = (Slider[])(object)new Slider[3];
				dialog.channelLabels = (TMP_Text[])(object)new TMP_Text[3];
				for (int num = 0; num < 3; num++)
				{
					dialog.Text((Transform)(object)dialog.panel, (new string[3] { "R", "G", "B" })[num], 135f, 179 + num * 39, 20f, 25f, 18);
					dialog.channelLabels[num] = dialog.Text((Transform)(object)dialog.panel, "", 477f, 179 + num * 39, 42f, 25f, 16);
					dialog.channels[num] = dialog.Channel(160f, 182 + num * 39);
					((UnityEvent<float>)(object)dialog.channels[num].onValueChanged).AddListener((UnityAction<float>)delegate
					{
						dialog.ReadChannels();
					});
				}
				dialog.Text((Transform)(object)dialog.panel, "HEX", 135f, 306f, 45f, 35f, 18);
				dialog.input = dialog.Field("Hex", 182f, 304f, 180f, 7, "#" + value);
				((UnityEvent<string>)(object)dialog.input.onValueChanged).AddListener((UnityAction<string>)dialog.ReadHex);
				dialog.notice = dialog.Text((Transform)(object)dialog.panel, "", 20f, 346f, 500f, 22f, 14);
				dialog.AddButtons(380);
				dialog.SetColor(value);
				dialog.Activate(focusText: false);
				return dialog;
			}
			catch
			{
				dialog.Close();
				throw;
			}
		}

		private void Activate(bool focusText)
		{
			InputManager manager = MonoSingleton<InputManager>.Instance;
			if (!Object.op_Implicit((Object)(object)manager) || manager.InputSource == null)
			{
				throw new InvalidOperationException("Gameplay input is not ready for a dialog.");
			}
			PlayerInput source = manager.InputSource;
			gameplayInput = ActionSuspension<InputAction>.Suspend((IEnumerable<InputAction>)source.Actions.asset, (InputAction action) => action.enabled, delegate(InputAction action)
			{
				action.Disable();
			}, delegate(InputAction action)
			{
				if (Object.op_Implicit((Object)(object)manager) && manager.InputSource == source)
				{
					action.Enable();
				}
			});
			((Component)this).gameObject.SetActive(true);
			EventSystem.current = modalSystem;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			if (focusText)
			{
				((MonoBehaviour)this).StartCoroutine(FocusAfterOpeningClick());
			}
			else
			{
				modalSystem.SetSelectedGameObject(((Component)save).gameObject);
			}
		}

		private IEnumerator FocusAfterOpeningClick()
		{
			yield return null;
			while (Mouse.current != null && Mouse.current.leftButton.isPressed)
			{
				yield return null;
			}
			yield return null;
			if (!closed && Object.op_Implicit((Object)(object)input))
			{
				modalSystem.SetSelectedGameObject(((Component)input).gameObject);
				((Selectable)input).Select();
				input.ActivateInputField();
			}
		}

		private TMP_InputField Field(string name, float x, float y, float width, int limit, string value)
		{
			//IL_0032: 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)
			RectTransform val = TerminalUi.Rect(name, (Transform)(object)panel, x, y, width, 40f);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)val2).color = new Color(0.1f, 0.19f, 0.21f);
			RectTransform val3 = TerminalUi.Rect("Viewport", (Transform)(object)val, 8f, 3f, width - 16f, 34f);
			((Component)val3).gameObject.AddComponent<RectMask2D>();
			TMP_Text val4 = Text((Transform)(object)val3, "", 0f, 0f, width - 16f, 34f, 22);
			val4.enableWordWrapping = false;
			TMP_InputField obj = ((Component)val).gameObject.AddComponent<TMP_InputField>();
			obj.textViewport = val3;
			obj.textComponent = val4;
			((Selectable)obj).targetGraphic = (Graphic)(object)val2;
			obj.characterLimit = limit;
			obj.lineType = (LineType)0;
			obj.richText = false;
			obj.customCaretColor = true;
			obj.caretColor = LoadoutTheme.Accent;
			obj.caretWidth = 2;
			obj.text = value;
			return obj;
		}

		private TMP_Text Text(Transform parent, string value, float x, float y, float width, float height, int size)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = ((Component)TerminalUi.Rect("Text", parent, x, y, width, height)).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = template.font;
			((TMP_Text)obj).fontSharedMaterial = template.fontSharedMaterial;
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).text = value;
			((Graphic)obj).color = Color.white;
			((TMP_Text)obj).richText = false;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
			return (TMP_Text)(object)obj;
		}

		private Button Button(Transform parent, string value, float x, float y, float width, float height, Action action)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			RectTransform val = TerminalUi.Rect(value, parent, x, y, width, height);
			Image image = ((Component)val).gameObject.AddComponent<Image>();
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			LoadoutTheme.Style(obj, image);
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				if (Time.frameCount > openedFrame + 1)
				{
					action();
				}
			});
			if (value.Length > 0)
			{
				Text((Transform)(object)val, value, 4f, 0f, width - 8f, height, 21).alignment = (TextAlignmentOptions)514;
			}
			return obj;
		}

		private void AddButtons(int y)
		{
			save = Button((Transform)(object)panel, "SAVE", 20f, y, 240f, 35f, Submit);
			Button((Transform)(object)panel, "CANCEL", 280f, y, 240f, 35f, Close);
		}

		private Slider Channel(float x, float y)
		{
			//IL_0037: 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)
			RectTransform val = TerminalUi.Rect("Channel", (Transform)(object)panel, x, y, 300f, 24f);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0.12f, 0.22f, 0.24f);
			RectTransform val2 = TerminalUi.Rect("Handle", (Transform)(object)val, 0f, 0f, 14f, 24f);
			Image val3 = ((Component)val2).gameObject.AddComponent<Image>();
			((Graphic)val3).color = LoadoutTheme.Accent;
			Slider obj = ((Component)val).gameObject.AddComponent<Slider>();
			obj.handleRect = val2;
			((Selectable)obj).targetGraphic = (Graphic)(object)val3;
			obj.minValue = 0f;
			obj.maxValue = 255f;
			obj.wholeNumbers = true;
			return obj;
		}

		private void ReadChannels()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			SetColor(ColorUtility.ToHtmlStringRGB(new Color(channels[0].value / 255f, channels[1].value / 255f, channels[2].value / 255f)));
		}

		private void ReadHex(string raw)
		{
			string text = raw.Trim().TrimStart('#');
			bool flag = Catalog.ValidColor(text);
			((Selectable)save).interactable = flag;
			notice.text = (flag ? "Color changes are saved only when you press SAVE." : "Use six hex digits, for example #28D9E8.");
			if (flag)
			{
				UpdateColor(text);
			}
		}

		private void SetColor(string hex)
		{
			input.SetTextWithoutNotify("#" + hex);
			ReadHex(hex);
		}

		private void UpdateColor(string hex)
		{
			//IL_0019: 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_0030: 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)
			Color val = default(Color);
			ColorUtility.TryParseHtmlString("#" + hex, ref val);
			((Graphic)sample).color = val;
			float[] array = new float[3] { val.r, val.g, val.b };
			for (int i = 0; i < 3; i++)
			{
				int num = Mathf.RoundToInt(array[i] * 255f);
				channels[i].SetValueWithoutNotify((float)num);
				channelLabels[i].text = num.ToString();
			}
		}

		private void Update()
		{
			if (Time.frameCount > openedFrame + 1)
			{
				if (Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
				{
					Close();
				}
				else if (Gamepad.current != null && Gamepad.current.buttonEast.wasPressedThisFrame)
				{
					Close();
				}
				else if (Object.op_Implicit((Object)(object)MonoSingleton<OptionsManager>.Instance) && MonoSingleton<OptionsManager>.Instance.paused)
				{
					Close();
				}
			}
		}

		private void Submit()
		{
			if (!closed && Time.frameCount > openedFrame + 1)
			{
				string text = (colorMode ? input.text.Trim().TrimStart('#').ToUpperInvariant() : input.text);
				if (colorMode && !Catalog.ValidColor(text))
				{
					ReadHex(input.text);
					return;
				}
				Action<string> action = accept;
				Close();
				action(text);
			}
		}

		internal void Close()
		{
			if (!closed)
			{
				closed = true;
				Release();
				((Component)this).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void Release()
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)current != (Object)(object)this)
			{
				return;
			}
			current = null;
			try
			{
				gameplayInput?.Release();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
			}
			gameplayInput = null;
			if (Object.op_Implicit((Object)(object)modalSystem))
			{
				((Component)modalSystem).gameObject.SetActive(false);
			}
			foreach (EventSystem suspendedSystem in suspendedSystems)
			{
				if (Object.op_Implicit((Object)(object)suspendedSystem))
				{
					((Behaviour)suspendedSystem).enabled = true;
				}
			}
			if (Object.op_Implicit((Object)(object)previousSystem) && ((Behaviour)previousSystem).isActiveAndEnabled)
			{
				EventSystem.current = previousSystem;
				previousSystem.SetSelectedGameObject(previousSelection);
			}
			if (Object.op_Implicit((Object)(object)GameStateManager.Instance))
			{
				GameStateManager.Instance.PopState("local.terminal-loadouts.dialog");
			}
			if (!Object.op_Implicit((Object)(object)MonoSingleton<OptionsManager>.Instance) || !MonoSingleton<OptionsManager>.Instance.paused)
			{
				Cursor.lockState = previousLock;
				Cursor.visible = previousVisible;
			}
		}

		private void OnDisable()
		{
			Release();
		}

		private void OnDestroy()
		{
			Release();
		}
	}
	internal static class LoadoutTheme
	{
		internal static readonly Color Accent = new Color(0.2f, 0.95f, 1f);

		internal static readonly Color Panel = new Color(0.015f, 0.08f, 0.095f);

		internal static void SlotColor(Button button, Color tint, bool selected)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0033: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			ColorBlock colors = ((Selectable)button).colors;
			((ColorBlock)(ref colors)).normalColor = Shade(tint, selected ? 0.6f : 0.38f);
			Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = Shade(tint, 0.7f));
			((ColorBlock)(ref colors)).highlightedColor = highlightedColor;
			((ColorBlock)(ref colors)).pressedColor = Shade(tint, 0.25f);
			((Selectable)button).colors = colors;
			((Shadow)((Component)button).GetComponent<Outline>()).effectColor = (selected ? Color.white : tint);
		}

		private static Color Shade(Color tint, float factor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			return new Color(tint.r * factor, tint.g * factor, tint.b * factor, 1f);
		}

		internal static void Style(Button button, Image image)
		{
			//IL_0008: 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_003a: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			image.sprite = null;
			((Graphic)image).color = Color.white;
			((Selectable)button).targetGraphic = (Graphic)(object)image;
			((Selectable)button).transition = (Transition)1;
			ColorBlock colors = default(ColorBlock);
			((ColorBlock)(ref colors)).normalColor = new Color(0.035f, 0.43f, 0.49f);
			((ColorBlock)(ref colors)).highlightedColor = new Color(0.06f, 0.62f, 0.69f);
			((ColorBlock)(ref colors)).selectedColor = new Color(0.06f, 0.62f, 0.69f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.02f, 0.27f, 0.32f);
			((ColorBlock)(ref colors)).disabledColor = new Color(0.025f, 0.2f, 0.23f);
			((ColorBlock)(ref colors)).colorMultiplier = 1f;
			((ColorBlock)(ref colors)).fadeDuration = 0.08f;
			((Selectable)button).colors = colors;
			Outline obj = ((Component)image).gameObject.AddComponent<Outline>();
			((Shadow)obj).effectColor = new Color(0.12f, 0.8f, 0.85f, 0.7f);
			((Shadow)obj).effectDistance = new Vector2(0.7f, -0.7f);
		}
	}
	[BepInPlugin("local.terminal-loadouts", "Terminal Loadouts", "1.1.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ShopZone), "Start")]
		private static class AttachPatch
		{
			private static void Postfix(ShopZone __instance)
			{
				Attach(__instance);
			}
		}

		[HarmonyPatch(typeof(ShopZone), "TurnOn")]
		private static class RetryAttachPatch
		{
			private static void Postfix(ShopZone __instance)
			{
				Attach(__instance);
			}
		}

		[HarmonyPatch]
		private static class TypingPointerPatch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ShopZone).Assembly.GetType("ControllerPointer"), "Update", (Type[])null, (Type[])null);
			}

			private static bool Prefix()
			{
				return !LoadoutDialog.IsOpen;
			}
		}

		[HarmonyPatch(typeof(GamepadObjectSelector), "Update")]
		private static class ModalSelectionPatch
		{
			private static bool Prefix()
			{
				return !LoadoutDialog.IsOpen;
			}
		}

		public const string Id = "local.terminal-loadouts";

		internal static PresetStore Store;

		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Store = new PresetStore(Path.Combine(Paths.ConfigPath, "TerminalLoadouts", "loadouts.json"));
			if (Store.Notice != null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(Store.Notice + " " + Store.ErrorDetail));
			}
			harmony = new Harmony("local.terminal-loadouts");
			harmony.PatchAll(typeof(Plugin).Assembly);
			BrutalV1Compatibility.Install(harmony);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Terminal Loadouts 1.1.4 ready. LOADOUTS appears below ARMS in start-room terminals.");
		}

		private void OnDestroy()
		{
			TerminalUi[] array = Resources.FindObjectsOfTypeAll<TerminalUi>();
			foreach (TerminalUi terminalUi in array)
			{
				if (Object.op_Implicit((Object)(object)terminalUi))
				{
					terminalUi.Remove();
				}
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			BrutalV1Compatibility.Restore();
		}

		private static void Attach(ShopZone shop)
		{
			if (!Object.op_Implicit((Object)(object)shop) || !Object.op_Implicit((Object)(object)((Component)shop).GetComponentInParent<FirstRoomPrefab>()) || Object.op_Implicit((Object)(object)((Component)shop).GetComponent<TerminalMarker>()))
			{
				return;
			}
			try
			{
				TerminalUi.Attach(shop);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not attach loadout UI; the vanilla terminal was left available. " + ex));
			}
		}
	}
	internal sealed class TerminalMarker : MonoBehaviour
	{
	}
	internal sealed class TerminalUi : MonoBehaviour
	{
		private sealed class UiButton
		{
			public readonly Button Button;

			public readonly ShopButton Shop;

			public readonly TMP_Text Label;

			public UiButton(Button button, ShopButton shop, TMP_Text label)
			{
				Button = button;
				Shop = shop;
				Label = label;
			}

			public void Enable(bool value)
			{
				((Selectable)Button).interactable = value;
				Shop.deactivated = !value;
			}
		}

		private ShopZone shop;

		private Transform weapons;

		private ShopButton arms;

		private TMP_Text fontSource;

		private UiButton entry;

		private UiButton apply;

		private UiButton save;

		private UiButton rename;

		private UiButton delete;

		private UiButton color;

		private UiButton moveUp;

		private UiButton moveDown;

		private UiButton previous;

		private UiButton next;

		private readonly List<UiButton> rows = new List<UiButton>();

		private readonly List<ShopButton> nativeButtons = new List<ShopButton>();

		private readonly Dictionary<RectTransform, Vector2> originalPositions = new Dictionary<RectTransform, Vector2>();

		private TMP_Text details;

		private TMP_Text status;

		private TMP_Text pageLabel;

		private TMP_Text availability;

		private GameObject content;

		private GameObject confirmation;

		private GameObject preview;

		private EquipmentIcons icons;

		private LoadoutDialog dialog;

		private int selected;

		private int page;

		private bool ready;

		private float nextSaveCheck;

		internal static void Attach(ShopZone shop)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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)
			ShopButton val = ((IEnumerable<ShopButton>)((Component)shop).GetComponentsInChildren<ShopButton>(true)).FirstOrDefault((Func<ShopButton, bool>)((ShopButton b) => ((Object)b).name == "ArmButton"));
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("ArmButton was not found in this terminal.");
			}
			Transform parent = ((Component)val).transform.parent.parent.parent;
			if (((Object)parent).name != "Weapons")
			{
				throw new InvalidOperationException("Unexpected Weapons panel hierarchy.");
			}
			GameObject val2 = new GameObject("TerminalLoadouts", new Type[1] { typeof(RectTransform) });
			val2.SetActive(false);
			val2.transform.SetParent(parent, false);
			val2.layer = ((Component)val).gameObject.layer;
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = new Vector2(212.5f, 0f);
			val3.offsetMax = Vector2.zero;
			TerminalUi terminalUi = val2.AddComponent<TerminalUi>();
			try
			{
				terminalUi.shop = shop;
				terminalUi.weapons = parent;
				terminalUi.arms = val;
				terminalUi.fontSource = ((Component)val).GetComponentInChildren<TMP_Text>(true);
				terminalUi.Build();
				((Component)shop).gameObject.AddComponent<TerminalMarker>();
				ManualLogSource log = Plugin.Log;
				Scene scene = ((Component)shop).gameObject.scene;
				log.LogInfo((object)("Attached LOADOUTS below ARMS: " + ((Scene)(ref scene)).name));
			}
			catch
			{
				terminalUi.Remove();
				throw;
			}
		}

		private void Build()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e8: Expected O, but got Unknown
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Expected O, but got Unknown
			//IL_0500: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
			Image obj = ((Component)this).gameObject.AddComponent<Image>();
			((Graphic)obj).color = LoadoutTheme.Panel;
			((Graphic)obj).raycastTarget = true;
			((Graphic)Label(((Component)this).transform, "LOADOUTS", 10f, 5f, 327f, 30f, 23f)).color = LoadoutTheme.Accent;
			icons = new EquipmentIcons(shop);
			content = ((Component)Rect("Content", ((Component)this).transform, 0f, 36f, 347f, 270f)).gameObject;
			for (int i = 0; i < 5; i++)
			{
				int localRow = i;
				rows.Add(MakeButton(content.transform, "Slot", 10f, i * 34 + 4, 122f, 30f, delegate
				{
					selected = page * 5 + localRow;
					Refresh();
				}));
			}
			Label(content.transform, "REORDER SELECTED SLOT", 10f, 174f, 122f, 13f, 9f);
			moveUp = MakeButton(content.transform, "UP", 10f, 188f, 55f, 24f, delegate
			{
				Move(-1);
			});
			moveDown = MakeButton(content.transform, "DOWN", 77f, 188f, 55f, 24f, delegate
			{
				Move(1);
			});
			previous = MakeButton(content.transform, "<", 10f, 219f, 55f, 24f, delegate
			{
				page--;
				selected = page * 5 + selected % 5;
				Refresh();
			});
			next = MakeButton(content.transform, ">", 77f, 219f, 55f, 24f, delegate
			{
				page++;
				selected = page * 5 + selected % 5;
				Refresh();
			});
			pageLabel = Label(content.transform, "", 10f, 245f, 122f, 18f, 12f);
			pageLabel.alignment = (TextAlignmentOptions)514;
			details = Label(content.transform, "", 143f, 4f, 194f, 156f, 13f);
			details.enableAutoSizing = true;
			details.fontSizeMin = 10f;
			details.fontSizeMax = 13f;
			apply = MakeButton(content.transform, "APPLY", 143f, 191f, 194f, 28f, Apply);
			save = MakeButton(content.transform, "SAVE CURRENT", 143f, 225f, 194f, 28f, Save);
			rename = MakeButton(((Component)this).transform, "RENAME", 143f, 295f, 94f, 28f, Rename);
			delete = MakeButton(((Component)this).transform, "DELETE", 243f, 295f, 94f, 28f, Delete);
			color = MakeButton(((Component)this).transform, "SLOT COLOR", 10f, 305f, 122f, 24f, ChooseColor);
			availability = Label(((Component)this).transform, "", 10f, 331f, 327f, 16f, 10f);
			((Graphic)availability).color = new Color(1f, 0.75f, 0.25f);
			status = Label(((Component)this).transform, "", 10f, 349f, 327f, 26f, 12f);
			status.enableAutoSizing = true;
			status.fontSizeMin = 9f;
			status.fontSizeMax = 12f;
			entry = MakeButton(((Component)arms).transform.parent, "LOADOUTS", 0f, 0f, 0f, 30f, Open);
			((Object)entry.Button).name = "LoadoutsButton";
			RectTransform val = (RectTransform)((Component)arms).transform;
			RectTransform val2 = (RectTransform)((Component)entry.Button).transform;
			val2.anchorMin = val.anchorMin;
			val2.anchorMax = val.anchorMax;
			val2.pivot = val.pivot;
			val2.sizeDelta = val.sizeDelta;
			ShopCategory[] componentsInChildren = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopCategory>(true);
			foreach (ShopCategory val3 in componentsInChildren)
			{
				Transform transform = ((Component)val3).transform;
				RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if (Object.op_Implicit((Object)(object)val4) && !((Object)(object)((Component)val3).transform.parent != (Object)(object)((Component)arms).transform.parent))
				{
					originalPositions[val4] = val4.anchoredPosition;
					val4.anchoredPosition = new Vector2(val4.anchoredPosition.x, val4.anchoredPosition.y * (13f / 14f));
				}
			}
			val2.anchoredPosition = val.anchoredPosition + new Vector2(0f, -32.5f);
			((Transform)val2).SetSiblingIndex(((Component)arms).transform.GetSiblingIndex() + 1);
			entry.Label.fontSize = fontSource.fontSize;
			ShopButton[] componentsInChildren2 = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopButton>(true);
			foreach (ShopButton val5 in componentsInChildren2)
			{
				if (!((Object)(object)val5 == (Object)(object)entry.Shop))
				{
					nativeButtons.Add(val5);
					val5.toDeactivate = (val5.toDeactivate ?? Array.Empty<GameObject>()).Concat((IEnumerable<GameObject>)(object)new GameObject[1] { ((Component)this).gameObject }).ToArray();
				}
			}
			ready = true;
		}

		private void Open()
		{
			if (LoadoutDialog.IsOpen || !Object.op_Implicit((Object)(object)shop) || shop.forcedOff)
			{
				return;
			}
			foreach (GameObject item in arms.toActivate.Concat(arms.toDeactivate).Distinct())
			{
				if (Object.op_Implicit((Object)(object)item) && (Object)(object)item != (Object)(object)((Component)weapons).gameObject && (Object)(object)item != (Object)(object)((Component)this).gameObject && !((Component)this).transform.IsChildOf(item.transform))
				{
					item.SetActive(false);
				}
			}
			ShopButtonListController[] componentsInChildren = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopButtonListController>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].ResetButtons();
			}
			ShopButtonListController componentInParent = ((Component)arms).GetComponentInParent<ShopButtonListController>();
			if (Object.op_Implicit((Object)(object)componentInParent))
			{
				componentInParent.ResetButtons();
			}
			((Component)this).gameObject.SetActive(true);
			entry.Enable(value: false);
			SetStatus(Plugin.Store.Notice ?? "SAVE CURRENT fills empty slots. OVERWRITE replaces changed setups. SAVED means they match.");
		}

		private void OnEnable()
		{
			if (ready)
			{
				Refresh();
			}
		}

		private void Update()
		{
			if (ready && !LoadoutDialog.IsOpen && !Object.op_Implicit((Object)(object)confirmation) && !(Time.unscaledTime < nextSaveCheck))
			{
				nextSaveCheck = Time.unscaledTime + 0.3f;
				RefreshSaveAction(Plugin.Store.Get(selected));
			}
		}

		private void OnDisable()
		{
			if (Object.op_Implicit((Object)(object)dialog))
			{
				dialog.Close();
				dialog = null;
			}
			if (Object.op_Implicit((Object)(object)confirmation))
			{
				Object.Destroy((Object)(object)confirmation);
			}
			if (Object.op_Implicit((Object)(object)content))
			{
				content.SetActive(true);
			}
			if (rename != null)
			{
				((Component)rename.Button).gameObject.SetActive(true);
			}
			if (delete != null)
			{
				((Component)delete.Button).gameObject.SetActive(true);
			}
			if (color != null)
			{
				((Component)color.Button).gameObject.SetActive(true);
			}
			if (entry != null && Object.op_Implicit((Object)(object)entry.Button))
			{
				entry.Enable(value: true);
			}
			if (ready && ((Component)this).gameObject.activeSelf)
			{
				((Component)this).gameObject.SetActive(false);
			}
		}

		private void Refresh()
		{
			//IL_008e: 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_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			PresetStore store = Plugin.Store;
			Color tint = default(Color);
			for (int i = 0; i < 5; i++)
			{
				int num = page * 5 + i;
				Loadout loadout = store.Get(num);
				rows[i].Label.text = ((num == selected) ? "> " : "") + (num + 1) + ". " + (loadout?.Name ?? "Empty");
				((Graphic)rows[i].Label).color = Color.white;
				ColorUtility.TryParseHtmlString("#" + store.GetColor(num), ref tint);
				LoadoutTheme.SlotColor(rows[i].Button, tint, num == selected);
			}
			pageLabel.text = "SLOTS " + (page * 5 + 1) + "–" + (page * 5 + 5) + " / 20";
			previous.Enable(page > 0);
			next.Enable(page < 3);
			moveUp.Enable(store.Writable && selected > 0);
			moveDown.Enable(store.Writable && selected < 19);
			color.Enable(store.Writable);
			Loadout loadout2 = store.Get(selected);
			bool flag = EquipmentService.HasUnavailableGrenades(loadout2, GrenadeLauncherCompatibility.IsLoaded);
			availability.text = (flag ? "GL missing: uses standard rockets. Saved GL choices kept." : "");
			status.rectTransform.anchoredPosition = new Vector2(10f, (float)(flag ? (-349) : (-331)));
			status.rectTransform.sizeDelta = new Vector2(327f, (float)(flag ? 26 : 44));
			details.enableWordWrapping = loadout2 == null;
			details.rectTransform.sizeDelta = new Vector2(194f, (float)((loadout2 == null) ? 156 : 20));
			details.text = ((loadout2 == null) ? "EMPTY SLOT\n\nConfigure weapons, variant order and arms normally, then choose SAVE CURRENT." : loadout2.Name);
			RefreshPreview(loadout2);
			apply.Enable(loadout2 != null);
			RefreshSaveAction(loadout2);
			rename.Enable(loadout2 != null && store.Writable);
			delete.Enable(loadout2 != null && store.Writable);
		}

		private void RefreshSaveAction(Loadout saved)
		{
			try
			{
				Loadout current = EquipmentService.Capture(new GameEquipment(), "Current");
				bool flag = saved?.SameEquipment(EquipmentService.PrepareSave(current, saved)) ?? false;
				save.Label.text = ((saved == null) ? "SAVE CURRENT" : (flag ? "SAVED" : "OVERWRITE"));
				save.Enable(Plugin.Store.Writable && !flag);
			}
			catch
			{
				save.Label.text = "UNAVAILABLE";
				save.Enable(value: false);
			}
		}

		private void RefreshPreview(Loadout current)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)preview))
			{
				preview.SetActive(false);
				Object.Destroy((Object)(object)preview);
			}
			if (current == null)
			{
				return;
			}
			preview = ((Component)Rect("Saved equipment", content.transform, 143f, 24f, 194f, 163f)).gameObject;
			((Graphic)Label(preview.transform, "SAVED CYCLE ORDER  >", 0f, 0f, 194f, 16f, 11f)).color = LoadoutTheme.Accent;
			string[] array = new string[6] { "REV", "SHOT", "NAIL", "RAIL", "ROCKET", "ARMS" };
			for (int i = 0; i < 6; i++)
			{
				float num = 18 + i * 21;
				Label(preview.transform, array[i], 0f, num + 4f, 43f, 17f, 10f);
				int[] array2 = ((i < 5) ? Catalog.OrderedWeapons(current, i) : (from index in Enumerable.Range(15, 4)
					where current.Equipment[index] != 0
					select index).ToArray());
				if (array2.Length == 0)
				{
					Label(preview.transform, "OFF", 48f, num + 4f, 140f, 16f, 10f);
				}
				for (int num2 = 0; num2 < array2.Length; num2++)
				{
					int num3 = array2[num2];
					float x = 46 + num2 * ((i < 5) ? 49 : 37);
					RectTransform parent = Rect(Catalog.Keys[num3], preview.transform, x, num, (i < 5) ? 46 : 34, 20f);
					bool flag = num3 >= 12 && num3 < 15 && current.GrenadeLauncherModes != null && current.GrenadeLauncherModes[num3 - 12];
					bool flag2 = flag && !GrenadeLauncherCompatibility.IsLoaded;
					Sprite val = icons.Get(num3, current.Equipment[num3]);
					if (Object.op_Implicit((Object)(object)val))
					{
						Image obj = ((Component)Rect("Icon", (Transform)(object)parent, (i < 5) ? 10 : 0, 0f, 31f, 19f)).gameObject.AddComponent<Image>();
						obj.sprite = val;
						obj.preserveAspect = true;
						((Graphic)obj).color = (flag2 ? Color.gray : EquipmentIcons.ColorFor(num3));
						((Graphic)obj).raycastTarget = false;
					}
					else
					{
						Label((Transform)(object)parent, Catalog.Keys[num3].ToUpperInvariant(), 9f, 4f, 35f, 15f, 8f);
					}
					if (i < 5)
					{
						((Graphic)Label((Transform)(object)parent, (num2 + 1).ToString(), 0f, 0f, 10f, 16f, 12f)).color = LoadoutTheme.Accent;
					}
					if (flag || current.Equipment[num3] == 2)
					{
						((Graphic)Label((Transform)(object)parent, flag2 ? "GL!" : (flag ? "GL" : "ALT"), 24f, 12f, 22f, 9f, 7f)).color = (flag2 ? ((Graphic)availability).color : Color.white);
					}
				}
			}
			Label(preview.transform, (current.GrenadeLauncherModes == null) ? "1 > 2 > 3 = cycle    ALT = alternate" : "1 > 2 > 3 = cycle  ALT / GL = alternate", 0f, 146f, 194f, 16f, 9f);
		}

		private void SetStatus(string message)
		{
			status.text = message;
		}

		private void Run(Action action)
		{
			try
			{
				action();
				Refresh();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				SetStatus((ex is IOException || ex is UnauthorizedAccessException) ? "Could not save presets. Existing slots are unchanged; see the BepInEx log." : ex.Message);
			}
		}

		private void Apply()
		{
			Run(delegate
			{
				Loadout loadout = Plugin.Store.Get(selected);
				if (loadout != null)
				{
					SetStatus(EquipmentService.Apply(new GameEquipment(), loadout));
					VariationInfo[] componentsInChildren = ((Component)shop).GetComponentsInChildren<VariationInfo>();
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						componentsInChildren[i].UpdateMoney();
					}
					WeaponOrderController[] componentsInChildren2 = ((Component)shop).GetComponentsInChildren<WeaponOrderController>();
					for (int i = 0; i < componentsInChildren2.Length; i++)
					{
						componentsInChildren2[i].ResetValues();
					}
				}
			});
		}

		private void Save()
		{
			Loadout loadout = Plugin.Store.Get(selected);
			try
			{
				if (loadout != null && loadout.SameEquipment(EquipmentService.PrepareSave(EquipmentService.Capture(new GameEquipment(), "Current"), loadout)))
				{
					SetStatus("This setup is already saved.");
					Refresh();
					return;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				SetStatus(ex.Message);
				Refresh();
				return;
			}
			Action action = delegate
			{
				Run(delegate
				{
					Loadout loadout2 = Plugin.Store.Get(selected);
					string text = loadout2?.Name ?? ("Loadout " + (selected + 1));
					Plugin.Store.Save(selected, EquipmentService.PrepareSave(EquipmentService.Capture(new GameEquipment(), text), loadout2));
					SetStatus("Saved " + text + ", including variant order.");
				});
			};
			if (loadout != null)
			{
				Confirm("Overwrite " + loadout.Name + " with your current setup?" + (EquipmentService.HasUnavailableGrenades(loadout, GrenadeLauncherCompatibility.IsLoaded) ? " Saved grenade choices will be kept while the mod is missing." : ""), action);
			}
			else
			{
				action();
			}
		}

		private void Delete()
		{
			Confirm("Delete " + Plugin.Store.Get(selected)?.Name + "?", delegate
			{
				Run(delegate
				{
					Plugin.Store.Save(selected, null);
					SetStatus("Slot " + (selected + 1) + " cleared.");
				});
			});
		}

		private void Rename()
		{
			if (LoadoutDialog.IsOpen)
			{
				return;
			}
			int slot = selected;
			dialog = LoadoutDialog.ShowRename(fontSource, Plugin.Store.Get(slot).Name, delegate(string name)
			{
				Run(delegate
				{
					Plugin.Store.Rename(slot, name);
					SetStatus("Loadout renamed.");
				});
			});
		}

		private void Move(int offset)
		{
			Run(delegate
			{
				int second = selected + offset;
				Plugin.Store.Swap(selected, second);
				selected = second;
				page = selected / 5;
				SetStatus("Swapped slots. The selected setup and its color moved to slot " + (selected + 1) + ".");
			});
		}

		private void ChooseColor()
		{
			if (LoadoutDialog.IsOpen)
			{
				return;
			}
			int slot = selected;
			dialog = LoadoutDialog.ShowColor(fontSource, Plugin.Store.GetColor(slot), delegate(string value)
			{
				Run(delegate
				{
					Plugin.Store.SetColor(slot, value);
					SetStatus("Slot " + (slot + 1) + " color saved.");
				});
			});
		}

		private void Confirm(string prompt, Action confirmed)
		{
			if (Object.op_Implicit((Object)(object)confirmation))
			{
				return;
			}
			content.SetActive(false);
			((Component)rename.Button).gameObject.SetActive(false);
			((Component)delete.Button).gameObject.SetActive(false);
			((Component)color.Button).gameObject.SetActive(false);
			confirmation = ((Component)Rect("Confirmation", ((Component)this).transform, 10f, 65f, 327f, 255f)).gameObject;
			TMP_Text obj = Label(confirmation.transform, prompt, 10f, 10f, 307f, 110f, 20f);
			obj.enableAutoSizing = true;
			obj.fontSizeMin = 12f;
			obj.fontSizeMax = 20f;
			Action close = delegate
			{
				if (Object.op_Implicit((Object)(object)confirmation))
				{
					confirmation.SetActive(false);
					Object.Destroy((Object)(object)confirmation);
					confirmation = null;
				}
				content.SetActive(true);
				((Component)rename.Button).gameObject.SetActive(true);
				((Component)delete.Button).gameObject.SetActive(true);
				((Component)color.Button).gameObject.SetActive(true);
			};
			MakeButton(confirmation.transform, "CONFIRM", 10f, 140f, 145f, 35f, delegate
			{
				close();
				confirmed();
			});
			MakeButton(confirmation.transform, "CANCEL", 172f, 140f, 145f, 35f, close);
		}

		private TMP_Text Label(Transform parent, string text, float x, float y, float width, float height, float size)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = ((Component)Rect("Label", parent, x, y, width, height)).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = fontSource.font;
			((TMP_Text)obj).fontSharedMaterial = fontSource.fontSharedMaterial;
			((TMP_Text)obj).fontSize = size;
			((Graphic)obj).color = Color.white;
			((TMP_Text)obj).richText = false;
			((TMP_Text)obj).text = text;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)257;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
			return (TMP_Text)(object)obj;
		}

		private UiButton MakeButton(Transform parent, string text, float x, float y, float width, float height, Action action)
		{
			//IL_0055: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			RectTransform val = Rect(text, parent, x, y, width, height);
			Image image = ((Component)val).gameObject.AddComponent<Image>();
			Button button = ((Component)val).gameObject.AddComponent<Button>();
			LoadoutTheme.Style(button, image);
			Button obj = button;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)3;
			((Selectable)obj).navigation = navigation;
			TMP_Text val2 = Label((Transform)(object)val, text, 4f, 0f, width - 8f, height, 16f);
			RectTransform rectTransform = val2.rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = new Vector2(4f, 0f);
			rectTransform.offsetMax = new Vector2(-4f, 0f);
			val2.alignment = (TextAlignmentOptions)514;
			val2.enableWordWrapping = false;
			ShopButton val3 = ((Component)val).gameObject.AddComponent<ShopButton>();
			val3.toActivate = Array.Empty<GameObject>();
			val3.toDeactivate = Array.Empty<GameObject>();
			val3.clickSound = arms.clickSound;
			val3.failSound = arms.failSound;
			int lastFrame = -1;
			Action invoke = delegate
			{
				if (lastFrame == Time.frameCount || !((Selectable)button).interactable || !((Component)button).gameObject.activeInHierarchy || LoadoutDialog.IsOpen)
				{
					return;
				}
				lastFrame = Time.frameCount;
				try
				{
					action();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)ex);
					if (Object.op_Implicit((Object)(object)status))
					{
						SetStatus(ex.Message);
					}
				}
			};
			((UnityEvent)button.onClick).AddListener((UnityAction)delegate
			{
				invoke();
			});
			val3.PointerClickSuccess += invoke;
			return new UiButton(button, val3, val2);
		}

		internal static RectTransform Rect(string name, Transform parent, float x, float y, float width, float height)
		{
			//IL_0014: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_005e: 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_0068: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			}.transform;
			((Transform)val).SetParent(parent, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(x, 0f - y);
			val.sizeDelta = new Vector2(width, height);
			return val;
		}

		internal void Remove()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)dialog))
			{
				dialog.Close();
			}
			foreach (ShopButton nativeButton in nativeButtons)
			{
				if (Object.op_Implicit((Object)(object)nativeButton))
				{
					nativeButton.toDeactivate = nativeButton.toDeactivate.Where((GameObject x) => (Object)(object)x != (Object)(object)((Component)this).gameObject).ToArray();
				}
			}
			foreach (KeyValuePair<RectTransform, Vector2> originalPosition in originalPositions)
			{
				if (Object.op_Implicit((Object)(object)originalPosition.Key))
				{
					originalPosition.Key.anchoredPosition = originalPosition.Value;
				}
			}
			if (entry != null && Object.op_Implicit((Object)(object)entry.Button))
			{
				Object.Destroy((Object)(object)((Component)entry.Button).gameObject);
			}
			if (Object.op_Implicit((Object)(object)shop) && Object.op_Implicit((Object)(object)((Component)shop).GetComponent<TerminalMarker>()))
			{
				Object.Destroy((Object)(object)((Component)shop).GetComponent<TerminalMarker>());
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
}
namespace TerminalLoadouts.Core
{
	internal sealed class ActionSuspension<T>
	{
		private readonly T[] enabled;

		private readonly Action<T> restore;

		private bool released;

		private ActionSuspension(T[] enabled, Action<T> restore)
		{
			this.enabled = enabled;
			this.restore = restore;
		}

		internal static ActionSuspension<T> Suspend(IEnumerable<T> actions, Func<T, bool> isEnabled, Action<T> disable, Action<T> restore)
		{
			ActionSuspension<T> actionSuspension = new ActionSuspension<T>(actions.Where(isEnabled).ToArray(), restore);
			try
			{
				T[] array = actionSuspension.enabled;
				foreach (T obj in array)
				{
					disable(obj);
				}
				return actionSuspension;
			}
			catch
			{
				actionSuspension.Release();
				throw;
			}
		}

		internal void Release()
		{
			if (released)
			{
				return;
			}
			released = true;
			List<Exception> list = new List<Exception>();
			T[] array = enabled;
			foreach (T obj in array)
			{
				try
				{
					restore(obj);
				}
				catch (Exception item)
				{
					list.Add(item);
				}
			}
			if (list.Count <= 0)
			{
				return;
			}
			throw new AggregateException("Some gameplay input actions could not be restored.", list);
		}
	}
	internal interface IEquipmentRuntime
	{
		bool Restricted { get; }

		int GetInt(string key, int fallback);

		string GetString(string key, string fallback);

		bool HasKey(string key);

		void SetInt(string key, int value);

		void SetString(string key, string value);

		void DeleteKey(string key);

		int Gear(string id);

		bool[] CaptureGrenadeModes();

		void SetGrenadeModes(bool[] modes);

		void RememberSelection();

		void ResetWeapons();

		void ResetFists();

		void RestoreSelection();
	}
	internal static class EquipmentService
	{
		public static Loadout PrepareSave(Loadout current, Loadout existing)
		{
			current.Validate();
			existing?.Validate();
			Loadout loadout = current.Copy();
			if (loadout.GrenadeLauncherModes == null && existing?.GrenadeLauncherModes != null)
			{
				loadout.GrenadeLauncherModes = (bool[])existing.GrenadeLauncherModes.Clone();
			}
			return loadout;
		}

		public static bool HasUnavailableGrenades(Loadout saved, bool modLoaded)
		{
			if (!modLoaded && saved?.GrenadeLauncherModes != null)
			{
				return Array.Exists(saved.GrenadeLauncherModes, (bool value) => value);
			}
			return false;
		}

		public static Loadout Capture(IEquipmentRuntime game, string name)
		{
			Loadout loadout = new Loadout
			{
				Name = name,
				Equipment = new int[19],
				Orders = new string[5]
			};
			for (int i = 0; i < Catalog.Keys.Length; i++)
			{
				loadout.Equipment[i] = game.GetInt("weapon." + Catalog.Keys[i], 1);
			}
			for (int j = 0; j < 5; j++)
			{
				loadout.Orders[j] = game.GetString("weapon." + Catalog.Families[j] + ".order", Catalog.DefaultOrder(j));
			}
			bool[] array = game.CaptureGrenadeModes();
			loadout.GrenadeLauncherModes = ((array == null) ? null : ((bool[])array.Clone()));
			loadout.Validate();
			return loadout;
		}

		public static string Apply(IEquipmentRuntime game, Loadout preset)
		{
			preset.Validate();
			Catalog.Resolve(preset, game.Gear, out var unavailable);
			Loadout loadout = Capture(game, "Rollback");
			bool flag = preset.GrenadeLauncherModes != null && loadout.GrenadeLauncherModes != null;
			HashSet<string> hashSet = new HashSet<string>();
			string[] keys = Catalog.Keys;
			foreach (string text in keys)
			{
				if (!game.HasKey("weapon." + text))
				{
					hashSet.Add("weapon." + text);
				}
			}
			keys = Catalog.Families;
			foreach (string text2 in keys)
			{
				if (!game.HasKey("weapon." + text2 + ".order"))
				{
					hashSet.Add("weapon." + text2 + ".order");
				}
			}
			game.RememberSelection();
			try
			{
				Write(game, preset);
				if (flag)
				{
					game.SetGrenadeModes((bool[])preset.GrenadeLauncherModes.Clone());
				}
				game.ResetWeapons();
				game.ResetFists();
				game.RestoreSelection();
			}
			catch (Exception ex)
			{
				try
				{
					Write(game, loadout);
					if (flag)
					{
						game.SetGrenadeModes((bool[])loadout.GrenadeLauncherModes.Clone());
					}
					foreach (string item in hashSet)
					{
						game.DeleteKey(item);
					}
					game.ResetWeapons();
					game.ResetFists();
					game.RestoreSelection();
				}
				catch (Exception ex2)
				{
					throw new AggregateException("Apply and rollback failed. Reload the level before continuing.", ex, ex2);
				}
				throw new InvalidOperationException("Could not apply loadout. Previous equipment was restored.", ex);
			}
			return "Applied " + preset.Name + " with saved variant order." + ((unavailable == 0) ? "" : (" " + unavailable + " locked choice(s) skipped or using standard equipment.")) + ((loadout.GrenadeLauncherModes == null && Array.Exists(preset.GrenadeLauncherModes ?? Array.Empty<bool>(), (bool value) => value)) ? " Grenade Launcher is not loaded; standard rockets are used. Saved GL choices were kept." : "") + ((loadout.GrenadeLauncherModes != null && preset.GrenadeLauncherModes == null) ? " No GL choices saved: current grenade modes unchanged. SAVE CURRENT to include them." : "") + (game.Restricted ? " This level's forced equipment still takes priority." : "");
		}

		private static void Write(IEquipmentRuntime game, Loadout preset)
		{
			for (int i = 0; i < 19; i++)
			{
				game.SetInt("weapon." + Catalog.Keys[i], preset.Equipment[i]);
			}
			for (int j = 0; j < 5; j++)
			{
				game.SetString("weapon." + Catalog.Families[j] + ".order", preset.Orders[j]);
			}
		}
	}
	[JsonObject(/*Could not decode attribute arguments.*/)]
	internal sealed class Loadout
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string Name { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int[] Equipment { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string[] Orders { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool[] GrenadeLauncherModes { get; set; }

		public Loadout Copy()
		{
			return new Loadout
			{
				Name = Name,
				Equipment = (int[])Equipment.Clone(),
				Orders = (string[])Orders.Clone(),
				GrenadeLauncherModes = ((GrenadeLauncherModes == null) ? null : ((bool[])GrenadeLauncherModes.Clone()))
			};
		}

		public bool SameEquipment(Loadout other)
		{
			if (other != null && Equipment.SequenceEqual(other.Equipment) && Orders.SequenceEqual(other.Orders))
			{
				if (GrenadeLauncherModes != null)
				{
					if (other.GrenadeLauncherModes != null)
					{
						return GrenadeLauncherModes.SequenceEqual(other.GrenadeLauncherModes);
					}
					return false;
				}
				return other.GrenadeLauncherModes == null;
			}
			return false;
		}

		public void Validate()
		{
			if (string.IsNullOrWhiteSpace(Name) || Name.Length > 32 || Name.Any(char.IsControl))
			{
				throw new FormatException("Loadout names must contain 1–32 printable characters.");
			}
			if (Equipment == null || Equipment.Length != Catalog.Keys.Length || Orders == null || Orders.Length != 5)
			{
				throw new FormatException("Incomplete equipment or ordering data.");
			}
			if (GrenadeLauncherModes != null && GrenadeLauncherModes.Length != 3)
			{
				throw new FormatException("Grenade Launcher requires three variant choices.");
			}
			for (int i = 0; i < Equipment.Length; i++)
			{
				if (Equipment[i] < 0 || Equipment[i] > ((i >= 9) ? 1 : 2))
				{
					throw new FormatException("Invalid equipment selection: " + Catalog.Keys[i]);
				}
			}
			string[] orders = Orders;
			foreach (string text in orders)
			{
				if (text == null || text.Length != 4 || text[3] != '4' || new string((from c in text.Take(3)
					orderby c
					select c).ToArray()) != "123")
				{
					throw new FormatException("Invalid variant order.");
				}
			}
		}
	}
	internal static class Catalog
	{
		public const int SlotCount = 20;

		public static readonly string[] Palette = new string[20]
		{
			"28D9E8", "FF647C", "83DD64", "FFB347", "AE83FF", "53A9FF", "F77EC4", "E8D554", "4CD8A2", "F58A61",
			"8BA4FF", "C6E96D", "DB91DF", "68C6F0", "E8B78B", "A5C6B1", "D0A5FF", "FFA6AF", "79E6D7", "BFC9D9"
		};

		public static readonly string[] Families = new string[5] { "rev", "sho", "nai", "rai", "rock" };

		public static readonly string[] FamilyNames = new string[5] { "Revolver", "Shotgun", "Nailgun", "Railcannon", "Rocket" };

		public static readonly string[] Keys = Families.SelectMany((string f) => from v in Enumerable.Range(0, 3)
			select f + v).Concat(new string[4] { "arm0", "arm1", "arm2", "arm3" }).ToArray();

		public static string DefaultColor(int slot)
		{
			return Palette[slot];
		}

		public static bool ValidColor(string color)
		{
			if (color != null && color.Length == 6)
			{
				return color.All(Uri.IsHexDigit);
			}
			return false;
		}

		public static string DefaultOrder(int family)
		{
			if (family != 0)
			{
				return "1234";
			}
			return "1324";
		}

		public static int[] OrderedWeapons(Loadout saved, int family)
		{
			return (from index in Enumerable.Range(family * 3, 3)
				where saved.Equipment[index] != 0
				orderby saved.Orders[family][index % 3]
				select index).ToArray();
		}

		public static string CleanName(string name, int slot)
		{
			string text = new string((name ?? "").Where((char c) => !char.IsControl(c)).ToArray()).Trim();
			if (text.Length == 0)
			{
				return "Loadout " + (slot + 1);
			}
			if (text.Length > 32)
			{
				text = text.Substring(0, 32);
			}
			if (char.IsHighSurrogate(text[text.Length - 1]))
			{
				text = text.Substring(0, text.Length - 1);
			}
			return text;
		}

		public static int[] Resolve(Loadout saved, Func<string, int> gear, out int unavailable)
		{
			saved.Validate();
			int[] array = (int[])saved.Equipment.Clone();
			unavailable = 0;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] != 0)
				{
					if (i != 15 && ((i < 15) ? (gear(Keys[i]) <= 0) : (gear(Keys[i]) != 1)))
					{
						array[i] = 0;
					}
					else if (array[i] == 2 && gear(Families[i / 3] + "alt") <= 0)
					{
						array[i] = 1;
					}
					if (array[i] != saved.Equipment[i])
					{
						unavailable++;
					}
				}
			}
			return array;
		}

		public static string Describe(Loadout saved)
		{
			List<string> list = new List<string>();
			int family;
			for (family = 0; family < 5; family++)
			{
				IEnumerable<string> values = from v in Enumerable.Range(0, 3)
					orderby saved.Orders[family][v]
					where saved.Equipment[family * 3 + v] != 0
					select ((v == 0) ? "B" : ((family != 0) ? ((v == 1) ? "G" : "R") : ((v == 1) ? "R" : "G"))) + ((saved.Equipment[family * 3 + v] == 2) ? "*" : "");
				string text = string.Join(" ", values);
				list.Add(FamilyNames[family] + ": " + ((text.Length == 0) ? "off" : text));
			}
			IEnumerable<string> enumerable = new string[4] { "Feedbacker", "Knuckleblaster", "Whiplash", "Gold" }.Where((string name, int i) => saved.Equipment[15 + i] == 1);
			list.Add("Arms: " + (enumerable.Any() ? string.Join(", ", enumerable) : "off"));
			return string.Join("\n", list);
		}
	}
	[JsonObject(/*Could not decode attribute arguments.*/)]
	internal sealed class PresetDocument
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int Version { get; set; } = 3;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Loadout[] Slots { get; set; } = new Loadout[20];

		[JsonProperty]
		public string[] Colors { get; set; }

		public void Validate()
		{
			if (Version < 1 || Version > 3)
			{
				throw new NotSupportedException("This preset file uses an unsupported version; it has not been changed.");
			}
			if (Slots == null || Slots.Length != ((Version == 1) ? 10 : 20))
			{
				throw new FormatException("Incorrect preset slot count.");
			}
			if (Version >= 2 && (Colors == null || Colors.Length != 20))
			{
				throw new FormatException("Incomplete slot colors.");
			}
			if (Colors != null)
			{
				string[] colors = Colors;
				for (int i = 0; i < colors.Length; i++)
				{
					if (!Catalog.ValidColor(colors[i]))
					{
						throw new FormatException("Invalid slot color.");
					}
				}
			}
			Loadout[] slots = Slots;
			for (int i = 0; i < slots.Length; i++)
			{
				slots[i]?.Validate();
			}
		}

		public void Upgrade()
		{
			if (Version == 1)
			{
				Loadout[] array = new Loadout[20];
				Array.Copy(Slots, array, Slots.Length);
				Slots = array;
				Version = 2;
			}
			if (Colors == null)
			{
				Colors = new string[20];
				for (int i = 0; i < Colors.Length; i++)
				{
					Colors[i] = Catalog.DefaultColor(i);
				}
			}
			Version = 3;
		}
	}
	internal sealed class PresetStore
	{
		private readonly string path;

		private PresetDocument document = new PresetDocument();

		private bool recovered;

		public string Notice { get; private set; }

		public bool Writable { get; private set; } = true;

		public string ErrorDetail { get; private set; }

		public PresetStore(string path)
		{
			this.path = path;
			document.Upgrade();
			Load();
		}

		public Loadout Get(int index)
		{
			CheckIndex(index);
			return document.Slots[index]?.Copy();
		}

		public string GetColor(int index)
		{
			CheckIndex(index);
			return document.Colors[index];
		}

		private static void CheckIndex(int i)
		{
			if (i < 0 || i >= 20)
			{
				throw new ArgumentOutOfRangeException("i", "Choose a slot from 1 to 20.");
			}
		}

		private static PresetDocument Read(string file)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (new FileInfo(file).Length > 1048576)
			{
				throw new FormatException("Preset file exceeds the size limit.");
			}
			PresetDocument obj = JsonConvert.DeserializeObject<PresetDocument>(File.ReadAllText(file), new JsonSerializerSettings
			{
				MaxDepth = 16,
				TypeNameHandling = (TypeNameHandling)0,
				MissingMemberHandling = (MissingMemberHandling)1
			}) ?? throw new FormatException("Empty preset file.");
			obj.Validate();
			obj.Upgrade();
			return obj;
		}

		private void Load()
		{
			if (!File.Exists(path) && !File.Exists(path + ".bak"))
			{
				return;
			}
			try
			{
				document = Read(path);
			}
			catch (NotSupportedException ex)
			{
				Writable = false;
				Notice = ex.Message;
			}
			catch (Exception ex2)
			{
				try
				{
					document = Read(path + ".bak");
					if (File.Exists(path))
					{
						File.Copy(path, path + ".corrupt-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + Guid.NewGuid().ToString("N"));
					}
					recovered = true;
					Notice = "Recovered presets from backup. The damaged file was preserved.";
				}
				catch (Exception ex3)
				{
					Writable = false;
					Notice = "Presets could not be read. Files were preserved; see the log and README for recovery.";
					ErrorDetail = ex2.Message + " Backup: " + ex3.Message;
				}
			}
		}

		public void Save(int index, Loadout preset)
		{
			CheckIndex(index);
			if (!Writable)
			{
				throw new IOException(Notice);
			}
			preset?.Validate();
			PresetDocument presetDocument = CopyDocument();
			presetDocument.Slots[index] = preset?.Copy();
			Commit(presetDocument);
		}

		private PresetDocument CopyDocument()
		{
			PresetDocument presetDocument = new PresetDocument
			{
				Colors = (string[])document.Colors.Clone()
			};
			for (int i = 0; i < 20; i++)
			{
				presetDocument.Slots[i] = document.Slots[i]?.Copy();
			}
			return presetDocument;
		}

		private void Commit(PresetDocument next)
		{
			if (!Writable)
			{
				throw new IOException(Notice);
			}
			next.Validate();
			Persist(next);
			document = next;
			Notice = null;
		}

		public void SetColor(int index, string color)
		{
			CheckIndex(index);
			if (!Catalog.ValidColor(color))
			{
				throw new FormatException("Enter six hexadecimal digits, such as 28D9E8.");
			}
			PresetDocument presetDocument = CopyDocument();
			presetDocument.Colors[index] = color.ToUpperInvariant();
			Commit(presetDocument);
		}

		public void Swap(int first, int second)
		{
			CheckIndex(first);
			CheckIndex(second);
			if (first != second)
			{
				PresetDocument presetDocument = CopyDocument();
				Loadout loadout = presetDocument.Slots[first];
				presetDocument.Slots[first] = presetDocument.Slots[second];
				presetDocument.Slots[second] = loadout;
				string text = presetDocument.Colors[first];
				presetDocument.Colors[first] = presetDocument.Colors[second];
				presetDocument.Colors[second] = text;
				Commit(presetDocument);
			}
		}

		public void Rename(int index, string name)
		{
			Loadout loadout = Get(index) ?? throw new InvalidOperationException("Save this slot before renaming it.");
			loadout.Name = Catalog.CleanName(name, index);
			Save(index, loadout);
		}

		private void Persist(PresetDocument next)
		{
			string sourceFileName = path + ".tmp-" + Guid.NewGuid().ToString("N");
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
				using (FileStream fileStream = new FileStream(sourceFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None))
				{
					using (StreamWriter streamWriter = new StreamWriter(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 4096, leaveOpen: true))
					{
						streamWriter.Write(JsonConvert.SerializeObject((object)next, (Formatting)1));
						streamWriter.Flush();
					}
					fileStream.Flush(flushToDisk: true);
				}
				if (File.Exists(path))
				{
					File.Replace(sourceFileName, path, recovered ? null : (path + ".bak"));
				}
				else
				{
					File.Move(sourceFileName, path);
				}
				recovered = false;
			}
			finally
			{
				if (File.Exists(sourceFileName))
				{
					File.Delete(sourceFileName);
				}
			}
		}
	}
}