Decompiled source of Boomerang v1.0.0

Boomerang.dll

Decompiled 23 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 System.Security;
using System.Security.Permissions;
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("Boomerang")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Bopl Battle ability: throw spinning playing cards that hang, then boomerang back.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+22f84b185125560232de604ea7376155da4310fa")]
[assembly: AssemblyProduct("Boomerang")]
[assembly: AssemblyTitle("Boomerang")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 Boomerang
{
	public static class BoomerangAbility
	{
		public const string AbilityName = "boomerang";

		public const string TemplateNameFragment = "grenade";

		public const float CooldownSeconds = 2.45f;

		public static readonly Fix ThrowDistance = (Fix)14.5f;

		public static readonly Fix MinThrowDistanceScale = (Fix)0.25;

		public static readonly Fix MaxThrowDistanceScale = (Fix)1.5;

		public static readonly Fix FullHoldSeconds = (Fix)1L;

		public static readonly Fix MinOutSpeed = (Fix)18L;

		public static readonly Fix MaxOutSpeed = (Fix)46L;

		public static readonly Fix ReturnSpeed = (Fix)60L;

		public const int SpinTicks = 90;

		public const int MaxReturnTicks = 180;

		public static readonly Fix CatchRadius = (Fix)2L;

		public static readonly Fix HitRadius = (Fix)2L;

		public const float SpinDegreesPerTick = 13f;

		public const float IconScale = 0.78f;

		public const float BoomerangWorldWidth = 4.2f;

		public const int BlinkTicks = 40;

		public const int BlinkPeriodTicks = 5;

		public static readonly Fix BlackHolePull = (Fix)0.6;

		public static readonly Fix BlackHoleSwallowRadius = (Fix)1L;

		public static readonly Fix FallbackBlackHoleMass = (Fix)1L;

		public static readonly Fix ShockwavePush = (Fix)0.55;

		public static readonly Fix DriftDecayPerTick = (Fix)0.97;

		public static readonly Fix MaxDriftSpeed = (Fix)30L;

		public static Fix ThrowDistanceFor(Fix heldSeconds)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_000b: 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_0011: 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)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			Fix val = Fix.Clamp01(heldSeconds / FullHoldSeconds);
			return ThrowDistance * Fix.Lerp(MinThrowDistanceScale, MaxThrowDistanceScale, val);
		}

		public static Fix OutSpeedFor(Fix heldSeconds)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_000b: 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_0011: 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)
			//IL_001b: 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)
			Fix val = Fix.Clamp01(heldSeconds / FullHoldSeconds);
			return Fix.Lerp(MinOutSpeed, MaxOutSpeed, val);
		}

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

		public static Sprite LoadBoomerang()
		{
			Texture2D val = LoadTexture("Boomerang.Boomerang.png");
			if (!((Object)(object)val == (Object)null))
			{
				return Build(val, (float)((Texture)val).width / 4.2f);
			}
			return null;
		}

		public static Sprite LoadIcon(string name, Sprite reference)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture("Boomerang." + name + ".png");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			float pixelsPerUnit = 100f;
			if ((Object)(object)reference != (Object)null)
			{
				Rect rect = reference.rect;
				if (((Rect)(ref rect)).width > 0f)
				{
					float pixelsPerUnit2 = reference.pixelsPerUnit;
					float num = ((Texture)val).width;
					rect = reference.rect;
					pixelsPerUnit = pixelsPerUnit2 * (num / ((Rect)(ref rect)).width) / 0.78f;
				}
			}
			return Build(val, pixelsPerUnit);
		}

		private static Sprite Build(Texture2D texture, float pixelsPerUnit)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
		}

		private static Texture2D LoadTexture(string resourceName)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				Plugin.Log.LogError((object)("Boomerang: embedded resource '" + resourceName + "' not found."));
				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)("Boomerang: '" + resourceName + "' failed to decode as a PNG."));
				return null;
			}
			return val;
		}
	}
	[HarmonyPatch(typeof(AbilityGrid), "Awake")]
	public static class CardInjectionPatch
	{
		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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_012f: 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)"Boomerang: 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("grenade"))
				{
					val = sprite;
					flag = true;
					break;
				}
			}
			if (!flag || (Object)(object)val.associatedGameObject == (Object)null)
			{
				Plugin.Log.LogError((object)"Boomerang: could not find a native instant ability to clone, so the cards were not added. (Looked for an ability whose name contains 'grenade'.)");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.associatedGameObject);
			Object.DontDestroyOnLoad((Object)(object)val2);
			((Object)val2).name = "boomerang";
			Ability component = val2.GetComponent<Ability>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)("Boomerang: '" + val.name + "' has no Ability component, so its cooldown could not be set; it keeps the grenade's."));
			}
			else
			{
				component.Cooldown = (Fix)2.45f;
			}
			SwapInHandSprite(val2);
			Sprite val3 = BoomerangAbility.LoadIcon("AbilityIconBoomerang", val.sprite) ?? val.sprite;
			abilityIcons.sprites.Add(new NamedSprite("boomerang", val3, val2, true));
			hasInjected = true;
			Plugin.Log.LogInfo((object)("Boomerang: ability injected into the select grid (cloned " + $"'{val.name}', cooldown {2.45f}s)."));
		}

		private static void SwapInHandSprite(GameObject clone)
		{
			if (clone.transform.childCount <= 1)
			{
				Plugin.Log.LogInfo((object)"Boomerang: the clone has no in-hand dummy, so it may still look like a grenade while you aim.");
				return;
			}
			SpriteRenderer componentInChildren = ((Component)clone.transform.GetChild(1)).GetComponentInChildren<SpriteRenderer>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				Plugin.Log.LogInfo((object)"Boomerang: no sprite on the in-hand dummy, so it may still look like a grenade while you aim.");
				return;
			}
			Sprite val = BoomerangVisuals.BoomerangSprite();
			if ((Object)(object)val != (Object)null)
			{
				componentInChildren.sprite = val;
			}
		}
	}
	[HarmonyPatch(typeof(ThrowItem2), "SpawnGrenade")]
	public static class BoomerangAppearancePatch
	{
		public static void Postfix(ThrowItem2 __instance)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (!BoomerangAbility.IsBoomerang(((Component)__instance).gameObject))
			{
				return;
			}
			BoplBody value = Traverse.Create((object)__instance).Field("grenadeBody").GetValue<BoplBody>();
			if ((Object)(object)value == (Object)null)
			{
				return;
			}
			GrenadeExplode component = ((Component)value).GetComponent<GrenadeExplode>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Grenade component2 = ((Component)value).GetComponent<Grenade>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.timedExplosion = false;
				component2.selfDestructDelay = -Fix.One;
			}
			SpriteRenderer componentInChildren = ((Component)value).GetComponentInChildren<SpriteRenderer>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Boomerang: the in-hand body has no SpriteRenderer, so it still looks like a grenade while you aim.");
				return;
			}
			Sprite val = BoomerangVisuals.BoomerangSprite();
			if ((Object)(object)val != (Object)null)
			{
				componentInChildren.sprite = val;
			}
		}
	}
	[HarmonyPatch(typeof(ThrowItem2), "ExitAbility", new Type[] { typeof(AbilityExitInfo) })]
	public static class BoomerangNoDropPatch
	{
		public static void Prefix(ThrowItem2 __instance)
		{
			if (!BoomerangAbility.IsBoomerang(((Component)__instance).gameObject))
			{
				return;
			}
			Traverse val = Traverse.Create((object)__instance);
			if (!val.Field("hasFired").GetValue<bool>())
			{
				BoplBody value = val.Field("grenadeBody").GetValue<BoplBody>();
				if ((Object)(object)value != (Object)null && !((MonoUpdatable)value).IsDestroyed)
				{
					Updater.DestroyFix(((Component)value).gameObject);
					Plugin.Log.LogInfo((object)"Boomerang: the throw was cancelled, so the item was removed rather than dropped.");
				}
				val.Field("grenade").SetValue((object)null);
				val.Field("grenadeBody").SetValue((object)null);
			}
		}
	}
	[HarmonyPatch(typeof(ThrowItem2), "Fire")]
	public static class BoomerangReleasePatch
	{
		public static void Postfix(ThrowItem2 __instance)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			if (!BoomerangAbility.IsBoomerang(((Component)__instance).gameObject))
			{
				return;
			}
			Ability component = ((Component)__instance).GetComponent<Ability>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Boomerang: the thrower has no Ability component, so no boomerang was thrown.");
				return;
			}
			int playerId = component.GetPlayerId();
			int abilityButtonUsedIndex = component.GetPlayerInfo().AbilityButtonUsedIndex012;
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null)
			{
				Traverse obj = Traverse.Create((object)__instance);
				Vec2 value = obj.Field("dir").GetValue<Vec2>();
				Fix value2 = obj.Field("FireInputTimeStamp").GetValue<Fix>();
				BoomerangState.Throw(playerId, abilityButtonUsedIndex, val2.Position, value, BoomerangAbility.ThrowDistanceFor(value2), BoomerangAbility.OutSpeedFor(value2));
				BoplBody value3 = obj.Field("grenadeBody").GetValue<BoplBody>();
				if ((Object)(object)value3 != (Object)null && !((MonoUpdatable)value3).IsDestroyed)
				{
					Updater.DestroyFix(((Component)value3).gameObject);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Shockwave), "ActivateShockWave")]
	public static class BoomerangShockwavePatch
	{
		public static void Postfix(Shockwave __instance)
		{
			//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_002f: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_003c: 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)
			FixTransform component = ((Component)__instance).GetComponent<FixTransform>();
			if (!((Object)(object)component == (Object)null) && !component.IsDestroyed)
			{
				Fix val = Traverse.Create((object)__instance).Field("scale").GetValue<Fix>();
				if (val <= Fix.Zero)
				{
					val = Fix.One;
				}
				BoomerangState.Shove(component.position, __instance.radius * val, __instance.defaultForce);
			}
		}
	}
	[HarmonyPatch(typeof(Updater), "TickSimulation")]
	public static class CardTickPatch
	{
		public static void Postfix()
		{
			BoomerangState.Tick();
			BoomerangState.PinCooldownsWhileCardsOut();
		}
	}
	[HarmonyPatch(typeof(PlayerHandler), "ResetForNextStage")]
	public static class CardResetPatch
	{
		public static void Prefix()
		{
			PlayerBodies.ForgetAll();
			BoomerangState.ClearAll();
		}
	}
	[HarmonyPatch(typeof(Updater), "PreLevelLoad")]
	public static class CardLevelLoadPatch
	{
		public static void Prefix()
		{
			BoomerangState.ClearAll();
		}
	}
	public static class BoomerangSound
	{
		private const string ResourceName = "Boomerang.Pickup.wav";

		private const float Volume = 0.6f;

		private static AudioClip clip;

		private static bool loadAttempted;

		public static void PlayPickup(Vector3 position)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!loadAttempted)
			{
				loadAttempted = true;
				clip = Load();
			}
			if (!((Object)(object)clip == (Object)null))
			{
				AudioSource.PlayClipAtPoint(clip, position, 0.6f);
			}
		}

		private static AudioClip Load()
		{
			byte[] data;
			using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Boomerang.Pickup.wav"))
			{
				if (stream == null)
				{
					Plugin.Log.LogWarning((object)"Boomerang: 'Boomerang.Pickup.wav' not found, so catching it will be silent.");
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				data = memoryStream.ToArray();
			}
			try
			{
				return ParseWav(data);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Boomerang: the pickup chime could not be read, so catching a card will be silent: " + ex.Message));
				return null;
			}
		}

		private static AudioClip ParseWav(byte[] data)
		{
			if (data.Length < 12 || data[0] != 82 || data[1] != 73 || data[2] != 70 || data[3] != 70 || data[8] != 87 || data[9] != 65 || data[10] != 86 || data[11] != 69)
			{
				throw new Exception("not a RIFF/WAVE file");
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = -1;
			int num5 = 0;
			int num6 = 12;
			while (num6 + 8 <= data.Length)
			{
				char c = (char)data[num6];
				string text = c.ToString();
				c = (char)data[num6 + 1];
				string text2 = c.ToString();
				c = (char)data[num6 + 2];
				string text3 = c.ToString();
				c = (char)data[num6 + 3];
				string text4 = text + text2 + text3 + c;
				int num7 = BitConverter.ToInt32(data, num6 + 4);
				int num8 = num6 + 8;
				if (text4 == "fmt ")
				{
					num = BitConverter.ToInt16(data, num8 + 2);
					num2 = BitConverter.ToInt32(data, num8 + 4);
					num3 = BitConverter.ToInt16(data, num8 + 14);
				}
				else if (text4 == "data")
				{
					num4 = num8;
					num5 = Math.Min(num7, data.Length - num8);
				}
				num6 = num8 + num7 + num7 % 2;
			}
			if (num4 < 0 || num <= 0 || num2 <= 0)
			{
				throw new Exception("missing fmt or data chunk");
			}
			if (num3 != 16)
			{
				throw new Exception($"only 16-bit PCM is supported, this is {num3}-bit");
			}
			int num9 = num5 / 2;
			float[] array = new float[num9];
			for (int i = 0; i < num9; i++)
			{
				array[i] = (float)BitConverter.ToInt16(data, num4 + i * 2) / 32768f;
			}
			AudioClip obj = AudioClip.Create("CardPickup", num9 / num, num, num2, false);
			obj.SetData(array, 0);
			Plugin.Log.LogInfo((object)($"Boomerang: pickup chime loaded ({num9 / num} samples, " + $"{num}ch, {num2}Hz)."));
			return obj;
		}
	}
	public static class BoomerangState
	{
		private enum Phase
		{
			Outbound,
			Spinning,
			Returning
		}

		private class Card
		{
			public GameObject Visual;

			public SpriteRenderer Renderer;

			public int OwnerId;

			public int Slot;

			public Phase Phase;

			public Vec2 Position;

			public Vec2 Direction;

			public Vec2 StopPoint;

			public Fix OutSpeed;

			public int SpinTicksLeft;

			public int TicksAlive;

			public int ReturnTicks;

			public float SpinAngle;

			public Vec2 Drift;

			public Fix Scale;

			public bool Swallowed;
		}

		private static readonly List<Card> cards = new List<Card>();

		private static readonly Dictionary<int, SlimeController> controllers = new Dictionary<int, SlimeController>();

		private static bool warnedAboutMass;

		public static long KeyFor(int playerId, int slot)
		{
			return (long)playerId * 16L + slot;
		}

		public static void Throw(int playerId, int slot, Vec2 origin, Vec2 aim, Fix distance, Fix outSpeed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0023: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (Vec2.SqrMagnitude(aim) <= Fix.Zero)
			{
				aim = Vec2.up;
			}
			aim = Vec2.Normalized(aim);
			Spawn(playerId, slot, origin, aim, distance, outSpeed);
			Plugin.Log.LogInfo((object)($"Boomerang: player {playerId} threw one " + $"{(float)distance:0.#} units."));
		}

		private static void Spawn(int playerId, int slot, Vec2 origin, Vec2 direction, Fix range, Fix outSpeed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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_0083: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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_0014: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Fix val = range;
			DetPhysics val2 = DetPhysics.Get();
			if ((Object)(object)val2 != (Object)null)
			{
				RaycastInformation val3 = val2.RaycastToClosest(origin, direction, range, LayerMask.op_Implicit(LayerMask.GetMask(new string[1] { "wall" })));
				if (RaycastInformation.op_Implicit(val3) && val3.nearDist < val)
				{
					val = Fix.Max(Fix.Zero, val3.nearDist - (Fix)0.4f);
				}
			}
			Fix val4 = ScaleOf(playerId);
			Card card = new Card
			{
				OwnerId = playerId,
				Scale = val4,
				OutSpeed = outSpeed,
				Slot = slot,
				Phase = Phase.Outbound,
				Position = origin,
				Direction = direction,
				StopPoint = origin + direction * val,
				SpinTicksLeft = 90
			};
			card.Visual = new GameObject("ThrownCard");
			card.Renderer = card.Visual.AddComponent<SpriteRenderer>();
			card.Renderer.sprite = BoomerangVisuals.BoomerangSprite();
			((Renderer)card.Renderer).sortingOrder = 900;
			card.Visual.transform.localScale = new Vector3((float)val4, (float)val4, 1f);
			cards.Add(card);
		}

		private static Fix ScaleOf(int playerId)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//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 val2.Scale;
			}
			return Fix.One;
		}

		public static void Tick()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: 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_0152: 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_015d: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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)
			//IL_0184: 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_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: 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_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			if (cards.Count == 0)
			{
				return;
			}
			Fix fixedTimeStep = GameTime.FixedTimeStep;
			for (int num = cards.Count - 1; num >= 0; num--)
			{
				Card card = cards[num];
				if (!GameTime.IsTimeStoppedFor(card.OwnerId))
				{
					card.TicksAlive++;
					bool flag = false;
					switch (card.Phase)
					{
					case Phase.Outbound:
						flag = Advance(card, card.StopPoint, card.OutSpeed * fixedTimeStep, delegate
						{
							card.Phase = Phase.Spinning;
						});
						break;
					case Phase.Spinning:
						card.SpinTicksLeft--;
						if (card.SpinTicksLeft <= 0)
						{
							card.Phase = Phase.Returning;
						}
						break;
					case Phase.Returning:
					{
						card.ReturnTicks++;
						if (card.ReturnTicks > 180)
						{
							flag = true;
							break;
						}
						if (!TryGetPlayerPosition(card.OwnerId, out var position))
						{
							flag = true;
							break;
						}
						Vec2.Magnitude(position - card.Position);
						Fix returnSpeed = BoomerangAbility.ReturnSpeed;
						if (Advance(card, position, returnSpeed * fixedTimeStep, null) || Vec2.SqrMagnitude(position - card.Position) <= BoomerangAbility.CatchRadius * card.Scale * (BoomerangAbility.CatchRadius * card.Scale))
						{
							BoomerangSound.PlayPickup(Vector2.op_Implicit((Vector2)card.Position));
							flag = true;
						}
						break;
					}
					}
					ApplyExternalForces(card, fixedTimeStep);
					if (card.Swallowed)
					{
						Remove(num);
					}
					else
					{
						HitThings(card);
						BoomerangVisuals.Draw(card.Visual, card.Renderer, card.Position, ref card.SpinAngle);
						BoomerangVisuals.Blink(card.Renderer, TicksBeforeGivingUp(card));
						if (flag)
						{
							Remove(num);
						}
					}
				}
			}
		}

		private static void ApplyExternalForces(Card card, Fix dt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_007a: 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_0042: 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)
			PullTowardsBlackHoles(card, dt);
			if (!(card.Drift == Vec2.zero))
			{
				if (Vec2.Magnitude(card.Drift) > BoomerangAbility.MaxDriftSpeed)
				{
					card.Drift = Vec2.Normalized(card.Drift) * BoomerangAbility.MaxDriftSpeed;
				}
				card.Position += card.Drift * dt;
				card.Drift *= BoomerangAbility.DriftDecayPerTick;
			}
		}

		private static void PullTowardsBlackHoles(Card card, Fix dt)
		{
			//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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0051: 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_0058: 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)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_00ad: 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_00b8: 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_00bf: 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_00cb: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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)
			BlackHole[] array = Object.FindObjectsOfType<BlackHole>();
			foreach (BlackHole val in array)
			{
				if ((Object)(object)val == (Object)null || ((MonoUpdatable)val).IsDestroyed || (Object)(object)val.dCircle == (Object)null)
				{
					continue;
				}
				Vec2 val2 = val.dCircle.position - card.Position;
				Fix val3 = Vec2.SqrMagnitude(val2);
				if (val3 <= Fix.Zero)
				{
					continue;
				}
				Fix val4 = Fix.Sqrt(val3);
				if (val4 <= val.dCircle.radius * BoomerangAbility.BlackHoleSwallowRadius)
				{
					card.Swallowed = true;
					Plugin.Log.LogInfo((object)"Boomerang: a black hole swallowed a boomerang.");
					break;
				}
				Fix val5 = val.dCircle.radius * val.influenceRadiusMultiplier;
				if (!(val4 >= val5))
				{
					Fix val6 = MassOf(val);
					Fix val7 = val3 * val4;
					if (!(val7 <= Fix.Zero))
					{
						Vec2 val8 = val2 * (val.G * val6 * BoomerangAbility.BlackHolePull) / val7;
						card.Drift += val8 * dt;
					}
				}
			}
		}

		private static Fix MassOf(BlackHole hole)
		{
			//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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0020: 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)
			try
			{
				return Traverse.Create((object)hole).Field("mass").GetValue<Fix>();
			}
			catch (Exception ex)
			{
				if (warnedAboutMass)
				{
					return BoomerangAbility.FallbackBlackHoleMass;
				}
				warnedAboutMass = true;
				Plugin.Log.LogWarning((object)("Boomerang: could not read a black hole's mass, so its pull on the boomerang uses a fixed strength: " + ex.Message));
				return BoomerangAbility.FallbackBlackHoleMass;
			}
		}

		public static void Shove(Vec2 origin, Fix radius, Fix strength)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0036: 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_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_003f: 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_0049: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (cards.Count == 0)
			{
				return;
			}
			Fix val = radius * radius;
			foreach (Card card in cards)
			{
				Vec2 val2 = card.Position - origin;
				Fix val3 = Vec2.SqrMagnitude(val2);
				if (!(val3 > val) && !(val3 <= Fix.Zero))
				{
					Fix val4 = Fix.One - Vec2.Magnitude(val2) / radius;
					card.Drift += Vec2.Normalized(val2) * strength * val4 * BoomerangAbility.ShockwavePush;
				}
			}
			Plugin.Log.LogInfo((object)"Boomerang: a shockwave shoved a boomerang off course.");
		}

		private static int TicksBeforeGivingUp(Card card)
		{
			if (card.Phase != Phase.Returning)
			{
				return -1;
			}
			return 180 - card.ReturnTicks;
		}

		private static bool Advance(Card card, Vec2 target, Fix step, Action onArrive)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			Vec2 val = target - card.Position;
			if (Vec2.Magnitude(val) <= step)
			{
				card.Position = target;
				onArrive?.Invoke();
				return onArrive == null;
			}
			card.Position += Vec2.Normalized(val) * step;
			return false;
		}

		private static void HitThings(Card card)
		{
			//IL_0006: 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_0011: 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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			Fix val = BoomerangAbility.HitRadius * card.Scale;
			Fix radiusSquared = val * val;
			PlayerHandler val2 = PlayerHandler.Get();
			if (val2 != null)
			{
				foreach (Player item in val2.PlayerList())
				{
					if (item == null || !item.IsAlive || item.Id == card.OwnerId)
					{
						continue;
					}
					Vec2 centre = card.Position;
					PlayerBodies.KillWhere(item.Id, card.OwnerId, (CauseOfDeath)0, (Vec2 position) => Vec2.SqrMagnitude(position - centre) <= radiusSquared, out var bodiesSeen);
					if (bodiesSeen != 0)
					{
						continue;
					}
					PlayerBodies.WarnIfBlind(bodiesSeen, "Boomerang");
					if (Vec2.SqrMagnitude(item.Position - card.Position) <= radiusSquared)
					{
						SlimeController val3 = ControllerFor(item.Id);
						PlayerCollision val4 = (((Object)(object)val3 == (Object)null) ? null : val3.GetActivePlayerCollision());
						if ((Object)(object)val4 != (Object)null)
						{
							val4.killPlayer(card.OwnerId, true, false, (CauseOfDeath)0);
						}
					}
				}
			}
			GrenadeExplode[] array = Object.FindObjectsOfType<GrenadeExplode>();
			foreach (GrenadeExplode grenade in array)
			{
				if (Near((Component)(object)grenade, card.Position, radiusSquared) && !SheepInterop.TryKill((Component)(object)grenade))
				{
					Detonate(delegate
					{
						grenade.Detonate();
					}, "grenade");
				}
			}
			Mine[] array2 = Object.FindObjectsOfType<Mine>();
			foreach (Mine mine in array2)
			{
				if (Near((Component)(object)mine, card.Position, radiusSquared))
				{
					Detonate(delegate
					{
						mine.Detonate();
					}, "mine");
				}
			}
		}

		private static bool Near(Component component, Vec2 point, Fix radiusSquared)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			FixTransform component2 = component.GetComponent<FixTransform>();
			if ((Object)(object)component2 == (Object)null || component2.IsDestroyed)
			{
				return false;
			}
			return Vec2.SqrMagnitude(component2.position - point) <= radiusSquared;
		}

		private static void Detonate(Action detonate, string what)
		{
			try
			{
				detonate();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Boomerang: setting off a " + what + " threw, so it was left alone: " + ex.Message));
			}
		}

		private static bool TryGetPlayerPosition(int playerId, out Vec2 position)
		{
			//IL_0020: 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_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)
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 == null || !val2.IsAlive)
			{
				position = Vec2.zero;
				return false;
			}
			position = val2.Position;
			return true;
		}

		private static SlimeController ControllerFor(int playerId)
		{
			if (controllers.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			SlimeController[] array = Object.FindObjectsOfType<SlimeController>();
			foreach (SlimeController val in array)
			{
				if (val.GetPlayerId() == playerId)
				{
					controllers[playerId] = val;
					return val;
				}
			}
			return null;
		}

		private static void Remove(int index)
		{
			if ((Object)(object)cards[index].Visual != (Object)null)
			{
				Object.Destroy((Object)(object)cards[index].Visual);
			}
			cards.RemoveAt(index);
		}

		public static bool HasCardsOut(long key)
		{
			foreach (Card card in cards)
			{
				if (KeyFor(card.OwnerId, card.Slot) == key)
				{
					return true;
				}
			}
			return false;
		}

		public static void PinCooldownsWhileCardsOut()
		{
			//IL_006b: 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)
			if (cards.Count == 0)
			{
				return;
			}
			foreach (Card card in cards)
			{
				SlimeController val = ControllerFor(card.OwnerId);
				if (!((Object)(object)val == (Object)null))
				{
					Fix[] value = Traverse.Create((object)val).Field("abilityCooldownTimers").GetValue<Fix[]>();
					if (value != null && card.Slot >= 0 && card.Slot < value.Length)
					{
						value[card.Slot] = Fix.Zero;
					}
				}
			}
		}

		public static void ClearAll()
		{
			for (int num = cards.Count - 1; num >= 0; num--)
			{
				Remove(num);
			}
			controllers.Clear();
		}
	}
	public static class BoomerangVisuals
	{
		private static Sprite boomerang;

		private static bool loadAttempted;

		public static Sprite BoomerangSprite()
		{
			EnsureLoaded();
			return boomerang;
		}

		public static void Draw(GameObject visual, SpriteRenderer renderer, Vec2 position, ref float spinAngle)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visual == (Object)null))
			{
				visual.transform.position = Vector2.op_Implicit((Vector2)position);
				spinAngle += 13f;
				visual.transform.rotation = Quaternion.Euler(0f, 0f, spinAngle);
			}
		}

		public static void Blink(SpriteRenderer renderer, int ticksLeft)
		{
			if (!((Object)(object)renderer == (Object)null))
			{
				if (ticksLeft < 0 || ticksLeft > 40)
				{
					((Renderer)renderer).enabled = true;
				}
				else
				{
					((Renderer)renderer).enabled = ticksLeft / 5 % 2 == 0;
				}
			}
		}

		private static void EnsureLoaded()
		{
			if (!loadAttempted)
			{
				loadAttempted = true;
				boomerang = BoomerangAbility.LoadBoomerang();
				if ((Object)(object)boomerang == (Object)null)
				{
					Plugin.Log.LogError((object)"Boomerang: the art failed to load, so a thrown boomerang will be invisible. It still cuts and still returns.");
				}
				else
				{
					Plugin.Log.LogInfo((object)"Boomerang: art ready.");
				}
			}
		}
	}
	internal static class PlayerBodies
	{
		private static bool warnedEmpty;

		private static readonly HashSet<int> alreadyKilled = new HashSet<int>();

		public static void ForgetAll()
		{
			alreadyKilled.Clear();
		}

		public static bool IsProtected(int playerId)
		{
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null && val2.InPlatformTransform)
			{
				return true;
			}
			ControlPlatform[] array = Object.FindObjectsOfType<ControlPlatform>();
			foreach (ControlPlatform val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && ((Behaviour)val3).isActiveAndEnabled)
				{
					IPlayerIdHolder component = ((Component)val3).GetComponent<IPlayerIdHolder>();
					if (component != null && component.GetPlayerId() == playerId)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static int KillWhere(int victimId, int killerId, CauseOfDeath causeOfDeath, Func<Vec2, bool> isInside, out int bodiesSeen, bool respectProtection = true)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			bodiesSeen = 0;
			int num = 0;
			if (respectProtection && IsProtected(victimId))
			{
				return 0;
			}
			PlayerCollision[] array = Object.FindObjectsOfType<PlayerCollision>();
			foreach (PlayerCollision val in array)
			{
				if ((Object)(object)val == (Object)null || ((MonoUpdatable)val).IsDestroyed || !((Component)val).gameObject.activeInHierarchy || val.GetPlayerId() != victimId)
				{
					continue;
				}
				FixTransform component = ((Component)val).GetComponent<FixTransform>();
				if (!((Object)(object)component == (Object)null) && !component.IsDestroyed)
				{
					bodiesSeen++;
					if (isInside(component.position) && !alreadyKilled.Contains(((Object)val).GetInstanceID()) && val.killPlayer(killerId, true, !respectProtection, causeOfDeath))
					{
						alreadyKilled.Add(((Object)val).GetInstanceID());
						num++;
					}
				}
			}
			return num;
		}

		public static int KillAll(int victimId, int killerId, CauseOfDeath causeOfDeath, out int bodiesSeen, bool respectProtection = true)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return KillWhere(victimId, killerId, causeOfDeath, (Vec2 position) => true, out bodiesSeen, respectProtection);
		}

		public static void WarnIfBlind(int bodiesSeen, string what)
		{
			if (bodiesSeen <= 0 && !warnedEmpty)
			{
				warnedEmpty = true;
				Plugin.Log.LogWarning((object)(what + ": no live PlayerCollision was found for the target, so nothing can be killed. Every kill in this mod goes through that lookup, so this is not a near miss -- the scan itself is blind and the ability will appear to do nothing. Falling back to the old single-body lookup for this hit."));
			}
		}
	}
	[BepInPlugin("com.maha.boplbattle.boomerang", "Boomerang", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.maha.boplbattle.boomerang";

		public const string PluginName = "Boomerang";

		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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Boomerang: loading...");
			new Harmony("com.maha.boplbattle.boomerang").PatchAll();
			Log.LogInfo((object)($"Boomerang: loaded (spin {90} ticks, cooldown " + $"{2.45f}s, return speed " + $"{(float)BoomerangAbility.ReturnSpeed:0.#}, gives up after " + $"{180} ticks)."));
		}
	}
	internal static class SheepInterop
	{
		private const string TypeName = "Sheep";

		private const string MethodName = "KillBySplat";

		private static MethodInfo cachedKill;

		private static Type cachedType;

		private static bool searched;

		public static bool IsSheep(Component component)
		{
			if ((Object)(object)component != (Object)null)
			{
				return (Object)(object)FindSheep(component.gameObject) != (Object)null;
			}
			return false;
		}

		public static bool TryKill(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			Component val = FindSheep(component.gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			MethodInfo methodInfo = ResolveKill(((object)val).GetType());
			if (methodInfo == null)
			{
				Plugin.Log.LogInfo((object)("Boomerang: '" + ((Object)component.gameObject).name + "' has a Sheep component but no usable KillBySplat(string), so it was left alone rather than blown up."));
				return true;
			}
			try
			{
				methodInfo.Invoke(val, new object[1] { "cut down by a boomerang" });
				Plugin.Log.LogInfo((object)"Boomerang: cut down a sheep.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Boomerang: killing a sheep threw, so it was left alone: " + ex.Message));
			}
			return true;
		}

		private static Component FindSheep(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 ResolveKill(Type type)
		{
			if (searched && cachedType == type)
			{
				return cachedKill;
			}
			searched = true;
			cachedType = type;
			cachedKill = type.GetMethod("KillBySplat", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
			return cachedKill;
		}
	}
}