Decompiled source of GlassSolReimagined v1.0.1

GlassSol.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GlassSol.Patches;
using HarmonyLib;
using I2.Loc;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using _3_Script.UI.SaveUI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("GlassSol")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GlassSol")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("35405476-8ed7-4539-a7d7-6d6506f009e5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace GlassSol
{
	internal static class Difficulty
	{
		public const int GlassSol = 2;

		public const int TrueGlassSol = 3;

		public static int Current()
		{
			PlayerGamePlayData instance = PlayerGamePlayData.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.gameMode == (Object)null)
			{
				return -1;
			}
			return ((AbstractScriptableData<FlagFieldInt, int>)(object)instance.gameMode).CurrentValue;
		}

		public static bool IsTrueGlassSol()
		{
			return Current() == 3;
		}

		public static bool IsOneShot()
		{
			int num = Current();
			if (num != 2)
			{
				return num == 3;
			}
			return true;
		}

		public static string Phrase(string russian, string english)
		{
			string currentLanguageCode = LocalizationManager.CurrentLanguageCode;
			if (!string.IsNullOrEmpty(currentLanguageCode) && currentLanguageCode.StartsWith("ru", StringComparison.OrdinalIgnoreCase))
			{
				return russian;
			}
			string currentLanguage = LocalizationManager.CurrentLanguage;
			if (currentLanguage == "Russian" || currentLanguage == "Русский")
			{
				return russian;
			}
			return english;
		}
	}
	[BepInPlugin("flyingRozenbaum.GlassSol", "GlassSol", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private const string ModGuid = "flyingRozenbaum.GlassSol";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0077: Expected O, but got Unknown
			Log = Logger.CreateLogSource("flyingRozenbaum.GlassSol");
			Log.LogInfo((object)"Starting Glass Sol");
			Harmony val = new Harmony("flyingRozenbaum.GlassSol");
			Patch(val, typeof(PlayerHealthPatch));
			Patch(val, typeof(ModeMenuPatch));
			Patch(val, typeof(NewGameModeSavePatch));
			Patch(val, typeof(SaveModeLabelPatch));
			Patch(val, typeof(GameplaySettingPatch));
			Log.LogInfo((object)"Finished loading Glass Sol");
		}

		private static void Patch(Harmony harmony, Type type)
		{
			try
			{
				harmony.PatchAll(type);
				Log.LogInfo((object)("Patched " + type.Name));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Patch failed for " + type.Name + ": " + ex));
			}
		}
	}
}
namespace GlassSol.Patches
{
	internal static class InternalKillSetting
	{
		public static bool InMemory()
		{
			PlayerGamePlayData instance = PlayerGamePlayData.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.memoryMode != (Object)null)
			{
				return instance.memoryMode.CurrentValue;
			}
			return false;
		}

		public static bool Shown()
		{
			if (!Difficulty.IsOneShot())
			{
				return InMemory();
			}
			return true;
		}

		public static bool Kills()
		{
			int num = ((!InMemory() && Difficulty.Current() == 3) ? 1 : 0);
			return PlayerPrefs.GetInt(Key(), num) == 1;
		}

		public static void Set(bool kills)
		{
			PlayerPrefs.SetInt(Key(), kills ? 1 : 0);
		}

