Decompiled source of SiphonBeam v1.0.0

SiphonBeam.dll

Decompiled 18 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;
using UnityEngine.Events;

[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("SiphonBeam")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Bopl Battle ability: no cooldown, only a circle. Stand near other players to charge, then fire a piercing beam.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+03cd6db5d3874468aefed4c8ac2503a8f168bcbd")]
[assembly: AssemblyProduct("SiphonBeam")]
[assembly: AssemblyTitle("SiphonBeam")]
[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 SiphonBeam
{
	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.siphonbeam", "Siphon Beam", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.maha.boplbattle.siphonbeam";

		public const string PluginName = "Siphon Beam";

		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_0047: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Siphon Beam: loading...");
			new Harmony("com.maha.boplbattle.siphonbeam").PatchAll();
			Log.LogInfo((object)($"Siphon Beam: loaded (charge {180} ticks per " + $"player in the circle, radius {(float)SiphonAbility.CircleRadius}, " + $"beam lasts {10} ticks)."));
		}
	}
	public static class SiphonAbility
	{
		public const string AbilityName = "siphonbeam";

		public const string TemplateNameFragment = "invis";

		public const int ChargeTicksNeeded = 180;

		public static readonly Fix CircleRadius = (Fix)8.5;

		public const int RingDashes = 16;

		public static readonly Fix DisplayCooldown = (Fix)10L;

		public const int LockedDirectionCount = 32;

		public const int MaxAimTicks = 270;

		public const float PreviewAlpha = 0.28f;

		public const float PreviewThickness = 0.3f;

		public const int BeamTicks = 10;

		public static readonly Fix BeamHalfWidth = (Fix)3.15;

		public static readonly Fix FallbackBeamLength = (Fix)40L;

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

		public const float BeamDrawThickness = 9.9f;

		public const float LaserSpriteHeightUnits = 0.125f;

		public const int PoseFrameTicks = 3;

		public static readonly Color DashEmpty = new Color(0.35f, 0.4f, 0.5f, 0.55f);

		public static readonly Color DashCharging = new Color(0.35f, 0.7f, 1f, 1f);

		public static readonly Color DashFull = new Color(0.75f, 0.95f, 1f, 1f);

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

		public static Sprite LoadIcon(Sprite template)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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)
			Texture2D val = LoadTexture("SiphonBeam.AbilityIcon.png");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			float pixelsPerUnit = 100f;
			if ((Object)(object)template != (Object)null)
			{
				Rect rect = template.rect;
				if (((Rect)(ref rect)).width > 0f)
				{
					float pixelsPerUnit2 = template.pixelsPerUnit;
					float num = ((Texture)val).width;
					rect = template.rect;
					pixelsPerUnit = pixelsPerUnit2 * (num / ((Rect)(ref rect)).width);
				}
			}
			return Build(val, pixelsPerUnit, new Vector2(0.5f, 0.5f));
		}

		public static Sprite LoadDash()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture("SiphonBeam.Dash.png");
			if (!((Object)(object)val == (Object)null))
			{
				return Build(val, ((Texture)val).width, new Vector2(0.5f, 0.5f));
			}
			return null;
		}

		public static Sprite LoadLaser()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture("SiphonBeam.Laser.png");
			if (!((Object)(object)val == (Object)null))
			{
				return Build(val, ((Texture)val).width, new Vector2(0f, 0.5f));
			}
			return null;
		}

		private static Sprite Build(Texture2D texture, float pixelsPerUnit, Vector2 pivot)
		{
			//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)
			return Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), pivot, 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)("Siphon Beam: 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)("Siphon Beam: '" + resourceName + "' failed to decode as a PNG."));
				return null;
			}
			return val;
		}
	}
	[HarmonyPatch(typeof(AbilityGrid), "Awake")]
	public static class SiphonInjectionPatch
	{
		private static bool hasInjected;

		public static void Prefix(AbilityGrid __instance)
		{
			//IL_0038: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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)"Siphon Beam: AbilityGrid.abilityIcons was empty this Awake; not injecting yet (will retry on the next grid build).");
				return;
			}
			SlimePose.CaptureFrom(abilityIcons);
			NamedSprite val = default(NamedSprite);
			bool flag = false;
			foreach (NamedSprite sprite in abilityIcons.sprites)
			{
				if (sprite.name != null && sprite.name.ToLower().Contains("invis"))
				{
					val = sprite;
					flag = true;
					break;
				}
			}
			if (!flag || (Object)(object)val.associatedGameObject == (Object)null)
			{
				Plugin.Log.LogError((object)"Siphon Beam: could not find a native instant ability to clone, so the beam was not added. (Looked for an ability whose name contains 'invis'.)");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.associatedGameObject);
			Object.DontDestroyOnLoad((Object)(object)val2);
			((Object)val2).name = "siphonbeam";
			StripTemplateEffect(val2);
			InstantAbility component = val2.GetComponent<InstantAbility>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)("Siphon Beam: '" + val.name + "' has no InstantAbility component, so it cannot be cast and the beam was not added."));
				Object.Destroy((Object)(object)val2);
				return;
			}
			component.SetCoolDown(SiphonAbility.DisplayCooldown);
			component.AudioOnCast = string.Empty;
			Sprite val3 = SiphonAbility.LoadIcon(val.sprite) ?? val.sprite;
			abilityIcons.sprites.Add(new NamedSprite("siphonbeam", val3, val2, true));
			hasInjected = true;
			Plugin.Log.LogInfo((object)("Siphon Beam: ability injected into the select grid (cloned " + $"'{val.name}', charge {180} ticks " + "per player in the circle)."));
		}

		private static void StripTemplateEffect(GameObject clone)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			InstantAbility component = clone.GetComponent<InstantAbility>();
			if ((Object)(object)component != (Object)null)
			{
				component.funcOnEnter = new UnityEvent();
				component.EffectOnEnter = null;
				component.isInvisibilty = false;
			}
			Invisibility[] componentsInChildren = clone.GetComponentsInChildren<Invisibility>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren[i]);
			}
		}
	}
	[HarmonyPatch(typeof(InstantAbility), "EnterAbility")]
	public static class SiphonCastPatch
	{
		public static void Postfix(InstantAbility __instance)
		{
			if (SiphonAbility.IsSiphonBeam(((Component)__instance).gameObject))
			{
				SiphonState.BeginAim(__instance.playerInfo.playerId, __instance.playerInfo.AbilityButtonUsedIndex012);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerPhysics), "Move")]
	public static class SiphonAimRootPatch
	{
		public static bool Prefix(PlayerPhysics __instance)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			IPlayerIdHolder component = ((Component)__instance).GetComponent<IPlayerIdHolder>();
			if (component == null || !SiphonState.IsPlayerAiming(component.GetPlayerId()))
			{
				return true;
			}
			__instance.groundedSpeed = Fix.Zero;
			return false;
		}
	}
	[HarmonyPatch(typeof(Updater), "TickSimulation")]
	public static class SiphonTickPatch
	{
		public static void Postfix()
		{
			SiphonState.Tick();
			SiphonVisuals.Sync();
		}
	}
	[HarmonyPatch(typeof(Player), "Kill")]
	public static class SiphonClearOnDeathPatch
	{
		public static void Prefix(Player __instance)
		{
			SiphonState.DropPlayer(__instance.Id);
		}
	}
	[HarmonyPatch(typeof(PlayerHandler), "ResetForNextStage")]
	public static class SiphonResetPatch
	{
		public static void Prefix()
		{
			PlayerBodies.ForgetAll();
			SiphonState.ResetForNextStage();
			SiphonVisuals.DestroyAll();
		}
	}
	[HarmonyPatch(typeof(Updater), "PreLevelLoad")]
	public static class SiphonLevelLoadPatch
	{
		public static void Prefix()
		{
			SiphonState.ResetForNextStage();
			SiphonVisuals.DestroyAll();
		}
	}
	public static class SiphonState
	{
		private struct Beam
		{
			public int Ticks;

			public Vec2 Origin;

			public Vec2 Dir;

			public Fix Length;
		}

		private struct Aim
		{
			public int Ticks;

			public int Slot;

			public Vec2 Dir;
		}

		public struct Carrier
		{
			public int OthersInside;

			public float RingProgress;

			public bool AnyFull;
		}

		private static readonly Vec2[] LockedDirections = BuildLockedDirections();

		private static readonly Dictionary<long, int> charge = new Dictionary<long, int>();

		private static readonly Dictionary<long, Beam> beams = new Dictionary<long, Beam>();

		private static readonly Dictionary<long, Aim> aiming = new Dictionary<long, Aim>();

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

		private static readonly Dictionary<int, Carrier> carriers = new Dictionary<int, Carrier>();

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

		private static bool warnedAboutBeamLength;

		private static Vec2[] BuildLockedDirections()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			int[][] array = new int[8][]
			{
				new int[2] { 1, 0 },
				new int[2] { 3, 1 },
				new int[2] { 2, 1 },
				new int[2] { 3, 2 },
				new int[2] { 1, 1 },
				new int[2] { 2, 3 },
				new int[2] { 1, 2 },
				new int[2] { 1, 3 }
			};
			int[][] array2 = new int[array.Length * 4][];
			for (int i = 0; i < array.Length; i++)
			{
				int num = array[i][0];
				int num2 = array[i][1];
				array2[i] = new int[2] { num, num2 };
				array2[i + array.Length] = new int[2]
				{
					-num2,
					num
				};
				array2[i + array.Length * 2] = new int[2]
				{
					-num,
					-num2
				};
				array2[i + array.Length * 3] = new int[2]
				{
					num2,
					-num
				};
			}
			Vec2[] array3 = (Vec2[])(object)new Vec2[array2.Length];
			for (int j = 0; j < array2.Length; j++)
			{
				array3[j] = Vec2.NormalizedSafe(new Vec2((Fix)(long)array2[j][0], (Fix)(long)array2[j][1]));
			}
			return array3;
		}

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

		public static int PlayerOfKey(long key)
		{
			return (int)(key / 16);
		}

		public static bool TryGetCarrier(int playerId, out Carrier carrier)
		{
			return carriers.TryGetValue(playerId, out carrier);
		}

		public static List<int> CarrierIds()
		{
			return new List<int>(carriers.Keys);
		}

		public static List<long> BeamKeys()
		{
			return new List<long>(beams.Keys);
		}

		public static bool IsBeaming(long key)
		{
			return beams.ContainsKey(key);
		}

		public static bool IsPlayerBeaming(int playerId)
		{
			foreach (long key in beams.Keys)
			{
				if (PlayerOfKey(key) == playerId)
				{
					return true;
				}
			}
			return false;
		}

		public static List<long> AimKeys()
		{
			return new List<long>(aiming.Keys);
		}

		public static bool IsAiming(long key)
		{
			return aiming.ContainsKey(key);
		}

		public static Vec2 AimDirection(long key)
		{
			//IL_0016: 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)
			if (!aiming.TryGetValue(key, out var value))
			{
				return Vec2.right;
			}
			return value.Dir;
		}

		public static bool IsPlayerAiming(int playerId)
		{
			foreach (long key in aiming.Keys)
			{
				if (PlayerOfKey(key) == playerId)
				{
					return true;
				}
			}
			return false;
		}

		public static int BeamTicksElapsed(long key)
		{
			if (!beams.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value.Ticks;
		}

		public static Vec2 BeamOrigin(long key)
		{
			//IL_0016: 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)
			if (!beams.TryGetValue(key, out var value))
			{
				return Vec2.zero;
			}
			return value.Origin;
		}

		public static Vec2 BeamDirection(long key)
		{
			//IL_0016: 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)
			if (!beams.TryGetValue(key, out var value))
			{
				return Vec2.right;
			}
			return value.Dir;
		}

		public static float BeamLengthOf(long key)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!beams.TryGetValue(key, out var value))
			{
				return 0f;
			}
			return (float)value.Length;
		}

		public static void Tick()
		{
			ChargeFromNeighbours();
			PushChargeToCooldownTimers();
			TickAiming();
			TickBeams();
		}

		private static void ChargeFromNeighbours()
		{
			//IL_0086: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_00d8: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			carriers.Clear();
			justFilled.Clear();
			PlayerHandler val = PlayerHandler.Get();
			if (val == null)
			{
				return;
			}
			List<Player> list = val.PlayerList();
			if (list == null)
			{
				Plugin.Log.LogWarning((object)"Siphon Beam: PlayerHandler returned no player list this tick; skipping charging.");
				return;
			}
			foreach (Player item in list)
			{
				if (item == null || !item.IsAlive || GameTime.IsTimeStoppedFor(item.Id))
				{
					continue;
				}
				List<int> list2 = SlotsHolding(item.Id);
				if (list2.Count == 0)
				{
					continue;
				}
				Fix val2 = SiphonAbility.CircleRadius * item.Scale;
				Fix val3 = val2 * val2;
				int num = 0;
				foreach (Player item2 in list)
				{
					if (item2 != null && item2.IsAlive && item2.Id != item.Id)
					{
						Vec2 val4 = item2.Position - item.Position;
						if (Vec2.Dot(val4, val4) <= val3)
						{
							num++;
						}
					}
				}
				float num2 = 0f;
				bool flag = false;
				foreach (int item3 in list2)
				{
					long num3 = KeyFor(item.Id, item3);
					int num4 = ChargeOf(num3);
					if (num4 < 180 && num > 0)
					{
						num4 = Mathf.Min(num4 + num, 180);
						charge[num3] = num4;
						if (num4 >= 180)
						{
							justFilled.Add(num3);
							AudioManager val5 = AudioManager.Get();
							if ((Object)(object)val5 != (Object)null)
							{
								val5.PlayRandomWithPrefix("beamSparks", 0f);
							}
							Plugin.Log.LogInfo((object)$"Siphon Beam: player {item.Id} slot {item3} is charged.");
						}
					}
					num2 = Mathf.Max(num2, (float)num4 / 180f);
					flag = flag || num4 >= 180;
				}
				carriers[item.Id] = new Carrier
				{
					OthersInside = num,
					RingProgress = num2,
					AnyFull = flag
				};
			}
		}

		private static void PushChargeToCooldownTimers()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0105: 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_010c: 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)
			//IL_00a8: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			foreach (int item in CarrierIds())
			{
				SlimeController val = ControllerFor(item);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Fix[] value = Traverse.Create((object)val).Field("abilityCooldownTimers").GetValue<Fix[]>();
				if (value == null)
				{
					continue;
				}
				foreach (int item2 in SlotsHolding(item))
				{
					if (item2 >= 0 && item2 < value.Length)
					{
						long num = KeyFor(item, item2);
						int num2 = ChargeOf(num);
						if (num2 >= 180)
						{
							value[item2] = (justFilled.Contains(num) ? (SiphonAbility.DisplayCooldown - (Fix)0.01) : SiphonAbility.DisplayCooldown);
							continue;
						}
						Fix val2 = (Fix)(long)num2 / (Fix)180L;
						Fix val3 = SiphonAbility.DisplayCooldown - (Fix)0.1;
						value[item2] = Fix.Min(SiphonAbility.DisplayCooldown * val2, val3);
					}
				}
			}
		}

		public static void BeginAim(int playerId, int slot)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			long key = KeyFor(playerId, slot);
			charge[key] = 0;
			aiming[key] = new Aim
			{
				Ticks = 0,
				Slot = slot,
				Dir = SnapToLockedDirection(CurrentAim(playerId), Vec2.right)
			};
			Plugin.Log.LogInfo((object)$"Siphon Beam: player {playerId} slot {slot} is aiming.");
		}

		private static void TickAiming()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			if (aiming.Count == 0)
			{
				return;
			}
			PlayerHandler val = PlayerHandler.Get();
			foreach (long item in AimKeys())
			{
				Aim value = aiming[item];
				int num = PlayerOfKey(item);
				if (GameTime.IsTimeStoppedFor(num))
				{
					continue;
				}
				Player val2 = ((val == null) ? null : val.GetPlayer(num));
				if (val2 == null || !val2.IsAlive)
				{
					aiming.Remove(item);
					Plugin.Log.LogInfo((object)($"Siphon Beam: player {num} died while aiming, so the shot " + "was lost."));
					continue;
				}
				value.Dir = SnapToLockedDirection(RawAim(num), value.Dir);
				value.Ticks++;
				if (!val2.AbilityButtonIsDown(value.Slot))
				{
					aiming.Remove(item);
					Fire(item, val2, value.Dir);
				}
				else if (value.Ticks >= 270)
				{
					aiming.Remove(item);
					Plugin.Log.LogInfo((object)($"Siphon Beam: player {num} held the aim to the limit, so " + "the shot went off by itself."));
					Fire(item, val2, value.Dir);
				}
				else
				{
					aiming[item] = value;
				}
			}
		}

		private static Vec2 RawAim(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.AimVector();
			}
			return Vec2.zero;
		}

		private static Vec2 CurrentAim(int playerId)
		{
			//IL_001e: 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_0017: 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_0066: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 == null)
			{
				return Vec2.zero;
			}
			Vec2 val3 = val2.AimVector();
			if (val3 != Vec2.zero)
			{
				return val3;
			}
			SlimeController val4 = ControllerFor(playerId);
			if ((Object)(object)val4 == (Object)null)
			{
				return Vec2.zero;
			}
			if (!val4.isFacingRight())
			{
				return new Vec2(-Fix.One, Fix.Zero);
			}
			return Vec2.right;
		}

		private static Vec2 SnapToLockedDirection(Vec2 aim, Vec2 fallback)
		{
			//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_0015: 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_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)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_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)
			if (aim == Vec2.zero)
			{
				return fallback;
			}
			Vec2 val = LockedDirections[0];
			Fix val2 = Vec2.Dot(aim, val);
			for (int i = 1; i < LockedDirections.Length; i++)
			{
				Fix val3 = Vec2.Dot(aim, LockedDirections[i]);
				if (val3 > val2)
				{
					val2 = val3;
					val = LockedDirections[i];
				}
			}
			return val;
		}

		private static void Fire(long key, Player player, Vec2 dir)
		{
			//IL_0013: 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_001e: 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_0028: 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_0037: 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_007e: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			Beam value = new Beam
			{
				Ticks = 0,
				Origin = player.Position + dir * SiphonAbility.BeamStartOffset,
				Dir = dir,
				Length = BeamLength()
			};
			beams[key] = value;
			AudioManager val = AudioManager.Get();
			if ((Object)(object)val != (Object)null)
			{
				val.Play("beamFire");
			}
			Plugin.Log.LogInfo((object)($"Siphon Beam: player {player.Id} fired along ({(float)dir.x:0.##}, " + $"{(float)dir.y:0.##})."));
		}

		private static Fix BeamLength()
		{
			//IL_0032: 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)
			DetPhysics val = DetPhysics.Get();
			if ((Object)(object)val == (Object)null)
			{
				if (!warnedAboutBeamLength)
				{
					warnedAboutBeamLength = true;
					Plugin.Log.LogWarning((object)"Siphon Beam: DetPhysics was not available, so the beam used its fallback length instead of the game's own beam range.");
				}
				return SiphonAbility.FallbackBeamLength;
			}
			return val.maxBeamDistance;
		}

		public static float PreviewLength()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return (float)BeamLength();
		}

		private static void TickBeams()
		{
			if (beams.Count == 0)
			{
				return;
			}
			foreach (long item in BeamKeys())
			{
				if (GameTime.IsTimeStoppedFor(PlayerOfKey(item)))
				{
					continue;
				}
				Beam beam = beams[item];
				KillAlongBeam(PlayerOfKey(item), beam);
				DetonateAlongBeam(beam);
				beam.Ticks++;
				if (beam.Ticks >= 10)
				{
					beams.Remove(item);
					AudioManager val = AudioManager.Get();
					if ((Object)(object)val != (Object)null)
					{
						val.Play("beamEnd");
					}
				}
				else
				{
					beams[item] = beam;
				}
			}
		}

		private static void KillAlongBeam(int casterId, Beam beam)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			if (val == null)
			{
				return;
			}
			foreach (Player item in val.PlayerList())
			{
				if (item == null || !item.IsAlive || item.Id == casterId)
				{
					continue;
				}
				Beam onBeam = beam;
				int bodiesSeen;
				int num = PlayerBodies.KillWhere(item.Id, casterId, (CauseOfDeath)4, (Vec2 position) => OnBeam(position, onBeam), out bodiesSeen);
				if (num > 0)
				{
					Plugin.Log.LogInfo((object)($"Siphon Beam: player {casterId}'s beam caught player " + $"{item.Id} ({num} of {bodiesSeen} bodies)."));
				}
				else
				{
					if (bodiesSeen != 0)
					{
						continue;
					}
					PlayerBodies.WarnIfBlind(bodiesSeen, "Siphon Beam");
					if (OnBeam(item.Position, beam))
					{
						SlimeController val2 = ControllerFor(item.Id);
						PlayerCollision val3 = (((Object)(object)val2 == (Object)null) ? null : val2.GetActivePlayerCollision());
						if ((Object)(object)val3 != (Object)null)
						{
							val3.killPlayer(casterId, true, false, (CauseOfDeath)4);
						}
					}
				}
			}
		}

		private static void DetonateAlongBeam(Beam beam)
		{
			FlammableSmoke[] array = Object.FindObjectsOfType<FlammableSmoke>();
			foreach (FlammableSmoke gas in array)
			{
				DPhysicsCircle component = ((Component)gas).GetComponent<DPhysicsCircle>();
				if ((!((Object)(object)component != (Object)null) || ((Behaviour)component).enabled) && OnBeam((Component)(object)gas, beam))
				{
					TryDetonate(delegate
					{
						gas.Ignite();
					}, "gas cloud");
				}
			}
			GrenadeExplode[] array2 = Object.FindObjectsOfType<GrenadeExplode>();
			foreach (GrenadeExplode grenade in array2)
			{
				if (OnBeam((Component)(object)grenade, beam))
				{
					TryDetonate(delegate
					{
						grenade.Detonate();
					}, "grenade");
				}
			}
			SmokeGrenadeExplode2[] array3 = Object.FindObjectsOfType<SmokeGrenadeExplode2>();
			foreach (SmokeGrenadeExplode2 smoke in array3)
			{
				if (OnBeam((Component)(object)smoke, beam))
				{
					TryDetonate(delegate
					{
						smoke.Detonate();
					}, "smoke grenade");
				}
			}
			Mine[] array4 = Object.FindObjectsOfType<Mine>();
			foreach (Mine mine in array4)
			{
				if (OnBeam((Component)(object)mine, beam))
				{
					TryDetonate(delegate
					{
						mine.Detonate();
					}, "mine");
				}
			}
		}

		private static bool OnBeam(Component component, Beam beam)
		{
			//IL_003d: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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;
			}
			DPhysicsCircle component3 = component.GetComponent<DPhysicsCircle>();
			Fix radius = (((Object)(object)component3 == (Object)null) ? Fix.Zero : component3.radius);
			return OnBeam(component2.position, beam, radius);
		}

		private static bool OnBeam(Vec2 position, Beam beam)
		{
			//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)
			return OnBeam(position, beam, Fix.Zero);
		}

		private static bool OnBeam(Vec2 position, Beam beam, Fix radius)
		{
			//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_0008: 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)
			return OnSegment(position, beam.Origin, beam.Dir, beam.Length, radius);
		}

		private static bool OnSegment(Vec2 position, Vec2 origin, Vec2 dir, Fix length, Fix radius)
		{
			//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_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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_000f: 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_0013: 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_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_0023: 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_0032: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			Vec2 val = position - origin;
			Fix val2 = Vec2.Dot(val, dir);
			if (val2 < -radius || val2 > length + radius)
			{
				return false;
			}
			return Fix.Abs(Vec2.Cross(dir, val)) <= SiphonAbility.BeamHalfWidth + radius;
		}

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

		public static int ChargeOf(long key)
		{
			if (!charge.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value;
		}

		public static List<int> SlotsHolding(int playerId)
		{
			List<int> list = new List<int>();
			SlimeController val = ControllerFor(playerId);
			if ((Object)(object)val == (Object)null || val.abilities == null)
			{
				return list;
			}
			for (int i = 0; i < val.abilities.Count; i++)
			{
				AbilityMonoBehaviour val2 = val.abilities[i];
				if ((Object)(object)val2 != (Object)null && SiphonAbility.IsSiphonBeam(((Component)val2).gameObject))
				{
					list.Add(i);
				}
			}
			return list;
		}

		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;
		}

		public static void ResetForNextStage()
		{
			charge.Clear();
			beams.Clear();
			aiming.Clear();
			carriers.Clear();
			controllers.Clear();
			justFilled.Clear();
		}

		public static void DropPlayer(int playerId)
		{
			foreach (long item in new List<long>(charge.Keys))
			{
				if (PlayerOfKey(item) == playerId)
				{
					charge.Remove(item);
				}
			}
			foreach (long item2 in new List<long>(beams.Keys))
			{
				if (PlayerOfKey(item2) == playerId)
				{
					beams.Remove(item2);
				}
			}
			foreach (long item3 in new List<long>(aiming.Keys))
			{
				if (PlayerOfKey(item3) == playerId)
				{
					aiming.Remove(item3);
				}
			}
			carriers.Remove(playerId);
		}
	}
	public static class SiphonVisuals
	{
		private const float DashFill = 0.55f;

		private const float DashThickness = 0.22f;

		private static Sprite dashSprite;

		private static Sprite laserSprite;

		private static float dashSpriteHeightUnits = 1f;

		private static bool loadAttempted;

		private static bool loadFailed;

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

		private static readonly Dictionary<long, GameObject> lasers = new Dictionary<long, GameObject>();

		private static readonly Dictionary<long, GameObject> previews = new Dictionary<long, GameObject>();

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

		public static void Sync()
		{
			if (!loadFailed && (loadAttempted || Load()))
			{
				SyncRings();
				SyncPreviews();
				SyncLasers();
				SyncPose();
			}
		}

		private static void SyncPreviews()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			foreach (long item in SiphonState.AimKeys())
			{
				if (!previews.TryGetValue(item, out var value) || (Object)(object)value == (Object)null)
				{
					value = new GameObject("SiphonBeamAimLine");
					value.AddComponent<SpriteRenderer>().sprite = laserSprite;
					previews[item] = value;
				}
				PositionPreview(item, value);
			}
			Sweep(previews, (long k) => SiphonState.IsAiming(k));
		}

		private static void PositionPreview(long key, GameObject preview)
		{
			//IL_0027: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//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_0043: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			int num = SiphonState.PlayerOfKey(key);
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(num));
			if (val2 == null)
			{
				preview.SetActive(false);
				return;
			}
			Vec2 val3 = SiphonState.AimDirection(key);
			Vec2 origin = val2.Position + val3 * SiphonAbility.BeamStartOffset;
			preview.SetActive(true);
			ShapeSegment(preview, origin, val3, SiphonState.PreviewLength(), 0.3f, 0.28f, 1999);
		}

		private static void ShapeSegment(GameObject go, Vec2 origin, Vec2 dir, float length, float thicknessScale, float alpha, int sortingOrder)
		{
			//IL_0006: 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_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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			go.transform.position = Vector2.op_Implicit((Vector2)origin);
			go.transform.right = new Vector3((float)dir.x, (float)dir.y, 0f);
			go.transform.localScale = new Vector3(length, 9.9f * thicknessScale / 0.125f, 1f);
			SpriteRenderer component = go.GetComponent<SpriteRenderer>();
			component.color = new Color(1f, 1f, 1f, alpha);
			((Renderer)component).sortingOrder = sortingOrder;
		}

		private static void SyncRings()
		{
			foreach (int item in SiphonState.CarrierIds())
			{
				if (!rings.TryGetValue(item, out var value) || (Object)(object)value == (Object)null)
				{
					value = BuildRing();
					rings[item] = value;
				}
				PositionRing(item, value);
			}
			Sweep(rings, (int id) => SiphonState.TryGetCarrier(id, out var _));
		}

		private static GameObject BuildRing()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_000b: 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_0060: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SiphonBeamRing");
			float num = (float)SiphonAbility.CircleRadius;
			float num2 = 22.5f;
			float num3 = MathF.PI * 2f * num / 16f * 0.55f;
			for (int i = 0; i < 16; i++)
			{
				float num4 = num2 * (float)i;
				float num5 = num4 * (MathF.PI / 180f);
				GameObject val2 = new GameObject("Dash" + i);
				val2.transform.SetParent(val.transform, false);
				val2.transform.localPosition = new Vector3(Mathf.Cos(num5) * num, Mathf.Sin(num5) * num, 0f);
				val2.transform.localRotation = Quaternion.Euler(0f, 0f, num4 + 90f);
				val2.transform.localScale = new Vector3(num3, 0.22f / dashSpriteHeightUnits, 1f);
				val2.AddComponent<SpriteRenderer>().sprite = dashSprite;
			}
			return val;
		}

		private static void PositionRing(int playerId, GameObject ring)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_005d: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			SpriteRenderer val = FindPlayerSprite(playerId);
			PlayerHandler val2 = PlayerHandler.Get();
			Player val3 = ((val2 == null) ? null : val2.GetPlayer(playerId));
			if (val3 == null || !SiphonState.TryGetCarrier(playerId, out var carrier))
			{
				ring.SetActive(false);
				return;
			}
			ring.SetActive(true);
			ring.transform.position = (Vector3)(((Object)(object)val != (Object)null) ? ((Component)val).transform.position : new Vector3((float)val3.Position.x, (float)val3.Position.y, 0f));
			float num = Mathf.Max(0.01f, (float)val3.Scale);
			ring.transform.localScale = new Vector3(num, num, 1f);
			float num2 = (float)(Updater.SimulationTicks * carrier.OthersInside) * 0.6f;
			ring.transform.rotation = Quaternion.Euler(0f, 0f, num2);
			int num3 = Mathf.RoundToInt(carrier.RingProgress * 16f);
			Color val4 = (carrier.AnyFull ? SiphonAbility.DashFull : SiphonAbility.DashCharging);
			for (int i = 0; i < ring.transform.childCount; i++)
			{
				SpriteRenderer component = ((Component)ring.transform.GetChild(i)).GetComponent<SpriteRenderer>();
				if (!((Object)(object)component == (Object)null))
				{
					component.color = ((i < num3) ? val4 : SiphonAbility.DashEmpty);
					if ((Object)(object)val != (Object)null)
					{
						((Renderer)component).sortingLayerID = ((Renderer)val).sortingLayerID;
						((Renderer)component).sortingOrder = ((Renderer)val).sortingOrder - 3;
					}
				}
			}
		}

		private static void SyncLasers()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			foreach (long item in SiphonState.BeamKeys())
			{
				if (!lasers.TryGetValue(item, out var value) || (Object)(object)value == (Object)null)
				{
					value = new GameObject("SiphonBeamLaser");
					value.AddComponent<SpriteRenderer>().sprite = laserSprite;
					lasers[item] = value;
				}
				PositionLaser(item, value);
			}
			Sweep(lasers, (long k) => SiphonState.IsBeaming(k));
		}

		private static float FadeRemaining(long key)
		{
			int num = SiphonState.BeamTicksElapsed(key);
			return 1f - (float)num / 10f;
		}

		private static float FadeThickness(long key)
		{
			return Mathf.Max(0.08f, FadeRemaining(key));
		}

		private static float FadeAlpha(long key)
		{
			return Mathf.Clamp01(FadeRemaining(key) * 1.6f);
		}

		private static void PositionLaser(long key, GameObject laser)
		{
			//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_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_0022: 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_0028: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_009e: 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)
			Vec2 val = SiphonState.BeamOrigin(key);
			Vec2 val2 = SiphonState.BeamDirection(key);
			float num = SiphonState.BeamLengthOf(key);
			laser.SetActive(true);
			laser.transform.position = Vector2.op_Implicit((Vector2)val);
			laser.transform.right = new Vector3((float)val2.x, (float)val2.y, 0f);
			int num2 = SiphonState.BeamTicksElapsed(key);
			float num3 = 1f - (float)num2 / 10f;
			float num4 = 9.9f * Mathf.Max(0.08f, num3);
			laser.transform.localScale = new Vector3(num, num4 / 0.125f, 1f);
			SpriteRenderer component = laser.GetComponent<SpriteRenderer>();
			component.color = new Color(1f, 1f, 1f, Mathf.Clamp01(num3 * 1.6f));
			((Renderer)component).sortingOrder = 2000;
		}

		private static void SyncPose()
		{
			Sprite[] frames = SlimePose.Frames;
			if (frames == null || frames.Length == 0)
			{
				return;
			}
			foreach (long item in SiphonState.AimKeys())
			{
				Apply(SiphonState.PlayerOfKey(item), frames, 0);
			}
			foreach (long item2 in SiphonState.BeamKeys())
			{
				Apply(frame: SiphonState.BeamTicksElapsed(item2) / 3, playerId: SiphonState.PlayerOfKey(item2), frames: frames);
			}
		}

		private static void Apply(int playerId, Sprite[] frames, int frame)
		{
			SpriteRenderer val = FindPlayerSprite(playerId);
			if (!((Object)(object)val == (Object)null))
			{
				Sprite val2 = frames[Mathf.Clamp(frame, 0, frames.Length - 1)];
				if ((Object)(object)val2 != (Object)null)
				{
					val.sprite = val2;
				}
			}
		}

		private static void Sweep<TKey>(Dictionary<TKey, GameObject> objects, Func<TKey, bool> stillWanted)
		{
			List<TKey> list = null;
			foreach (KeyValuePair<TKey, GameObject> @object in objects)
			{
				if (!stillWanted(@object.Key))
				{
					(list ?? (list = new List<TKey>())).Add(@object.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (TKey item in list)
			{
				if ((Object)(object)objects[item] != (Object)null)
				{
					Object.Destroy((Object)(object)objects[item]);
				}
				objects.Remove(item);
			}
		}

		public static void DestroyAll()
		{
			foreach (KeyValuePair<int, GameObject> ring in rings)
			{
				if ((Object)(object)ring.Value != (Object)null)
				{
					Object.Destroy((Object)(object)ring.Value);
				}
			}
			rings.Clear();
			foreach (KeyValuePair<long, GameObject> laser in lasers)
			{
				if ((Object)(object)laser.Value != (Object)null)
				{
					Object.Destroy((Object)(object)laser.Value);
				}
			}
			lasers.Clear();
			foreach (KeyValuePair<long, GameObject> preview in previews)
			{
				if ((Object)(object)preview.Value != (Object)null)
				{
					Object.Destroy((Object)(object)preview.Value);
				}
			}
			previews.Clear();
			playerSprites.Clear();
		}

		private static SpriteRenderer FindPlayerSprite(int playerId)
		{
			if (playerSprites.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && ((Component)value).gameObject.activeInHierarchy)
			{
				return value;
			}
			SlimeController[] array = Object.FindObjectsOfType<SlimeController>();
			foreach (SlimeController val in array)
			{
				if (val.GetPlayerId() == playerId)
				{
					SpriteRenderer playerSprite = val.GetPlayerSprite();
					if ((Object)(object)playerSprite != (Object)null && ((Component)playerSprite).gameObject.activeInHierarchy)
					{
						playerSprites[playerId] = playerSprite;
						return playerSprite;
					}
				}
			}
			return null;
		}

		private static bool Load()
		{
			//IL_0050: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			loadAttempted = true;
			dashSprite = SiphonAbility.LoadDash();
			laserSprite = SiphonAbility.LoadLaser();
			if ((Object)(object)dashSprite == (Object)null || (Object)(object)laserSprite == (Object)null)
			{
				loadFailed = true;
				Plugin.Log.LogError((object)"Siphon Beam: art failed to load, so the circle and the beam will be invisible. The ability itself still works.");
				return false;
			}
			Rect rect = dashSprite.rect;
			float height = ((Rect)(ref rect)).height;
			rect = dashSprite.rect;
			dashSpriteHeightUnits = height / ((Rect)(ref rect)).width;
			Plugin.Log.LogInfo((object)"Siphon Beam: art ready.");
			return true;
		}
	}
	public static class SlimePose
	{
		private static readonly string[] WantedAnimations = new string[4] { "loop", "loopUp", "loopAir", "enter" };

		public static Sprite[] Frames { get; private set; }

		public static void CaptureFrom(NamedSpriteList icons)
		{
			//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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (Frames != null || (Object)(object)icons == (Object)null || icons.sprites == null)
			{
				return;
			}
			Beam val = null;
			foreach (NamedSprite sprite in icons.sprites)
			{
				if (!((Object)(object)sprite.associatedGameObject == (Object)null))
				{
					Beam component = sprite.associatedGameObject.GetComponent<Beam>();
					if ((Object)(object)component != (Object)null)
					{
						val = component;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Siphon Beam: the game's own beam ability was not in the ability grid, so the slime will keep its normal sprite while firing. Everything else works.");
				return;
			}
			AnimationData value = Traverse.Create((object)val).Field("animData").GetValue<AnimationData>();
			if ((Object)(object)value == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Siphon Beam: the beam ability had no animation data, so the slime will keep its normal sprite while firing.");
				return;
			}
			string[] wantedAnimations = WantedAnimations;
			foreach (string text in wantedAnimations)
			{
				List<Sprite> list = Extract(value, text);
				if (list != null && list.Count != 0)
				{
					Frames = list.ToArray();
					Plugin.Log.LogInfo((object)("Siphon Beam: borrowed the game's '" + text + "' beam pose " + $"({Frames.Length} frames) for the firing animation."));
					return;
				}
			}
			Plugin.Log.LogWarning((object)("Siphon Beam: none of the expected beam animations were present (" + string.Join(", ", WantedAnimations) + "), so the slime will keep its normal sprite while firing."));
		}

		private static List<Sprite> Extract(AnimationData data, string name)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			SpriteFrame[] animation;
			try
			{
				animation = data.GetAnimation(name);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Siphon Beam: beam animation '" + name + "' is not present (" + ex.Message + "); trying the next one."));
				return null;
			}
			if (animation == null)
			{
				return null;
			}
			List<Sprite> list = new List<Sprite>();
			SpriteFrame[] array = animation;
			foreach (SpriteFrame val in array)
			{
				if ((Object)(object)val.sprite != (Object)null)
				{
					list.Add(val.sprite);
				}
			}
			return list;
		}
	}
}