Decompiled source of RodamortaSkillCycler v1.0.0

RodamortaSkillCycler.dll

Decompiled 9 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.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using HG;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Rewired;
using RoR2;
using RoR2.ExpansionManagement;
using RoR2.Skills;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("RodamortaSkillCycler")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RodamortaSkillCycler")]
[assembly: AssemblyTitle("RodamortaSkillCycler")]
[assembly: AssemblyVersion("1.0.0.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 RainCycler
{
	internal static class FirstRun
	{
		private const string Section = "Rodamorta - Modules";

		private static bool shown;

		public static void Check()
		{
			if (!shown && !RainCyclerPlugin.FirstRunDone.Value && Object.op_Implicit((Object)(object)RainCyclerPlugin.Instance))
			{
				shown = true;
				((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(Ask());
			}
		}

		private static IEnumerator Ask()
		{
			yield return (object)new WaitForSecondsRealtime(2.5f);
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name != "title")
			{
				shown = false;
				yield break;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("This mod is made of two parts:");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("<b>SkillCycler</b>: swap skills, passives and skins (already on).");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("<b>Rodamorta</b>: miscellaneous features that change how the game plays. They are off until you enable them:");
				stringBuilder.AppendLine();
				ConfigFile config = ((BaseUnityPlugin)RainCyclerPlugin.Instance).Config;
				foreach (ConfigDefinition key in config.Keys)
				{
					if (!(key.Section != "Rodamorta - Modules"))
					{
						stringBuilder.AppendLine("<b>" + key.Key + "</b>");
						stringBuilder.AppendLine(config[key].Description.Description);
						stringBuilder.AppendLine();
					}
				}
				stringBuilder.Append("You can change any of them later in Risk of Options or in the config file. This question is only asked once.");
				try
				{
					Util.PlaySound("Play_UI_menuClick", ((Component)RoR2Application.instance).gameObject);
				}
				catch (Exception)
				{
				}
				Show("Rodamorta SkillCycler", stringBuilder.ToString(), new string[3] { "Enable All", "Keep Them Off", "Enable only Rodamorta" }, new Action[3]
				{
					delegate
					{
						Answer(rodamorta: true, skillCycler: true);
					},
					delegate
					{
						Answer(rodamorta: false, skillCycler: true);
					},
					delegate
					{
						Answer(rodamorta: true, skillCycler: false);
					}
				});
			}
			catch (Exception ex2)
			{
				shown = false;
				RainCyclerPlugin.Log.LogWarning((object)("First start window failed: " + ex2.Message));
			}
		}

		private static void Show(string header, string body, string[] buttons, Action[] actions)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0035: 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_0069: Expected O, but got Unknown
			SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)null);
			Dim(val);
			val.headerToken = new TokenParamsPair
			{
				token = header
			};
			val.descriptionToken = new TokenParamsPair
			{
				token = body
			};
			for (int i = 0; i < buttons.Length; i++)
			{
				Action action = actions[i];
				val.AddActionButton((UnityAction)delegate
				{
					action();
				}, buttons[i], true, Array.Empty<object>());
			}
		}

		private static void Dim(SimpleDialogBox box)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("RainCyclerDim", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				})
				{
					layer = ((Component)box).gameObject.layer
				};
				RectTransform val2 = (RectTransform)val.transform;
				((Transform)val2).SetParent(((Component)box).transform, false);
				Vector2 anchorMin = (val2.anchorMax = new Vector2(0.5f, 0.5f));
				val2.anchorMin = anchorMin;
				val2.sizeDelta = new Vector2(8000f, 8000f);
				((Transform)val2).SetAsFirstSibling();
				Image component = val.GetComponent<Image>();
				((Graphic)component).color = new Color(0f, 0f, 0f, 0.6f);
				((Graphic)component).raycastTarget = true;
			}
			catch (Exception)
			{
			}
		}

		private static void Answer(bool rodamorta, bool skillCycler)
		{
			bool flag = rodamorta;
			ConfigFile config = ((BaseUnityPlugin)RainCyclerPlugin.Instance).Config;
			if (flag)
			{
				foreach (ConfigDefinition key in config.Keys)
				{
					if (!(key.Section != "Rodamorta - Modules") && config[key] is ConfigEntry<bool> val)
					{
						val.Value = true;
					}
				}
			}
			if (!skillCycler)
			{
				RainCyclerPlugin.ModSkillCycler.Value = false;
			}
			RainCyclerPlugin.FirstRunDone.Value = true;
			config.Save();
			if (flag)
			{
				try
				{
					Show("Rodamorta Features", "The features are enabled. Restarting the game is recommended so everything starts cleanly.", new string[1] { "OK" }, new Action[1]
					{
						delegate
						{
						}
					});
				}
				catch (Exception)
				{
				}
			}
		}
	}
	internal static class Floppy
	{
		private sealed class Bone
		{
			public DynamicBone Db;

			public float Born;

			public float In;

			public float OutAt = -1f;

			public float OutFrom = 1f;

			public float Last = -1f;

			public float Max = 1f;

			public float Fade = 1f;
		}

		private sealed class Hold
		{
			public SkillSlot Slot;

			public GenericSkill Skill;

			public float Until;

			public float Last;
		}

		private static readonly string[] buffs = new string[12]
		{
			"TearGasBerserk", "Fracture", "Blight", "TeleportOnLowHealthActive", "KnockbackFinGuaranteedCritDebuff", "KnockUpHitEnemiesJuggleCount", "KnockUpHitEnemies", "Entangle", "LunarSecondaryRoot", "NanoBug",
			"NullifyStack", "TransferDebuffOnHit"
		};

		private static readonly Dictionary<CharacterBody, float> voidUntil = new Dictionary<CharacterBody, float>();

		private static readonly Dictionary<CharacterBody, bool> hadVoid = new Dictionary<CharacterBody, bool>();

		private static readonly Dictionary<CharacterBody, float> firstSeen = new Dictionary<CharacterBody, float>();

		private static float next;

		private static readonly Dictionary<Object, Bone> bones = new Dictionary<Object, Bone>();

		private static MethodInfo setWeight;

		private static bool setWeightSearched;

		private static float nextLobby;

		private static Type slotType;

		private static bool slotSearched;

		private static readonly Dictionary<CharacterBody, Hold> holds = new Dictionary<CharacterBody, Hold>();

		private static readonly Dictionary<CharacterBody, float> lastHealth = new Dictionary<CharacterBody, float>();

		private static readonly Dictionary<CharacterBody, float> hitUntil = new Dictionary<CharacterBody, float>();

		public static void Tick()
		{
			if (!RainCyclerPlugin.FloppyEnabled.Value && !RainCyclerPlugin.ModHeresyAnims.Value)
			{
				if (bones.Count > 0)
				{
					ReleaseAll();
				}
			}
			else
			{
				if (Time.unscaledTime < next)
				{
					return;
				}
				next = Time.unscaledTime + 0.1f;
				try
				{
					Forget();
					foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
					{
						if (!Object.op_Implicit((Object)(object)readOnlyInstances) || !Object.op_Implicit((Object)(object)readOnlyInstances.modelLocator))
						{
							continue;
						}
						int num;
						int num2;
						if (Object.op_Implicit((Object)(object)readOnlyInstances.healthComponent) && readOnlyInstances.healthComponent.alive)
						{
							num = ((!Ragdoll.IsFallen(readOnlyInstances)) ? 1 : 0);
							if (num != 0 && RainCyclerPlugin.FloppyEnabled.Value)
							{
								num2 = (Wanted(readOnlyInstances) ? 1 : 0);
								goto IL_00c0;
							}
						}
						else
						{
							num = 0;
						}
						num2 = 0;
						goto IL_00c0;
						IL_00c0:
						bool flag = (byte)num2 != 0;
						bool quick = false;
						float num3 = ((num != 0) ? HeresyStrength(readOnlyInstances, out quick) : 0f);
						bool flag2 = num3 > 0f && !flag && quick;
						bool flag3 = flag || num3 > 0f;
						bool flag4 = bones.ContainsKey((Object)(object)readOnlyInstances);
						if (flag3 && flag4)
						{
							Bone bone = bones[(Object)(object)readOnlyInstances];
							bone.Max = (flag ? 1f : num3);
							bone.Fade = (flag2 ? 0.15f : 1f);
							StopFading((Object)(object)readOnlyInstances);
						}
						else if (flag3)
						{
							AddBones((Object)(object)readOnlyInstances, Object.op_Implicit((Object)(object)readOnlyInstances.modelLocator.modelTransform) ? ((Component)readOnlyInstances.modelLocator.modelTransform).gameObject : null, flag2 ? 0.1f : 0.5f);
							if (bones.TryGetValue((Object)(object)readOnlyInstances, out var value))
							{
								value.Max = (flag ? 1f : num3);
								value.Fade = (flag2 ? 0.15f : 1f);
							}
						}
						else if (flag4)
						{
							RemoveBones((Object)(object)readOnlyInstances);
						}
					}
				}
				catch (Exception ex)
				{
					RainCyclerPlugin.Log.LogWarning((object)("Floppy failed: " + ex.Message));
				}
				try
				{
					LobbyTick();
				}
				catch (Exception)
				{
				}
			}
		}

		private static void AddBones(Object key, GameObject model, float fadeIn)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			Transform val = (Object.op_Implicit((Object)(object)model) ? TryFindRoot(model) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				bones[key] = new Bone();
				return;
			}
			DynamicBone val2 = ((Component)val).gameObject.AddComponent<DynamicBone>();
			val2.m_Root = val;
			val2.m_UpdateRate = 60f;
			val2.m_UpdateMode = (UpdateMode)0;
			val2.m_Damping = 0.344f;
			val2.m_DampingDistrib = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 1f)
			});
			val2.m_Elasticity = 0.1f;
			val2.m_ElasticityDistrib = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 0f)
			});
			Bone bone = new Bone
			{
				Db = val2,
				Born = Time.time,
				In = fadeIn
			};
			bones[key] = bone;
			Apply(bone, (fadeIn > 0f) ? 0f : 1f);
		}

		private static float WeightOf(Bone b)
		{
			if (b.OutAt >= 0f)
			{
				return Mathf.Clamp01(b.OutFrom * (1f - (Time.time - b.OutAt) / b.Fade)) * b.Max;
			}
			return ((b.In > 0f) ? Mathf.Clamp01((Time.time - b.Born) / b.In) : 1f) * b.Max;
		}

		private static void Apply(Bone b, float w)
		{
			if (!Object.op_Implicit((Object)(object)b.Db) || Mathf.Abs(w - b.Last) < 0.004f)
			{
				return;
			}
			b.Last = w;
			try
			{
				if (!setWeightSearched)
				{
					setWeightSearched = true;
					setWeight = typeof(DynamicBone).GetMethod("SetWeight", new Type[1] { typeof(float) });
				}
				if (setWeight != null)
				{
					setWeight.Invoke(b.Db, new object[1] { w });
				}
				else
				{
					b.Db.m_Elasticity = Mathf.Lerp(1f, 0.1f, w);
				}
			}
			catch (Exception)
			{
				b.Db.m_Elasticity = Mathf.Lerp(1f, 0.1f, w);
			}
		}

		private static void RemoveBones(Object key)
		{
			if (bones.TryGetValue(key, out var value))
			{
				if (!Object.op_Implicit((Object)(object)value.Db))
				{
					bones.Remove(key);
				}
				else if (!(value.OutAt >= 0f))
				{
					value.OutFrom = ((value.Max > 0f) ? (WeightOf(value) / value.Max) : 0f);
					value.OutAt = Time.time;
				}
			}
		}

		private static void StopFading(Object key)
		{
			if (bones.TryGetValue(key, out var value) && !(value.OutAt < 0f))
			{
				float num = ((value.Max > 0f) ? (WeightOf(value) / value.Max) : 0f);
				value.OutAt = -1f;
				value.In = ((value.Fade < 0.5f) ? 0.1f : 0.5f);
				value.Born = Time.time - num * value.In;
			}
		}

		public static void Frame()
		{
			if (bones.Count == 0)
			{
				return;
			}
			List<Object> list = null;
			foreach (KeyValuePair<Object, Bone> bone in bones)
			{
				Bone value = bone.Value;
				if (!Object.op_Implicit(bone.Key) || !Object.op_Implicit((Object)(object)value.Db))
				{
					(list ?? (list = new List<Object>())).Add(bone.Key);
					continue;
				}
				float num = WeightOf(value);
				if (value.OutAt >= 0f && num <= 0.001f)
				{
					Object.Destroy((Object)(object)value.Db);
					(list ?? (list = new List<Object>())).Add(bone.Key);
				}
				else
				{
					Apply(value, num);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Object item in list)
			{
				bones.Remove(item);
			}
		}

		private static void LobbyTick()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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: Invalid comparison between Unknown and I4
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			Scene activeScene = SceneManager.GetActiveScene();
			bool flag = ((Scene)(ref activeScene)).name == "lobby";
			HashSet<Transform> hashSet = new HashSet<Transform>();
			if (flag && Time.unscaledTime >= nextLobby)
			{
				nextLobby = Time.unscaledTime + 0.5f;
				bool flag2 = false;
				try
				{
					flag2 = Object.op_Implicit((Object)(object)PreGameController.instance) && (int)PreGameController.instance.readOnlyRuleBook.FindDifficulty() == 0;
				}
				catch (Exception)
				{
				}
				if (flag2)
				{
					Object[] array = FindSlots();
					for (int i = 0; i < array.Length; i++)
					{
						Transform val = MannequinOf(array[i]);
						if (Object.op_Implicit((Object)(object)val))
						{
							hashSet.Add(val);
						}
					}
				}
			}
			else if (flag)
			{
				return;
			}
			foreach (Transform item in hashSet)
			{
				if (!bones.ContainsKey((Object)(object)item))
				{
					AddBones((Object)(object)item, ((Component)item).gameObject, 2f);
				}
				else
				{
					StopFading((Object)(object)item);
				}
			}
			foreach (Object item2 in new List<Object>(bones.Keys))
			{
				if (item2 is Transform && !hashSet.Contains((Transform)item2))
				{
					RemoveBones(item2);
				}
			}
		}

		private static Object[] FindSlots()
		{
			if (!slotSearched)
			{
				slotSearched = true;
				Type[] types = typeof(CharacterBody).Assembly.GetTypes();
				foreach (Type type in types)
				{
					if (type.Name == "SurvivorMannequinSlotController")
					{
						slotType = type;
						break;
					}
				}
				if (slotType == null)
				{
					RainCyclerPlugin.Log.LogInfo((object)"Lobby display slots not found; lobby floppy is off.");
				}
			}
			if (!(slotType != null))
			{
				return (Object[])(object)new Object[0];
			}
			return Object.FindObjectsOfType(slotType);
		}

		private static Transform MannequinOf(Object slot)
		{
			Type type = ((object)slot).GetType();
			FieldInfo field = type.GetField("mannequinInstanceTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object? value = field.GetValue(slot);
				return (Transform)((value is Transform) ? value : null);
			}
			PropertyInfo property = type.GetProperty("mannequinInstanceTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property != null))
			{
				return null;
			}
			object? value2 = property.GetValue(slot, null);
			return (Transform)((value2 is Transform) ? value2 : null);
		}

		private static Transform TryFindRoot(GameObject prefab)
		{
			ChildLocator componentInChildren = prefab.GetComponentInChildren<ChildLocator>();
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				Transform val = componentInChildren.FindChild("Base");
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
				val = componentInChildren.FindChild("Root");
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
				val = componentInChildren.FindChild("ROOT");
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			SkinnedMeshRenderer componentInChildren2 = prefab.GetComponentInChildren<SkinnedMeshRenderer>();
			if (!Object.op_Implicit((Object)(object)componentInChildren2))
			{
				return null;
			}
			return componentInChildren2.rootBone;
		}

		private static void ReleaseAll()
		{
			foreach (Object item in new List<Object>(bones.Keys))
			{
				RemoveBones(item);
			}
		}

		private static void Forget()
		{
			List<CharacterBody> list = null;
			foreach (CharacterBody key in lastHealth.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key))
				{
					(list ?? (list = new List<CharacterBody>())).Add(key);
				}
			}
			foreach (CharacterBody key2 in hitUntil.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key2))
				{
					(list ?? (list = new List<CharacterBody>())).Add(key2);
				}
			}
			if (list != null)
			{
				foreach (CharacterBody item in list)
				{
					lastHealth.Remove(item);
					hitUntil.Remove(item);
				}
			}
			List<CharacterBody> list2 = null;
			foreach (CharacterBody key3 in voidUntil.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key3))
				{
					(list2 ?? (list2 = new List<CharacterBody>())).Add(key3);
				}
			}
			foreach (CharacterBody key4 in hadVoid.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key4))
				{
					(list2 ?? (list2 = new List<CharacterBody>())).Add(key4);
				}
			}
			foreach (CharacterBody key5 in firstSeen.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key5))
				{
					(list2 ?? (list2 = new List<CharacterBody>())).Add(key5);
				}
			}
			if (list2 == null)
			{
				return;
			}
			foreach (CharacterBody item2 in list2)
			{
				voidUntil.Remove(item2);
				hadVoid.Remove(item2);
				firstSeen.Remove(item2);
			}
		}

		public static void HeresyUsed(CharacterBody body, SkillSlot slot, GenericSkill skill)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			if (Object.op_Implicit((Object)(object)body) && RainCyclerPlugin.ModHeresyAnims.Value)
			{
				float time = Time.time;
				Hold hold = new Hold
				{
					Slot = slot,
					Skill = skill,
					Last = time
				};
				hold.Until = (((int)slot == 3) ? (time + 1.5f) : (((int)slot == 2) ? (time + 0.35f) : (time + 0.2f)));
				holds[body] = hold;
			}
		}

		private static float HeresyStrength(CharacterBody body, out bool quick)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Invalid comparison between Unknown and I4
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			quick = true;
			if (!holds.TryGetValue(body, out var value))
			{
				return 0f;
			}
			float time = Time.time;
			bool flag = false;
			SkillSlot slot = value.Slot;
			if ((int)slot != 0)
			{
				if ((int)slot == 1)
				{
					flag = Object.op_Implicit((Object)(object)body.inputBank) && body.inputBank.skill2.down && time < value.Last + 8f;
					if (!flag)
					{
						flag = time < value.Until;
					}
				}
				else
				{
					flag = time < value.Until;
				}
			}
			else
			{
				flag = Object.op_Implicit((Object)(object)value.Skill) && value.Skill.stock > 0 && time < value.Last + 0.5f;
			}
			if (!flag)
			{
				holds.Remove(body);
				return 0f;
			}
			if ((int)value.Slot == 3)
			{
				quick = false;
				return 0.3f;
			}
			if ((int)value.Slot == 1)
			{
				return 0.2f;
			}
			if ((int)value.Slot == 0 && Object.op_Implicit((Object)(object)value.Skill))
			{
				int num = Mathf.Max(2, value.Skill.maxStock);
				float num2 = Mathf.Clamp01((float)(num - value.Skill.stock) / (float)(num - 1));
				return 0.24f * Mathf.Max(1f, (float)num / 12f) * num2;
			}
			return 0.12f;
		}

		private static bool Wanted(CharacterBody body)
		{
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			bool flag = firstLocalUser != null && (Object)(object)firstLocalUser.cachedBody == (Object)(object)body;
			string[] array = buffs;
			foreach (string text in array)
			{
				if ((!(text == "NanoBug" && flag) || !(Time.time < Swapper.FlashUntil)) && Swapper.HasBuff(body, Swapper.BuffIndexOf(text)))
				{
					return true;
				}
			}
			if (Object.op_Implicit((Object)(object)body.inventory))
			{
				if (Swapper.CountItem(body, "SlipperyGround") > 0)
				{
					return true;
				}
				if (HasGoobo(body) && Time.time < HitUntil(body))
				{
					return true;
				}
			}
			if (IsGooboClone(body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.combinedHealthFraction < 0.5f)
			{
				return true;
			}
			object index = Swapper.BuffIndexOf("EliteVoid");
			bool flag2 = Swapper.HasBuff(body, index);
			hadVoid.TryGetValue(body, out var value);
			hadVoid[body] = flag2;
			if (!firstSeen.ContainsKey(body))
			{
				firstSeen[body] = Time.time;
			}
			if (flag2 && !value && Time.time - firstSeen[body] > 1.5f)
			{
				voidUntil[body] = Time.time + 1.5f;
			}
			if (voidUntil.TryGetValue(body, out var value2) && Time.time < value2)
			{
				return true;
			}
			return false;
		}

		private static float HitUntil(CharacterBody body)
		{
			HealthComponent healthComponent = body.healthComponent;
			if (!Object.op_Implicit((Object)(object)healthComponent))
			{
				return 0f;
			}
			float num = healthComponent.health + healthComponent.shield;
			bool isPlayerControlled = body.isPlayerControlled;
			if (lastHealth.TryGetValue(body, out var value) && num < value - 0.01f)
			{
				hitUntil[body] = (isPlayerControlled ? float.MaxValue : (Time.time + 0.5f));
			}
			if (isPlayerControlled && hitUntil.TryGetValue(body, out var value2) && value2 > Time.time && Object.op_Implicit((Object)(object)body.inputBank) && body.inputBank.jump.down)
			{
				hitUntil[body] = 0f;
			}
			lastHealth[body] = num;
			if (!hitUntil.TryGetValue(body, out var value3))
			{
				return 0f;
			}
			return value3;
		}

		private static bool HasGoobo(CharacterBody body)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			EquipmentSlot equipmentSlot = body.equipmentSlot;
			if (!Object.op_Implicit((Object)(object)equipmentSlot))
			{
				return false;
			}
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentSlot.equipmentIndex);
			if (Object.op_Implicit((Object)(object)equipmentDef))
			{
				return ((Object)equipmentDef).name == "GummyClone";
			}
			return false;
		}

		private static bool IsGooboClone(CharacterBody body)
		{
			CharacterMaster master = body.master;
			if (Object.op_Implicit((Object)(object)master))
			{
				return ((Object)master).name.ToLowerInvariant().Contains("gummyclone");
			}
			return false;
		}
	}
	internal static class Fx
	{
		private static HashSet<string> events;

		private static string infoText;

		private static readonly HashSet<string> banksTried = new HashSet<string>();

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

		private static bool critLogged;

		private static Material particleMaterial;

		private static bool particlesBroken;

		private static void LoadEvents()
		{
			if (events != null)
			{
				return;
			}
			events = new HashSet<string>();
			try
			{
				string path = Path.Combine(Application.streamingAssetsPath, Path.Combine("Audio", Path.Combine("GeneratedSoundBanks", "Windows")));
				string[] array = new string[2] { "SoundbanksInfo.xml", "SoundbanksInfo.json" };
				foreach (string path2 in array)
				{
					string path3 = Path.Combine(path, path2);
					if (!File.Exists(path3))
					{
						continue;
					}
					infoText = File.ReadAllText(path3);
					foreach (Match item in Regex.Matches(infoText, "Play_[A-Za-z0-9_]+"))
					{
						events.Add(item.Value);
					}
					break;
				}
				if (events.Count <= 0)
				{
					return;
				}
				List<string> list = new List<string>();
				foreach (string @event in events)
				{
					if (Has(@event, "laserturbine") || Has(@event, "engi", "m1") || Has(@event, "infestor") || Has(@event, "ui", "menu"))
					{
						list.Add(@event);
					}
				}
				list.Sort();
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Reading sound events failed: " + ex.Message));
			}
		}

		private static bool Has(string name, params string[] tokens)
		{
			string text = name.ToLowerInvariant();
			foreach (string value in tokens)
			{
				if (!text.Contains(value))
				{
					return false;
				}
			}
			return true;
		}

		private static void Play(string key, GameObject go, string[] tokens, string[] prefer, string[] avoid, string[] guesses)
		{
			if (!Object.op_Implicit((Object)(object)go))
			{
				return;
			}
			try
			{
				if (working.TryGetValue(key, out var value))
				{
					if (value.Length > 0)
					{
						Util.PlaySound(value, go);
					}
					return;
				}
				LoadEvents();
				List<string> list = new List<string>();
				List<string> list2 = new List<string>();
				foreach (string @event in events)
				{
					if (!Has(@event, tokens))
					{
						continue;
					}
					bool flag = false;
					string[] array = avoid;
					foreach (string text in array)
					{
						if (Has(@event, text))
						{
							flag = true;
						}
					}
					if (flag)
					{
						continue;
					}
					bool flag2 = prefer.Length == 0;
					array = prefer;
					foreach (string text2 in array)
					{
						if (Has(@event, text2))
						{
							flag2 = true;
						}
					}
					(flag2 ? list2 : list).Add(@event);
				}
				list2.Sort();
				list.Sort();
				List<string> list3 = new List<string>(list2);
				list3.AddRange(list);
				list3.AddRange(guesses);
				foreach (string item in list3)
				{
					if (Util.PlaySound(item, go) != 0)
					{
						working[key] = item;
						return;
					}
				}
				working[key] = "";
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Sound '" + key + "' failed: " + ex.Message));
			}
		}

		public static void Disc(GameObject go)
		{
			Play("disc", go, new string[1] { "laserturbine" }, new string[4] { "throw", "return", "launch", "fire" }, new string[2] { "loop", "stop" }, new string[8] { "Play_item_use_laserTurbine_throw", "Play_item_use_laserturbine_throw", "Play_item_use_laserTurbine_return", "Play_item_use_laserturbine_return", "Play_item_use_laserTurbine_launch", "Play_item_use_laserturbine_launch", "Play_item_use_laserTurbine", "Play_item_use_laserturbine" });
		}

		public static void Engi(GameObject go)
		{
			if (RainCyclerPlugin.ModSwapSounds.Value)
			{
				string text = RainCyclerPlugin.SwapSound.Value.Trim();
				Util.PlaySound((text.Length > 0) ? text : "Play_UI_menuClick", go);
			}
		}

		public static void Crit(GameObject go)
		{
			if (RainCyclerPlugin.ModSwapSounds.Value)
			{
				Play("crit", go, new string[1] { "crit" }, new string[5] { "hit", "impact", "enemy", "damage", "player" }, new string[11]
				{
					"loop", "stop", "glasses", "lens", "attackspeed", "chance", "heal", "explo", "void", "chain",
					"buff"
				}, new string[5] { "Play_player_crit", "Play_hitenemy_crit", "Play_UI_crit", "Play_item_proc_crit", "Play_UI_menuClick" });
				if (!critLogged && working.TryGetValue("crit", out var value))
				{
					critLogged = true;
					RainCyclerPlugin.Log.LogInfo((object)("Passive change sound: " + ((value.Length > 0) ? value : "none found")));
				}
			}
		}

		public static void Hover(GameObject go)
		{
			if (RainCyclerPlugin.ModSwapSounds.Value && Object.op_Implicit((Object)(object)go))
			{
				Play("hover", go, new string[3] { "ui", "menu", "hover" }, new string[0], new string[1] { "stop" }, new string[2] { "Play_UI_menuHover", "Play_UI_menuClick" });
			}
		}

		public static void Laugh(GameObject go)
		{
			Play("laugh", go, new string[1] { "laugh" }, new string[5] { "haunt", "ghost", "spectral", "circlet", "equip" }, new string[2] { "loop", "stop" }, new string[3] { "Play_item_use_haunted_laugh", "Play_item_proc_haunted_laugh", "Play_ghost_laugh" });
		}

		public static void Infestor(GameObject go)
		{
			Play("infestor", go, new string[2] { "infestor", "spawn" }, new string[0], new string[1] { "stop" }, new string[5] { "Play_voidinfestor_spawn", "Play_voidInfestor_spawn", "Play_void_infestor_spawn", "Play_infestor_spawn", "Play_UI_menuCancel" });
		}

		public static void MenuOpen(GameObject go)
		{
			Play("menuopen", go, new string[3] { "ui", "menu", "hover" }, new string[0], new string[1] { "stop" }, new string[2] { "Play_UI_menuHover", "Play_UI_menuClick" });
		}

		public static void MenuClose(GameObject go)
		{
			Play("menuclose", go, new string[3] { "ui", "menu", "cancel" }, new string[0], new string[1] { "stop" }, new string[3] { "Play_UI_menuCancel", "Play_UI_menuBack", "Play_UI_menuClick" });
		}

		public static void Burst(CharacterBody body)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_0154: 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_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			try
			{
				if (!Object.op_Implicit((Object)(object)body) || particlesBroken)
				{
					return;
				}
				GameObject val = new GameObject("RainCyclerBurst");
				Object.Destroy((Object)(object)val, 2f);
				val.transform.position = body.corePosition;
				ParticleSystem val2 = val.AddComponent<ParticleSystem>();
				val2.Stop(true, (ParticleSystemStopBehavior)0);
				MainModule main = val2.main;
				((MainModule)(ref main)).duration = 0.5f;
				((MainModule)(ref main)).loop = false;
				((MainModule)(ref main)).playOnAwake = false;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.8f);
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(2.2f);
				((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.16f);
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.7f, 1f, 1f));
				((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
				((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.15f);
				EmissionModule emission = val2.emission;
				((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
				((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1]
				{
					new Burst(0f, (short)26)
				});
				ShapeModule shape = val2.shape;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0;
				((ShapeModule)(ref shape)).radius = Mathf.Max(0.4f, body.radius * 0.8f);
				Gradient val3 = new Gradient();
				val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
				{
					new GradientColorKey(Color.white, 0f),
					new GradientColorKey(Color.white, 1f)
				}, (GradientAlphaKey[])(object)new GradientAlphaKey[2]
				{
					new GradientAlphaKey(1f, 0f),
					new GradientAlphaKey(0f, 1f)
				});
				ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime;
				((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
				((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3);
				ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
				if (!Object.op_Implicit((Object)(object)particleMaterial))
				{
					Shader val4 = Shader.Find("Sprites/Default");
					if (Object.op_Implicit((Object)(object)val4))
					{
						particleMaterial = new Material(val4)
						{
							mainTexture = (Texture)(object)RoundSprites.Disc.texture
						};
					}
				}
				if (Object.op_Implicit((Object)(object)particleMaterial))
				{
					((Renderer)component).material = particleMaterial;
				}
				val2.Play();
			}
			catch (Exception)
			{
				particlesBroken = true;
			}
		}

		public static void JumpAnimation(CharacterBody body)
		{
			try
			{
				Transform val = ((Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.modelLocator)) ? body.modelLocator.modelTransform : null);
				Animator val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponentInChildren<Animator>() : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(JumpRoutine(val2));
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Jump animation failed: " + ex.Message));
			}
		}

		private static IEnumerator JumpRoutine(Animator animator)
		{
			bool value = RainCyclerPlugin.ReverseJump.Value;
			int layer = animator.GetLayerIndex("Body");
			if (layer < 0)
			{
				layer = 0;
			}
			float oldSpeed = animator.speed;
			try
			{
				animator.speed = (value ? (-1f) : 1f);
				animator.Play("Jump", layer, value ? 0.9f : 0f);
			}
			catch (Exception)
			{
			}
			yield return (object)new WaitForSeconds(0.35f);
			if (Object.op_Implicit((Object)(object)animator))
			{
				animator.speed = oldSpeed;
				animator.CrossFadeInFixedTime("Idle", 0.1f, layer);
			}
		}
	}
	internal static class HeresyAnim
	{
		private sealed class Found
		{
			public string Layer;

			public string State;
		}

		private static readonly Dictionary<string, Found> learnt = new Dictionary<string, Found>();

		private static readonly Dictionary<string, Found> cache = new Dictionary<string, Found>();

		private static readonly Dictionary<Type, List<string>> stringCache = new Dictionary<Type, List<string>>();

		private static readonly HashSet<long> running = new HashSet<long>();

		private static int logs;

		private static readonly Dictionary<CharacterBody, KeyValuePair<SkillDef, float>> lastUsed = new Dictionary<CharacterBody, KeyValuePair<SkillDef, float>>();

		private static int noteLogs;

		public static void Install()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			try
			{
				Harmony val = new Harmony("local.rodamortaraincycler.anim");
				MethodInfo methodInfo = AccessTools.Method(typeof(GenericSkill), "ExecuteIfReady", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HeresyAnim).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				HarmonyMethod val2 = new HarmonyMethod(typeof(HeresyAnim).GetMethod("Heard", BindingFlags.Static | BindingFlags.Public));
				MethodInfo[] methods = typeof(EntityState).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (!(methodInfo2.Name != "PlayAnimation") || !(methodInfo2.Name != "PlayCrossfade"))
					{
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if (parameters.Length >= 2 && !(parameters[0].ParameterType != typeof(string)) && !(parameters[1].ParameterType != typeof(string)))
						{
							val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						}
					}
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Heresy animation patch failed: " + ex.Message));
			}
		}

		private static string KeyOf(CharacterBody body, SkillDef def)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected I4, but got Unknown
			return (int)body.bodyIndex + "/" + def.skillNameToken;
		}

		private static bool Usable(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf("empty", StringComparison.OrdinalIgnoreCase) < 0;
			}
			return false;
		}

		public static void Heard(EntityState __instance, object[] __args)
		{
			try
			{
				if (__args == null || __args.Length < 2)
				{
					return;
				}
				string text = __args[0] as string;
				string text2 = __args[1] as string;
				if (!Usable(text) || !Usable(text2))
				{
					return;
				}
				EntityStateMachine outer = __instance.outer;
				if (!Object.op_Implicit((Object)(object)outer))
				{
					return;
				}
				CharacterBody component = ((Component)outer).GetComponent<CharacterBody>();
				LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
				if (!Object.op_Implicit((Object)(object)component) || firstLocalUser == null || (Object)(object)firstLocalUser.cachedBody != (Object)(object)component)
				{
					return;
				}
				Type type = ((object)__instance).GetType();
				GenericSkill[] components = ((Component)component).GetComponents<GenericSkill>();
				for (int i = 0; i < components.Length; i++)
				{
					SkillDef skillDef = components[i].skillDef;
					if (Object.op_Implicit((Object)(object)skillDef) && !(((SerializableEntityStateType)(ref skillDef.activationState)).stateType != type))
					{
						string key = KeyOf(component, skillDef);
						if (!learnt.ContainsKey(key))
						{
							learnt[key] = new Found
							{
								Layer = text,
								State = text2
							};
							Note("learnt (state) ", component, skillDef, text, text2);
						}
						return;
					}
				}
				if ((text.Contains("Gesture") || text.Contains("FullBody") || text.Contains("Override")) && lastUsed.TryGetValue(component, out var value) && Time.time - value.Value < 0.6f && Object.op_Implicit((Object)(object)value.Key))
				{
					string key2 = KeyOf(component, value.Key);
					if (!learnt.ContainsKey(key2))
					{
						learnt[key2] = new Found
						{
							Layer = text,
							State = text2
						};
						Note("learnt (after use) ", component, value.Key, text, text2);
					}
				}
			}
			catch (Exception)
			{
			}
		}

		private static void Note(string what, CharacterBody body, SkillDef def, string layer, string state)
		{
			if (noteLogs++ < 40)
			{
				RainCyclerPlugin.Log.LogInfo((object)("Heresy animation " + what + ((Object)body).name + " (" + def.skillNameToken + "): " + layer + " / " + state));
			}
		}

		public static void Postfix(GenericSkill __instance, bool __result)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (!__result)
			{
				return;
			}
			try
			{
				Swapper.NoteUse(__instance);
				if (!Object.op_Implicit((Object)(object)Swapper.HeresyAnimationSource(__instance, out var body, out var slotOut)) || !Object.op_Implicit((Object)(object)body))
				{
					CharacterBody val = (Object.op_Implicit((Object)(object)__instance) ? ((Component)__instance).GetComponent<CharacterBody>() : null);
					LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
					if (Object.op_Implicit((Object)(object)val) && firstLocalUser != null && (Object)(object)firstLocalUser.cachedBody == (Object)(object)val && Object.op_Implicit((Object)(object)__instance.skillDef))
					{
						lastUsed[val] = new KeyValuePair<SkillDef, float>(__instance.skillDef, Time.time);
					}
				}
				else
				{
					Floppy.HeresyUsed(body, slotOut, __instance);
				}
			}
			catch (Exception)
			{
			}
		}

		private static IEnumerator Run(Animator animator, int layer, Found found, float forwardSpeed, float backSpeed)
		{
			long id = ((long)((Object)animator).GetInstanceID() << 8) | (uint)layer;
			if (!running.Add(id))
			{
				yield break;
			}
			try
			{
				animator.PlayInFixedTime(found.State, layer, 0f);
				animator.Update(0f);
				AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(layer);
				float num = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length;
				if (float.IsInfinity(num) || num < 0.05f)
				{
					num = 0.5f;
				}
				float duration = Mathf.Min(num, 0.7f);
				float portion = Mathf.Clamp01(duration / num);
				float t = 0f;
				while (t < duration)
				{
					if (!Object.op_Implicit((Object)(object)animator))
					{
						yield break;
					}
					t += Time.deltaTime * forwardSpeed;
					animator.Play(found.State, layer, Mathf.Clamp01(t / duration) * portion);
					animator.Update(0f);
					yield return null;
				}
				while (backSpeed > 0f && t > 0f)
				{
					if (!Object.op_Implicit((Object)(object)animator))
					{
						yield break;
					}
					t -= Time.deltaTime * backSpeed;
					animator.Play(found.State, layer, Mathf.Clamp01(t / duration) * portion);
					animator.Update(0f);
					yield return null;
				}
				if (Object.op_Implicit((Object)(object)animator))
				{
					Release(animator, layer, found.Layer);
				}
			}
			finally
			{
				running.Remove(id);
			}
		}

		private static void Release(Animator animator, int layer, string layerName)
		{
			string[] array = new string[2] { "BufferEmpty", "Empty" };
			foreach (string text in array)
			{
				if (animator.HasState(layer, Animator.StringToHash(text)))
				{
					animator.CrossFadeInFixedTime(text, 0.12f, layer);
					return;
				}
			}
			if (animator.HasState(layer, Animator.StringToHash("Idle")))
			{
				animator.CrossFadeInFixedTime("Idle", 0.12f, layer);
			}
		}

		private static Found Search(SkillDef source, Animator animator)
		{
			Type stateType = ((SerializableEntityStateType)(ref source.activationState)).stateType;
			if (stateType == null)
			{
				return null;
			}
			List<string> list = StringsOf(stateType);
			for (int i = 0; i < list.Count; i++)
			{
				int layerIndex = animator.GetLayerIndex(list[i]);
				if (layerIndex < 0)
				{
					continue;
				}
				for (int j = i + 1; j < list.Count && j <= i + 3; j++)
				{
					if (Usable(list[j]) && animator.HasState(layerIndex, Animator.StringToHash(list[j])))
					{
						return new Found
						{
							Layer = list[i],
							State = list[j]
						};
					}
				}
			}
			Found found = null;
			foreach (string item in list)
			{
				if (!Usable(item))
				{
					continue;
				}
				for (int k = 0; k < animator.layerCount; k++)
				{
					if (animator.HasState(k, Animator.StringToHash(item)))
					{
						string layerName = animator.GetLayerName(k);
						bool flag = layerName.Contains("Gesture") || layerName.Contains("Override");
						if (found == null || (flag && !found.Layer.Contains("Gesture") && !found.Layer.Contains("Override")))
						{
							found = new Found
							{
								Layer = layerName,
								State = item
							};
						}
					}
				}
			}
			return found;
		}

		private static List<string> StringsOf(Type type)
		{
			if (stringCache.TryGetValue(type, out var value))
			{
				return value;
			}
			List<string> list = new List<string>();
			try
			{
				Type type2 = type;
				while (type2 != null && type2 != typeof(object) && type2.Name != "EntityState" && type2.Name != "BaseState" && type2.Name != "BaseSkillState")
				{
					List<MethodInfo> list2 = new List<MethodInfo>();
					MethodInfo method = type2.GetMethod("OnEnter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null)
					{
						list2.Add(method);
					}
					MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo in methods)
					{
						if (methodInfo != method && methodInfo.Name != "OnExit" && methodInfo.Name != "FixedUpdate" && methodInfo.Name != "Update")
						{
							list2.Add(methodInfo);
						}
					}
					FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (fieldInfo.FieldType != typeof(string))
						{
							continue;
						}
						try
						{
							string text = fieldInfo.GetValue(null) as string;
							if (!string.IsNullOrEmpty(text))
							{
								list.Add(text);
							}
						}
						catch (Exception)
						{
						}
					}
					foreach (MethodInfo item in list2)
					{
						byte[] array = item.GetMethodBody()?.GetILAsByteArray();
						if (array == null)
						{
							continue;
						}
						for (int j = 0; j + 4 < array.Length; j++)
						{
							byte num = array[j];
							OpCode ldstr = OpCodes.Ldstr;
							if (num != ldstr.Value)
							{
								continue;
							}
							int num2 = BitConverter.ToInt32(array, j + 1);
							if (num2 >> 24 == 112)
							{
								try
								{
									list.Add(type2.Module.ResolveString(num2));
									j += 4;
								}
								catch (Exception)
								{
								}
							}
						}
					}
					type2 = type2.BaseType;
				}
			}
			catch (Exception)
			{
			}
			stringCache[type] = list;
			return list;
		}
	}
	internal static class ItemBuffs
	{
		private sealed class Link
		{
			public string Item;

			public string[] Buffs;
		}

		private sealed class Line
		{
			public float At;

			public string Tag;

			public string Text;
		}

		private sealed class KeyState
		{
			public float Since;

			public bool Second;
		}

		private static readonly Link[] links = new Link[2]
		{
			new Link
			{
				Item = "MasterBattery",
				Buffs = new string[1] { "KineticArmor" }
			},
			new Link
			{
				Item = "MasterCore",
				Buffs = new string[2] { "CollectiveShareBuff", "KineticArmor" }
			}
		};

		private static readonly string[] hexItems = new string[14]
		{
			"SlipperyGround", "Blindness", "LowerHealing", "ShareItemsWithEnemies", "HexHaunting", "WeakAssHamstring", "RoamingItemDisable", "Mimicry", "RandomDebuffOnInteract", "BarrierEnemiesOnKill",
			"HexCurse", "OutOfTPRadius", "IncreasedDifficulty", "HexMountain"
		};

		private static readonly Dictionary<CharacterBody, HashSet<string>> given = new Dictionary<CharacterBody, HashSet<string>>();

		private static readonly HashSet<CharacterBody> affixHandled = new HashSet<CharacterBody>();

		private static Run hexRun;

		private static float next;

		private static readonly List<Line> queue = new List<Line>();

		private static readonly HashSet<string> said = new HashSet<string>();

		private static Run messageRun;

		private const string Green = "#7aff9a";

		private const string Light = "#b9ffce";

		private const string Dark = "#3fb868";

		private static float firstAt = -1f;

		private static readonly Dictionary<CharacterBody, KeyState> keyStates = new Dictionary<CharacterBody, KeyState>();

		private static readonly Dictionary<CharacterBody, float> weakUntilHit = new Dictionary<CharacterBody, float>();

		private static void Say(string key, string text, string color, float delay = 0f, string tag = null)
		{
			if (!said.Contains(key))
			{
				said.Add(key);
				queue.Add(new Line
				{
					At = Time.time + delay,
					Tag = tag,
					Text = "<color=" + color + ">" + text + "</color>"
				});
			}
		}

		private static void Flush()
		{
			queue.Sort((Line x, Line y) => x.At.CompareTo(y.At));
			while (queue.Count > 0 && queue[0].At <= Time.time)
			{
				Chat.AddMessage(queue[0].Text);
				queue.RemoveAt(0);
			}
		}

		private static void Messages(CharacterBody body)
		{
			if (!Object.op_Implicit((Object)(object)Run.instance))
			{
				return;
			}
			if (messageRun != Run.instance)
			{
				messageRun = Run.instance;
				said.Clear();
				queue.Clear();
				firstAt = -1f;
			}
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			if (firstLocalUser == null || (Object)(object)firstLocalUser.cachedBody != (Object)(object)body)
			{
				return;
			}
			int num = 0;
			string[] array = hexItems;
			foreach (string itemName in array)
			{
				num += Swapper.CountItem(body, itemName);
			}
			if (num >= 7)
			{
				Say("aware", "You feel Her awareness...", "#7aff9a");
				Say("avarice", "Maintain your avarice.", "#3fb868", 1.5f);
			}
			object obj = Swapper.BuffIndexOf("PromoteStygianWhenHurt");
			object obj2 = Swapper.BuffIndexOf("EliteDeathAffixOnExpire");
			bool num2 = obj2 != null && Swapper.HasBuff(body, obj2);
			if (obj != null && Swapper.HasBuff(body, obj) && !said.Contains("first"))
			{
				Say("first", "You have sufficed Her approval...", "#7aff9a");
				firstAt = Time.time;
			}
			if (num2)
			{
				queue.RemoveAll((Line q) => q.Tag == "imp");
				if (!said.Contains("impatient"))
				{
					said.Add("impatient");
					said.Add("weaken");
				}
				Say("hold", "Hold steady for Her grasp.", "#3fb868");
			}
			else if (firstAt >= 0f && Time.time - firstAt >= 5f)
			{
				Say("impatient", "Her Impatience is growing,", "#7aff9a", 0f, "imp");
				Say("weaken", "Weaken your soul.", "#b9ffce", 0.5f, "imp");
			}
		}

		public static void Tick()
		{
			Flush();
			WeakCheck();
			if (Time.unscaledTime < next || !NetworkServer.active)
			{
				return;
			}
			next = Time.unscaledTime + 0.5f;
			try
			{
				ForgetGone();
				foreach (CharacterBody item in new List<CharacterBody>(CharacterBody.readOnlyInstancesList))
				{
					if (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)item.inventory))
					{
						continue;
					}
					if (RainCyclerPlugin.ModBatteryCore.Value)
					{
						ItemLinks(item);
					}
					if (RainCyclerPlugin.ModArtifactKey.Value)
					{
						KeyBuffs(item);
					}
					if (item.isPlayerControlled)
					{
						if (RainCyclerPlugin.ModHex.Value)
						{
							Messages(item);
							HexCount(item);
						}
						if (RainCyclerPlugin.ModHerApproval.Value)
						{
							DeathAffix(item);
						}
					}
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Item buffs failed: " + ex.Message));
			}
		}

		private static void ForgetGone()
		{
			List<CharacterBody> list = null;
			foreach (CharacterBody key in given.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key))
				{
					(list ?? (list = new List<CharacterBody>())).Add(key);
				}
			}
			if (list != null)
			{
				foreach (CharacterBody item in list)
				{
					given.Remove(item);
				}
			}
			affixHandled.RemoveWhere((CharacterBody b) => !Object.op_Implicit((Object)(object)b));
			List<CharacterBody> list2 = null;
			foreach (CharacterBody key2 in keyStates.Keys)
			{
				if (!Object.op_Implicit((Object)(object)key2))
				{
					(list2 ?? (list2 = new List<CharacterBody>())).Add(key2);
				}
			}
			if (list2 == null)
			{
				return;
			}
			foreach (CharacterBody item2 in list2)
			{
				keyStates.Remove(item2);
			}
		}

		private static void KeyBuffs(CharacterBody body)
		{
			int num = Swapper.CountItem(body, "ArtifactKey");
			keyStates.TryGetValue(body, out var value);
			if (num > 0)
			{
				if (value == null)
				{
					keyStates[body] = new KeyState
					{
						Since = Time.time
					};
					Swapper.GiveBuff(body, Swapper.BuffIndexOf("Weak"));
				}
				else if (!value.Second && Time.time - value.Since >= 1.5f)
				{
					value.Second = true;
					Swapper.TakeBuff(body, Swapper.BuffIndexOf("Weak"));
					Swapper.GiveBuff(body, Swapper.BuffIndexOf("Ethereal"));
					Swapper.GiveBuff(body, Swapper.BuffIndexOf("Warbanner"));
					if (body.isPlayerControlled)
					{
						Swapper.NanoFlash(body, hop: true);
					}
				}
			}
			else if (value != null)
			{
				keyStates.Remove(body);
				string[] array = new string[3] { "Weak", "Ethereal", "Warbanner" };
				foreach (string name in array)
				{
					Swapper.TakeBuff(body, Swapper.BuffIndexOf(name));
				}
			}
		}

		private static void ItemLinks(CharacterBody body)
		{
			HashSet<string> hashSet = new HashSet<string>();
			Link[] array = links;
			foreach (Link link in array)
			{
				if (Swapper.CountItem(body, link.Item) > 0)
				{
					string[] buffs = link.Buffs;
					foreach (string item in buffs)
					{
						hashSet.Add(item);
					}
				}
			}
			if (!given.TryGetValue(body, out var value))
			{
				if (hashSet.Count == 0)
				{
					return;
				}
				HashSet<string> hashSet2 = (given[body] = new HashSet<string>());
				value = hashSet2;
			}
			foreach (string item2 in hashSet)
			{
				if (!value.Contains(item2))
				{
					object obj = Swapper.BuffIndexOf(item2);
					if (obj != null)
					{
						Swapper.GiveBuff(body, obj);
						value.Add(item2);
					}
				}
			}
			List<string> list = null;
			foreach (string item3 in value)
			{
				if (!hashSet.Contains(item3))
				{
					Swapper.TakeBuff(body, Swapper.BuffIndexOf(item3));
					(list ?? (list = new List<string>())).Add(item3);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (string item4 in list)
			{
				value.Remove(item4);
			}
		}

		private static void HexCount(CharacterBody body)
		{
			if (!Object.op_Implicit((Object)(object)Run.instance) || hexRun == Run.instance)
			{
				return;
			}
			int num = 0;
			string[] array = hexItems;
			foreach (string itemName in array)
			{
				num += Swapper.CountItem(body, itemName);
			}
			if (num >= 13)
			{
				object obj = Swapper.BuffIndexOf("PromoteStygianWhenHurt");
				if (obj != null)
				{
					hexRun = Run.instance;
					Swapper.GiveBuff(body, obj);
				}
			}
		}

		private static void DeathAffix(CharacterBody body)
		{
			object obj = Swapper.BuffIndexOf("EliteDeathAffixOnExpire");
			if (obj == null)
			{
				return;
			}
			if (!Swapper.HasBuff(body, obj))
			{
				affixHandled.Remove(body);
			}
			else if (affixHandled.Add(body))
			{
				if (!Swapper.CallOn(body.inventory, "SetEquipmentIndex", (object)(EquipmentIndex)(-1)))
				{
					Swapper.CallOn(body.inventory, "SetEquipmentIndex", (object)(EquipmentIndex)(-1), false);
				}
				Fx.Laugh(((Component)body).gameObject);
				SpawnHealingCore(body);
				Swapper.GiveBuff(body, Swapper.BuffIndexOf("Weak"));
				weakUntilHit[body] = HealthOf(body);
			}
		}

		private static float HealthOf(CharacterBody body)
		{
			if (!Object.op_Implicit((Object)(object)body.healthComponent))
			{
				return 0f;
			}
			return body.healthComponent.health + body.healthComponent.shield;
		}

		private static void WeakCheck()
		{
			if (weakUntilHit.Count == 0)
			{
				return;
			}
			List<CharacterBody> list = null;
			foreach (KeyValuePair<CharacterBody, float> item in weakUntilHit)
			{
				CharacterBody key = item.Key;
				if (!Object.op_Implicit((Object)(object)key))
				{
					(list ?? (list = new List<CharacterBody>())).Add(key);
				}
				else if (HealthOf(key) < item.Value - 0.01f)
				{
					Swapper.TakeBuff(key, Swapper.BuffIndexOf("Weak"));
					(list ?? (list = new List<CharacterBody>())).Add(key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (CharacterBody item2 in list)
			{
				weakUntilHit.Remove(item2);
			}
		}

		private static void SpawnHealingCore(CharacterBody body)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = MasterCatalog.FindMasterPrefab("AffixEarthHealerMaster");
				if (!Object.op_Implicit((Object)(object)val))
				{
					foreach (CharacterMaster allMaster in MasterCatalog.allMasters)
					{
						if (Object.op_Implicit((Object)(object)allMaster) && ((Object)allMaster).name.ToLowerInvariant().Contains("earthhealer"))
						{
							val = ((Component)allMaster).gameObject;
							break;
						}
					}
				}
				if (!Object.op_Implicit((Object)(object)val))
				{
					RainCyclerPlugin.Log.LogWarning((object)"Healing Core master not found.");
					return;
				}
				MasterSummon val2 = new MasterSummon();
				Swapper.SetOn(val2, "masterPrefab", val);
				Swapper.SetOn(val2, "position", body.corePosition + Vector3.up * 1.5f);
				Swapper.SetOn(val2, "rotation", ((Component)body).transform.rotation);
				Swapper.SetOn(val2, "summonerBodyObject", ((Component)body).gameObject);
				Swapper.SetOn(val2, "ignoreTeamMemberLimit", true);
				Swapper.SetOn(val2, "useAmbientLevel", true);
				if (Object.op_Implicit((Object)(object)body.teamComponent))
				{
					Swapper.SetOn(val2, "teamIndexOverride", body.teamComponent.teamIndex);
				}
				CharacterMaster val3 = val2.Perform();
				if (Object.op_Implicit((Object)(object)val3))
				{
					((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(DressCore(val3));
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Healing Core failed: " + ex.Message));
			}
		}

		private static IEnumerator DressCore(CharacterMaster master)
		{
			yield return (object)new WaitForSeconds(0.3f);
			if (!Object.op_Implicit((Object)(object)master))
			{
				yield break;
			}
			EquipmentIndex val = EquipmentCatalog.FindEquipmentIndex("EliteHauntedEquipment");
			if ((int)val != -1 && Object.op_Implicit((Object)(object)master.inventory) && !Swapper.CallOn(master.inventory, "SetEquipmentIndex", val))
			{
				Swapper.CallOn(master.inventory, "SetEquipmentIndex", val, false);
			}
			CharacterBody body = master.GetBody();
			if (Object.op_Implicit((Object)(object)body))
			{
				string[] array = new string[3] { "ReaperSiphonTarget", "HealingDisabled", "Fruiting" };
				foreach (string name in array)
				{
					Swapper.GiveBuff(body, Swapper.BuffIndexOf(name));
				}
				yield return (object)new WaitForSeconds(0.2f);
				if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent))
				{
					Swapper.SetOn(body.healthComponent, "Networkhealth", 1f);
				}
			}
		}
	}
	internal static class ItemCountFix
	{
		[ThreadStatic]
		public static bool Bypass;

		public static Inventory Target;

		public static readonly HashSet<int> Items = new HashSet<int>();

		private static readonly string[] shopWords = new string[13]
		{
			"cost", "purchase", "shrine", "cleans", "scrap", "duplicat", "cauldron", "shop", "terminal", "transfer",
			"steal", "inventoryui", "itemtake"
		};

		public static void Clear()
		{
			Target = null;
			Items.Clear();
		}

		public static void Install()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			try
			{
				Harmony val = new Harmony("local.rodamortaraincycler");
				HarmonyMethod val2 = new HarmonyMethod(typeof(ItemCountFix).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public));
				int num = 0;
				MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name.StartsWith("GetItemCount") && !(methodInfo.ReturnType != typeof(int)))
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						if (parameters.Length != 0 && (!(parameters[0].ParameterType != typeof(ItemIndex)) || !(parameters[0].ParameterType != typeof(ItemDef))))
						{
							val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							num++;
						}
					}
				}
				RainCyclerPlugin.Log.LogInfo((object)("Item count patch installed on " + num + " methods"));
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Item count patch failed: " + ex.Message));
			}
		}

		public static void Postfix(Inventory __instance, object[] __args, ref int __result)
		{
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected I4, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected I4, but got Unknown
			if (Bypass || __result > 0 || Items.Count == 0 || __instance != Target || __args == null || __args.Length == 0)
			{
				return;
			}
			int num = -1;
			if (__args[0] is ItemIndex val)
			{
				num = (int)val;
			}
			else
			{
				object obj = __args[0];
				ItemDef val2 = (ItemDef)((obj is ItemDef) ? obj : null);
				if (val2 != null && Object.op_Implicit((Object)(object)val2))
				{
					num = (int)val2.itemIndex;
				}
			}
			if (num >= 0 && Items.Contains(num) && !AskedByAShop())
			{
				__result = 1;
			}
		}

		private static bool AskedByAShop()
		{
			try
			{
				StackFrame[] frames = new StackTrace(2, fNeedFileInfo: false).GetFrames();
				if (frames == null)
				{
					return false;
				}
				StackFrame[] array = frames;
				for (int i = 0; i < array.Length; i++)
				{
					Type type = array[i].GetMethod()?.DeclaringType;
					if (type == null)
					{
						continue;
					}
					string text = (type.FullName ?? type.Name).ToLowerInvariant();
					string[] array2 = shopWords;
					foreach (string value in array2)
					{
						if (text.Contains(value))
						{
							return true;
						}
					}
				}
			}
			catch (Exception)
			{
			}
			return false;
		}
	}
	internal static class Keys
	{
		private static string interactName;

		private static float interactCheck;

		public static KeyCode Passive
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				KeyboardShortcut value = RainCyclerPlugin.PassiveKey.Value;
				return ((KeyboardShortcut)(ref value)).MainKey;
			}
		}

		public static KeyCode Skill(int index)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = RainCyclerPlugin.SkillKeys[Mathf.Clamp(index, 0, 3)].Value;
			return ((KeyboardShortcut)(ref value)).MainKey;
		}

		public unsafe static string Label(KeyCode key)
		{
			string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("Alpha"))
			{
				return text.Substring(5);
			}
			if (text.StartsWith("Keypad"))
			{
				return "Num" + text.Substring(6);
			}
			if (text.StartsWith("Mouse"))
			{
				return "M" + text.Substring(5);
			}
			return text;
		}

		public static bool InteractDown(LocalUser user)
		{
			try
			{
				if (user != null && user.inputPlayer != null)
				{
					return user.inputPlayer.GetButtonDown("Interact");
				}
			}
			catch (Exception)
			{
			}
			return Input.GetKeyDown((KeyCode)101);
		}

		public static string InteractName(LocalUser user)
		{
			if (interactName != null && Time.unscaledTime < interactCheck)
			{
				return interactName;
			}
			interactCheck = Time.unscaledTime + 3f;
			interactName = "E";
			try
			{
				Player val = ((user != null) ? user.inputPlayer : null);
				if (val == null)
				{
					return interactName;
				}
				object obj = ((object)val).GetType().GetProperty("controllers")?.GetValue(val, null);
				object obj2 = obj?.GetType().GetProperty("maps")?.GetValue(obj, null);
				if (obj2 == null)
				{
					return interactName;
				}
				MethodInfo[] methods = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "GetFirstElementMapWithAction")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 3 && parameters[0].ParameterType.IsEnum && !(parameters[1].ParameterType != typeof(string)))
					{
						object obj3 = Enum.Parse(parameters[0].ParameterType, "Keyboard");
						object obj4 = methodInfo.Invoke(obj2, new object[3] { obj3, "Interact", true });
						string value = obj4?.GetType().GetProperty("elementIdentifierName")?.GetValue(obj4, null) as string;
						if (!string.IsNullOrEmpty(value))
						{
							interactName = value;
						}
						break;
					}
				}
			}
			catch (Exception)
			{
			}
			return interactName;
		}

		public static bool Typing()
		{
			try
			{
				GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null);
				if (Object.op_Implicit((Object)(object)val) && (Object.op_Implicit((Object)(object)val.GetComponent<InputField>()) || (Object)(object)val.GetComponent("TMP_InputField") != (Object)null))
				{
					return true;
				}
			}
			catch (Exception)
			{
			}
			return false;
		}

		public static bool Paused()
		{
			try
			{
				return Time.timeScale <= 0.001f;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static bool InteractableTargeted(CharacterBody body)
		{
			try
			{
				InteractionDriver val = (Object.op_Implicit((Object)(object)body) ? ((Component)body).GetComponent<InteractionDriver>() : null);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return false;
				}
				return Object.op_Implicit((Object)(object)val.FindBestInteractableObject());
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	internal static class OptionsMenu
	{
		public static void Register(ConfigFile config)
		{
			Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "RiskOfOptions");
			if (assembly == null)
			{
				return;
			}
			Type type = assembly.GetType("RiskOfOptions.ModSettingsManager");
			MethodInfo methodInfo = type?.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "AddOption" && m.GetParameters().Length == 1);
			if (methodInfo == null)
			{
				RainCyclerPlugin.Log.LogWarning((object)"Risk of Options found, but its API was not recognised.");
				return;
			}
			type.GetMethod("SetModDescription", new Type[1] { typeof(string) })?.Invoke(null, new object[1] { "Rodamorta SkillCycler: swap skills, passives and skins; optional extras." });
			int num = 0;
			foreach (ConfigDefinition item in config.Keys.OrderBy((ConfigDefinition k) => (!(k.Section == "SkillCycler - Modules")) ? ((k.Section == "Rodamorta - Modules") ? 1 : ((!(k.Section == "SkillCycler - Keybinds")) ? 3 : 2)) : 0).ToList())
			{
				if (item.Section == "Setup")
				{
					continue;
				}
				ConfigEntryBase entry = config[item];
				object obj = Make(assembly, entry);
				if (obj != null)
				{
					try
					{
						methodInfo.Invoke(null, new object[1] { obj });
						num++;
					}
					catch (Exception ex)
					{
						RainCyclerPlugin.Log.LogWarning((object)("Option " + item.Key + " not added: " + (ex.InnerException ?? ex).Message));
					}
				}
			}
			RainCyclerPlugin.Log.LogInfo((object)("Risk of Options: " + num + " options added."));
		}

		private static object Make(Assembly asm, ConfigEntryBase entry)
		{
			Type settingType = entry.SettingType;
			string text;
			if (settingType == typeof(bool))
			{
				text = "CheckBoxOption";
			}
			else if (settingType == typeof(string))
			{
				text = "StringInputFieldOption";
			}
			else if (settingType == typeof(float))
			{
				text = "FloatFieldOption";
			}
			else
			{
				if (!(settingType == typeof(KeyboardShortcut)))
				{
					return null;
				}
				text = "KeyBindOption";
			}
			Type type = asm.GetType("RiskOfOptions.Options." + text);
			if (type == null)
			{
				return null;
			}
			ConstructorInfo[] constructors = type.GetConstructors();
			foreach (ConstructorInfo constructorInfo in constructors)
			{
				ParameterInfo[] parameters = constructorInfo.GetParameters();
				if (parameters.Length != 0 && parameters[0].ParameterType.IsAssignableFrom(((object)entry).GetType()) && !parameters.Skip(1).Any((ParameterInfo p) => !p.IsOptional))
				{
					object[] array = new object[parameters.Length];
					array[0] = entry;
					for (int num = 1; num < parameters.Length; num++)
					{
						array[num] = parameters[num].DefaultValue;
					}
					try
					{
						return constructorInfo.Invoke(array);
					}
					catch (Exception)
					{
					}
				}
			}
			return null;
		}
	}
	internal static class Ragdoll
	{
		private sealed class Saved
		{
			public Rigidbody Body;

			public bool Kinematic;

			public bool DetectCollisions;

			public int Layer;

			public Collider[] Colliders;

			public bool[] ColliderOn;

			public Transform Transform;

			public Vector3 LocalPosition;

			public Quaternion LocalRotation;
		}

		private sealed class Active
		{
			public Animator Animator;

			public bool AnimatorWasOn;

			public List<Saved> Parts = new List<Saved>();

			public Transform Model;

			public Rigidbody Pin;

			public Vector3 PinLocalPosition;

			public Quaternion PinLocalRotation;
		}

		private static readonly Dictionary<CharacterBody, Active> active = new Dictionary<CharacterBody, Active>();

		private static readonly HashSet<CharacterBody> fallen = new HashSet<CharacterBody>();

		private static GameObject tentabauble;

		private static bool tentabaubleSearched;

		public static bool IsActive(CharacterBody body)
		{
			if (Object.op_Implicit((Object)(object)body))
			{
				return active.ContainsKey(body);
			}
			return false;
		}

		public static bool IsFallen(CharacterBody body)
		{
			if (Object.op_Implicit((Object)(object)body))
			{
				return fallen.Contains(body);
			}
			return false;
		}

		public static bool Begin(CharacterBody body, bool puppet)
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!Object.op_Implicit((Object)(object)body) || Ragdoll.active.ContainsKey(body))
				{
					return false;
				}
				Transform val = (Object.op_Implicit((Object)(object)body.modelLocator) ? body.modelLocator.modelTransform : null);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return false;
				}
				Rigidbody[] componentsInChildren = ((Component)val).GetComponentsInChildren<Rigidbody>(true);
				if (componentsInChildren.Length < 2)
				{
					return false;
				}
				Active active = new Active
				{
					Model = val,
					Animator = ((Component)val).GetComponentInChildren<Animator>()
				};
				int num = LayerMask.NameToLayer("Ragdoll");
				Rigidbody val2 = null;
				int num2 = int.MaxValue;
				Rigidbody[] array = componentsInChildren;
				foreach (Rigidbody val3 in array)
				{
					Collider[] components = ((Component)val3).GetComponents<Collider>();
					Saved saved = new Saved
					{
						Body = val3,
						Kinematic = val3.isKinematic,
						DetectCollisions = val3.detectCollisions,
						Layer = ((Component)val3).gameObject.layer,
						Colliders = components,
						ColliderOn = new bool[components.Length],
						Transform = ((Component)val3).transform,
						LocalPosition = ((Component)val3).transform.localPosition,
						LocalRotation = ((Component)val3).transform.localRotation
					};
					for (int j = 0; j < components.Length; j++)
					{
						saved.ColliderOn[j] = components[j].enabled;
					}
					active.Parts.Add(saved);
					int num3 = 0;
					Transform val4 = ((Component)val3).transform;
					while (Object.op_Implicit((Object)(object)val4) && (Object)(object)val4 != (Object)(object)val)
					{
						num3++;
						val4 = val4.parent;
					}
					if (num3 < num2)
					{
						num2 = num3;
						val2 = val3;
					}
				}
				if (Object.op_Implicit((Object)(object)active.Animator))
				{
					active.AnimatorWasOn = ((Behaviour)active.Animator).enabled;
					((Behaviour)active.Animator).enabled = false;
				}
				Vector3 velocity = Vector3.zero;
				Component component = ((Component)body).GetComponent("CharacterMotor");
				if ((Object)(object)component != (Object)null && !puppet)
				{
					velocity = Swapper.ReadVelocity(component);
				}
				foreach (Saved part in active.Parts)
				{
					part.Body.isKinematic = false;
					part.Body.detectCollisions = true;
					if (!puppet)
					{
						part.Body.velocity = velocity;
					}
					if (num >= 0)
					{
						((Component)part.Body).gameObject.layer = num;
					}
					Collider[] colliders = part.Colliders;
					foreach (Collider val5 in colliders)
					{
						if (Object.op_Implicit((Object)(object)val5))
						{
							val5.enabled = true;
						}
					}
				}
				if (puppet && Object.op_Implicit((Object)(object)val2))
				{
					active.Pin = val2;
					active.PinLocalPosition = val.InverseTransformPoint(val2.position);
					active.PinLocalRotation = Quaternion.Inverse(val.rotation) * val2.rotation;
					val2.isKinematic = true;
				}
				Ragdoll.active[body] = active;
				return true;
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Ragdoll failed: " + ex.Message));
				return false;
			}
		}

		public static void End(CharacterBody body)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body) || !active.TryGetValue(body, out var value))
			{
				return;
			}
			active.Remove(body);
			try
			{
				foreach (Saved part in value.Parts)
				{
					if (!Object.op_Implicit((Object)(object)part.Body))
					{
						continue;
					}
					part.Body.isKinematic = true;
					part.Body.detectCollisions = part.DetectCollisions;
					((Component)part.Body).gameObject.layer = part.Layer;
					for (int i = 0; i < part.Colliders.Length; i++)
					{
						if (Object.op_Implicit((Object)(object)part.Colliders[i]))
						{
							part.Colliders[i].enabled = part.ColliderOn[i];
						}
					}
					part.Body.isKinematic = part.Kinematic;
					if (Object.op_Implicit((Object)(object)part.Transform))
					{
						part.Transform.localPosition = part.LocalPosition;
						part.Transform.localRotation = part.LocalRotation;
					}
				}
				if (Object.op_Implicit((Object)(object)value.Animator) && value.AnimatorWasOn)
				{
					((Behaviour)value.Animator).enabled = true;
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Ending ragdoll failed: " + ex.Message));
			}
		}

		public static void Pin()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (active.Count == 0)
			{
				return;
			}
			List<CharacterBody> list = null;
			foreach (KeyValuePair<CharacterBody, Active> item in active)
			{
				if (!Object.op_Implicit((Object)(object)item.Key))
				{
					(list ?? (list = new List<CharacterBody>())).Add(item.Key);
					continue;
				}
				Active value = item.Value;
				if (Object.op_Implicit((Object)(object)value.Pin) && Object.op_Implicit((Object)(object)value.Model))
				{
					value.Pin.position = value.Model.TransformPoint(value.PinLocalPosition);
					value.Pin.rotation = value.Model.rotation * value.PinLocalRotation;
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (CharacterBody item2 in list)
			{
				active.Remove(item2);
			}
		}

		public static void FakeDeath(CharacterBody body, float seconds = 1.5f)
		{
			if (Object.op_Implicit((Object)(object)body) && !fallen.Contains(body) && !active.ContainsKey(body))
			{
				((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(FakeDeathRoutine(body, seconds));
			}
		}

		private static IEnumerator FakeDeathRoutine(CharacterBody body, float seconds)
		{
			fallen.Add(body);
			try
			{
				Lock(body, locked: true);
				Begin(body, puppet: false);
				Tentabauble(body);
				float end = Time.time + seconds;
				while (Time.time < end && Object.op_Implicit((Object)(object)body))
				{
					yield return null;
				}
			}
			finally
			{
				End(body);
				if (Object.op_Implicit((Object)(object)body))
				{
					Lock(body, locked: false);
					Swapper.PlayEffect(body);
					Swapper.NanoFlash(body, hop: true, buff: false);
				}
				fallen.Remove(body);
			}
		}

		private static void Tentabauble(CharacterBody body)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			try
			{
				if (!tentabaubleSearched)
				{
					tentabaubleSearched = true;
					GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
					foreach (GameObject val in array)
					{
						if (Object.op_Implicit((Object)(object)val) && ((Object)val).name.ToLowerInvariant().Contains("tentabauble") && Object.op_Implicit((Object)(object)val.GetComponent<EffectComponent>()))
						{
							tentabauble = val;
							break;
						}
					}
					if (!Object.op_Implicit((Object)(object)tentabauble))
					{
						RainCyclerPlugin.Log.LogInfo((object)"No Tentabauble effect prefab found.");
					}
				}
				if (Object.op_Implicit((Object)(object)tentabauble) && Object.op_Implicit((Object)(object)body))
				{
					EffectManager.SpawnEffect(tentabauble, new EffectData
					{
						origin = body.corePosition,
						scale = body.radius
					}, NetworkServer.active);
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Tentabauble failed: " + ex.Message));
			}
		}

		private static void Lock(CharacterBody body, bool locked)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			try
			{
				EntityStateMachine[] components = ((Component)body).GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine val in components)
				{
					if (!Object.op_Implicit((Object)(object)val))
					{
						continue;
					}
					if (val.customName == "Body")
					{
						if (locked)
						{
							val.SetNextState((EntityState)new Idle());
						}
						else
						{
							val.SetNextStateToMain();
						}
					}
					else if (locked)
					{
						val.SetNextStateToMain();
					}
				}
			}
			catch (Exception ex)
			{
				RainCyclerPlugin.Log.LogWarning((object)("Locking the body failed: " + ex.Message));
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("local.rodamortaskillcycler", "Rodamorta SkillCycler", "0.9.5")]
	public class RainCyclerPlugin : BaseUnityPlugin
	{
		internal sealed class Fixed<T>
		{
			public readonly T Value;

			public Fixed(T value)
			{
				Value = value;
			}
		}

		internal static ManualLogSource Log;

		internal static RainCyclerPlugin Instance;

		internal static ConfigEntry<bool> ShowPassives;

		internal static ConfigEntry<bool> UseWheel;

		internal static ConfigEntry<bool> ChatMessage;

		internal static ConfigEntry<string> PeacefulStages;

		internal static ConfigEntry<string> ProudStages;

		internal static ConfigEntry<float> ProudPassiveSeconds;

		internal static ConfigEntry<float> SkinCooldown;

		internal static ConfigEntry<bool> UseKeys;

		internal static ConfigEntry<bool> ShowKeyHints;

		internal static ConfigEntry<bool> FloppyEnabled;

		internal static ConfigEntry<bool> ModSkillCycler;

		internal static ConfigEntry<bool> ModPassiveSwap;

		internal static ConfigEntry<bool> ModSkinSwap;

		internal static ConfigEntry<bool> ModPassivesSafe;

		internal static ConfigEntry<bool> ModPassivesProud;

		internal static ConfigEntry<bool> ModHeresyAnims;

		internal static ConfigEntry<bool> ModStageNames;

		internal static ConfigEntry<bool> ModBatteryCore;

		internal static ConfigEntry<bool> ModArtifactKey;

		internal static ConfigEntry<bool> ModHex;

		internal static ConfigEntry<bool> FirstRunDone;

		internal static readonly Fixed<bool> ModFakeDeath = new Fixed<bool>(value: true);

		internal static readonly Fixed<bool> ModSwapSounds = new Fixed<bool>(value: true);

		internal static readonly Fixed<bool> ReverseJump = new Fixed<bool>(value: true);

		internal static readonly Fixed<string> SwapSound = new Fixed<string>("");

		internal static ConfigEntry<KeyboardShortcut>[] SkillKeys;

		internal static ConfigEntry<KeyboardShortcut> PassiveKey;

		internal static int SettingsVersion;

		private float nextTick;

		private static Run highlightedRun;

		internal static ConfigEntry<bool> ModSeerQuotes => ModStageNames;

		internal static ConfigEntry<bool> ModHerApproval => ModHex;

		private void Awake()
		{
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			ShowPassives = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - UI", "Show Passive Row", true, "Show the survivor's passive above the skill bar.");
			ShowPassives.SettingChanged += delegate
			{
				SettingsVersion++;
			};
			UseWheel = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Input", "Mouse Wheel Scrolls Menus", true, "Scroll the mouse wheel to browse the options of the hovered skill, passive or skin.");
			ChatMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - UI", "Chat Messages", true, "Print what happened (skill, passive or skin changed) in chat.");
			PeacefulStages = ((BaseUnityPlugin)this).Config.Bind<string>("SkillCycler - Rules", "Semi-arid Stages (Safe)", "bazaar,computationalexchange,ss2_voidshop,mysteryspace", "Comma separated words. A stage whose internal name contains one of them is a Semi-arid (safe) stage: free switching, passives and skins can be changed.");
			ProudStages = ((BaseUnityPlugin)this).Config.Bind<string>("SkillCycler - Rules", "Cataclysmic Environment (Proud)", "moon2,moon,voidraid,solutionalhaunt,solusweb,soulbound threshold,soulboundthreshold,ultima,limbo,artifactworld,goldshores,meridian,bulwarkshaunt_ghostwave,enemiesreturns_outoftime", "Final boss stages (same kind of list). Passives can be changed here, but only once every 'Passive Cooldown' seconds.");
			ProudPassiveSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("SkillCycler - Rules", "Passive Cooldown in Cataclysmic Stages (seconds)", 120f, "Seconds between passive changes in the Cataclysmic Environment (Proud) stages.");
			SkinCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("SkillCycler - Rules", "Skin Change Cooldown (seconds)", 1.5f, "Seconds before the skin can be changed again (a lock shows on the skin button meanwhile).");
			ModSkillCycler = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Enable SkillCycler (skill, passive and skin swapping)", true, "The whole swapping feature (skill, passive and skin menus). Needs a new stage to fully apply.");
			ModPassiveSwap = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive Swapping", true, "Passive swapping (where the stage options below allow it).");
			ModSkinSwap = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Skin Swapping", true, "Skin swapping (in Semi-arid stages).");
			ModPassivesSafe = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive and Skin Swapping in Semi-arid Stages (Safe)", true, "Passives and skins can be changed in Semi-arid (safe) stages.");
			ModPassivesProud = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive Swapping in Cataclysmic Environment (Proud)", true, "Passives can be changed in Cataclysmic Environment (Proud, final boss) stages, with a cooldown.");
			ModHeresyAnims = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Heresy Skills Slightly Floppy", true, "Using Heresy skills makes your bones very slightly floppy (Ruin: as floppy as usual). Not for the Heretic. Needs a game restart.");
			ModStageNames = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Stage Names and Seer Quotes", true, "The Semi-arid / Cataclysmic text, the stage name with its icon on top of the timer, and the Lunar Seer's line under the skills (both extra lines show with the scoreboard open).");
			ModBatteryCore = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Core and Battery Items Give Buffs", false, "Charged Battery and Core items give their buff (Kinetic Armor, Collective Share) while held.");
			ModArtifactKey = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Artifact Key Gives Buffs", false, "The Artifact Key weakens you, then after 1.5 s Ethereal and Warbanner They go away with the item.");
			ModHex = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Her Approval", false, "\"Collect my hexes\"");
			FloppyEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Floppy Bones", false, "Loose, floppy bones (like the Floppy Survivors mod) on certain occasions: debuffs like Blight, Collapse or Fracture, Slippery Ground, Goobo Jr., and after becoming Void elite.");
			UseKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Keybinds", "Enable Number Key Menus", true, "Open the swap menus with the keys below while playing (Interact picks).");
			ShowKeyHints = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Keybinds", "Show Key Hints Over Skills", true, "Show the keys over the skills for a few seconds (after the first Interact press, and on first entering a safe stage).");
			SkillKeys = new ConfigEntry<KeyboardShortcut>[4]
			{
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Primary Skill Menu Key", new KeyboardShortcut((KeyCode)49, Array.Empty<KeyCode>()), "Opens the primary skill menu."),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Secondary Skill Menu Key", new KeyboardShortcut((KeyCode)50, Array.Empty<KeyCode>()), "Opens the secondary skill menu."),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Utility Skill Menu Key", new KeyboardShortcut((KeyCode)51, Array.Empty<KeyCode>()), "Opens the utility skill menu."),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Special Skill Menu Key", new KeyboardShortcut((KeyCode)52, Array.Empty<KeyCode>()), "Opens the special skill menu.")
			};
			PassiveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Passive Menu Key", new KeyboardShortcut((KeyCode)53, Array.Empty<KeyCode>()), "Opens the passive menu (Semi-arid stages, and Cataclysmic ones when allowed).");
			FirstRunDone = ((BaseUnityPlugin)this).Config.Bind<bool>("Setup", "FirstRunQuestionAnswered", false, "Internal: the first-start question about the Rodamorta features was answered.");
			HUD.onHudTargetChangedGlobal += OnHud;
			CharacterBody.onBodyStartGlobal += OnBodyStart;
			SceneManager.activeSceneChanged += OnScene;
			Run.onRunStartGlobal += OnRunStart;
			ItemCountFix.Install();
			if (ModHeresyAnims.Value)
			{
				HeresyAnim.Install();
			}
		}

		private void Start()
		{
			try
			{
				OptionsMenu.Register(((BaseUnityPlugin)this).Config);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Risk of Options setup failed: " + ex.Message));
			}
			if (Chainloader.PluginInfos.TryGetValue("ntshtng.PassiveSkillHud", out var value) && (Object)(object)value.Instance != (Object)null)
			{
				ConfigFile config = value.Instance.Config;
				ConfigEntry<bool> val = default(ConfigEntry<bool>);
				if (config.TryGetEntry<bool>("General", "Show passives", ref val))
				{
					bool saveOnConfigSet = config.SaveOnConfigSet;
					config.SaveOnConfigSet = false;
					val.Value = false;
					config.SaveOnConfigSet = saveOnConfigSet;
					Log.LogWarning((object)"PassiveSkillHud is installed: its passive display was switched off, Rain Cycler shows passives itself. You can uninstall PassiveSkillHud.");
				}
			}
		}

		private void OnDestroy()
		{
			HUD.onHudTargetChangedGlobal -= OnHud;
			CharacterBody.onBodyStartGlobal -= OnBodyStart;
			SceneManager.activeSceneChanged -= OnScene;
			Run.onRunStartGlobal -= OnRunStart;
		}

		private static void OnHud(HUD hud)
		{
			if (ModSkillCycler.Value && !Object.op_Implicit((Object)(object)((Component)hud).GetComponent<SkillBarUi>()))
			{
				((Component)hud).gameObject.AddComponent<SkillBarUi>();
			}
		}

		private static void OnRunStart(Run run)
		{
			Swapper.ResetRun();
		}

		private static void OnScene(Scene from, Scene to)
		{
			if (((Scene)(ref to)).name == "title")
			{
				FirstRun.Check();
			}
			if (Object.op_Implicit((Object)(object)Run.instance))
			{
				StageInfo.OnSceneEntered();
			}
			if (Swapper.IsPeaceful() && Object.op_Implicit((Object)(object)Run.instance) && highlightedRun != Run.instance)
			{
				highlightedRun = Run.instance;
				SkillBarUi.HighlightPending = true;
			}
			if (Swapper.IsProud())
			{
				SkillBarUi.ProudPending = true;
			}
		}

		private void OnBodyStart(CharacterBody body)
		{
			if (Object.op_Implicit((Object)(object)body) && body.isPlayerControlled && body.hasEffectiveAuthority)
			{
				((MonoBehaviour)this).StartCoroutine(ApplyLater(body));
			}
		}

		private IEnumerator ApplyLater(CharacterBody body)
		{
			yield return null;
			yield return null;
			if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.skillLocator))
			{
				LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
				if (firstLocalUser != null)
				{
					Swapper.ApplySaved(firstLocalUser, body);
				}
			}
		}

		private void LateUpdate()
		{
			Ragdoll.Pin();
		}

		private void Update()
		{
			Floppy.Tick();
			Floppy.Frame();
			ItemBuffs.Tick();
			if (!ModSkillCycler.Value)
			{
				return;
			}
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				Swapper.Frame(val);
				if (!(Time.unscaledTime < nextTick))
				{
					nextTick = Time.unscaledTime + 0.25f;
					Swapper.Tick(val);
				}
			}
		}
	}
	internal static class RoundSprites
	{
		private const int Size = 128;

		private const float RingInnerRadius = 0.93f;

		private static Sprite disc;

		private static Sprite ring;

		private static Sprite frame;

		private static Sprite glow;

		private static Sprite pulse;

		private static Sprite outline;

		private static Sprite skinSpiral;

		private static Sprite lockClosed;

		private static Sprite lockOpen;

		public static Sprite Disc
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)disc))
				{
					return disc = Create("RainCyclerDisc", 0f);
				}
				return disc;
			}
		}

		public static Sprite Ring
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ring))
				{
					return ring = Create("RainCyclerRing", 0.93f);
				}
				return ring;
			}
		}

		public static Sprite Frame
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)frame))
				{
					return frame = CreateFrame();
				}
				return frame;
			}
		}

		public static Sprite Glow
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)glow))
				{
					return glow = CreateSpiral(3, 3.2f, "RainCyclerSpiral");
				}
				return glow;
			}
		}

		public static Sprite Outline
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)outline))
				{
					return outline = CreateOutline();
				}
				return outline;
			}
		}

		public static Sprite SkinSpiral
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)skinSpiral))
				{
					return skinSpiral = CreateSpiral(2, 2.4f, "RainCyclerSkinSpiral");
				}
				return skinSpiral;
			}
		}

		public static Sprite LockClosed
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)lockClosed))
				{
					return lockClosed = CreateLock(open: false);
				}
				return lockClosed;
			}
		}

		public static Sprite LockOpen
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)lockOpen))
				{
					return lockOpen = CreateLock(open: true);
				}
				return lockOpen;
			}
		}

		public static Sprite Pulse
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)pulse))
				{
					return pulse = CreatePulse();
				}
				return pulse;
			}
		}

		private static bool InLock(float u, float v, bool open)
		{
			float num = Mathf.Max(Mathf.Abs(u - 0.5f) - 0.22f, 0f);
			float num2 = Mathf.Max(Mathf.Abs(v - 0.31f) - 0.14f, 0f);
			if (Mathf.Sqrt(num * num + num2 * num2) < 0.05f)
			{
				float num3 = u - 0.5f;
				float num4 = v - 0.35f;
				if (num3 * num3 + num4 * num4 < 0.002025f)
				{
					return false;
				}
				if (Mathf.Abs(num3) < 0.018f && v > 0.22f && v < 0.35f)
				{
					return false;
				}
				return true;
			}
			float num5 = (open ? 0.64f : 0.52f);
			float num6 = u - 0.5f;
			float num7 = v - num5;
			float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7);
			if