		private static string Key()
		{
			if (InMemory())
			{
				return "GlassSol.InternalKills.memory";
			}
			return "GlassSol.InternalKills." + Difficulty.Current();
		}
	}
	internal static class NohitSetting
	{
		public static bool Enabled()
		{
			return PlayerPrefs.GetInt("GlassSol.Nohit", 0) == 1;
		}

		public static void Set(bool enabled)
		{
			PlayerPrefs.SetInt("GlassSol.Nohit", enabled ? 1 : 0);
		}

		public static bool Active()
		{
			if (Enabled())
			{
				return InternalKillSetting.InMemory();
			}
			return false;
		}
	}
	internal static class GameplaySettingPatch
	{
		private const string OptionName = "InternalKillOption";

		private const string NohitOptionName = "NohitOption";

		internal const string TitleRu = "Внутренний урон убивает";

		internal const string TitleEn = "Internal damage kills";

		internal const string NohitTitleRu = "Включить ноухит";

		internal const string NohitTitleEn = "Enable Nohit";

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GamePreferenceManager), "Start")]
		private static void AddOption(GamePreferenceManager __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(Watch());
		}

		private static IEnumerator Watch()
		{
			while (true)
			{
				Transform[] array = Resources.FindObjectsOfTypeAll<Transform>();
				foreach (Transform val in array)
				{
					if ((Object)(object)val == (Object)null || ((Object)val).name != "Show HUD")
					{
						continue;
					}
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && !((Object)(object)val.parent == (Object)null) && !(((Object)val.parent).name != "Layout"))
					{
						Transform val2 = val.parent.Find("InternalKillOption");
						if ((Object)(object)val2 == (Object)null)
						{
							AddRow(val, nohit: false);
						}
						else
						{
							((Component)val2).gameObject.SetActive(InternalKillSetting.Shown());
						}
						Transform val3 = val.parent.Find("NohitOption");
						if ((Object)(object)val3 == (Object)null)
						{
							AddRow(val, nohit: true);
						}
						else
						{
							((Component)val3).gameObject.SetActive(InternalKillSetting.InMemory());
						}
					}
				}
				yield return (object)new WaitForSecondsRealtime(0.5f);
			}
		}

		private static void AddRow(Transform row, bool nohit)
		{
			bool activeSelf = ((Component)row).gameObject.activeSelf;
			((Component)row).gameObject.SetActive(false);
			Transform transform = Object.Instantiate<GameObject>(((Component)row).gameObject, row.parent).transform;
			((Component)row).gameObject.SetActive(activeSelf);
			((Object)transform).name = (nohit ? "NohitOption" : "InternalKillOption");
			transform.SetSiblingIndex(row.GetSiblingIndex() + ((!nohit) ? 1 : 2));
			Component val = null;
			MonoBehaviour[] componentsInChildren = ((Component)transform).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Type type = ((object)val2).GetType();
				while (type != null)
				{
					if (type.Name == "MultipleOptionSelector" || type.Name.StartsWith("ListRotateSelector"))
					{
						val = (Component)(object)val2;
						break;
					}
					type = type.BaseType;
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"Show HUD has no selector");
				return;
			}
			object obj = null;
			Type type2 = ((object)val).GetType();
			while (type2 != null)
			{
				FieldInfo field = type2.GetField("entry", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field == null))
				{
					obj = field.GetValue(val);
					break;
				}
				type2 = type2.BaseType;
			}
			obj.GetType().GetField("flagBase").SetValue(obj, null);
			((Component)transform).gameObject.SetActive(true);
			TMP_Text val3 = null;
			Transform[] componentsInChildren2 = ((Component)transform).GetComponentsInChildren<Transform>(true);
			foreach (Transform val4 in componentsInChildren2)
			{
				if (!(((Object)val4).name != "Label"))
				{
					val3 = ((Component)val4).GetComponent<TMP_Text>() ?? ((Component)val4).GetComponentInChildren<TMP_Text>(true);
					break;
				}
			}
			if ((Object)(object)val3 != (Object)null)
			{
				DestroyLocalization(((Component)val3).gameObject);
				val3.text = (nohit ? Difficulty.Phrase("Включить ноухит", "Enable Nohit") : Difficulty.Phrase("Внутренний урон убивает", "Internal damage kills"));
			}
			UIControlButton obj2 = ((Component)transform).GetComponent<UIControlButton>() ?? ((Component)transform).GetComponentInChildren<UIControlButton>(true);
			RetargetLocal(obj2, transform);
			obj2.RefreshState();
			object value = ((object)val).GetType().GetField("list", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(val);
			PropertyInfo? property = value.GetType().GetProperty("Count");
			PropertyInfo property2 = value.GetType().GetProperty("Item");
			int yesIndex = 1;
			int num = (int)property.GetValue(value, null);
			for (int j = 0; j < num; j++)
			{
				string text = property2.GetValue(value, new object[1] { j })?.ToString();
				if (text == "Да" || text == "Yes")
				{
					yesIndex = j;
					break;
				}
			}
			if (nohit)
			{
				((Component)transform).gameObject.AddComponent<NohitOption>().Setup(val, obj, yesIndex, val3);
			}
			else
			{
				((Component)transform).gameObject.AddComponent<InternalKillOption>().Setup(val, obj, yesIndex, val3);
			}
			SelectableNavigationProvider componentInParent = ((Component)transform).GetComponentInParent<SelectableNavigationProvider>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				componentInParent.AutoNavigateBindForAll();
			}
			Plugin.Log.LogInfo((object)(nohit ? "Added nohit setting" : "Added internal damage setting"));
		}

		private static void RetargetLocal(UIControlButton control, Transform root)
		{
			FieldInfo[] fields = typeof(UIControlButton).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.FieldType == typeof(RectTransform) || !typeof(Component).IsAssignableFrom(fieldInfo.FieldType) || fieldInfo.Name == "belongGroup" || fieldInfo.Name == "provider" || fieldInfo.Name == "instructionPanelProvider")
				{
					continue;
				}
				object? value = fieldInfo.GetValue(control);
				Component val = (Component)((value is Component) ? value : null);
				if (!((Object)(object)val != (Object)null) || (!((Object)(object)val.transform == (Object)(object)root) && !val.transform.IsChildOf(root)))
				{
					Component val2 = ((Component)control).GetComponent(fieldInfo.FieldType) ?? ((Component)control).GetComponentInChildren(fieldInfo.FieldType, true);
					if ((Object)(object)val2 != (Object)null)
					{
						fieldInfo.SetValue(control, val2);
					}
				}
			}
		}

		internal static void DestroyLocalization(GameObject root)
		{
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "Localize")
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}
	}
	internal class InternalKillOption : MonoBehaviour
	{
		private Component selector;

		private object entry;

		private int yesIndex;

		private TMP_Text title;

		public void Setup(Component selector, object entry, int yesIndex, TMP_Text title)
		{
			this.selector = selector;
			this.entry = entry;
			this.yesIndex = yesIndex;
			this.title = title;
		}

		private void OnEnable()
		{
			if (!InternalKillSetting.Shown())
			{
				((Component)this).gameObject.SetActive(false);
				return;
			}
			ApplyTitle();
			Value(InternalKillSetting.Kills() ? yesIndex : ((yesIndex == 0) ? 1 : 0));
			((object)selector).GetType().GetMethod("UpdateView").Invoke(selector, null);
			ApplyTitle();
		}

		private void LateUpdate()
		{
			if (InternalKillSetting.Shown())
			{
				bool flag = Value() == yesIndex;
				if (flag != InternalKillSetting.Kills())
				{
					InternalKillSetting.Set(flag);
				}
				ApplyTitle();
			}
		}

		private void ApplyTitle()
		{
			if (!((Object)(object)title == (Object)null))
			{
				GameplaySettingPatch.DestroyLocalization(((Component)title).gameObject);
				title.text = Difficulty.Phrase("Внутренний урон убивает", "Internal damage kills");
			}
		}

		private int Value(int? next = null)
		{
			object obj = entry.GetType().GetMethod("get_field").Invoke(entry, null);
			if (!next.HasValue)
			{
				return (int)obj.GetType().GetMethod("get_CurrentValue").Invoke(obj, null);
			}
			obj.GetType().GetMethod("set_CurrentValue").Invoke(obj, new object[1] { next.Value });
			return next.Value;
		}
	}
	internal class NohitOption : MonoBehaviour
	{
		private Component selector;

		private object entry;

		private int yesIndex;

		private TMP_Text title;

		public void Setup(Component selector, object entry, int yesIndex, TMP_Text title)
		{
			this.selector = selector;
			this.entry = entry;
			this.yesIndex = yesIndex;
			this.title = title;
		}

		private void OnEnable()
		{
			if (!InternalKillSetting.InMemory())
			{
				((Component)this).gameObject.SetActive(false);
				return;
			}
			ApplyTitle();
			Value(NohitSetting.Enabled() ? yesIndex : ((yesIndex == 0) ? 1 : 0));
			((object)selector).GetType().GetMethod("UpdateView").Invoke(selector, null);
			ApplyTitle();
		}

		private void LateUpdate()
		{
			bool flag = Value() == yesIndex;
			if (flag != NohitSetting.Enabled())
			{
				NohitSetting.Set(flag);
			}
			ApplyTitle();
		}

		private void ApplyTitle()
		{
			if (!((Object)(object)title == (Object)null))
			{
				GameplaySettingPatch.DestroyLocalization(((Component)title).gameObject);
				title.text = Difficulty.Phrase("Включить ноухит", "Enable Nohit");
			}
		}

		private int Value(int? next = null)
		{
			object obj = entry.GetType().GetMethod("get_field").Invoke(entry, null);
			if (!next.HasValue)
			{
				return (int)obj.GetType().GetMethod("get_CurrentValue").Invoke(obj, null);
			}
			obj.GetType().GetMethod("set_CurrentValue").Invoke(obj, new object[1] { next.Value });
			return next.Value;
		}
	}
	internal static class ModeMenuPatch
	{
		internal const string GlassSolName = "Стеклянный Сол";

		internal const string GlassSolNameEn = "Glass Sol";

		internal const string TrueGlassSolName = "Истинный Стеклянный Сол";

		internal const string TrueGlassSolNameEn = "True Glass Sol";

		private const string GlassSolDescription = "Повышенная сложность Nine Sols.\nПрямой урон вас мгновенно убивает. Ваше сохранение при этом остается целым.";

		private const string GlassSolDescriptionEn = "An increased difficulty for Nine Sols.\nDirect damage kills you instantly. Your save remains intact.";

		private const string TrueGlassSolDescription = "Наивысшая сложность Nine Sols.\nЛюбой полученный вами урон фатальный, второго шанса не дается.";

		private const string TrueGlassSolDescriptionEn = "The highest difficulty for Nine Sols.\nAny damage you take is fatal. There is no second chance.";

		private static Image glassArt;

		private static Image trueArt;

		private static int shownMode = 1;

		private static UIControlButton soundButton;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartMenuLogic), "Start")]
		private static void AddDifficultyButtons(StartMenuLogic __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(AddWhenReady(__instance));
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIControlButton), "OnSelect")]
		private static void ShowPlaceholder(UIControlButton __instance)
		{
			Transform val = OptionsOf(((Component)__instance).transform);
			if (!((Object)(object)val == (Object)null))
			{
				ReleaseOthers(val, __instance);
				int num = ModeOf(((Component)__instance).transform, val);
				if ((Object)(object)glassArt != (Object)null && num >= 0)
				{
					shownMode = num;
					ApplyArt();
				}
				Transform val2 = val.Find("GlassSolMode");
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2.Find("ActionText")).GetComponent<TMP_Text>().text = Difficulty.Phrase("Стеклянный Сол", "Glass Sol");
				}
				Transform val3 = val.Find("TrueGlassSolMode");
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3.Find("ActionText")).GetComponent<TMP_Text>().text = Difficulty.Phrase("Истинный Стеклянный Сол", "True Glass Sol");
				}
				if (IsCustom(((Component)__instance).transform))
				{
					PlaySelectSound();
					Transform obj = val.Find("Selected Description");
					DestroyLocalization(((Component)obj).gameObject);
					((Component)obj).GetComponentInChildren<TMP_Text>(true).text = (IsTrue(((Component)__instance).transform) ? Difficulty.Phrase("Наивысшая сложность Nine Sols.\nЛюбой полученный вами урон фатальный, второго шанса не дается.", "The highest difficulty for Nine Sols.\nAny damage you take is fatal. There is no second chance.") : Difficulty.Phrase("Повышенная сложность Nine Sols.\nПрямой урон вас мгновенно убивает. Ваше сохранение при этом остается целым.", "An increased difficulty for Nine Sols.\nDirect damage kills you instantly. Your save remains intact."));
				}
			}
		}

		private static int ModeOf(Transform transform, Transform options)
		{
			if (IsTrue(transform))
			{
				return 3;
			}
			if (IsCustom(transform) && !IsTrue(transform))
			{
				return 2;
			}
			Transform val = transform;
			while ((Object)(object)val.parent != (Object)null && (Object)(object)val.parent != (Object)(object)options)
			{
				val = val.parent;
			}
			int num = 0;
			for (int i = 0; i < options.childCount; i++)
			{
				if (((Object)options.GetChild(i)).name.Contains("Start Game"))
				{
					if ((Object)(object)options.GetChild(i) == (Object)(object)val)
					{
						return num;
					}
					num++;
				}
			}
			return -1;
		}

		internal static void ApplyArt()
		{
			if (!((Object)(object)glassArt == (Object)null))
			{
				((Component)glassArt).gameObject.SetActive(shownMode == 2);
				((Component)trueArt).gameObject.SetActive(shownMode == 3);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIControlButton), "OnDeselect")]
		private static void Release(UIControlButton __instance)
		{
			if (IsCustom(((Component)__instance).transform))
			{
				((MonoBehaviour)__instance).StartCoroutine(ClearWhenLeft(__instance));
			}
		}

		private static IEnumerator ClearWhenLeft(UIControlButton button)
		{
			yield return null;
			button.RefreshState();
		}

		private static IEnumerator AddWhenReady(StartMenuLogic menu)
		{
			for (int i = 0; i < 40; i++)
			{
				if (TryAdd(menu))
				{
					yield return null;
					Rebind(FindOptionsRoot());
					break;
				}
				yield return (object)new WaitForSecondsRealtime(0.25f);
			}
		}

		private static bool TryAdd(StartMenuLogic menu)
		{
			Transform val = FindOptionsRoot();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if ((Object)(object)val.Find("TrueGlassSolMode") != (Object)null)
			{
				return true;
			}
			Transform val2 = FindChild(val, "Start Game");
			soundButton = ((Component)val2).GetComponent<UIControlButton>() ?? ((Component)val2).GetComponentInChildren<UIControlButton>(true);
			CreateArts(val);
			Transform child = val.GetChild(val2.GetSiblingIndex() + 1);
			TryAddMode(menu, val, val2, child, 2, "GlassSolMode", Difficulty.Phrase("Стеклянный Сол", "Glass Sol"));
			TryAddMode(menu, val, val2, child, 3, "TrueGlassSolMode", Difficulty.Phrase("Истинный Стеклянный Сол", "True Glass Sol"));
			Rebind(val);
			return (Object)(object)val.Find("TrueGlassSolMode") != (Object)null;
		}

		private static void Rebind(Transform root)
		{
			SelectableNavigationProvider val = ((Component)root).GetComponent<SelectableNavigationProvider>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)root).GetComponentInParent<SelectableNavigationProvider>();
			}
			if ((Object)(object)val != (Object)null)
			{
				val.AutoNavigateBindForAll();
			}
		}

		private static void TryAddMode(StartMenuLogic menu, Transform root, Transform template, Transform padding, int mode, string objectName, string title)
		{
			try
			{
				AddMode(menu, root, template, padding, mode, objectName, title);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)(objectName + ": " + ex));
			}
		}

		private static void AddMode(StartMenuLogic menu, Transform root, Transform template, Transform padding, int mode, string objectName, string title)
		{
			if (!((Object)(object)root.Find(objectName) != (Object)null))
			{
				int num = InsertIndex(root);
				bool activeSelf = ((Component)template).gameObject.activeSelf;
				((Component)template).gameObject.SetActive(false);
				Transform transform = Object.Instantiate<GameObject>(((Component)template).gameObject, root).transform;
				((Component)template).gameObject.SetActive(activeSelf);
				transform.SetParent(root, false);
				((Object)transform).name = objectName;
				transform.SetSiblingIndex(num);
				DetachStandardMode(((Component)transform).gameObject);
				PointArt(transform, (mode == 3) ? trueArt : glassArt);
				Transform transform2 = Object.Instantiate<GameObject>(((Component)padding).gameObject, root).transform;
				transform2.SetParent(root, false);
				transform2.SetSiblingIndex(num + 1);
				((Component)transform).gameObject.SetActive(true);
				DestroyLocalization(((Component)transform).gameObject);
				((Component)transform.Find("ActionText")).GetComponent<TMP_Text>().text = title;
				UIControlButton val = ((Component)transform).GetComponent<UIControlButton>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)transform).GetComponentInChildren<UIControlButton>(true);
				}
				RetargetLocal(val, transform);
				val.RefreshState();
				BindDirectStart(menu, val, mode);
			}
		}

		private static void PointArt(Transform button, Image art)
		{
			FieldInfo fieldInfo = null;
			MonoBehaviour[] componentsInChildren = ((Component)button).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name != "AnimatorColorControlNode"))
				{
					if (fieldInfo == null)
					{
						fieldInfo = ((object)val).GetType().GetField("imageTarget", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					}
					fieldInfo.SetValue(val, art);
				}
			}
		}

		private static void DetachStandardMode(GameObject button)
		{
			MonoBehaviour[] componentsInChildren = button.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "CreateGameAction")
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		private static void RetargetLocal(UIControlButton control, Transform root)
		{
			FieldInfo[] fields = typeof(UIControlButton).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.FieldType == typeof(RectTransform) || !typeof(Component).IsAssignableFrom(fieldInfo.FieldType) || fieldInfo.Name == "belongGroup" || fieldInfo.Name == "provider" || fieldInfo.Name == "instructionPanelProvider")
				{
					continue;
				}
				object? value = fieldInfo.GetValue(control);
				Component val = (Component)((value is Component) ? value : null);
				if (!((Object)(object)val != (Object)null) || (!((Object)(object)val.transform == (Object)(object)root) && !val.transform.IsChildOf(root)))
				{
					Component val2 = ((Component)control).GetComponent(fieldInfo.FieldType) ?? ((Component)control).GetComponentInChildren(fieldInfo.FieldType, true);
					if ((Object)(object)val2 != (Object)null)
					{
						fieldInfo.SetValue(control, val2);
					}
				}
			}
		}

		private static int InsertIndex(Transform root)
		{
			int num = 0;
			for (int i = 0; i < root.childCount; i++)
			{
				string name = ((Object)root.GetChild(i)).name;
				if (name.Contains("Start Game") || name == "GlassSolMode" || name == "TrueGlassSolMode")
				{
					num = i;
				}
			}
			int num2 = num + 1;
			if (num2 < root.childCount && ((Object)root.GetChild(num2)).name.StartsWith("Pedding"))
			{
				num2++;
			}
			return num2;
		}

		private static Transform FindOptionsRoot()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Transform[] array = Resources.FindObjectsOfTypeAll<Transform>();
			foreach (Transform val in array)
			{
				if (((Object)val).name == "UIOptions")
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && (Object)(object)FindChild(val, "Start Game") != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static Transform FindChild(Transform root, string namePart)
		{
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (((Object)child).name.Contains(namePart))
				{
					return child;
				}
			}
			return null;
		}

		private static bool IsCustom(Transform transform)
		{
			while ((Object)(object)transform != (Object)null && ((Object)transform).name != "UIOptions")
			{
				if (((Object)transform).name == "GlassSolMode" || ((Object)transform).name == "TrueGlassSolMode")
				{
					return true;
				}
				transform = transform.parent;
			}
			return false;
		}

		private static bool IsTrue(Transform transform)
		{
			while ((Object)(object)transform != (Object)null && ((Object)transform).name != "UIOptions")
			{
				if (((Object)transform).name == "TrueGlassSolMode")
				{
					return true;
				}
				transform = transform.parent;
			}
			return false;
		}

		private static void CreateArts(Transform options)
		{
			if ((Object)(object)glassArt != (Object)null)
			{
				return;
			}
			Transform val = options;
			while ((Object)(object)val != (Object)null && (Object)(object)val.Find("BG") == (Object)null)
			{
				val = val.parent;
			}
			Transform val2 = val.Find("BG");
			Image source = null;
			int num = 0;
			for (int i = 0; i < val2.childCount; i++)
			{
				if (!(((Object)val2.GetChild(i)).name != "BG Image"))
				{
					num++;
					if (num == 2)
					{
						source = ((Component)val2.GetChild(i)).GetComponent<Image>();
						break;
					}
				}
			}
			glassArt = CopyArt(source, "GlassSolArt", "GlassSol.png");
			trueArt = CopyArt(source, "TrueGlassSolArt", "TrueGlassSol.png");
			if ((Object)(object)((Component)val2).GetComponent<ModeArtKeep>() == (Object)null)
			{
				((Component)val2).gameObject.AddComponent<ModeArtKeep>();
			}
		}

		private static Image CopyArt(Image source, string name, string fileName)
		{
			//IL_0053: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			bool activeSelf = ((Component)source).gameObject.activeSelf;
			((Component)source).gameObject.SetActive(false);
			Image component = Object.Instantiate<GameObject>(((Component)source).gameObject, ((Component)source).transform.parent).GetComponent<Image>();
			((Component)source).gameObject.SetActive(activeSelf);
			((Object)component).name = name;
			component.sprite = LoadArt(fileName);
			Color color = ((Graphic)component).color;
			color.a = 1f;
			((Graphic)component).color = color;
			Animator component2 = ((Component)component).GetComponent<Animator>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Behaviour)component2).enabled = false;
			}
			((Component)component).transform.SetSiblingIndex(((Component)source).transform.GetSiblingIndex() + 1);
			((Component)component).gameObject.SetActive(false);
			return component;
		}

		private static Sprite LoadArt(string fileName)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GlassSol." + fileName);
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			ImageConversion.LoadImage(val, array);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}

		private static void PlaySelectSound()
		{
			object value = AccessTools.Field(typeof(UIControlButton), "_buttonSoundGroup").GetValue(soundButton);
			AccessTools.Method(value.GetType(), "PlaySelectSound", (Type[])null, (Type[])null).Invoke(value, null);
		}

		private static Transform OptionsOf(Transform transform)
		{
			while ((Object)(object)transform != (Object)null && ((Object)transform).name != "UIOptions")
			{
				transform = transform.parent;
			}
			return transform;
		}

		private static void ReleaseOthers(Transform options, UIControlButton current)
		{
			ReleaseIfOther(options.Find("GlassSolMode"), current);
			ReleaseIfOther(options.Find("TrueGlassSolMode"), current);
		}

		private static void ReleaseIfOther(Transform row, UIControlButton current)
		{
			if (!((Object)(object)row == (Object)null) && !((Component)current).transform.IsChildOf(row) && !((Object)(object)((Component)current).transform == (Object)(object)row))
			{
				(((Component)row).GetComponent<UIControlButton>() ?? ((Component)row).GetComponentInChildren<UIControlButton>(true)).RefreshState();
			}
		}

		private static void BindDirectStart(StartMenuLogic menu, UIControlButton button, int mode)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			FieldInfo fieldInfo = AccessTools.Field(typeof(UIControlButton), "_onSubmitActions");
			Type elementType = fieldInfo.FieldType.GetElementType();
			fieldInfo.SetValue(button, Array.CreateInstance(elementType, 0));
			AccessTools.Field(typeof(UIControlButton), "clickToShowGroup").SetValue(button, null);
			if (button.onSubmit == null)
			{
				button.onSubmit = new UnityEvent();
			}
			button.onSubmit.AddListener((UnityAction)delegate
			{
				menu.CreateNewGame(mode);
			});
		}

		internal static void DestroyLocalization(GameObject root)
		{
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().FullName == "I2.Loc.Localize")
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}
	}
	internal static class SaveModeLabelPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(RCGAbstractUILabel<int>), "UpdateText")]
		private static void WriteCustomMode(RCGAbstractUILabel<int> __instance)
		{
			if (!(AccessTools.Field(((object)__instance).GetType(), "propertyName").GetValue(__instance) as string != "gameMode") && AccessTools.Method(((object)__instance).GetType(), "GetValueOfData", (Type[])null, (Type[])null).Invoke(__instance, null) is int num && (num == 2 || num == 3))
			{
				ModeMenuPatch.DestroyLocalization(((Component)__instance).gameObject);
				object? value = AccessTools.Field(typeof(RCGAbstractUILabel<int>), "text").GetValue(__instance);
				((TMP_Text)((value is TMP_Text) ? value : null)).text = ((num == 3) ? Difficulty.Phrase("Истинный Стеклянный Сол", "True Glass Sol") : Difficulty.Phrase("Стеклянный Сол", "Glass Sol"));
			}
		}
	}
	internal class ModeArtKeep : MonoBehaviour
	{
		private void LateUpdate()
		{
			ModeMenuPatch.ApplyArt();
		}
	}
	internal static class NewGameModeSavePatch
	{
		private static int pendingMode = -1;

		private static StartMenuLogic menu;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartMenuLogic), "CreateNewGame")]
		private static void RememberMode(StartMenuLogic __instance, int mode)
		{
			menu = __instance;
			pendingMode = mode;
			Apply(mode);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StartMenuLogic), "CreateOrLoadSaveSlotAndPlay")]
		private static void ClearOnContinue()
		{
			pendingMode = -1;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(A0_S6_IntroVideo), "Start")]
		private static bool SkipIntro(A0_S6_IntroVideo __instance)
		{
			if (pendingMode != 3)
			{
				return true;
			}
			AccessTools.Method(typeof(A0_S6_IntroVideo), "ChangeToStartScene", (Type[])null, (Type[])null).Invoke(__instance, null);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ApplicationCore), "ChangeSceneClean")]
		private static void SaveMode(string sceneName)
		{
			if (!(sceneName != "A0_S6_Intro_Video"))
			{
				Apply(pendingMode);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerGamePlayData), "SaveMetaData")]
		private static void StampSave(SaveSlotMetaData __result)
		{
			if (__result != null && (pendingMode == 2 || pendingMode == 3))
			{
				__result.gameMode = pendingMode;
			}
		}

		private static void Apply(int mode)
		{
			if (mode == 2 || mode == 3)
			{
				if ((Object)(object)menu != (Object)null)
				{
					((AbstractScriptableData<FlagFieldInt, int>)(object)menu.gameModeFlag).CurrentValue = mode;
				}
				PlayerGamePlayData instance = PlayerGamePlayData.Instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.gameMode != (Object)null)
				{
					((AbstractScriptableData<FlagFieldInt, int>)(object)instance.gameMode).CurrentValue = mode;
				}
			}
		}
	}
	internal static class PlayerHealthPatch
	{
		private static void Kill(PlayerHealth health)
		{
			if (!((Health)health).IsDead && (Difficulty.IsOneShot() || NohitSetting.Active()))
			{
				if (Difficulty.IsTrueGlassSol())
				{
					DeleteSaveAndReturnToMenu();
				}
				else
				{
					PlayDeath(health);
				}
			}
		}

		private static bool InternalShouldKill()
		{
			if (InternalKillSetting.Shown())
			{
				return InternalKillSetting.Kills();
			}
			return false;
		}

		private static void KeepAlive(PlayerHealth health)
		{
			float num = ((Health)health).maxHealth.Value * 0.01f;
			if (num < 1f)
			{
				num = 1f;
			}
			if (((Health)health).currentValue < num)
			{
				((Health)health).currentValue = num;
			}
		}

		private static void PlayDeath(PlayerHealth health)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			Player i = Player.i;
			((Health)health).currentValue = 0f;
			((Health)health).Die();
			if ((Object)(object)i != (Object)null && (Object)(object)i.health == (Object)(object)health)
			{
				i.DeadCheck(true);
			}
			GameObject val = new GameObject("GlassSolDeathAnim");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<DeathAnim>();
		}

		internal static void DeleteSaveAndReturnToMenu()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			SaveManager instance = SingletonBehaviour<SaveManager>.Instance;
			int num = (int)AccessTools.Field(typeof(SaveManager), "currentSlotIndex").GetValue(instance);
			if (num >= 0)
			{
				AccessTools.Method(typeof(SaveManager), "DeleteSave", (Type[])null, (Type[])null).Invoke(instance, new object[1] { num });
			}
			Time.timeScale = 1f;
			ApplicationUIGroupManager instance2 = SingletonBehaviour<ApplicationUIGroupManager>.Instance;
			if ((Object)(object)instance2 != (Object)null && (Object)(object)instance2.blackCover != (Object)null)
			{
				Color color = ((Graphic)instance2.blackCover).color;
				color.a = 0f;
				((Graphic)instance2.blackCover).color = color;
				((Component)instance2.blackCover).gameObject.SetActive(false);
			}
			GameObject val = new GameObject("GlassSolRevealMenu");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<RevealMenu>();
			SingletonBehaviour<ApplicationCore>.Instance.QuitToMenu();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAbilityData), "get_IsActivated")]
		private static bool DisableJades(PlayerAbilityData __instance, ref bool __result)
		{
			if (!Difficulty.IsOneShot())
			{
				return true;
			}
			Player i = Player.i;
			if ((Object)(object)i == (Object)null)
			{
				return true;
			}
			PlayerMainAbilityCollection mainAbilities = i.mainAbilities;
			if ((Object)(object)__instance != (Object)(object)mainAbilities.ReviveJade.AbilityData && (Object)(object)__instance != (Object)(object)mainAbilities.EndureFooExplodeJade)
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerHealth), "ReceiveDamage")]
		private static void ReceiveDamage(PlayerHealth __instance, DamageDealer damageDealer, bool __result)
		{
			if (__result && !((Health)__instance).IsInvincible && !((Object)(object)damageDealer == (Object)null) && !(damageDealer.DamageAmount <= 0f))
			{
				Kill(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerHealth), "ReceiveDOT_Damage")]
		private static void ReceiveDotDamage(PlayerHealth __instance, float damageValue)
		{
			if (!((Health)__instance).IsInvincible && !(damageValue <= 0f))
			{
				Kill(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerHealth), "ReceiveRecoverableDamage")]
		private static void ReceiveRecoverableDamage(PlayerHealth __instance, float damage)
		{
			//IL_0038: 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_0043: Expected O, but got Unknown
			if (damage <= 0f || ((Health)__instance).IsDead)
			{
				return;
			}
			if (!InternalShouldKill())
			{
				if (Difficulty.IsOneShot())
				{
					KeepAlive(__instance);
				}
				return;
			}
			PlayDeath(__instance);
			if (Difficulty.IsTrueGlassSol())
			{
				GameObject val = new GameObject("GlassSolInternalDeath");
				Object.DontDestroyOnLoad((Object)val);
				val.AddComponent<InternalDeathWipe>();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerHealth), "CoughHurt")]
		private static void CoughHurt(PlayerHealth __instance, float damageValue)
		{
			if (!(damageValue <= 0f))
			{
				Kill(__instance);
			}
		}
	}
	internal class DeathAnim : MonoBehaviour
	{
		private bool played;

		private int frames = 8;

		private void LateUpdate()
		{
			Player i = Player.i;
			if ((Object)(object)i != (Object)null && (Object)(object)((Actor)i).animator != (Object)null)
			{
				((Actor)i).animator.SetLayerWeight(1, 0f);
				if (!played)
				{
					((Actor)i).animator.Play("Die", 0, 0f);
					played = true;
				}
			}
			frames--;
			if (frames <= 0)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal class InternalDeathWipe : MonoBehaviour
	{
		private float left = 1.4f;

		private void Update()
		{
			left -= Time.unscaledDeltaTime;
			if (!(left > 0f))
			{
				PlayerHealthPatch.DeleteSaveAndReturnToMenu();
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal class RevealMenu : MonoBehaviour
	{
		private int left = 90;

		private void LateUpdate()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			Time.timeScale = 1f;
			Scene activeScene = SceneManager.GetActiveScene();
			if (!(((Scene)(ref activeScene)).name != "TitleScreenMenu") || !((Object)(object)Object.FindObjectOfType<StartMenuLogic>() == (Object)null))
			{
				ApplicationUIGroupManager instance = SingletonBehaviour<ApplicationUIGroupManager>.Instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.blackCover != (Object)null)
				{
					Color color = ((Graphic)instance.blackCover).color;
					color.a = 0f;
					((Graphic)instance.blackCover).color = color;
					((Graphic)instance.blackCover).raycastTarget = false;
					((Component)instance.blackCover).gameObject.SetActive(false);
				}
				left--;
				if (left <= 0)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
		}
	}
}