Decompiled source of EscapedTestSubject v0.9.3

WKEscapedSubject.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.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 WKEscapedSubject
{
	internal static class Assets
	{
		private static Dictionary<string, Texture2D>[] overlays;

		private static int frameCount = -1;

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

		private static readonly Sprite[] counter = (Sprite[])(object)new Sprite[10];

		private const int ShootFrames = 9;

		private static readonly Dictionary<string, Texture2D>[] shootTex = new Dictionary<string, Texture2D>[10];

		private static Dictionary<string, float[]> hands;

		private static HandPose[] shootKeys;

		public static int FrameCount
		{
			get
			{
				if (frameCount < 0)
				{
					frameCount = 0;
					while (AssetStore.DirExists("Overlays/stage" + (frameCount + 1)))
					{
						frameCount++;
					}
					overlays = new Dictionary<string, Texture2D>[frameCount];
					Plugin.Log.LogInfo((object)("촉수 덧그림 프레임 " + frameCount + "개"));
				}
				return frameCount;
			}
		}

		public static Texture2D LoadTexture(string rel, bool point)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			byte[] array = AssetStore.Read(rel);
			if (array == null)
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!(bool)typeof(ImageConversion).GetMethod("LoadImage", new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}).Invoke(null, new object[3] { val, array, false }))
			{
				return null;
			}
			((Texture)val).filterMode = (FilterMode)(!point);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Object)val).hideFlags = (HideFlags)32;
			return val;
		}

		public static Sprite LoadIcon(string file, WKAssetDatabase db, PerkType type)
		{
			//IL_0110: 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_006f: 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_007f: 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_0094: 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)
			Texture2D val = LoadTexture(file, point: true);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("아이콘 파일이 없음: " + file));
				val = Texture2D.whiteTexture;
			}
			List<float> list = new List<float>();
			if (db.perkAssets != null)
			{
				foreach (Perk perkAsset in db.perkAssets)
				{
					if (!((Object)(object)perkAsset == (Object)null) && !((Object)(object)perkAsset.icon == (Object)null) && perkAsset.perkType == type)
					{
						Rect rect = perkAsset.icon.rect;
						float width = ((Rect)(ref rect)).width;
						rect = perkAsset.icon.rect;
						list.Add(Mathf.Max(width, ((Rect)(ref rect)).height) / perkAsset.icon.pixelsPerUnit);
					}
				}
			}
			list.Sort();
			float num = ((list.Count > 0) ? list[list.Count / 2] : 1f);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)Mathf.Max(((Texture)val).width, ((Texture)val).height) / num);
			((Object)obj).name = Path.GetFileNameWithoutExtension(file);
			((Object)obj).hideFlags = (HideFlags)32;
			return obj;
		}

		public static void PreloadStep()
		{
			for (int i = 0; i < FrameCount; i++)
			{
				if (overlays[i] == null)
				{
					overlays[i] = LoadFrame(i + 1);
					return;
				}
			}
			for (int j = 2; j <= 9; j++)
			{
				if (shootTex[j] == null)
				{
					shootTex[j] = LoadShootFrame(j);
					break;
				}
			}
		}

		private static Dictionary<string, Texture2D> LoadFrame(int frame)
		{
			Dictionary<string, Texture2D> dictionary = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in AssetStore.List("Overlays/stage" + frame, ".png"))
			{
				Texture2D val = LoadTexture(item, point: true);
				if ((Object)(object)val != (Object)null)
				{
					dictionary[Path.GetFileNameWithoutExtension(item)] = val;
				}
			}
			return dictionary;
		}

		public static Sprite GetOverlay(int stage, Sprite baseSprite)
		{
			if ((Object)(object)baseSprite == (Object)null || stage < 1 || stage > FrameCount)
			{
				return null;
			}
			if (overlays[stage - 1] == null)
			{
				overlays[stage - 1] = LoadFrame(stage);
			}
			string text = ((Object)baseSprite).name.Replace("(Clone)", "").Trim();
			if (!overlays[stage - 1].TryGetValue(text, out var value))
			{
				return null;
			}
			return MakeSprite("Tentacle_" + stage, text, value, baseSprite);
		}

		private static void LoadHands()
		{
			if (hands != null)
			{
				return;
			}
			hands = new Dictionary<string, float[]>(StringComparer.OrdinalIgnoreCase);
			string[] array = AssetStore.ReadLines("Shoot/hands.txt");
			if (array == null)
			{
				return;
			}
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string[] array3 = array2[i].Split(new char[1] { ' ' });
				if (array3.Length >= 4 && TryF(array3[1], out var v) && TryF(array3[2], out var v2))
				{
					hands[array3[0]] = new float[3]
					{
						v,
						v2,
						(array3[3] == "1") ? 1f : 0f
					};
				}
			}
		}

		private static bool TryF(string s, out float v)
		{
			return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out v);
		}

		private static string BaseName(Sprite sp)
		{
			return ((Object)sp).name.Replace("(Clone)", "").Trim();
		}

		public static Vector2 GetWrist(string spriteName, float width, float height)
		{
			//IL_0052: 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)
			LoadHands();
			if (hands.TryGetValue(spriteName.Replace("(Clone)", "").Trim(), out var value))
			{
				return new Vector2(value[0] * width / 128f, value[1] * height / 128f);
			}
			return new Vector2(width * 0.4f, height * 0.85f);
		}

		public static HandPose ShootKey(int frame)
		{
			if (shootKeys == null)
			{
				shootKeys = new HandPose[10];
				for (int i = 0; i <= 9; i++)
				{
					shootKeys[i] = HandPose.Identity;
				}
				string[] array = AssetStore.ReadLines("Shoot/keys.txt");
				if (array != null)
				{
					string[] array2 = array;
					for (int j = 0; j < array2.Length; j++)
					{
						string[] array3 = array2[j].Split(new char[1] { ' ' });
						if (array3.Length >= 6 && int.TryParse(array3[0], out var result) && result >= 1 && result <= 9 && TryF(array3[2], out var v) && TryF(array3[3], out var v2) && TryF(array3[4], out var v3) && TryF(array3[5], out var v4))
						{
							shootKeys[result] = new HandPose
							{
								scale = v,
								rot = v2,
								dx = v3,
								dy = v4
							};
						}
					}
				}
			}
			return shootKeys[Mathf.Clamp(frame, 1, 9)];
		}

		private static Dictionary<string, Texture2D> LoadShootFrame(int frame)
		{
			Dictionary<string, Texture2D> dictionary = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in AssetStore.List("Shoot/frame" + frame, ".png"))
			{
				Texture2D val = LoadTexture(item, point: true);
				if ((Object)(object)val != (Object)null)
				{
					dictionary[Path.GetFileNameWithoutExtension(item)] = val;
				}
			}
			return dictionary;
		}

		public static Sprite GetShoot(int frame, Sprite baseSprite, out bool full)
		{
			full = false;
			if ((Object)(object)baseSprite == (Object)null || frame < 2 || frame > 9)
			{
				return null;
			}
			if (shootTex[frame] == null)
			{
				shootTex[frame] = LoadShootFrame(frame);
			}
			string text = BaseName(baseSprite);
			if (!shootTex[frame].TryGetValue(text, out var value))
			{
				return null;
			}
			LoadHands();
			full = hands.TryGetValue(text, out var value2) && value2[2] > 0f;
			return MakeSprite("Shoot_" + frame, text, value, baseSprite);
		}

		private static Sprite MakeSprite(string prefix, string name, Texture2D tex, Sprite baseSprite)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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)
			Rect rect = baseSprite.rect;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(baseSprite.pivot.x / ((Rect)(ref rect)).width, baseSprite.pivot.y / ((Rect)(ref rect)).height);
			float num = baseSprite.pixelsPerUnit * ((float)((Texture)tex).width / ((Rect)(ref rect)).width);
			string key = prefix + "|" + name + "|" + num + "|" + val.x + "," + val.y;
			if (!spriteCache.TryGetValue(key, out var value) || (Object)(object)value == (Object)null)
			{
				value = Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), val, num);
				((Object)value).name = prefix + "_" + name;
				((Object)value).hideFlags = (HideFlags)32;
				spriteCache[key] = value;
			}
			return value;
		}

		public static Sprite GetCounter(int remaining)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			remaining = Mathf.Clamp(remaining, 0, counter.Length - 1);
			if ((Object)(object)counter[remaining] == (Object)null)
			{
				Texture2D val = LoadTexture("UI/barnacle_counter_" + remaining + ".png", point: true);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				counter[remaining] = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(1f, 0f), 1f);
				((Object)counter[remaining]).hideFlags = (HideFlags)32;
			}
			return counter[remaining];
		}
	}
	internal static class AssetStore
	{
		private const string Prefix = "Assets/";

		private static Dictionary<string, string> res;

		private static void Init()
		{
			if (res != null)
			{
				return;
			}
			res = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			string[] manifestResourceNames = typeof(Plugin).Assembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				string text2 = text.Replace('\\', '/');
				if (text2.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
				{
					res[text2.Substring("Assets/".Length)] = text;
				}
			}
			Plugin.Log.LogInfo((object)("Embedded assets: " + res.Count));
		}

		private static string DiskPath(string rel)
		{
			return Path.Combine(Plugin.AssetDir, rel.Replace('/', Path.DirectorySeparatorChar));
		}

		public static byte[] Read(string rel)
		{
			Init();
			if (res.TryGetValue(rel, out var value))
			{
				using (Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream(value))
				{
					using MemoryStream memoryStream = new MemoryStream();
					stream.CopyTo(memoryStream);
					return memoryStream.ToArray();
				}
			}
			string path = DiskPath(rel);
			if (!File.Exists(path))
			{
				return null;
			}
			return File.ReadAllBytes(path);
		}

		public static string[] ReadLines(string rel)
		{
			byte[] array = Read(rel);
			if (array == null)
			{
				return null;
			}
			return Encoding.UTF8.GetString(array).Replace("\r", "").Split(new char[1] { '\n' });
		}

		public static bool DirExists(string relDir)
		{
			Init();
			string value = relDir.TrimEnd(new char[1] { '/' }) + "/";
			foreach (string key in res.Keys)
			{
				if (key.StartsWith(value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return Directory.Exists(DiskPath(relDir));
		}

		public static List<string> List(string relDir, string ext)
		{
			Init();
			string text = relDir.TrimEnd(new char[1] { '/' }) + "/";
			List<string> list = new List<string>();
			foreach (string key in res.Keys)
			{
				if (key.StartsWith(text, StringComparison.OrdinalIgnoreCase) && key.IndexOf('/', text.Length) < 0 && key.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(key);
				}
			}
			if (list.Count == 0 && Directory.Exists(DiskPath(relDir)))
			{
				string[] files = Directory.GetFiles(DiskPath(relDir), "*" + ext);
				foreach (string path in files)
				{
					list.Add(text + Path.GetFileName(path));
				}
			}
			return list;
		}
	}
	internal static class BindingFactory
	{
		public const string BindingName = "Trinket_Binding_EscapedSubject";

		public const string PerkId = "Perk_Binding_EscapedSubject";

		public const string BioTrinketName = "Trinket_BioExperimented";

		private const string HotZoneFlag = "session_sacrificed_grub";

		private static Trinket binding;

		private static Perk perk;

		internal static string Title => Plugin.L("Escaped Test Subject", "탈출한 생체 실험자");

		public static void EnsureRegistered()
		{
			IList value = Traverse.Create(typeof(CL_AssetManager)).Field("databases").GetValue<IList>();
			if (value == null || value.Count == 0)
			{
				return;
			}
			WKAssetDatabase value2 = Traverse.Create(value[0]).Field("database").GetValue<WKAssetDatabase>();
			if ((Object)(object)value2 == (Object)null)
			{
				return;
			}
			if ((Object)(object)binding == (Object)null)
			{
				Build(value2);
			}
			if (value2.perkAssets != null && !value2.perkAssets.Contains(perk))
			{
				value2.perkAssets.Add(perk);
			}
			if (value2.trinketAssets != null && !value2.trinketAssets.Contains(binding))
			{
				value2.trinketAssets.Add(binding);
			}
			if (value2.gamemodeAssets == null)
			{
				return;
			}
			foreach (M_Gamemode gamemodeAsset in value2.gamemodeAssets)
			{
				AddToGamemode(gamemodeAsset);
			}
		}

		public static void AddToGamemode(M_Gamemode gm)
		{
			if (!((Object)(object)gm == (Object)null) && !((Object)(object)gm.availableTrinkets == (Object)null) && !((Object)(object)binding == (Object)null))
			{
				List<Trinket> bindings = gm.availableTrinkets.bindings;
				if (bindings != null && !bindings.Contains(binding))
				{
					bindings.Add(binding);
				}
			}
		}

		private static string PickerText()
		{
			return string.Format(Plugin.L("A test subject mutated while escaping the lab. Weakened, but grotesque mutations awaken. <color=#FFD454>(No leaderboards)</color>\n<color=#7CFF7C>+ Sticky Surface</color>: stay on the ground {0:0}s for the grub effect ({1:0}s once you grab a wall, no stamina drain for the first {2:0}s)\n<color=#7CFF7C>+ Tentacle Mutation</color>: after eating a grub, pill, injector or Lemon Roach, reach with a bare hand for {3:0}s → {4} tentacle shots, stamina +{5:0}%\n<color=#FF6B6B>- Weakness</color>: health {6:0}%, move speed {7:0}%, inventory {8:0}, gravity +{9:0}%, stamina {10:0}%  <color=#FFD454>!</color> Hostile Mother, incompatible with 'Biologically Experimented'", "실험실을 탈출하며 변이된 실험체. 몸은 약해졌지만 기괴한 변이 능력이 발현됩니다. <color=#FFD454>(리더보드 제외)</color>\n<color=#7CFF7C>+ 점착성 표면</color>: 지면에 {0:0}초 머무르면 굼벵이 효과 (벽을 짚고 {1:0}초, 처음 {2:0}초는 스태미나 유지)\n<color=#7CFF7C>+ 촉수 변이</color>: 굼벵이·알약·주사기·Lemon 로치 섭취 후 맨손 {3:0}초 → 촉수 사출 {4}회, 스태미나 +{5:0}%\n<color=#FF6B6B>- 약화</color>: 체력 {6:0}%, 이동속도 {7:0}%, 인벤토리 {8:0}, 중력 +{9:0}%, 스태미나 {10:0}%  <color=#FFD454>!</color> 둥지의 어머니가 적대, '생체 실험된'과 함께 쓸 수 없음"), Plugin.StickyGroundSeconds.Value, Plugin.StickyDuration.Value, Plugin.StickyNoDrain.Value, Plugin.MutateSeconds.Value, Plugin.Charges.Value, Plugin.TentacleStamina.Value * 100f, Plugin.Health.Value * 100f, Plugin.MoveSpeed.Value * 100f, Plugin.Capacity.Value, Plugin.Gravity.Value * 100f, Plugin.Stamina.Value * 100f);
		}

		private static string PerkText()
		{
			return string.Format(Plugin.L("A test subject whose body mutated while escaping the lab. Heavier and weaker, but in extreme situations grotesque mutations awaken.\n<color=#7CFF7C>+ Sticky Surface</color>: stay on the ground for {0:0}s to gain the grub effect. It lasts {1:0}s from the moment you grab a wall, and stamina doesn't drain for the first {7:0}s\n<color=#7CFF7C>+ Tentacle Mutation</color>: after eating a grub, pill, injector or Lemon Roach, reach out with a bare hand for {2:0}s to turn both hands into tentacles. {3} tentacle shots (hold the bare-hand button {8:0.##}s, range {10:0}m). The tentacle stays while the button is held, and the shooting hand can grab bare wall near the anchor. Stamina +{11:0}% while in tentacle form\n<color=#FF6B6B>- Weakness</color>: health {9:0}%, move speed {12:0}%, inventory capacity {4:0}, gravity +{5:0}%, stamina {6:0}%\n<color=#FFD454>! Nest</color>: the Mother recognizes the escaped subject and turns hostile\n<color=#FFD454>! Incompatible</color>: trinket 'Biologically Experimented'\n<color=#FFD454>! Leaderboards</color>: runs with this binding are not submitted", "실험실을 탈출하는 과정에서 신체가 변이된 실험체. 몸은 무겁고 약해졌지만, 극한의 상황에서 기괴한 변이 능력이 발현됩니다.\n<color=#7CFF7C>+ 점착성 표면</color>: 지면에 {0:0}초간 머무르면 굼벵이 효과 발현. 벽을 짚는 순간부터 {1:0}초 유지, 처음 {7:0}초는 스태미나가 줄지 않음\n<color=#7CFF7C>+ 촉수 변이</color>: 굼벵이·알약·주사기·Lemon 로치 섭취 후 맨손을 {2:0}초간 뻗고 있으면 양손이 촉수로 변이, 촉수 사출 {3}회 (맨손 버튼 {8:0.##}초 유지, 사거리 {10:0}m). 버튼을 누르고 있는 동안 촉수가 유지되고, 박힌 곳 가까이에서는 쏜 손으로 맨벽도 잡을 수 있음. 촉수 상태 동안 스태미나 +{11:0}%\n<color=#FF6B6B>- 약화</color>: 체력 {9:0}%, 이동속도 {12:0}%, 인벤토리 용량 {4:0}, 중력 +{5:0}%, 스태미나 {6:0}%\n<color=#FFD454>! 둥지</color>: 어머니가 탈출한 실험체를 알아보고 적대합니다\n<color=#FFD454>! 함께 쓸 수 없음</color>: 장신구 '생체 실험된'\n<color=#FFD454>! 리더보드</color>: 이 속박을 낀 판은 기록이 제출되지 않습니다"), Plugin.StickyGroundSeconds.Value, Plugin.StickyDuration.Value, Plugin.MutateSeconds.Value, Plugin.Charges.Value, Plugin.Capacity.Value, Plugin.Gravity.Value * 100f, Plugin.Stamina.Value * 100f, Plugin.StickyNoDrain.Value, Plugin.ShootHold.Value, Plugin.Health.Value * 100f, Plugin.TentacleRange.Value, Plugin.TentacleStamina.Value * 100f, Plugin.MoveSpeed.Value * 100f);
		}

		private static void Build(WKAssetDatabase db)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: 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_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			Sprite val = Assets.LoadIcon("binding_icon.png", db, (PerkType)9);
			string description = PerkText();
			perk = ScriptableObject.CreateInstance<Perk>();
			((Object)perk).name = "Perk_Binding_EscapedSubject";
			((Object)perk).hideFlags = (HideFlags)32;
			perk.id = "Perk_Binding_EscapedSubject";
			perk.title = Title;
			perk.description = description;
			perk.flavorText = "";
			perk.perkType = (PerkType)9;
			perk.tags = new List<string> { "binding" };
			perk.flags = new List<string> { "session_sacrificed_grub" };
			perk.playerTag = new List<string>();
			perk.spawnPool = (PerkPool)2;
			perk.spawnInEndless = false;
			perk.canStack = false;
			perk.stackMax = 1;
			perk.multiplierCurve = AnimationCurve.Constant(0f, 1f, 0f);
			perk.competitive = true;
			perk.removeOnCleanse = false;
			perk.unlockProgressionID = "";
			perk.icon = val;
			perk.useBuff = true;
			perk.buff = new BuffContainer
			{
				id = "Perk_Binding_EscapedSubject",
				desc = "",
				buffs = new List<Buff>
				{
					MakeBuff("addGravity", Plugin.Gravity.Value),
					MakeBuff("addStamina", Plugin.Stamina.Value),
					MakeBuff("addCapacity", Plugin.Capacity.Value),
					MakeBuff("addSpeed", Plugin.MoveSpeed.Value)
				},
				loseOverTime = false,
				loseRate = 0f,
				buffTime = 1f,
				multiplier = 1f
			};
			perk.useBaseBuff = false;
			perk.baseBuff = new BuffContainer
			{
				id = "",
				desc = "",
				buffs = new List<Buff>()
			};
			perk.modules = new List<PerkModule>();
			binding = ScriptableObject.CreateInstance<Trinket>();
			((Object)binding).name = "Trinket_Binding_EscapedSubject";
			((Object)binding).hideFlags = (HideFlags)32;
			binding.title = Title;
			binding.description = PickerText();
			binding.flavorText = "";
			binding.isBinding = true;
			binding.icon = val;
			binding.lockIcon = val;
			binding.cost = Plugin.Cost.Value;
			binding.itemsToGrant = new List<Item_Object>();
			binding.perksToGrant = new List<Perk> { perk };
			binding.pouchesToGrant = 0;
			binding.progressionUnlock = null;
			binding.scoreMultiplierBonus = Plugin.ScoreBonus.Value;
			binding.scoreBonus = 0f;
			binding.comingSoon = false;
			binding.settingBlacklist = new List<string>();
			binding.activateOrder = 0;
			Plugin.Log.LogInfo((object)"속박 생성 완료: Trinket_Binding_EscapedSubject");
		}

		private static Buff MakeBuff(string id, float amount)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return new Buff
			{
				id = id,
				maxAmount = amount,
				amount = amount
			};
		}

		public static bool IsActive(ENT_Player p)
		{
			if ((Object)(object)p != (Object)null)
			{
				return p.HasPerk("Perk_Binding_EscapedSubject");
			}
			return false;
		}
	}
	internal struct HandPose
	{
		public float scale;

		public float rot;

		public float dx;

		public float dy;

		public static readonly HandPose Identity = new HandPose
		{
			scale = 1f
		};

		public bool IsIdentity
		{
			get
			{
				if (scale == 1f && rot == 0f && dx == 0f)
				{
					return dy == 0f;
				}
				return false;
			}
		}

		public static HandPose Lerp(HandPose a, HandPose b, float t)
		{
			return new HandPose
			{
				scale = Mathf.Lerp(a.scale, b.scale, t),
				rot = Mathf.Lerp(a.rot, b.rot, t),
				dx = Mathf.Lerp(a.dx, b.dx, t),
				dy = Mathf.Lerp(a.dy, b.dy, t)
			};
		}
	}
	internal class HandOverlay : MonoBehaviour
	{
		public static readonly int[] Stage = new int[2];

		public static readonly int[] ShootFrame = new int[2];

		public static readonly HandPose[] Pose = new HandPose[2]
		{
			HandPose.Identity,
			HandPose.Identity
		};

		public static float Pulse;

		private SpriteRenderer target;

		private SpriteRenderer bodySprite;

		private SpriteRenderer overlay;

		private Material overlayMat;

		private int hand;

		private Vector3 restPos;

		private Vector3 restScale;

		private Quaternion restRot;

		private bool moves;

		private bool hidBase;

		public static void SetStage(int s)
		{
			Stage[0] = (Stage[1] = s);
		}

		public static void Attach(SpriteRenderer target, int hand, SpriteRenderer body)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null) && !((Object)(object)((Component)target).GetComponentInChildren<HandOverlay>(true) != (Object)null))
			{
				GameObject val = new GameObject("WKEscaped_TentacleOverlay");
				val.layer = ((Component)target).gameObject.layer;
				val.transform.SetParent(((Component)target).transform, false);
				HandOverlay handOverlay = val.AddComponent<HandOverlay>();
				handOverlay.target = target;
				handOverlay.bodySprite = (((Object)(object)body != (Object)null) ? body : target);
				handOverlay.hand = Mathf.Clamp(hand, 0, 1);
				handOverlay.overlay = val.AddComponent<SpriteRenderer>();
				handOverlay.overlayMat = ((Renderer)handOverlay.overlay).sharedMaterial;
				Transform transform = ((Component)target).transform;
				handOverlay.restPos = transform.localPosition;
				handOverlay.restRot = transform.localRotation;
				handOverlay.restScale = transform.localScale;
				handOverlay.moves = (Object)(object)target == (Object)(object)handOverlay.bodySprite || !transform.IsChildOf(((Component)handOverlay.bodySprite).transform);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)target != (Object)null && hidBase)
			{
				((Renderer)target).forceRenderingOff = false;
			}
		}

		private void LateUpdate()
		{
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			ApplyPose();
			bool num = ((Renderer)target).enabled && ((Component)target).gameObject.activeInHierarchy;
			Sprite val = null;
			bool full = false;
			if (num && ShootFrame[hand] >= 2)
			{
				val = Assets.GetShoot(ShootFrame[hand], target.sprite, out full);
			}
			if (num && (Object)(object)val == (Object)null && Stage[hand] > 0)
			{
				val = Assets.GetOverlay(Stage[hand], target.sprite);
				full = false;
			}
			bool flag = (Object)(object)val != (Object)null && full;
			if (flag != hidBase)
			{
				((Renderer)target).forceRenderingOff = flag;
				hidBase = flag;
			}
			((Renderer)overlay).enabled = (Object)(object)val != (Object)null;
			if (!((Object)(object)val == (Object)null))
			{
				overlay.sprite = val;
				overlay.flipX = target.flipX;
				overlay.flipY = target.flipY;
				((Renderer)overlay).sortingLayerID = ((Renderer)target).sortingLayerID;
				((Renderer)overlay).sortingOrder = ((Renderer)target).sortingOrder + 1;
				overlay.color = new Color(1f, 1f, 1f, target.color.a);
				((Renderer)overlay).sharedMaterial = ((full && (Object)(object)((Renderer)target).sharedMaterial != (Object)null) ? ((Renderer)target).sharedMaterial : overlayMat);
				float num2 = (full ? 1f : (1f + Pulse * 0.025f * Mathf.Sin(Time.time * 16f)));
				((Component)this).transform.localScale = new Vector3(num2, 1f / num2, 1f);
			}
		}

		private void ApplyPose()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: 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_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			if (moves)
			{
				Transform transform = ((Component)target).transform;
				HandPose handPose = Pose[hand];
				Sprite val = (((Object)(object)bodySprite != (Object)null) ? bodySprite.sprite : null);
				if (handPose.IsIdentity || (Object)(object)val == (Object)null)
				{
					transform.localPosition = restPos;
					transform.localRotation = restRot;
					transform.localScale = restScale;
					return;
				}
				Rect rect = val.rect;
				float pixelsPerUnit = val.pixelsPerUnit;
				float num = ((Rect)(ref rect)).width / 128f;
				Vector2 wrist = Assets.GetWrist(((Object)val).name, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
				float num2 = (bodySprite.flipX ? (-1f) : 1f);
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor((wrist.x - val.pivot.x) / pixelsPerUnit * num2, (((Rect)(ref rect)).height - wrist.y - val.pivot.y) / pixelsPerUnit, 0f);
				Quaternion val3 = Quaternion.Euler(0f, 0f, (0f - handPose.rot) * num2);
				Vector3 val4 = val2 - val3 * (val2 * handPose.scale) + new Vector3(handPose.dx * num * num2 / pixelsPerUnit, (0f - handPose.dy) * num / pixelsPerUnit, 0f);
				transform.localPosition = restPos + restRot * Vector3.Scale(restScale, val4);
				transform.localRotation = restRot * val3;
				transform.localScale = restScale * handPose.scale;
			}
		}
	}
	internal static class HandSkin
	{
		private const string CosmeticId = "Infested";

		private static ENT_Player appliedTo;

		private static readonly List<Cosmetic_HandItem>[] original = new List<Cosmetic_HandItem>[2];

		private static Cosmetic_HandItem infested;

		private static Cosmetic_HandItem Infested()
		{
			if ((Object)(object)infested != (Object)null)
			{
				return infested;
			}
			Traverse.Create(typeof(CL_CosmeticManager)).Field("cosmeticHandDict").GetValue<Dictionary<string, Cosmetic_HandItem>>()?.TryGetValue("Infested", out infested);
			if ((Object)(object)infested == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Infested 손 코스메틱을 찾지 못함");
			}
			return infested;
		}

		public static void Set(ENT_Player player, bool on)
		{
			if (on)
			{
				if ((Object)(object)appliedTo == (Object)(object)player || (Object)(object)player == (Object)null)
				{
					return;
				}
				if ((Object)(object)appliedTo != (Object)null)
				{
					Restore();
				}
				Cosmetic_HandItem val = Infested();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				for (int i = 0; i < player.hands.Length && i < 2; i++)
				{
					Hand val2 = player.hands[i];
					if (val2.currentCosmetics == null)
					{
						val2.currentCosmetics = new List<Cosmetic_HandItem>();
					}
					original[i] = new List<Cosmetic_HandItem>(val2.currentCosmetics);
					foreach (Cosmetic_HandItem currentCosmetic in val2.currentCosmetics)
					{
						currentCosmetic.ClearCosmetic();
					}
					val2.currentCosmetics.Clear();
					val2.currentCosmetics.Add(val);
				}
				appliedTo = player;
			}
			else if ((Object)(object)appliedTo != (Object)null)
			{
				Restore();
			}
		}

		private static void Restore()
		{
			ENT_Player val = appliedTo;
			appliedTo = null;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)infested != (Object)null)
			{
				infested.ClearCosmetic();
			}
			for (int i = 0; i < val.hands.Length && i < 2; i++)
			{
				Hand val2 = val.hands[i];
				if (val2.currentCosmetics != null)
				{
					val2.currentCosmetics.Clear();
					if (original[i] != null)
					{
						val2.currentCosmetics.AddRange(original[i]);
					}
					original[i] = null;
				}
			}
		}
	}
	[HarmonyPatch(typeof(M_Gamemode), "Finish")]
	internal static class Patch_Finish_NoLeaderboard
	{
		private static void Prefix(M_Gamemode __instance, out bool __state)
		{
			__state = WK_Leaderboard_Core.disableLeaderboards;
			if (UsedThisRun(__instance))
			{
				WK_Leaderboard_Core.disableLeaderboards = true;
				Plugin.Log.LogInfo((object)"Escaped Test Subject was used this run: leaderboard submission skipped");
			}
		}

		private static Exception Finalizer(Exception __exception, bool __state)
		{
			WK_Leaderboard_Core.disableLeaderboards = __state;
			return __exception;
		}

		private static bool UsedThisRun(M_Gamemode gm)
		{
			try
			{
				if (BindingFactory.IsActive(ENT_Player.GetPlayer()))
				{
					return true;
				}
			}
			catch (Exception)
			{
			}
			try
			{
				List<string> gamemodeTrinkets = StatManager.saveData.GetGamemodeTrinkets(gm.GetGamemodeName(true));
				if (gamemodeTrinkets != null && gamemodeTrinkets.Exists((string n) => n?.Contains("Trinket_Binding_EscapedSubject") ?? false))
				{
					return true;
				}
			}
			catch (Exception)
			{
			}
			return false;
		}
	}
	internal class MutationController : MonoBehaviour
	{
		private enum State
		{
			Idle,
			Charged,
			Tentacle,
			Reverting
		}

		private enum Sticky
		{
			None,
			Armed,
			Counting
		}

		private enum Shot
		{
			None,
			Charging,
			Fired,
			Retract
		}

		private static MutationController instance;

		private State state;

		private float progress;

		private float revertTime;

		private int charges;

		private Sticky sticky;

		private float groundTime;

		private BuffContainer stickyBuff;

		private BuffContainer grubTemplate;

		private bool grubLoaded;

		private readonly TentacleGrapple grapple = new TentacleGrapple();

		private readonly float[] holdTime = new float[2];

		private readonly bool[] pending = new bool[2];

		private readonly float[] lastGrip = new float[2];

		private Image counterImage;

		private float stickyNoDrainLeft;

		private Image stickyVignette;

		private float stickyVignetteAlpha;

		private ENT_Player healthAppliedTo;

		private static readonly Color StickyTint = new Color(0.24f, 0.04f, 0.33f, 1f);

		private const string TentacleStaminaBuffId = "escapedSubject_tentacleStamina";

		private readonly Sounds.Player chargeSound = new Sounds.Player("mutation_charge.wav");

		private readonly Sounds.Player shootSound = new Sounds.Player("tentacle_shoot.wav");

		private readonly Dictionary<int, Camera> layerCamera = new Dictionary<int, Camera>();

		private readonly Shot[] shot = new Shot[2];

		private readonly float[] shotTime = new float[2];

		private float trembleNext;

		private readonly HandPose[] trembleTarget = new HandPose[2]
		{
			HandPose.Identity,
			HandPose.Identity
		};

		private static readonly float[] ChargeKeyTimes = new float[5] { 0f, 0.1f, 0.35f, 0.6f, 0.75f };

		private static readonly float[] FiredKeyTimes = new float[4] { 0f, 0.07f, 0.16f, 0.34f };

		private const float RetractSeconds = 0.16f;

		private void Awake()
		{
			instance = this;
			grapple.OnLatch = delegate
			{
				charges = Mathf.Max(0, charges - 1);
			};
			grapple.OnRelease = delegate
			{
				if (state == State.Tentacle && charges <= 0)
				{
					StartRevert();
				}
			};
			grapple.OnShotEnd = delegate(int hand)
			{
				if (hand >= 0 && hand < 2)
				{
					pending[hand] = false;
					holdTime[hand] = 0f;
				}
			};
			grapple.PalmPoint = PalmPoint;
		}

		private void OnEnable()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDisable()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene s, LoadSceneMode m)
		{
			BindingFactory.EnsureRegistered();
			grapple.Reset();
		}

		public static void ResetRun()
		{
			if (!((Object)(object)instance == (Object)null))
			{
				instance.state = State.Idle;
				instance.progress = 0f;
				instance.charges = 0;
				instance.groundTime = 0f;
				instance.sticky = Sticky.None;
				instance.stickyBuff = null;
				instance.stickyNoDrainLeft = 0f;
				instance.grapple.Reset();
				instance.chargeSound.Stop();
				instance.shootSound.Stop();
				instance.RemoveTentacleStamina(ENT_Player.GetPlayer());
			}
		}

		public static void OnConsume(HandItem_Buff item)
		{
			if (!((Object)(object)instance == (Object)null) && BindingFactory.IsActive(ENT_Player.GetPlayer()) && IsChargeItem(item) && instance.state == State.Idle)
			{
				instance.state = State.Charged;
				instance.progress = 0f;
				Plugin.Log.LogInfo((object)("변이 충전: " + ((Object)((Component)item).gameObject).name));
			}
		}

		private static bool IsChargeItem(HandItem_Buff h)
		{
			if (h is HandItem_Buff_Grub)
			{
				return true;
			}
			string text = ((Object)((Component)h).gameObject).name;
			if (((HandItem)h).item != null)
			{
				text = text + "|" + ((HandItem)h).item.prefabName + "|" + ((HandItem)h).item.itemName;
			}
			string[] array = Plugin.ChargeKeywords.Value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0 && text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private void Update()
		{
			ENT_Player val = null;
			try
			{
				val = ENT_Player.GetPlayer();
			}
			catch (Exception)
			{
			}
			if (!((Object)(object)val != (Object)null) || ((GameEntity)val).dead || !BindingFactory.IsActive(val))
			{
				HandOverlay.SetStage(0);
				HandOverlay.Pulse = 0f;
				ResetHandMotion();
				ShowCounter(0);
				UpdateStickyVignette(0f);
				HandSkin.Set(val, on: false);
				if (grapple.Latched || grapple.Primed)
				{
					grapple.Reset();
				}
				chargeSound.Stop();
				shootSound.Stop();
				return;
			}
			ApplyHealth(val);
			Assets.PreloadStep();
			grapple.Tick(val);
			HandSkin.Set(val, (state == State.Charged && progress > 0f) || state == State.Tentacle || state == State.Reverting);
			bool flag = (Object)(object)CL_GameManager.gMan != (Object)null && CL_GameManager.gMan.isPaused;
			for (int i = 0; i < val.hands.Length && i < 2; i++)
			{
				Hand val2 = val.hands[i];
				HandOverlay.Attach(val2.handSprite, i, val2.handSprite);
				HandOverlay.Attach(val2.handForegroundSprite, i, val2.handSprite);
			}
			grapple.Load();
			if (Plugin.DebugKeys.Value)
			{
				if (KeyDown((KeyCode)287) && state == State.Idle)
				{
					state = State.Charged;
				}
				if (KeyDown((KeyCode)288))
				{
					EnterTentacle();
				}
			}
			if (!flag)
			{
				UpdateSticky(val);
			}
			switch (state)
			{
			case State.Idle:
				HandOverlay.SetStage(0);
				HandOverlay.Pulse = 0f;
				ResetHandMotion();
				break;
			case State.Charged:
				UpdateMutating(val, flag);
				break;
			case State.Tentacle:
			{
				HandOverlay.SetStage(Assets.FrameCount);
				float num = Mathf.Max(holdTime[0], holdTime[1]);
				HandOverlay.Pulse = 0.6f + 1.6f * Mathf.Clamp01(num / Mathf.Max(0.1f, Plugin.ShootHold.Value));
				if (!flag)
				{
					UpdateTentacle(val);
				}
				UpdateShootMotion(val, flag);
				break;
			}
			case State.Reverting:
				revertTime += Time.deltaTime;
				HandOverlay.SetStage(Mathf.Clamp(Mathf.CeilToInt((1f - revertTime / 0.5f) * (float)Assets.FrameCount), 0, Assets.FrameCount));
				HandOverlay.Pulse = 0f;
				UpdateShootMotion(val, flag);
				if (revertTime >= 0.5f)
				{
					state = State.Idle;
					HandOverlay.SetStage(0);
				}
				break;
			}
			ShowCounter((state == State.Tentacle) ? charges : 0);
		}

		private void LateUpdate()
		{
			grapple.LateUpdate();
		}

		private void UpdateMutating(ENT_Player player, bool paused)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			bool flag = true;
			bool flag2 = false;
			Hand[] hands = player.hands;
			foreach (Hand val in hands)
			{
				if ((Object)(object)val.GetHandItem() != (Object)null)
				{
					flag = false;
				}
				if (InputManager.GetButton(val.fireButton).Pressed && (int)val.interactState == 0)
				{
					flag2 = true;
				}
			}
			if (flag && flag2 && !paused && !Inventory.IsShowingInventory())
			{
				if (progress <= 0f)
				{
					chargeSound.Play(((Component)this).gameObject);
				}
				progress += Time.deltaTime;
			}
			else
			{
				if (progress > 0f)
				{
					chargeSound.Stop();
				}
				progress = 0f;
			}
			float num = Mathf.Max(0.5f, Plugin.MutateSeconds.Value);
			float num2 = progress / num;
			HandOverlay.SetStage((progress > 0f) ? Mathf.Clamp(Mathf.CeilToInt(num2 * (float)Assets.FrameCount), 1, Assets.FrameCount) : 0);
			HandOverlay.Pulse = Mathf.Clamp01((num2 - 0.6f) / 0.4f);
			UpdateTremble((progress > 0f && !paused) ? (num2 * 5f) : (-1f));
			if (progress >= num)
			{
				EnterTentacle();
				ResetHandMotion();
			}
		}

		private void ApplyHealth(ENT_Player player)
		{
			if (!((Object)(object)healthAppliedTo == (Object)(object)player))
			{
				healthAppliedTo = player;
				float num = Mathf.Max(0.05f, 1f + Plugin.Health.Value);
				((GameEntity)player).maxHealth = ((GameEntity)player).maxHealth * num;
				((GameEntity)player).health = Mathf.Min(((GameEntity)player).health, ((GameEntity)player).maxHealth);
				Plugin.Log.LogInfo((object)("최대 체력 적용: " + ((GameEntity)player).maxHealth));
			}
		}

		private void EnterTentacle()
		{
			state = State.Tentacle;
			charges = Plugin.Charges.Value;
			progress = 0f;
			pending[0] = (pending[1] = false);
			ENT_Player player = ENT_Player.GetPlayer();
			if ((Object)(object)player != (Object)null)
			{
				for (int i = 0; i < player.hands.Length && i < 2; i++)
				{
					lastGrip[i] = player.hands[i].gripStrength;
				}
			}
			if ((Object)(object)player != (Object)null)
			{
				AddTentacleStamina(player);
			}
			Plugin.Log.LogInfo((object)("촉수 변이 완료: " + charges + "회"));
		}

		private void StartRevert()
		{
			state = State.Reverting;
			revertTime = 0f;
			grapple.Reset();
			RemoveTentacleStamina(ENT_Player.GetPlayer());
		}

		private void UpdateTentacle(ENT_Player player)
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < player.hands.Length && i < 2; i++)
			{
				Hand val = player.hands[i];
				ButtonInput button = InputManager.GetButton(val.fireButton);
				if (button.Down && (Object)(object)val.GetHandItem() == (Object)null)
				{
					holdTime[i] = 0f;
					pending[i] = true;
				}
				if (!button.Pressed)
				{
					if (pending[i] && grapple.HandId == i)
					{
						grapple.StopPrime(charges <= 0);
					}
					if (pending[i] && holdTime[i] < Plugin.ShootHold.Value)
					{
						shootSound.Stop();
					}
					pending[i] = false;
					holdTime[i] = 0f;
				}
				else
				{
					if (!pending[i])
					{
						continue;
					}
					if ((!grapple.Primed && !grapple.Latched) || grapple.HandId != i)
					{
						if ((Object)(object)val.GetHandItem() != (Object)null || (int)val.interactState != 0)
						{
							if (holdTime[i] > 0f && holdTime[i] < Plugin.ShootHold.Value)
							{
								shootSound.Stop();
							}
							pending[i] = false;
							holdTime[i] = 0f;
							continue;
						}
						if (((grapple.Primed || grapple.Latched) && grapple.HandId != i) || charges <= 0)
						{
							continue;
						}
						if (holdTime[i] <= 0f)
						{
							shootSound.Play(((Component)this).gameObject);
						}
						holdTime[i] += Time.deltaTime;
					}
					if (holdTime[i] >= Plugin.ShootHold.Value)
					{
						grapple.Prime(i);
					}
				}
			}
			grapple.Update(player, charges <= 0);
		}

		private void ResetHandMotion()
		{
			for (int i = 0; i < 2; i++)
			{
				shot[i] = Shot.None;
				HandOverlay.Pose[i] = HandPose.Identity;
				HandOverlay.ShootFrame[i] = 0;
			}
		}

		private void UpdateTremble(float sec)
		{
			if (sec < 0f)
			{
				HandOverlay.Pose[0] = (HandOverlay.Pose[1] = HandPose.Identity);
				return;
			}
			bool flag = (sec >= 1f && sec < 1.12f) || (sec >= 3.5f && sec < 3.62f);
			if (Time.time >= trembleNext || flag)
			{
				trembleNext = Time.time + 0.06f;
				float num = 0.4f + 1.8f * sec / 5f;
				for (int i = 0; i < 2; i++)
				{
					trembleTarget[i] = new HandPose
					{
						scale = (flag ? 0.95f : (1f + Random.Range(-0.01f, 0.01f))),
						rot = Random.Range(-1f, 1f) * (0.6f + sec * 0.5f) + (flag ? 4f : 0f),
						dx = Random.Range(-1f, 1f) * num,
						dy = Random.Range(-1f, 1f) * num * 0.7f + (flag ? 3f : 0f)
					};
				}
			}
			for (int j = 0; j < 2; j++)
			{
				HandOverlay.Pose[j] = HandPose.Lerp(HandOverlay.Pose[j], trembleTarget[j], Mathf.Clamp01(Time.deltaTime * 30f));
			}
		}

		private void UpdateShootMotion(ENT_Player player, bool paused)
		{
			if (paused)
			{
				return;
			}
			float num = Mathf.Max(0.05f, Plugin.ShootHold.Value);
			for (int i = 0; i < player.hands.Length && i < 2; i++)
			{
				bool pressed = InputManager.GetButton(player.hands[i].fireButton).Pressed;
				bool flag = (grapple.Primed || grapple.Latched) && grapple.HandId == i;
				switch (shot[i])
				{
				case Shot.None:
					if (state == State.Tentacle && pending[i] && holdTime[i] > 0f)
					{
						shot[i] = Shot.Charging;
					}
					break;
				case Shot.Charging:
					if (holdTime[i] >= num)
					{
						shot[i] = Shot.Fired;
						shotTime[i] = 0f;
					}
					else if (!pending[i] || holdTime[i] <= 0f)
					{
						shot[i] = Shot.None;
					}
					break;
				case Shot.Fired:
					shotTime[i] += Time.deltaTime;
					if (!(pressed && flag) && shotTime[i] >= FiredKeyTimes[2])
					{
						shot[i] = Shot.Retract;
						shotTime[i] = 0f;
					}
					break;
				case Shot.Retract:
					shotTime[i] += Time.deltaTime;
					if (shotTime[i] >= 0.16f)
					{
						shot[i] = Shot.None;
					}
					break;
				}
				int num2;
				HandPose handPose;
				switch (shot[i])
				{
				case Shot.Charging:
				{
					float num4 = holdTime[i] / num * 0.75f;
					int k;
					for (k = 0; k < ChargeKeyTimes.Length - 2 && num4 >= ChargeKeyTimes[k + 1]; k++)
					{
					}
					float t2 = Mathf.SmoothStep(0f, 1f, (num4 - ChargeKeyTimes[k]) / (ChargeKeyTimes[k + 1] - ChargeKeyTimes[k]));
					num2 = k + 1;
					handPose = HandPose.Lerp(Assets.ShootKey(k + 1), Assets.ShootKey(k + 2), t2);
					if (num2 >= 3)
					{
						handPose.dx += Random.Range(-0.6f, 0.6f);
						handPose.dy += Random.Range(-0.6f, 0.6f);
					}
					break;
				}
				case Shot.Fired:
				{
					float num3 = shotTime[i];
					int j;
					for (j = 0; j < FiredKeyTimes.Length - 1 && num3 >= FiredKeyTimes[j + 1]; j++)
					{
					}
					num2 = 5 + j;
					if (j < FiredKeyTimes.Length - 1)
					{
						float t = Mathf.SmoothStep(0f, 1f, (num3 - FiredKeyTimes[j]) / (FiredKeyTimes[j + 1] - FiredKeyTimes[j]));
						handPose = HandPose.Lerp(Assets.ShootKey(5 + j), Assets.ShootKey(6 + j), t);
					}
					else
					{
						handPose = Assets.ShootKey(8);
					}
					break;
				}
				case Shot.Retract:
					num2 = 9;
					handPose = HandPose.Lerp(Assets.ShootKey(9), HandPose.Identity, Mathf.SmoothStep(0f, 1f, shotTime[i] / 0.16f));
					break;
				default:
					num2 = 0;
					handPose = HandPose.Identity;
					break;
				}
				HandOverlay.ShootFrame[i] = num2;
				HandOverlay.Pose[i] = handPose;
			}
		}

		private void AddTentacleStamina(ENT_Player p)
		{
			//IL_0019: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0075: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			if (!((GameEntity)p).curBuffs.HasBuffContainer("escapedSubject_tentacleStamina"))
			{
				((GameEntity)p).curBuffs.AddBuff(new BuffContainer
				{
					id = "escapedSubject_tentacleStamina",
					desc = "",
					buffs = new List<Buff>
					{
						new Buff
						{
							id = "addStamina",
							maxAmount = Plugin.TentacleStamina.Value,
							amount = Plugin.TentacleStamina.Value
						}
					},
					loseOverTime = false,
					loseRate = 0f,
					buffTime = 1f,
					multiplier = 1f
				});
			}
		}

		private void RemoveTentacleStamina(ENT_Player p)
		{
			if ((Object)(object)p != (Object)null && ((GameEntity)p).curBuffs != null && ((GameEntity)p).curBuffs.HasBuffContainer("escapedSubject_tentacleStamina"))
			{
				((GameEntity)p).curBuffs.RemoveBuffContainer("escapedSubject_tentacleStamina");
			}
		}

		private Vector3? PalmPoint(int handId, float depth)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ENT_Player player = ENT_Player.GetPlayer();
				Camera main = Camera.main;
				if ((Object)(object)player == (Object)null || (Object)(object)main == (Object)null || handId < 0 || handId >= player.hands.Length)
				{
					return null;
				}
				SpriteRenderer handSprite = player.hands[handId].handSprite;
				if ((Object)(object)handSprite == (Object)null || (Object)(object)handSprite.sprite == (Object)null || !((Renderer)handSprite).enabled)
				{
					return null;
				}
				int layer = ((Component)handSprite).gameObject.layer;
				if (!layerCamera.TryGetValue(layer, out var value) || (Object)(object)value == (Object)null)
				{
					value = null;
					Camera[] allCameras = Camera.allCameras;
					foreach (Camera val in allCameras)
					{
						if ((val.cullingMask & (1 << layer)) != 0 && ((Object)(object)value == (Object)null || val.depth > value.depth))
						{
							value = val;
						}
					}
					layerCamera[layer] = value;
				}
				if ((Object)(object)value == (Object)null)
				{
					return null;
				}
				Bounds bounds = ((Renderer)handSprite).bounds;
				Vector3 val2 = ((Bounds)(ref bounds)).center - ((Component)handSprite).transform.up * (((Bounds)(ref bounds)).extents.y * 0.2f);
				Vector3 val3 = value.WorldToScreenPoint(val2);
				if (val3.z <= 0f)
				{
					return null;
				}
				return main.ScreenToWorldPoint(new Vector3(val3.x, val3.y, depth));
			}
			catch (Exception)
			{
				return null;
			}
		}

		private void UpdateSticky(ENT_Player player)
		{
			if (sticky != Sticky.None && (stickyBuff == null || !((GameEntity)player).curBuffs.currentBuffs.Contains(stickyBuff)))
			{
				sticky = Sticky.None;
				stickyBuff = null;
				groundTime = 0f;
				stickyNoDrainLeft = 0f;
			}
			if (sticky == Sticky.Armed)
			{
				UpdateStickyVignette(0.5f);
				if (player.IsHanging())
				{
					sticky = Sticky.Counting;
					stickyBuff.buffTime = 1f;
					stickyBuff.loseOverTime = true;
					stickyNoDrainLeft = Plugin.StickyNoDrain.Value;
					for (int i = 0; i < player.hands.Length && i < 2; i++)
					{
						lastGrip[i] = player.hands[i].gripStrength;
					}
				}
				return;
			}
			if (sticky == Sticky.Counting)
			{
				UpdateStickyVignette(0.5f * Mathf.Clamp01(stickyBuff.buffTime));
				if (!(stickyNoDrainLeft > 0f))
				{
					return;
				}
				stickyNoDrainLeft -= Time.deltaTime;
				for (int j = 0; j < player.hands.Length && j < 2; j++)
				{
					Hand val = player.hands[j];
					if (val.gripStrength < lastGrip[j])
					{
						val.SetGripStrength(lastGrip[j]);
					}
					lastGrip[j] = val.gripStrength;
				}
				return;
			}
			UpdateStickyVignette(0f);
			if (player.IsGrounded(false) && !player.IsHanging())
			{
				groundTime += Time.deltaTime;
			}
			else
			{
				groundTime = 0f;
			}
			if (!(groundTime < Plugin.StickyGroundSeconds.Value))
			{
				groundTime = 0f;
				stickyBuff = MakeGrubBuff();
				if (stickyBuff != null)
				{
					((GameEntity)player).Buff(stickyBuff);
					stickyBuff = ((GameEntity)player).curBuffs.GetBuffContainer(stickyBuff.id) ?? stickyBuff;
					stickyBuff.loseOverTime = false;
					stickyBuff.buffTime = 1f;
					sticky = Sticky.Armed;
				}
			}
		}

		private BuffContainer MakeGrubBuff()
		{
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: 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_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Expected O, but got Unknown
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			if (!grubLoaded)
			{
				grubLoaded = true;
				try
				{
					GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Denizen_SlugGrub", "");
					Item_Object val = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null);
					HandItem_Buff val2 = (HandItem_Buff)(((Object)(object)val != (Object)null && val.itemData != null) ? /*isinst with value type is only supported in some contexts*/: null);
					if ((Object)(object)val2 != (Object)null && val2.buff != null && val2.buff.buffs != null)
					{
						grubTemplate = val2.buff;
						List<string> list = new List<string>();
						foreach (Buff buff in val2.buff.buffs)
						{
							list.Add(buff.id + "=" + buff.maxAmount);
						}
						Plugin.Log.LogInfo((object)("굼벵이 효과 로드: " + val2.buff.id + " [" + string.Join(", ", list.ToArray()) + "]"));
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("굼벵이 효과 로드 실패: " + ex.Message));
				}
				if (grubTemplate == null)
				{
					Plugin.Log.LogWarning((object)"굼벵이 효과를 찾지 못해 grabAnything으로 대체");
				}
			}
			BuffContainer val3 = new BuffContainer
			{
				id = "escapedSubject_sticky",
				desc = "",
				buffs = new List<Buff>(),
				loseOverTime = false,
				loseRateEffectedByPerks = false,
				loseRate = 1f / Mathf.Max(0.1f, Plugin.StickyDuration.Value)
			};
			if (grubTemplate != null)
			{
				foreach (Buff buff2 in grubTemplate.buffs)
				{
					if (!(buff2.id == "gooped_screen"))
					{
						val3.buffs.Add(new Buff
						{
							id = buff2.id,
							maxAmount = buff2.maxAmount,
							amount = buff2.maxAmount
						});
					}
				}
			}
			else
			{
				val3.buffs.Add(new Buff
				{
					id = "grabAnything",
					maxAmount = 1f,
					amount = 1f
				});
			}
			val3.Initialize();
			return val3;
		}

		private void UpdateStickyVignette(float target)
		{
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			stickyVignetteAlpha = Mathf.Lerp(stickyVignetteAlpha, target, Time.unscaledDeltaTime * 3f);
			if ((Object)(object)stickyVignette == (Object)null)
			{
				if (stickyVignetteAlpha < 0.01f)
				{
					return;
				}
				try
				{
					CL_UIManager val = CL_UIManager.instance;
					if ((Object)(object)val == (Object)null || val.vignettes == null)
					{
						return;
					}
					Vignette val2 = val.vignettes.Find((Vignette v) => v.name == "goop");
					if (val2 == null || (Object)(object)val2.image == (Object)null)
					{
						return;
					}
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val2.image).gameObject, ((Component)val2.image).transform.parent);
					((Object)val3).name = "WKEscaped_StickyVignette";
					val3.transform.SetSiblingIndex(((Component)val2.image).transform.GetSiblingIndex() + 1);
					stickyVignette = val3.GetComponent<Image>();
					Plugin.Log.LogInfo((object)("보라색 화면 생성 (원본 goop 색: " + ((object)Unsafe.As<Color, Color>(ref val2.color)/*cast due to .constrained prefix*/).ToString() + ")"));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("보라색 화면 생성 실패: " + ex.Message));
					return;
				}
			}
			Color stickyTint = StickyTint;
			stickyTint.a = stickyVignetteAlpha;
			((Graphic)stickyVignette).color = stickyTint;
			((Behaviour)stickyVignette).enabled = stickyVignetteAlpha > 0.005f;
		}

		private void ShowCounter(int remaining)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			if (remaining <= 0)
			{
				if ((Object)(object)counterImage != (Object)null)
				{
					((Behaviour)counterImage).enabled = false;
				}
				return;
			}
			if ((Object)(object)counterImage == (Object)null)
			{
				GameObject val = new GameObject("WKEscaped_BarnacleCounter", new Type[1] { typeof(Canvas) });
				Object.DontDestroyOnLoad((Object)(object)val);
				Canvas component = val.GetComponent<Canvas>();
				component.renderMode = (RenderMode)0;
				component.sortingOrder = 29000;
				GameObject val2 = new GameObject("Counter", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val2.transform.SetParent(val.transform, false);
				RectTransform val3 = (RectTransform)val2.transform;
				Vector2 val4 = default(Vector2);
				((Vector2)(ref val4))..ctor(1f, 0f);
				val3.anchorMax = val4;
				val3.anchorMin = val4;
				val3.pivot = new Vector2(1f, 0f);
				val3.anchoredPosition = new Vector2(-28f, 28f);
				counterImage = val2.GetComponent<Image>();
				((Graphic)counterImage).raycastTarget = false;
			}
			Sprite counter = Assets.GetCounter(remaining);
			((Behaviour)counterImage).enabled = (Object)(object)counter != (Object)null;
			if (!((Object)(object)counter == (Object)null))
			{
				counterImage.sprite = counter;
				RectTransform val5 = (RectTransform)((Component)counterImage).transform;
				Rect rect = counter.rect;
				float width = ((Rect)(ref rect)).width;
				rect = counter.rect;
				val5.sizeDelta = new Vector2(width, ((Rect)(ref rect)).height) * Plugin.CounterScale.Value;
			}
		}

		private static bool KeyDown(KeyCode key)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				if (current != null)
				{
					if ((int)key == 287)
					{
						return ((ButtonControl)current.f6Key).wasPressedThisFrame;
					}
					if ((int)key == 288)
					{
						return ((ButtonControl)current.f7Key).wasPressedThisFrame;
					}
				}
			}
			catch (Exception)
			{
			}
			try
			{
				return Input.GetKeyDown(key);
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(CL_AssetManager), "InitializeDatabases")]
	internal static class Patch_InitializeDatabases
	{
		private static void Postfix()
		{
			BindingFactory.EnsureRegistered();
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "ReloadTrinkets")]
	internal static class Patch_ReloadTrinkets
	{
		private static void Prefix(UI_TrinketPicker __instance)
		{
			BindingFactory.EnsureRegistered();
			BindingFactory.AddToGamemode(Traverse.Create((object)__instance).Field("currentGamemode").GetValue<M_Gamemode>());
		}

		private static void Postfix(UI_TrinketPicker __instance)
		{
			PickerLayout.FitBindings(__instance);
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "ShowTrinketDescription")]
	internal static class Patch_ShowTrinketDescription
	{
		private static void Prefix(UI_TrinketPicker __instance, Trinket t)
		{
			PickerLayout.OnShowDescription(__instance, t);
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "SelectTrinket")]
	internal static class Patch_SelectTrinket
	{
		private static void Prefix(UI_TrinketPicker __instance, Trinket t)
		{
			if (!((Object)(object)t == (Object)null) && __instance.selectedTrinkets != null)
			{
				string other = ((((Object)t).name == "Trinket_Binding_EscapedSubject") ? "Trinket_BioExperimented" : ((((Object)t).name == "Trinket_BioExperimented") ? "Trinket_Binding_EscapedSubject" : null));
				if (other != null && !__instance.selectedTrinkets.Contains(t) && __instance.selectedTrinkets.RemoveAll((Trinket x) => (Object)(object)x != (Object)null && ((Object)x).name == other) > 0)
				{
					Plugin.Log.LogInfo((object)("함께 쓸 수 없어 선택 해제: " + other));
				}
			}
		}
	}
	[HarmonyPatch(typeof(M_Gamemode), "StartFreshGamemode")]
	internal static class Patch_StartFreshGamemode
	{
		private static void Prefix(M_Gamemode __instance)
		{
			BindingFactory.EnsureRegistered();
			MutationController.ResetRun();
			try
			{
				string gamemodeName = __instance.GetGamemodeName(true);
				List<string> gamemodeTrinkets = StatManager.saveData.GetGamemodeTrinkets(gamemodeName);
				if (gamemodeTrinkets != null && gamemodeTrinkets.Exists((string n) => n?.Contains("Trinket_Binding_EscapedSubject") ?? false) && gamemodeTrinkets.RemoveAll((string n) => n?.Contains("Trinket_BioExperimented") ?? false) > 0)
				{
					StatManager.saveData.SetGamemodeTrinkets(gamemodeName, gamemodeTrinkets);
					Plugin.Log.LogInfo((object)"속박과 함께 쓸 수 없어 '생체 실험된'을 이번 판에서 제외");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("선택 목록 확인 실패: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ENT_Player), "GrabAnywhere")]
	internal static class Patch_GrabAnywhere
	{
		private static bool Prefix(ENT_Player __instance, Hand curhand, ref InteractHit interactHit, ref bool __result)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			TentacleGrapple active = TentacleGrapple.Active;
			if (active == null || !active.WallGrabOn || ((GameEntity)__instance).curBuffs.GetBuff("grabAnything") > 0f)
			{
				return true;
			}
			if (Array.IndexOf(__instance.hands, curhand) == active.WallGrabHand && Vector3.Distance(interactHit.point, active.AnchorPoint) <= Plugin.AnchorGrabRadius.Value)
			{
				return true;
			}
			((Component)__instance.grabAnywhereFakeHandholds[curhand.id]).gameObject.SetActive(false);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(HandItem_Buff), "StartBuff")]
	internal static class Patch_StartBuff
	{
		private static void Prefix(HandItem_Buff __instance)
		{
			MutationController.OnConsume(__instance);
		}
	}
	internal static class PickerLayout
	{
		private class Saved
		{
			public Vector3 scale;

			public Vector3 position;

			public Constraint constraint;

			public int constraintCount;

			public Vector2 cellSize;

			public Vector2 spacing;
		}

		internal class Fitter : MonoBehaviour
		{
			public int dirtyFrame = -1;

			private void LateUpdate()
			{
				if (dirtyFrame < 0 || Time.frameCount <= dirtyFrame)
				{
					return;
				}
				dirtyFrame = -1;
				try
				{
					Transform transform = ((Component)this).transform;
					Fit((RectTransform)(object)((transform is RectTransform) ? transform : null));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("속박 칸 배치 조정 실패: " + ex.Message));
				}
			}
		}

		private static readonly Dictionary<int, Saved> saved = new Dictionary<int, Saved>();

		private static TMP_Text descText;

		private static bool descSaved;

		private static bool descAuto;

		private static float descMin;

		private static float descMax;

		public static void FitBindings(UI_TrinketPicker picker)
		{
			if (!((Object)(object)picker == (Object)null) && !((Object)(object)picker.bindingIconRoot == (Object)null))
			{
				(((Component)picker.bindingIconRoot).GetComponent<Fitter>() ?? ((Component)picker.bindingIconRoot).gameObject.AddComponent<Fitter>()).dirtyFrame = Time.frameCount;
			}
		}

		private static void Fit(RectTransform root)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			GridLayoutGroup component = ((Component)root).GetComponent<GridLayoutGroup>();
			if (saved.TryGetValue(((Object)root).GetInstanceID(), out var value))
			{
				((Transform)root).localScale = value.scale;
				((Transform)root).position = value.position;
				if ((Object)(object)component != (Object)null)
				{
					component.constraint = value.constraint;
					component.constraintCount = value.constraintCount;
					component.cellSize = value.cellSize;
					component.spacing = value.spacing;
				}
			}
			else
			{
				value = new Saved
				{
					scale = ((Transform)root).localScale,
					position = ((Transform)root).position
				};
				if ((Object)(object)component != (Object)null)
				{
					value.constraint = component.constraint;
					value.constraintCount = component.constraintCount;
					value.cellSize = component.cellSize;
					value.spacing = component.spacing;
				}
				saved[((Object)root).GetInstanceID()] = value;
			}
			List<RectTransform> list = new List<RectTransform>();
			foreach (Transform item in (Transform)root)
			{
				Transform val = item;
				if (((Component)val).gameObject.activeSelf && val is RectTransform)
				{
					list.Add((RectTransform)val);
				}
			}
			if (list.Count <= 9)
			{
				return;
			}
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogWarning((object)"속박 칸에 GridLayoutGroup이 없어 배치를 맞추지 못함");
				return;
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(root);
			Rect val2 = WorldBounds(list, 9);
			int num = CountColumns(list);
			int num2 = Mathf.CeilToInt(9f / (float)num);
			int constraintCount = num;
			float num3 = 0f;
			for (int i = num; i <= num + 3; i++)
			{
				int num4 = Mathf.CeilToInt((float)list.Count / (float)i);
				float num5 = Mathf.Min((float)num / (float)i, (float)num2 / (float)num4);
				if (num5 > num3 + 0.001f)
				{
					num3 = num5;
					constraintCount = i;
				}
			}
			component.constraint = (Constraint)1;
			component.constraintCount = constraintCount;
			((Transform)root).localScale = value.scale * num3;
			LayoutRebuilder.ForceRebuildLayoutImmediate(root);
			Rect val3 = WorldBounds(list, list.Count);
			((Transform)root).position = ((Transform)root).position + new Vector3(((Rect)(ref val2)).center.x - ((Rect)(ref val3)).center.x, ((Rect)(ref val2)).yMax - ((Rect)(ref val3)).yMax, 0f);
			Plugin.Log.LogInfo((object)("속박 칸 배치 조정: " + list.Count + "개, " + num + "열 → " + constraintCount + "열, 크기 ×" + num3.ToString("0.00")));
		}

		private static int CountColumns(List<RectTransform> icons)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			float y = ((Transform)icons[0]).position.y;
			int num = 0;
			foreach (RectTransform icon in icons)
			{
				float num2 = Mathf.Abs(((Transform)icon).position.y - y);
				Rect rect = icons[0].rect;
				if (num2 < 0.01f * Mathf.Max(1f, ((Rect)(ref rect)).height * ((Transform)icons[0]).lossyScale.y))
				{
					num++;
				}
			}
			return Mathf.Max(1, num);
		}

		private static Rect WorldBounds(List<RectTransform> icons, int count)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			float num3 = float.MinValue;
			float num4 = float.MinValue;
			for (int i = 0; i < count && i < icons.Count; i++)
			{
				icons[i].GetWorldCorners(array);
				Vector3[] array2 = array;
				foreach (Vector3 val in array2)
				{
					num = Mathf.Min(num, val.x);
					num2 = Mathf.Min(num2, val.y);
					num3 = Mathf.Max(num3, val.x);
					num4 = Mathf.Max(num4, val.y);
				}
			}
			return Rect.MinMaxRect(num, num2, num3, num4);
		}

		public static void OnShowDescription(UI_TrinketPicker picker, Trinket t)
		{
			TMP_Text val = (((Object)(object)picker != (Object)null) ? picker.descriptionText : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)descText != (Object)(object)val)
			{
				descText = val;
				descSaved = false;
			}
			if (!descSaved)
			{
				descSaved = true;
				descAuto = val.enableAutoSizing;
				descMin = val.fontSizeMin;
				descMax = val.fontSizeMax;
				if (!descAuto)
				{
					descMax = val.fontSize;
				}
			}
			if ((Object)(object)t != (Object)null && (((Object)t).name == "Trinket_Binding_EscapedSubject" || ((Object)t).name == "Trinket_BioExperimented"))
			{
				val.fontSizeMax = descMax;
				val.fontSizeMin = descMax * 0.7f;
				val.enableAutoSizing = true;
			}
			else if (val.enableAutoSizing != descAuto || val.fontSizeMin != descMin)
			{
				val.enableAutoSizing = descAuto;
				val.fontSizeMin = descMin;
				val.fontSizeMax = descMax;
				if (!descAuto)
				{
					val.fontSize = descMax;
				}
			}
		}
	}
	[BepInPlugin("LUNAEGO.EscapedTestSubject", "WK Escaped Test Subject", "0.9.3")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "LUNAEGO.EscapedTestSubject";

		internal static ManualLogSource Log;

		internal static string AssetDir;

		internal static ConfigEntry<string> Language;

		internal static ConfigEntry<int> Cost;

		internal static ConfigEntry<float> ScoreBonus;

		internal static ConfigEntry<float> Gravity;

		internal static ConfigEntry<float> Stamina;

		internal static ConfigEntry<float> Capacity;

		internal static ConfigEntry<float> Health;

		internal static ConfigEntry<float> MoveSpeed;

		internal static ConfigEntry<float> StickyGroundSeconds;

		internal static ConfigEntry<float> StickyDuration;

		internal static ConfigEntry<float> StickyNoDrain;

		internal static ConfigEntry<float> MutateSeconds;

		internal static ConfigEntry<float> TentacleStamina;

		internal static ConfigEntry<float> TentacleRange;

		internal static ConfigEntry<float> PullForce;

		internal static ConfigEntry<float> WallGrabDistance;

		internal static ConfigEntry<float> AnchorGrabRadius;

		internal static ConfigEntry<int> Charges;

		internal static ConfigEntry<string> ChargeKeywords;

		internal static ConfigEntry<float> ShootHold;

		internal static ConfigEntry<float> CounterScale;

		internal static ConfigEntry<bool> DebugKeys;

		internal static bool Korean
		{
			get
			{
				if (Language != null)
				{
					return Language.Value == "Korean";
				}
				return false;
			}
		}

		internal static string L(string en, string ko)
		{
			if (!Korean)
			{
				return en;
			}
			return ko;
		}

		private void Awake()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Expected O, but got Unknown
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			AssetDir = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "Assets");
			Language = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Language", "English", new ConfigDescription("Text language for the binding name and description / 속박 이름·설명 언어", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "English", "Korean" }), Array.Empty<object>()));
			Cost = ((BaseUnityPlugin)this).Config.Bind<int>("Binding", "Cost", 1, "Binding cost (a binding adds this much to the trinket budget)");
			ScoreBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "ScoreMultiplierBonus", 0.35f, "Final score multiplier bonus (0.35 = +35%). Runs with this binding are never submitted to leaderboards");
			Gravity = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "Gravity", 0.2f, "Gravity change (0.2 = +20%)");
			Stamina = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "Stamina", -0.2f, "Stamina change (-0.2 = -20%)");
			Capacity = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "InventoryCapacity", -2f, "Inventory capacity change (-2 = 5 slots down to 3)");
			Health = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "MaxHealth", -0.2f, "Max health change (-0.2 = -20%)");
			MoveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Binding", "MoveSpeed", -0.2f, "Move speed change (-0.2 = -20%)");
			StickyGroundSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sticky", "GroundSeconds", 5f, "Seconds on the ground before Sticky Surface triggers");
			StickyDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Sticky", "Duration", 7f, "Grub effect duration (seconds), counted from the first wall grab after it triggers");
			StickyNoDrain = ((BaseUnityPlugin)this).Config.Bind<float>("Sticky", "NoStaminaDrainSeconds", 5f, "Stamina does not drain for this long after the first wall grab");
			MutateSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "HoldSeconds", 5f, "Seconds you must reach out with a bare hand to mutate");
			Charges = ((BaseUnityPlugin)this).Config.Bind<int>("Mutation", "Charges", 5, "Tentacle shots per mutation");
			ChargeKeywords = ((BaseUnityPlugin)this).Config.Bind<string>("Mutation", "ChargeItemKeywords", "Pill,Injector,Inoculator,Syringe,Adrenaline,Grub,Roach_Lemon", "Items whose name contains one of these words charge the mutation (comma separated, case-insensitive)");
			TentacleStamina = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "TentacleStaminaBonus", 0.35f, "Temporary stamina bonus while in tentacle form (0.35 = +35%). Removed when all shots are used");
			TentacleRange = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "TentacleRange", 30f, "Tentacle range (m). The Barnacle Hook has 20m");
			PullForce = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "PullForceMultiplier", 1.1f, "Tentacle pull force multiplier relative to the Barnacle Hook (1.10 = +10%)");
			WallGrabDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "WallGrabDistance", 2.8f, "Within this distance (m) of the tentacle anchor, the shooting hand can grab bare walls while the button is held");
			AnchorGrabRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "AnchorGrabRadius", 1.4f, "Bare walls can only be grabbed within this radius (m) of the anchor (walls along the pull path can't be grabbed)");
			ShootHold = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "ShootHoldSeconds", 0.75f, "In tentacle form, hold the bare-hand button this long to shoot (grabbing something cancels it)");
			CounterScale = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "CounterScale", 3f, "Scale of the remaining-shots counter at the bottom right");
			DebugKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugKeys", false, "If true: F6 = charge mutation, F7 = instant tentacle form (for testing)");
			new Harmony("LUNAEGO.EscapedTestSubject").PatchAll(typeof(Plugin).Assembly);
			GameObject val = new GameObject("WKEscapedSubject_Controller");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<MutationController>();
			Log.LogInfo((object)("Escaped Test Subject binding loaded (language: " + Language.Value + ")"));
		}
	}
	internal static class Sounds
	{
		public class Player
		{
			private readonly string file;

			private AudioClip clip;

			private bool loaded;

			private AudioSource src;

			public bool IsPlaying
			{
				get
				{
					if ((Object)(object)src != (Object)null)
					{
						return src.isPlaying;
					}
					return false;
				}
			}

			public Player(string file)
			{
				this.file = file;
			}

			public void Play(GameObject host, float volume = 1f)
			{
				if (!loaded)
				{
					clip = LoadWav(file);
					loaded = true;
				}
				if (!((Object)(object)clip == (Object)null))
				{
					if ((Object)(object)src == (Object)null)
					{
						src = host.AddComponent<AudioSource>();
						src.playOnAwake = false;
						src.spatialBlend = 0f;
					}
					if ((Object)(object)Mixer != (Object)null)
					{
						src.outputAudioMixerGroup = Mixer;
					}
					src.clip = clip;
					src.volume = volume;
					src.Play();
				}
			}

			public void Stop()
			{
				if ((Object)(object)src != (Object)null && src.isPlaying)
				{
					src.Stop();
				}
			}
		}

		public static AudioMixerGroup Mixer;

		public static AudioClip LoadWav(string file)
		{
			byte[] array = AssetStore.Read("Sounds/" + file);
			if (array == null)
			{
				Plugin.Log.LogWarning((object)("Sound not found: " + file));
				return null;
			}
			try
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = -1;
				int num5 = 0;
				int num6;
				for (int i = 12; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1))
				{
					string text = Encoding.ASCII.GetString(array, i, 4);
					num6 = BitConverter.ToInt32(array, i + 4);
					if (text == "fmt ")
					{
						num = BitConverter.ToInt16(array, i + 10);
						num2 = BitConverter.ToInt32(array, i + 12);
						num3 = BitConverter.ToInt16(array, i + 22);
					}
					else if (text == "data")
					{
						num4 = i + 8;
						num5 = Math.Min(num6, array.Length - num4);
						break;
					}
				}
				if (num4 < 0 || num3 != 16 || num < 1)
				{
					Plugin.Log.LogWarning((object)("지원하지 않는 WAV 형식(16bit PCM만): " + file));
					return null;
				}
				int num7 = num5 / 2;
				float[] array2 = new float[num7];
				for (int j = 0; j < num7; j++)
				{
					array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f;
				}
				AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(file), num7 / num, num, num2, false);
				typeof(AudioClip).GetMethod("SetData", new Type[2]
				{
					typeof(float[]),
					typeof(int)
				}).Invoke(val, new object[2] { array2, 0 });
				((Object)val).hideFlags = (HideFlags)32;
				Plugin.Log.LogInfo((object)$"소리 로드: {file} ({val.length:0.00}초)");
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("소리 로드 실패 " + file + ": " + ex.Message));
				return null;
			}
		}
	}
	internal static class TentacleFX
	{
		private static ParticleSystem ps;

		private static readonly Color Ink = new Color(0.04f, 0.03f, 0.055f, 1f);

		private static readonly Color Shade = new Color(0.13f, 0.086f, 0.157f, 1f);

		private static readonly Color Sheen = new Color(0.275f, 0.157f, 0.353f, 1f);

		private static ParticleSystem Get()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ps != (Object)null)
			{
				return ps;
			}
			GameObject val = new GameObject("WKEscaped_TentacleFX");
			Object.DontDestroyOnLoad((Object)val);
			ps = val.AddComponent<ParticleSystem>();
			ps.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = ps.main;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			((MainModule)(ref main)).playOnAwake = false;
			((MainModule)(ref main)).loop = false;
			((MainModule)(ref main)).maxParticles = 600;
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(1.2f);
			EmissionModule emission = ps.emission;
			((EmissionModule)(ref emission)).enabled = false;
			ShapeModule shape = ps.shape;
			((ShapeModule)(ref shape)).enabled = false;
			SizeOverLifetimeModule sizeOverLifetime = ps.sizeOverLifetime;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, AnimationCurve.Linear(0f, 1f, 1f, 0.2f));
			LimitVelocityOverLifetimeModule limitVelocityOverLifetime = ps.limitVelocityOverLifetime;
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).enabled = true;
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).dampen = 0.08f;
			((LimitVelocityOverLifetimeModule)(ref limitVelocityOverLifetime)).limit = MinMaxCurve.op_Implicit(0f);
			ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>();
			component.renderMode = (ParticleSystemRenderMode)0;
			((Renderer)component).material = MakeMaterial();
			ps.Play();
			return ps;
		}

		private static Material MakeMaterial()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0091: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00ac: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(8, 8, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 8; j++)
				{
					float num = (float)j - 3.5f;
					float num2 = (float)i - 3.5f;
					val.SetPixel(j, i, (num * num + num2 * num2 <= 11f) ? Color.white : Color.clear);
				}
			}
			val.Apply();
			Shader val2 = Shader.Find("Sprites/Default");
			Material val3;
			if ((Object)(object)val2 != (Object)null)
			{
				val3 = new Material(val2);
			}
			else
			{
				GameObject val4 = new GameObject("tmp");
				val3 = new Material(((Renderer)val4.AddComponent<SpriteRenderer>()).sharedMaterial);
				Object.Destroy((Object)val4);
			}
			val3.mainTexture = (Texture)(object)val;
			return val3;
		}

		private static Color RandomInk()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			float value = Random.value;
			if (!(value < 0.65f))
			{
				if (!(value < 0.9f))
				{
					return Sheen;
				}
				return Shade;
			}
			return Ink;
		}

		public static void Burst(Vector3 start, Vector3 dir)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem val = Get();
			EmitParams val2 = default(EmitParams);
			dir = ((Vector3)(ref dir)).normalized;
			for (int i = 0; i < 40; i++)
			{
				Vector3 val3 = dir + Random.insideUnitSphere * 0.9f;
				Vector3 velocity = ((Vector3)(ref val3)).normalized * Random.Range(0.8f, 3.2f);
				((EmitParams)(ref val2)).position = start + Random.insideUnitSphere * 0.05f;
				((EmitParams)(ref val2)).velocity = velocity;
				((EmitParams)(ref val2)).startSize = Random.Range(0.03f, 0.075f);
				((EmitParams)(ref val2)).startLifetime = Random.Range(0.3f, 0.6f);
				((EmitParams)(ref val2)).startColor = Color32.op_Implicit(RandomInk());
				val.Emit(val2, 1);
			}
			for (int j = 0; j < 18; j++)
			{
				float num = Random.Range(0.1f, 3f);
				((EmitParams)(ref val2)).position = start + dir * num + Random.insideUnitSphere * 0.04f;
				((EmitParams)(ref val2)).velocity = Random.insideUnitSphere * 0.4f + dir * 0.5f;
				((EmitParams)(ref val2)).startSize = Random.Range(0.02f, 0.05f);
				((EmitParams)(ref val2)).startLifetime = Random.Range(0.35f, 0.7f);
				((EmitParams)(ref val2)).startColor = Color32.op_Implicit(RandomInk());
				val.Emit(val2, 1);
			}
		}

		public static void Splat(Vector3 pos, Vector3 normal, float scale = 1f)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			ParticleSystem val = Get();
			EmitParams val2 = default(EmitParams);
			int num = Mathf.RoundToInt(30f * scale);
			for (int i = 0; i < num; i++)
			{
				Vector3 val3 = ((Vector3)(ref normal)).normalized + Random.insideUnitSphere * 0.9f;
				Vector3 velocity = ((Vector3)(ref val3)).normalized * Random.Range(1.2f, 4.5f) * Mathf.Sqrt(scale);
				((EmitParams)(ref val2)).position = pos + normal * 0.03f;
				((EmitParams)(ref val2)).velocity = velocity;
				((EmitParams)(ref val2)).startSize = Random.Range(0.03f, 0.11f) * Mathf.Sqrt(scale);
				((EmitParams)(ref val2)).startLifetime = Random.Range(0.45f, 0.9f);
				((EmitParams)(ref val2)).startColor = Color32.op_Implicit(RandomInk());
				val.Emit(val2, 1);
			}
		}
	}
	internal class TentacleGrapple
	{
		private float distance = 20f;

		private float force = 1f;

		private float deadzone = 3f;

		private float forceTime = 5f;

		private float whipForce = 5f;

		private float whipUp = 2f;

		private float whipTorque = 20f;

		private Vector3 forceMult = Vector3.one;

		private AnimationCurve forceCurve = AnimationCurve.Linear(1f, 1f, 1f, 1f);

		private LayerMask mask = LayerMask.op_Implicit(-1);

		private string[] foodTags = new string[0];

		private string[] lesserFoodTags = new string[0];

		private string[] blacklistTags = new string[0];

		private GameObject kit;

		private UT_AudioClipHandler audio;

		private Transform tentacle;

		private MeshRenderer tentacleRenderer;

		priva