Decompiled source of FreezeRay v1.0.0

FreezeRay.dll

Decompiled 20 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using BoplFixedMath;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FreezeRay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bopl Battle ability: a ray gun that freezes whoever it hits in place.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+68449a836cee4b463c2618bb101bb08a9d84a03a")]
[assembly: AssemblyProduct("FreezeRay")]
[assembly: AssemblyTitle("FreezeRay")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FreezeRay
{
	internal static class FreezableExtras
	{
		private const string ComponentName = "Sheep";

		private const string MethodName = "Freeze";

		private static MethodInfo cachedFreeze;

		private static Type cachedType;

		private static bool searchedForType;

		public static bool TryFreeze(FixTransform target)
		{
			if ((Object)(object)target == (Object)null || target.IsDestroyed)
			{
				return false;
			}
			Component val = FindFreezableComponent(((Component)target).gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			MethodInfo methodInfo = ResolveFreezeMethod(((object)val).GetType());
			if (methodInfo == null)
			{
				Plugin.Log.LogInfo((object)("Freeze Ray: '" + ((Object)((Component)target).gameObject).name + "' has a Sheep component but no usable Freeze(int) method - not frozen."));
				return false;
			}
			try
			{
				methodInfo.Invoke(val, new object[1] { 90 });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Freeze Ray: Sheep.Freeze threw, so it was not frozen: " + ex.Message));
				return false;
			}
			FrozenObjects.Freeze(((Component)target).gameObject, 90);
			AudioManager.Get().Play("shrink");
			Plugin.Log.LogInfo((object)("Freeze Ray: froze '" + ((Object)((Component)target).gameObject).name + "' for " + $"{90} ticks."));
			return true;
		}

		private static Component FindFreezableComponent(GameObject go)
		{
			Component[] components = go.GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "Sheep")
				{
					return val;
				}
			}
			return null;
		}

		private static MethodInfo ResolveFreezeMethod(Type type)
		{
			if (searchedForType && cachedType == type)
			{
				return cachedFreeze;
			}
			searchedForType = true;
			cachedType = type;
			cachedFreeze = type.GetMethod("Freeze", new Type[1] { typeof(int) });
			return cachedFreeze;
		}
	}
	public static class FreezeManager
	{
		private struct FreezeState
		{
			public int TicksRemaining;

			public bool CanUseAbilitiesBeforeFreeze;
		}

		public const int FreezeDurationTicks = 90;

		public const int CrackingStartsAtTicks = 36;

		private static readonly Dictionary<int, FreezeState> frozen = new Dictionary<int, FreezeState>();

		public static bool IsFrozen(int playerId)
		{
			return frozen.ContainsKey(playerId);
		}

		public static int TicksRemaining(int playerId)
		{
			if (!frozen.TryGetValue(playerId, out var value))
			{
				return 0;
			}
			return value.TicksRemaining;
		}

		public static List<int> FrozenPlayerIds()
		{
			return new List<int>(frozen.Keys);
		}

		public static void Freeze(int playerId)
		{
			if (frozen.TryGetValue(playerId, out var value))
			{
				value.TicksRemaining = 90;
				frozen[playerId] = value;
				Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} freeze refreshed to {90} ticks.");
			}
			else
			{
				Player val = SafeGetPlayer(playerId);
				frozen[playerId] = new FreezeState
				{
					TicksRemaining = 90,
					CanUseAbilitiesBeforeFreeze = (val == null || val.CanUseAbilities)
				};
				Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} frozen for {90} ticks.");
			}
		}

		public static void TickAll()
		{
			if (frozen.Count == 0)
			{
				return;
			}
			bool flag = GameTime.IsTimeStopped();
			List<int> list = null;
			foreach (int item in FrozenPlayerIds())
			{
				if (!flag || !GameTime.IsTimeStoppedFor(item))
				{
					Player val = SafeGetPlayer(item);
					if (val != null)
					{
						val.CanUseAbilities = false;
					}
					FreezeState value = frozen[item];
					value.TicksRemaining--;
					if (value.TicksRemaining <= 0)
					{
						(list ?? (list = new List<int>())).Add(item);
					}
					else
					{
						frozen[item] = value;
					}
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item2 in list)
			{
				Thaw(item2, "freeze expired");
			}
		}

		public static void ClearAll()
		{
			if (frozen.Count == 0)
			{
				return;
			}
			Plugin.Log.LogInfo((object)$"Freeze Ray: clearing {frozen.Count} active freeze(s) on round reset.");
			foreach (int item in FrozenPlayerIds())
			{
				Thaw(item, "round reset");
			}
		}

		public static void Clear(int playerId)
		{
			if (frozen.ContainsKey(playerId))
			{
				Thaw(playerId, "player died");
			}
		}

		private static void Thaw(int playerId, string reason)
		{
			if (frozen.TryGetValue(playerId, out var value))
			{
				frozen.Remove(playerId);
				Player val = SafeGetPlayer(playerId);
				if (val == null)
				{
					Plugin.Log.LogInfo((object)($"Freeze Ray: player {playerId} thawed ({reason}), but the Player object " + "was gone so CanUseAbilities was not restored."));
					return;
				}
				val.CanUseAbilities = value.CanUseAbilitiesBeforeFreeze;
				Plugin.Log.LogInfo((object)$"Freeze Ray: player {playerId} thawed ({reason}).");
			}
		}

		private static Player SafeGetPlayer(int playerId)
		{
			PlayerHandler val = PlayerHandler.Get();
			if (val != null)
			{
				return val.GetPlayer(playerId);
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Updater), "TickSimulation")]
	public static class FreezeTickPatch
	{
		public static void Postfix()
		{
			FreezeManager.TickAll();
			FrozenObjects.Tick();
			FreezeVisuals.Sync();
		}
	}
	[HarmonyPatch(typeof(SlimeController), "isAbilityCastable")]
	public static class FreezeBlockCastPatch
	{
		public static bool Prefix(SlimeController __instance, ref bool __result)
		{
			if (!FreezeManager.IsFrozen(__instance.GetPlayerId()))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	internal static class FreezeGate
	{
		public static bool IsFrozen(PlayerPhysics physics)
		{
			IPlayerIdHolder component = ((Component)physics).GetComponent<IPlayerIdHolder>();
			if (component != null)
			{
				return FreezeManager.IsFrozen(component.GetPlayerId());
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerPhysics), "Move")]
	public static class FreezeSuppressMovePatch
	{
		public static bool Prefix(PlayerPhysics __instance)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!FreezeGate.IsFrozen(__instance))
			{
				return true;
			}
			__instance.groundedSpeed = Fix.Zero;
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerPhysics), "UpdateSim")]
	public static class FreezeSuppressUpdateSimPatch
	{
		public static bool Prefix(PlayerPhysics __instance)
		{
			return !FreezeGate.IsFrozen(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerBody), "UpdateSim")]
	public static class FreezeHoldBodyStillPatch
	{
		public static void Prefix(PlayerBody __instance)
		{
			//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_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)
			IPlayerIdHolder component = ((Component)__instance).GetComponent<IPlayerIdHolder>();
			if (component != null && FreezeManager.IsFrozen(component.GetPlayerId()))
			{
				__instance.selfImposedVelocity = Vec2.zero;
				__instance.externalVelocity = Vec2.zero;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHandler), "ResetForNextStage")]
	public static class FreezeResetOnStagePatch
	{
		public static void Prefix()
		{
			FreezeManager.ClearAll();
			FrozenObjects.ClearAll();
			FreezeVisuals.DestroyAll();
		}
	}
	[HarmonyPatch(typeof(Player), "Kill")]
	public static class FreezeClearOnDeathPatch
	{
		public static void Prefix(Player __instance)
		{
			FreezeManager.Clear(__instance.Id);
		}
	}
	public static class FreezeRayAbility
	{
		public const string AbilityName = "freezeray";

		public const int CooldownSeconds = 3;

		public const float IconScale = 0.85f;

		private const string TemplateNameFragment = "grow";

		public static bool IsFreezeRay(GameObject go)
		{
			if ((Object)(object)go != (Object)null)
			{
				return ((Object)go).name.ToLower().Contains("freezeray");
			}
			return false;
		}

		public static Sprite LoadIcon(Sprite template)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_016d: 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_018a: 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_01b8: 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)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("FreezeRay.AbilityIcon.png");
			if (stream == null)
			{
				Plugin.Log.LogError((object)"Freeze Ray: embedded resource 'FreezeRay.AbilityIcon.png' not found; falling back to the cloned ability's own icon.");
				return null;
			}
			byte[] array;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			Texture2D val = new Texture2D(1, 1);
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogError((object)"Freeze Ray: embedded icon failed to decode as a PNG; falling back to the cloned ability's own icon.");
				return null;
			}
			float num = 100f;
			if ((Object)(object)template != (Object)null)
			{
				Rect val2 = template.rect;
				if (((Rect)(ref val2)).width > 0f)
				{
					float pixelsPerUnit = template.pixelsPerUnit;
					float num2 = ((Texture)val).width;
					val2 = template.rect;
					num = pixelsPerUnit * (num2 / ((Rect)(ref val2)).width) / 0.85f;
					ManualLogSource log = Plugin.Log;
					string text = $"Freeze Ray: icon built at {num:0.#} pixels/unit to match the ";
					val2 = template.rect;
					log.LogInfo((object)(text + $"cloned ability ({((Rect)(ref val2)).width:0}px at {template.pixelsPerUnit:0.#})."));
					ManualLogSource log2 = Plugin.Log;
					string[] obj = new string[8]
					{
						"Freeze Ray: [icon-bg] template texture '",
						((Object)template.texture).name,
						"' ",
						$"{((Texture)template.texture).width}x{((Texture)template.texture).height}, ",
						$"textureRect {template.textureRect}, ",
						null,
						null,
						null
					};
					val2 = template.textureRect;
					obj[5] = $"centre ({((Rect)(ref val2)).center.x / (float)((Texture)template.texture).width:0.###}, ";
					val2 = template.textureRect;
					obj[6] = $"{((Rect)(ref val2)).center.y / (float)((Texture)template.texture).height:0.###}) ";
					obj[7] = $"| ours {((Texture)val).width}x{((Texture)val).height}, centre (0.5, 0.5)";
					log2.LogInfo((object)string.Concat(obj));
					goto IL_0221;
				}
			}
			Plugin.Log.LogWarning((object)"Freeze Ray: could not read the cloned ability's sprite scale, so the icon uses Unity's default 100 pixels/unit and may look oversized.");
			goto IL_0221;
			IL_0221:
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), num);
		}
	}
	[HarmonyPatch(typeof(AbilityGrid), "Awake")]
	public static class AbilityInjectionPatch
	{
		private static bool hasInjected;

		public static void Prefix(AbilityGrid __instance)
		{
			//IL_0032: 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_0052: 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_0073: 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_0096: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (hasInjected)
			{
				return;
			}
			NamedSpriteList abilityIcons = __instance.abilityIcons;
			if ((Object)(object)abilityIcons == (Object)null || abilityIcons.sprites == null)
			{
				Plugin.Log.LogWarning((object)"Freeze Ray: AbilityGrid.abilityIcons was empty this Awake; not injecting yet (will retry on the next grid build).");
				return;
			}
			NamedSprite val = default(NamedSprite);
			bool flag = false;
			foreach (NamedSprite sprite in abilityIcons.sprites)
			{
				if (sprite.name != null && sprite.name.ToLower().Contains("grow"))
				{
					val = sprite;
					flag = true;
					break;
				}
			}
			if (!flag || (Object)(object)val.associatedGameObject == (Object)null)
			{
				Plugin.Log.LogError((object)"Freeze Ray: could not find the native grow ray to clone, so the ability was not added. (Looked for an ability whose name contains 'grow' in AbilityGrid.abilityIcons.)");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.associatedGameObject);
			Object.DontDestroyOnLoad((Object)(object)val2);
			((Object)val2).name = "freezeray";
			Ability component = val2.GetComponent<Ability>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)"Freeze Ray: the cloned ray has no Ability component, so its cooldown could not be set; it will keep the grow ray's cooldown.");
			}
			else
			{
				component.Cooldown = (Fix)3L;
			}
			Sprite val3 = FreezeRayAbility.LoadIcon(val.sprite) ?? val.sprite;
			abilityIcons.sprites.Add(new NamedSprite("freezeray", val3, val2, true));
			hasInjected = true;
			Plugin.Log.LogInfo((object)("Freeze Ray: ability injected into the select grid " + $"(cloned '{val.name}', cooldown {3}s)."));
		}
	}
	public static class FreezeVisuals
	{
		private const float CubeWorldSize = 2.2f;

		private const float CubeSizeVsPlayer = 1.45f;

		public const float CubeSizeVsTarget = 1.09f;

		private const int StageCount = 4;

		private static Sprite[] stages;

		private static bool loadAttempted;

		private static bool loadFailed;

		private static bool announced;

		private static readonly Dictionary<int, GameObject> cubes = new Dictionary<int, GameObject>();

		private static readonly Dictionary<int, SpriteRenderer> targets = new Dictionary<int, SpriteRenderer>();

		private static readonly Dictionary<int, bool> cachedIsSlime = new Dictionary<int, bool>();

		private static readonly Dictionary<int, GameObject> objectCubes = new Dictionary<int, GameObject>();

		public static void Sync()
		{
			if (loadFailed)
			{
				return;
			}
			if (!loadAttempted)
			{
				loadAttempted = true;
				if (!LoadStages())
				{
					loadFailed = true;
					return;
				}
				Plugin.Log.LogInfo((object)$"Freeze Ray: ice visuals ready ({4} stages loaded).");
			}
			foreach (int item in FreezeManager.FrozenPlayerIds())
			{
				if (!cubes.TryGetValue(item, out var value) || (Object)(object)value == (Object)null)
				{
					value = CreateCube();
					cubes[item] = value;
				}
				PositionCube(item, value);
			}
			SyncObjectCubes();
			List<int> list = null;
			foreach (KeyValuePair<int, GameObject> cube in cubes)
			{
				if (!FreezeManager.IsFrozen(cube.Key))
				{
					(list ?? (list = new List<int>())).Add(cube.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item2 in list)
			{
				GameObject val = cubes[item2];
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				cubes.Remove(item2);
				targets.Remove(item2);
				cachedIsSlime.Remove(item2);
			}
		}

		private static void SyncObjectCubes()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			foreach (int item in FrozenObjects.FrozenIds())
			{
				if (FrozenObjects.TryGet(item, out var target, out var renderer, out var cubeWidth))
				{
					if (!objectCubes.TryGetValue(item, out var value) || (Object)(object)value == (Object)null)
					{
						value = CreateCube();
						objectCubes[item] = value;
					}
					value.SetActive(true);
					value.transform.position = target.transform.position;
					float num = cubeWidth / 2.2f;
					value.transform.localScale = new Vector3(num, num, 1f);
					SpriteRenderer component = value.GetComponent<SpriteRenderer>();
					if ((Object)(object)renderer != (Object)null)
					{
						((Renderer)component).sortingLayerID = ((Renderer)renderer).sortingLayerID;
						((Renderer)component).sortingOrder = ((Renderer)renderer).sortingOrder + 1;
					}
					else
					{
						((Renderer)component).sortingOrder = 1000;
					}
					component.sprite = stages[StageForRemainingTicks(FrozenObjects.TicksRemaining(item))];
				}
			}
			List<int> list = null;
			foreach (KeyValuePair<int, GameObject> objectCube in objectCubes)
			{
				if (!FrozenObjects.IsFrozen(objectCube.Key))
				{
					(list ?? (list = new List<int>())).Add(objectCube.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item2 in list)
			{
				if ((Object)(object)objectCubes[item2] != (Object)null)
				{
					Object.Destroy((Object)(object)objectCubes[item2]);
				}
				objectCubes.Remove(item2);
			}
		}

		public static void DestroyAll()
		{
			foreach (KeyValuePair<int, GameObject> cube in cubes)
			{
				if ((Object)(object)cube.Value != (Object)null)
				{
					Object.Destroy((Object)(object)cube.Value);
				}
			}
			foreach (KeyValuePair<int, GameObject> objectCube in objectCubes)
			{
				if ((Object)(object)objectCube.Value != (Object)null)
				{
					Object.Destroy((Object)(object)objectCube.Value);
				}
			}
			objectCubes.Clear();
			cubes.Clear();
			targets.Clear();
			cachedIsSlime.Clear();
		}

		private static GameObject CreateCube()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			GameObject val = new GameObject("FreezeRayIceCube");
			val.AddComponent<SpriteRenderer>().sprite = stages[0];
			if (!announced)
			{
				announced = true;
				Plugin.Log.LogInfo((object)"Freeze Ray: first ice block spawned.");
			}
			return val;
		}

		private static void PositionCube(int playerId, GameObject cube)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			bool isSlime;
			SpriteRenderer val = ResolveTarget(playerId, out isSlime);
			if ((Object)(object)val == (Object)null)
			{
				cube.SetActive(false);
				return;
			}
			cube.SetActive(true);
			SpriteRenderer component = cube.GetComponent<SpriteRenderer>();
			cube.transform.position = ((Component)val).transform.position;
			float num = Mathf.Max(0.01f, PlayerScaleOf(playerId)) * 1.45f;
			cube.transform.localScale = new Vector3(num, num, 1f);
			((Renderer)component).sortingLayerID = ((Renderer)val).sortingLayerID;
			((Renderer)component).sortingOrder = ((Renderer)val).sortingOrder + 1;
			component.sprite = stages[StageForRemainingTicks(FreezeManager.TicksRemaining(playerId))];
		}

		private static float PlayerScaleOf(int playerId)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null)
			{
				return (float)val2.Scale;
			}
			return 1f;
		}

		private static SpriteRenderer ResolveTarget(int playerId, out bool isSlime)
		{
			isSlime = false;
			if (targets.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && ((Component)value).gameObject.activeInHierarchy)
			{
				cachedIsSlime.TryGetValue(playerId, out isSlime);
				return value;
			}
			SpriteRenderer val = null;
			bool flag = false;
			SlimeController[] array = Object.FindObjectsOfType<SlimeController>();
			foreach (SlimeController val2 in array)
			{
				if (val2.GetPlayerId() == playerId)
				{
					SpriteRenderer playerSprite = val2.GetPlayerSprite();
					if ((Object)(object)playerSprite != (Object)null && ((Component)playerSprite).gameObject.activeInHierarchy)
					{
						val = playerSprite;
						flag = true;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Ability[] array2 = Object.FindObjectsOfType<Ability>();
				foreach (Ability val3 in array2)
				{
					if (val3.GetPlayerId() == playerId)
					{
						SpriteRenderer component = ((Component)val3).GetComponent<SpriteRenderer>();
						if ((Object)(object)component != (Object)null && ((Component)component).gameObject.activeInHierarchy)
						{
							val = component;
							break;
						}
					}
				}
			}
			targets[playerId] = val;
			cachedIsSlime[playerId] = flag;
			isSlime = flag;
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)($"Freeze Ray: no active sprite found for frozen player {playerId}; " + "hiding their ice block this tick."));
			}
			return val;
		}

		private static int StageForRemainingTicks(int remaining)
		{
			if (remaining > 36)
			{
				return 0;
			}
			int num = 12;
			if (num < 1)
			{
				num = 1;
			}
			return Mathf.Clamp(3 - remaining / num, 0, 3);
		}

		private static bool LoadStages()
		{
			//IL_0066: 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)
			Sprite[] array = (Sprite[])(object)new Sprite[4];
			for (int i = 0; i < 4; i++)
			{
				string text = $"FreezeRay.IceCube{i}.png";
				Texture2D val = LoadTexture(text);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)("Freeze Ray: could not load embedded '" + text + "', so frozen players will have no visible ice. The freeze itself still works."));
					return false;
				}
				array[i] = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width / 2.2f);
			}
			stages = array;
			return true;
		}

		private static Texture2D LoadTexture(string resourceName)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				return null;
			}
			byte[] array;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			Texture2D val = new Texture2D(1, 1);
			return ImageConversion.LoadImage(val, array) ? val : null;
		}
	}
	public static class FrozenObjects
	{
		private class Entry
		{
			public GameObject Target;

			public SpriteRenderer Renderer;

			public int TicksRemaining;

			public float CubeWidth;
		}

		private static readonly Dictionary<int, Entry> frozen = new Dictionary<int, Entry>();

		public static void Freeze(GameObject target, int ticks)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)target).GetInstanceID();
			if (frozen.TryGetValue(instanceID, out var value))
			{
				value.TicksRemaining = ticks;
				return;
			}
			SpriteRenderer componentInChildren = target.GetComponentInChildren<SpriteRenderer>();
			float num;
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				Bounds bounds = ((Renderer)componentInChildren).bounds;
				float x = ((Bounds)(ref bounds)).size.x;
				bounds = ((Renderer)componentInChildren).bounds;
				num = Mathf.Max(x, ((Bounds)(ref bounds)).size.y);
			}
			else
			{
				num = 2f;
			}
			float num2 = num;
			frozen[instanceID] = new Entry
			{
				Target = target,
				Renderer = componentInChildren,
				TicksRemaining = ticks,
				CubeWidth = Mathf.Max(0.5f, num2 * 1.09f)
			};
		}

		public static void Tick()
		{
			if (frozen.Count == 0)
			{
				return;
			}
			List<int> list = null;
			foreach (KeyValuePair<int, Entry> item in frozen)
			{
				Entry value = item.Value;
				if ((Object)(object)value.Target == (Object)null || --value.TicksRemaining <= 0)
				{
					(list ?? (list = new List<int>())).Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item2 in list)
			{
				frozen.Remove(item2);
			}
		}

		public static List<int> FrozenIds()
		{
			return new List<int>(frozen.Keys);
		}

		public static bool TryGet(int id, out GameObject target, out SpriteRenderer renderer, out float cubeWidth)
		{
			if (frozen.TryGetValue(id, out var value) && (Object)(object)value.Target != (Object)null)
			{
				target = value.Target;
				renderer = value.Renderer;
				cubeWidth = value.CubeWidth;
				return true;
			}
			target = null;
			renderer = null;
			cubeWidth = 0f;
			return false;
		}

		public static bool IsFrozen(int id)
		{
			if (frozen.TryGetValue(id, out var value))
			{
				return (Object)(object)value.Target != (Object)null;
			}
			return false;
		}

		public static int TicksRemaining(int id)
		{
			if (!frozen.TryGetValue(id, out var value))
			{
				return 0;
			}
			return value.TicksRemaining;
		}

		public static void ClearAll()
		{
			frozen.Clear();
		}
	}
	[BepInPlugin("com.maha.boplbattle.freezeray", "Freeze Ray", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.maha.boplbattle.freezeray";

		public const string PluginName = "Freeze Ray";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Freeze Ray: loading...");
			new Harmony("com.maha.boplbattle.freezeray").PatchAll();
			Log.LogInfo((object)"Freeze Ray: Harmony patches applied.");
			Log.LogInfo((object)($"Freeze Ray: loaded (freeze {90} ticks / " + $"{1.5f:0.##}s, cooldown {3}s)."));
		}
	}
	[HarmonyPatch(typeof(ShootScaleChange), "ApplyScaleChange")]
	public static class FreezeOnHitPatch
	{
		public static bool Prefix(ShootScaleChange __instance, RaycastInformation hit, Vec2 firepoint, Vec2 direction, ref bool hasFired, int playerId)
		{
			//IL_000f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!FreezeRayAbility.IsFreezeRay(((Component)__instance).gameObject))
			{
				return true;
			}
			if (hit.layer == LayerMask.NameToLayer("Water"))
			{
				return true;
			}
			__instance.spawnRayCastEffect((Vector2)firepoint, (Vector2)direction, (float)hit.nearDist, true, false);
			if (hit.layer != LayerMask.NameToLayer("Player"))
			{
				if (!FreezableExtras.TryFreeze(hit.pp.fixTrans))
				{
					Plugin.Log.LogInfo((object)("Freeze Ray: beam hit layer '" + LayerMask.LayerToName(hit.layer) + "', which is not a player - no freeze applied."));
				}
				hasFired = true;
				return false;
			}
			FixTransform fixTrans = hit.pp.fixTrans;
			if ((Object)(object)fixTrans == (Object)null || fixTrans.IsDestroyed)
			{
				Plugin.Log.LogInfo((object)"Freeze Ray: hit a player-layer collider whose FixTransform was already destroyed - no freeze applied.");
				hasFired = true;
				return false;
			}
			IPlayerIdHolder component = ((Component)fixTrans).GetComponent<IPlayerIdHolder>();
			if (component == null)
			{
				if (!FreezableExtras.TryFreeze(fixTrans))
				{
					Plugin.Log.LogInfo((object)("Freeze Ray: hit '" + ((Object)((Component)fixTrans).gameObject).name + "' on the Player layer, but it has no IPlayerIdHolder so its owner is unknown - no freeze applied."));
				}
				hasFired = true;
				return false;
			}
			FreezeManager.Freeze(component.GetPlayerId());
			AudioManager.Get().Play("shrink");
			hasFired = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(ShootScaleChange), "spawnRayCastEffect")]
	public static class BeamTintPatch
	{
		private static readonly Color IceBlue = new Color(0.35f, 0.8f, 1f, 1f);

		public static void Prefix(ShootScaleChange __instance)
		{
			if (FreezeRayAbility.IsFreezeRay(((Component)__instance).gameObject))
			{
				Tint(Traverse.Create((object)__instance).Field("rayParticle").GetValue<ParticleSystem>());
				Tint(Traverse.Create((object)__instance).Field("hitParticle").GetValue<ParticleSystem>());
			}
		}

		private static void Tint(ParticleSystem system)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)system == (Object)null))
			{
				ParticleSystem[] componentsInChildren = ((Component)system).GetComponentsInChildren<ParticleSystem>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					MainModule main = componentsInChildren[i].main;
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(IceBlue);
				}
			}
		}
	}
}