Decompiled source of FourthAbility v1.0.0

BepInEx\plugins\FourthAbility\FourthAbilitySlot.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Logging;
using BoplFixedMath;
using HarmonyLib;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FourthAbilitySlotMod;

[BepInPlugin("com.openai.boplbattle.fourthabilityslot", "Fourth Ability Slot", "1.1.3")]
public sealed class FourthAbilityPlugin : BaseUnityPlugin
{
	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		FourthAbilityRuntime.Log = ((BaseUnityPlugin)this).Logger;
		new Harmony("com.openai.boplbattle.fourthabilityslot").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Fourth Ability Slot v1.1.3 loaded: repaired local loss selector, visible four-player HUD slots, diamond indicator layout, and synchronized online play enabled.");
	}

	private void Update()
	{
		FourthAbilityRuntime.NetworkUpdate();
	}
}
internal sealed class FourthSlotPointer : MonoBehaviour, IPointerEnterHandler, IPointerClickHandler, IEventSystemHandler
{
	internal CharacterSelectBox Box;

	internal SelectAbility Slot;

	private int SlotIndex()
	{
		List<SelectableMonoBehaviour> field = FourthAbilityRuntime.GetField<List<SelectableMonoBehaviour>>(Box, "selectables");
		if (field != null && !((Object)(object)Slot == (Object)null))
		{
			return field.IndexOf((SelectableMonoBehaviour)(object)Slot);
		}
		return -1;
	}

	public void OnPointerEnter(PointerEventData eventData)
	{
		int num = SlotIndex();
		if ((Object)(object)Box != (Object)null && num >= 0)
		{
			Box.SetSelectedHover(num);
		}
	}

	public void OnPointerClick(PointerEventData eventData)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		if (eventData == null || (int)eventData.button == 0)
		{
			int num = SlotIndex();
			if (!((Object)(object)Box == (Object)null) && num >= 0)
			{
				Box.SetSelectedHover(num);
				Box.ClickEnterAbilityGrid();
			}
		}
	}
}
internal sealed class MidGameFourthPointer : MonoBehaviour, IPointerEnterHandler, IPointerClickHandler, IEventSystemHandler
{
	internal MidGameAbilitySelect Selector;

	public void OnPointerEnter(PointerEventData eventData)
	{
		if (!((Object)(object)Selector == (Object)null))
		{
			FourthAbilityRuntime.SetField(Selector, "YPos", 3);
			Selector.SyncArrowPositionToCurrentYPos();
			AudioManager.Get().Play("navigateMenu");
		}
	}

	public void OnPointerClick(PointerEventData eventData)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		if ((eventData == null || (int)eventData.button == 0) && !((Object)(object)Selector == (Object)null))
		{
			FourthAbilityRuntime.SetField(Selector, "YPos", 3);
			Selector.SyncArrowPositionToCurrentYPos();
		}
	}
}
internal sealed class MatchTeamTextColor : MonoBehaviour
{
	internal TMP_Text Source;

	private TMP_Text target;

	private void Awake()
	{
		target = ((Component)this).GetComponent<TMP_Text>();
	}

	private void LateUpdate()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)target == (Object)null)
		{
			target = ((Component)this).GetComponent<TMP_Text>();
		}
		if ((Object)(object)target != (Object)null && (Object)(object)Source != (Object)null)
		{
			((Graphic)target).color = ((Graphic)Source).color;
		}
	}
}
internal static class FourthAbilityRuntime
{
	internal sealed class PickupState
	{
		internal AbilityMonoBehaviour FourthAbility;

		internal AbilityReadyIndicator FourthIndicator;

		internal Fix FourthCooldown;

		internal bool Active;
	}

	internal const int KeyboardChoiceKey = -1;

	internal const int FourthBindingIndex = 8;

	internal const byte PacketHello = 1;

	internal const byte PacketChoice = 2;

	internal static ManualLogSource Log;

	internal static NamedSpriteList AllIcons;

	internal static readonly Dictionary<int, SelectAbility> SlotsByBox = new Dictionary<int, SelectAbility>();

	internal static readonly Dictionary<int, CharacterSelectBox> BoxesBySlot = new Dictionary<int, CharacterSelectBox>();

	internal static readonly Dictionary<int, int> Choices = new Dictionary<int, int>();

	internal static readonly Dictionary<int, InputControl> FourthBindings = new Dictionary<int, InputControl>();

	internal static readonly Dictionary<int, Vector2[]> MidGameOriginalPositions = new Dictionary<int, Vector2[]>();

	internal static readonly HashSet<int> VerifiedInputPlayers = new HashSet<int>();

	internal static readonly Dictionary<int, int> OnlineChoices = new Dictionary<int, int>();

	internal static readonly HashSet<string> SeenOnlinePeers = new HashSet<string>();

	internal static readonly byte[] PacketMagic = new byte[4] { 70, 65, 83, 55 };

	internal static float nextNetworkHeartbeat;

	internal static FieldInfo Field(Type type, string name)
	{
		return AccessTools.Field(type, name);
	}

	internal static T GetField<T>(object instance, string name)
	{
		if (instance == null)
		{
			return default(T);
		}
		FieldInfo fieldInfo = Field(instance.GetType(), name);
		if (fieldInfo == null)
		{
			return default(T);
		}
		object value = fieldInfo.GetValue(instance);
		if (value == null)
		{
			return default(T);
		}
		return (T)value;
	}

	internal static void SetField(object instance, string name, object value)
	{
		if (instance != null)
		{
			FieldInfo fieldInfo = Field(instance.GetType(), name);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(instance, value);
			}
		}
	}

	internal static bool IsOnline()
	{
		try
		{
			FieldInfo fieldInfo = Field(typeof(GameLobby), "isOnlineGame");
			return fieldInfo != null && (bool)fieldInfo.GetValue(null);
		}
		catch
		{
			return false;
		}
	}

	internal static bool IsOurPacket(byte[] data)
	{
		if (data != null && data.Length >= 5 && data[0] == PacketMagic[0] && data[1] == PacketMagic[1] && data[2] == PacketMagic[2])
		{
			return data[3] == PacketMagic[3];
		}
		return false;
	}

	internal static byte[] NewPacket(byte type, int payloadBytes)
	{
		byte[] array = new byte[5 + payloadBytes];
		for (int i = 0; i < PacketMagic.Length; i++)
		{
			array[i] = PacketMagic[i];
		}
		array[4] = type;
		return array;
	}

	internal static void WriteInt(byte[] data, int offset, int value)
	{
		byte[] bytes = BitConverter.GetBytes(value);
		for (int i = 0; i < 4; i++)
		{
			data[offset + i] = bytes[i];
		}
	}

	internal static void SendPacket(byte[] data)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		if (!IsOnline() || data == null)
		{
			return;
		}
		try
		{
			SteamManager instance = SteamManager.instance;
			if ((Object)(object)instance == (Object)null || instance.connectedPlayers == null)
			{
				return;
			}
			foreach (SteamConnection connectedPlayer in instance.connectedPlayers)
			{
				if (connectedPlayer != null && ((ConnectionManager)connectedPlayer).Connected)
				{
					((Connection)(ref ((ConnectionManager)connectedPlayer).Connection)).SendMessage(data, (SendType)8);
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Fourth-slot network send failed: " + ex.Message));
		}
	}

	internal static void SendHello()
	{
		byte[] array = NewPacket(1, 1);
		array[5] = 11;
		SendPacket(array);
	}

	internal static void SendChoice(int playerId, int choice)
	{
		byte[] data = NewPacket(2, 8);
		WriteInt(data, 5, playerId);
		WriteInt(data, 9, choice);
		SendPacket(data);
	}

	internal static void NetworkUpdate()
	{
		if (!IsOnline() || Time.unscaledTime < nextNetworkHeartbeat)
		{
			return;
		}
		nextNetworkHeartbeat = Time.unscaledTime + 0.5f;
		SendHello();
		foreach (KeyValuePair<int, int> onlineChoice in OnlineChoices)
		{
			SendChoice(onlineChoice.Key, onlineChoice.Value);
		}
	}

	internal static bool SenderMatchesPlayer(int playerId, NetIdentity identity)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		try
		{
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 == null || val2.IsLocalPlayer)
			{
				return false;
			}
			return string.Equals(((object)val2.steamId/*cast due to .constrained prefix*/).ToString(), ((object)((NetIdentity)(ref identity)).SteamId/*cast due to .constrained prefix*/).ToString(), StringComparison.Ordinal);
		}
		catch
		{
			return false;
		}
	}

	internal static void ReceivePacket(byte[] data, NetIdentity identity)
	{
		//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_0095: Unknown result type (might be due to invalid IL or missing references)
		if (!IsOurPacket(data))
		{
			return;
		}
		try
		{
			switch (data[4])
			{
			case 1:
			{
				string text = ((object)((NetIdentity)(ref identity)).SteamId/*cast due to .constrained prefix*/).ToString();
				int num2 = ((data.Length > 5) ? data[5] : 0);
				if (SeenOnlinePeers.Add(text))
				{
					if (num2 == 11)
					{
						Log.LogInfo((object)("Fourth Ability Slot v1.1.3 handshake received from online peer " + text + "."));
					}
					else
					{
						Log.LogWarning((object)("Online peer " + text + " is using an older Fourth Ability Slot build. Install v1.1.3 on every computer for identical menus."));
					}
				}
				break;
			}
			case 2:
				if (data.Length >= 13)
				{
					int num = BitConverter.ToInt32(data, 5);
					if (SenderMatchesPlayer(num, identity))
					{
						int value = BitConverter.ToInt32(data, 9);
						OnlineChoices[num] = value;
					}
				}
				break;
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Ignored malformed fourth-slot network packet: " + ex.Message));
		}
	}

	internal static int GetBoxKey(CharacterSelectBox box)
	{
		if (GetField<bool>(box, "UseskeyboardMouse"))
		{
			return -1;
		}
		Gamepad field = GetField<Gamepad>(box, "currentGamePad");
		if (field != null)
		{
			return ((InputDevice)field).deviceId;
		}
		return int.MinValue;
	}

	internal static int GetPlayerKey(Player player)
	{
		if (player.UsesKeyboardAndMouse)
		{
			return -1;
		}
		InputDevice inputDevice = player.inputDevice;
		Gamepad val = (Gamepad)(object)((inputDevice is Gamepad) ? inputDevice : null);
		if (val != null)
		{
			return ((InputDevice)val).deviceId;
		}
		return int.MinValue;
	}

	internal static void SaveChoice(CharacterSelectBox box)
	{
		if ((Object)(object)box == (Object)null || !SlotsByBox.TryGetValue(((Object)box).GetInstanceID(), out var value) || (Object)(object)value == (Object)null)
		{
			return;
		}
		int boxKey = GetBoxKey(box);
		if (boxKey == int.MinValue)
		{
			return;
		}
		Choices[boxKey] = value.SelectedIndex;
		if (!IsOnline())
		{
			return;
		}
		PlayerHandler val = PlayerHandler.Get();
		List<Player> list = ((val == null) ? null : val.PlayerList());
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			Player val2 = list[i];
			if (val2 != null && val2.IsLocalPlayer && GetPlayerKey(val2) == boxKey)
			{
				OnlineChoices[val2.Id] = value.SelectedIndex;
				SendChoice(val2.Id, value.SelectedIndex);
				break;
			}
		}
	}

	internal static void AdjustAnimationTarget(SelectAbility slot, float oldTarget, float newTarget)
	{
		//IL_0077: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)slot == (Object)null)
		{
			return;
		}
		float num = newTarget - oldTarget;
		AnimateInOutUI component = ((Component)slot).GetComponent<AnimateInOutUI>();
		if ((Object)(object)component != (Object)null)
		{
			bool field = GetField<bool>(component, "horizontalInstead");
			float[] field2 = GetField<float[]>(component, "originalHeights");
			if (!field && field2 != null)
			{
				for (int i = 0; i < field2.Length; i++)
				{
					field2[i] += num;
				}
			}
		}
		RectTransform component2 = ((Component)slot).GetComponent<RectTransform>();
		if ((Object)(object)component2 != (Object)null && Mathf.Abs(component2.anchoredPosition.y - oldTarget) < 1f)
		{
			Vector2 anchoredPosition = component2.anchoredPosition;
			anchoredPosition.y = newTarget;
			component2.anchoredPosition = anchoredPosition;
		}
	}

	internal static AnimateInOutUI[] InsertAnimation(AnimateInOutUI[] source, AnimateInOutUI after, AnimateInOutUI item)
	{
		if (source == null)
		{
			if (!((Object)(object)item == (Object)null))
			{
				return (AnimateInOutUI[])(object)new AnimateInOutUI[1] { item };
			}
			return null;
		}
		int num = source.Length;
		for (int i = 0; i < source.Length; i++)
		{
			if ((Object)(object)source[i] == (Object)(object)after)
			{
				num = i + 1;
				break;
			}
		}
		AnimateInOutUI[] array = (AnimateInOutUI[])(object)new AnimateInOutUI[source.Length + 1];
		for (int j = 0; j < num; j++)
		{
			array[j] = source[j];
		}
		array[num] = item;
		for (int k = num; k < source.Length; k++)
		{
			array[k + 1] = source[k];
		}
		return array;
	}

	internal static T[] AppendValue<T>(T[] source, T value)
	{
		int num = ((source != null) ? source.Length : 0);
		T[] array = new T[num + 1];
		for (int i = 0; i < num; i++)
		{
			array[i] = source[i];
		}
		array[num] = value;
		return array;
	}

	internal static T[] PrependValue<T>(T[] source, T value)
	{
		int num = ((source != null) ? source.Length : 0);
		T[] array = new T[num + 1];
		array[0] = value;
		for (int i = 0; i < num; i++)
		{
			array[i + 1] = source[i];
		}
		return array;
	}

	internal static T CloneUiBelow<T>(T[] source, string objectName) where T : Component
	{
		//IL_0115: 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_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		if (source == null || source.Length == 0 || (Object)(object)source[^1] == (Object)null)
		{
			return default(T);
		}
		T val = source[^1];
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
		((Object)val2).name = objectName;
		val2.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
		RectTransform component = val2.GetComponent<RectTransform>();
		RectTransform component2 = ((Component)val/*cast due to .constrained prefix*/).GetComponent<RectTransform>();
		if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
		{
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0f, -34f);
			if (source.Length > 1 && (Object)(object)source[^2] != (Object)null)
			{
				RectTransform component3 = ((Component)source[^2]/*cast due to .constrained prefix*/).GetComponent<RectTransform>();
				if ((Object)(object)component3 != (Object)null)
				{
					val3 = component2.anchoredPosition - component3.anchoredPosition;
				}
			}
			component.anchoredPosition = component2.anchoredPosition + val3;
		}
		return val2.GetComponent<T>();
	}

	internal static T CloneUiAbove<T>(T[] source, string objectName) where T : Component
	{
		//IL_0100: 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_0107: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		if (source == null || source.Length == 0 || (Object)(object)source[0] == (Object)null)
		{
			return default(T);
		}
		T val = source[0];
		GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
		((Object)val2).name = objectName;
		val2.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex());
		RectTransform component = val2.GetComponent<RectTransform>();
		RectTransform component2 = ((Component)val/*cast due to .constrained prefix*/).GetComponent<RectTransform>();
		if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
		{
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0f, 34f);
			if (source.Length > 1 && (Object)(object)source[1] != (Object)null)
			{
				RectTransform component3 = ((Component)source[1]/*cast due to .constrained prefix*/).GetComponent<RectTransform>();
				if ((Object)(object)component3 != (Object)null)
				{
					val3 = component2.anchoredPosition - component3.anchoredPosition;
				}
			}
			component.anchoredPosition = component2.anchoredPosition + val3;
		}
		return val2.GetComponent<T>();
	}

	internal static void PrepareKeyBindMenu(KeyBindButton button)
	{
		if ((Object)(object)button == (Object)null)
		{
			return;
		}
		try
		{
			string[] field = GetField<string[]>(button, "KeyListGamePad");
			string[] field2 = GetField<string[]>(button, "KeyListKeyboardMouse");
			if (field == null || field2 == null || field.Length >= 9 || field2.Length >= 9)
			{
				return;
			}
			SetField(button, "KeyListGamePad", PrependValue(field, field[Math.Min(3, field.Length - 1)]));
			SetField(button, "KeyListKeyboardMouse", PrependValue(field2, field2[Math.Min(3, field2.Length - 1)]));
			bool[] field3 = GetField<bool[]>(button, "MouseOnlyKeyList");
			SetField(button, "MouseOnlyKeyList", PrependValue(field3, value: false));
			Sprite[] field4 = GetField<Sprite[]>(button, "CircleIndicators_gamePad");
			Sprite[] field5 = GetField<Sprite[]>(button, "CircleIndicators_keyboard");
			Sprite value = ((field4 != null && field4.Length > 3) ? field4[3] : null);
			Sprite value2 = ((field5 != null && field5.Length > 3) ? field5[3] : null);
			SetField(button, "CircleIndicators_gamePad", PrependValue(field4, value));
			SetField(button, "CircleIndicators_keyboard", PrependValue(field5, value2));
			SetField(button, "indicatorRotations_keyboard", PrependValue(GetField<float[]>(button, "indicatorRotations_keyboard"), 0f));
			TextMeshProUGUI[] field6 = GetField<TextMeshProUGUI[]>(button, "bindingListLabels");
			TextMeshProUGUI val = FourthAbilityRuntime.CloneUiAbove<TextMeshProUGUI>(field6, "Ability 4 Binding Label");
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)val).text = "A4";
				MatchTeamTextColor matchTeamTextColor = ((Component)val).gameObject.GetComponent<MatchTeamTextColor>();
				if ((Object)(object)matchTeamTextColor == (Object)null)
				{
					matchTeamTextColor = ((Component)val).gameObject.AddComponent<MatchTeamTextColor>();
				}
				matchTeamTextColor.Source = (TMP_Text)(object)((field6 != null && field6.Length > 0) ? field6[0] : null);
			}
			SetField(button, "bindingListLabels", PrependValue(field6, val));
			TextMeshProUGUI[] field7 = GetField<TextMeshProUGUI[]>(button, "bindingListChoices");
			TextMeshProUGUI val2 = FourthAbilityRuntime.CloneUiAbove<TextMeshProUGUI>(field7, "Ability 4 Binding Choice");
			if ((Object)(object)val2 != (Object)null)
			{
				((TMP_Text)val2).text = "";
				MatchTeamTextColor matchTeamTextColor2 = ((Component)val2).gameObject.GetComponent<MatchTeamTextColor>();
				if ((Object)(object)matchTeamTextColor2 == (Object)null)
				{
					matchTeamTextColor2 = ((Component)val2).gameObject.AddComponent<MatchTeamTextColor>();
				}
				matchTeamTextColor2.Source = (TMP_Text)(object)((field7 != null && field7.Length > 0) ? field7[0] : null);
			}
			SetField(button, "bindingListChoices", PrependValue(field7, val2));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not extend the in-game keybind menu: " + ex));
		}
	}

	internal static void FinishKeyBindMenu(KeyBindButton button)
	{
		if (!((Object)(object)button == (Object)null))
		{
			string[] field = GetField<string[]>(button, "keyListGamepad_spaced");
			string[] field2 = GetField<string[]>(button, "KeyListKeyboardMouse_spaced");
			if (field != null && field.Length > 8)
			{
				field[0] = "A4";
			}
			if (field2 != null && field2.Length > 8)
			{
				field2[0] = "A4";
			}
		}
	}

	internal static InputControl DefaultFourthBinding(bool keyboardMouse, Gamepad pad)
	{
		if (keyboardMouse)
		{
			Mouse current = Mouse.current;
			if (current != null)
			{
				return (InputControl)(object)current.middleButton;
			}
			return null;
		}
		if (pad != null)
		{
			return (InputControl)(object)pad.rightTrigger;
		}
		return null;
	}

	internal static InputControl FourthBindingFor(Player player)
	{
		if (player == null)
		{
			return null;
		}
		int playerKey = GetPlayerKey(player);
		if (playerKey != int.MinValue && FourthBindings.TryGetValue(playerKey, out var value) && value != null)
		{
			return value;
		}
		bool usesKeyboardAndMouse = player.UsesKeyboardAndMouse;
		InputDevice inputDevice = player.inputDevice;
		return DefaultFourthBinding(usesKeyboardAndMouse, (Gamepad)(object)((inputDevice is Gamepad) ? inputDevice : null));
	}

	internal static InputControl[] ToBindingMenuOrder(Player player)
	{
		if (player == null)
		{
			return null;
		}
		InputControl[] customKeyBinding = player.CustomKeyBinding;
		InputControl[] array = (InputControl[])(object)new InputControl[9]
		{
			FourthBindingFor(player),
			default(InputControl),
			default(InputControl),
			default(InputControl),
			default(InputControl),
			default(InputControl),
			default(InputControl),
			default(InputControl),
			default(InputControl)
		};
		for (int i = 0; i < 8; i++)
		{
			array[i + 1] = ((customKeyBinding != null && customKeyBinding.Length > i) ? customKeyBinding[i] : null);
		}
		return array;
	}

	internal static InputControl[] ToVanillaBindingOrder(InputControl[] ordered)
	{
		if (ordered == null || ordered.Length <= 8)
		{
			return ordered;
		}
		InputControl[] array = (InputControl[])(object)new InputControl[8];
		for (int i = 0; i < 8; i++)
		{
			array[i] = ordered[i + 1];
		}
		return array;
	}

	internal static void EnsureFourthBinding(Player player)
	{
		if (player != null && player.IsLocalPlayer)
		{
			int playerKey = GetPlayerKey(player);
			if (playerKey != int.MinValue && !FourthBindings.ContainsKey(playerKey))
			{
				Dictionary<int, InputControl> fourthBindings = FourthBindings;
				bool usesKeyboardAndMouse = player.UsesKeyboardAndMouse;
				InputDevice inputDevice = player.inputDevice;
				fourthBindings[playerKey] = DefaultFourthBinding(usesKeyboardAndMouse, (Gamepad)(object)((inputDevice is Gamepad) ? inputDevice : null));
			}
		}
	}

	internal static InputControl[] HideFourthBinding(Player player)
	{
		return null;
	}

	internal static bool EventCalls(UnityEvent callback, string methodName)
	{
		if (callback == null)
		{
			return false;
		}
		for (int i = 0; i < ((UnityEventBase)callback).GetPersistentEventCount(); i++)
		{
			if (string.Equals(((UnityEventBase)callback).GetPersistentMethodName(i), methodName, StringComparison.Ordinal))
			{
				return true;
			}
		}
		return false;
	}

	internal static void InstallFourthSlotPointer(CharacterSelectBox box, SelectAbility fourth)
	{
		if ((Object)(object)box == (Object)null || (Object)(object)fourth == (Object)null)
		{
			return;
		}
		bool flag = false;
		CallOnHover[] componentsInChildren = ((Component)fourth).GetComponentsInChildren<CallOnHover>(true);
		foreach (CallOnHover val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && (EventCalls(val.onHover, "SetSelectedHover") || EventCalls(val.onClick, "ClickEnterAbilityGrid")))
			{
				GameObject gameObject = ((Component)val).gameObject;
				Object.Destroy((Object)(object)val);
				FourthSlotPointer fourthSlotPointer = gameObject.GetComponent<FourthSlotPointer>();
				if ((Object)(object)fourthSlotPointer == (Object)null)
				{
					fourthSlotPointer = gameObject.AddComponent<FourthSlotPointer>();
				}
				fourthSlotPointer.Box = box;
				fourthSlotPointer.Slot = fourth;
				flag = true;
			}
		}
		if (!flag)
		{
			Image field = GetField<Image>(fourth, "abilityIconRenderer");
			GameObject val2 = (((Object)(object)field == (Object)null) ? ((Component)fourth).gameObject : ((Component)field).gameObject);
			FourthSlotPointer fourthSlotPointer2 = val2.GetComponent<FourthSlotPointer>();
			if ((Object)(object)fourthSlotPointer2 == (Object)null)
			{
				fourthSlotPointer2 = val2.AddComponent<FourthSlotPointer>();
			}
			fourthSlotPointer2.Box = box;
			fourthSlotPointer2.Slot = fourth;
		}
	}

	internal static void CreateFourthSlot(CharacterSelectBox box)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: 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)
		//IL_00a2: 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_00bc: 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)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)box == (Object)null)
		{
			return;
		}
		try
		{
			List<SelectableMonoBehaviour> field = GetField<List<SelectableMonoBehaviour>>(box, "selectables");
			if (field == null || field.Count < 5 || SlotsByBox.ContainsKey(((Object)box).GetInstanceID()))
			{
				return;
			}
			SelectableMonoBehaviour obj = field[2];
			SelectAbility val = (SelectAbility)(object)((obj is SelectAbility) ? obj : null);
			SelectableMonoBehaviour obj2 = field[3];
			SelectAbility val2 = (SelectAbility)(object)((obj2 is SelectAbility) ? obj2 : null);
			SelectableMonoBehaviour obj3 = field[4];
			SelectAbility val3 = (SelectAbility)(object)((obj3 is SelectAbility) ? obj3 : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				return;
			}
			Vector3 localScale = ((Component)val).transform.localScale * 0.76f;
			((Component)val).transform.localScale = localScale;
			((Component)val2).transform.localScale = localScale;
			((Component)val3).transform.localScale = localScale;
			GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, ((Component)val3).transform.parent);
			((Object)val4).name = "Fourth Ability Slot";
			val4.transform.SetSiblingIndex(((Component)val3).transform.GetSiblingIndex() + 1);
			SelectAbility component = val4.GetComponent<SelectAbility>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val4);
				return;
			}
			SetField(component, "csb", box);
			SetField(component, "Skip", false);
			((Component)component).transform.localScale = localScale;
			field.Insert(5, (SelectableMonoBehaviour)(object)component);
			List<Vector2> field2 = GetField<List<Vector2>>(box, "arrow_Separation_YPos");
			if (field2 != null && field2.Count >= 5)
			{
				field2.Insert(5, field2[4]);
			}
			List<Image> field3 = GetField<List<Image>>(box, "imagesToDisable");
			if (field3 != null && field3.Count >= 5)
			{
				field3.Insert(5, null);
			}
			AnimateInOutUI[] field4 = GetField<AnimateInOutUI[]>(box, "animateSelectables");
			SetField(box, "animateSelectables", InsertAnimation(field4, ((Component)val3).GetComponent<AnimateInOutUI>(), ((Component)component).GetComponent<AnimateInOutUI>()));
			float[] field5 = GetField<float[]>(box, "originalAbilitySelectPos");
			if (field5 != null && field5.Length >= 3)
			{
				float num = field5[0];
				float num2 = field5[2];
				float num3 = (num + num2) * 0.5f;
				float num4 = (num2 - num) * 0.5f * 0.78f;
				float newTarget = num3 - num4 * 1.5f;
				float newTarget2 = num3 - num4 * 0.5f;
				float newTarget3 = num3 + num4 * 0.5f;
				float newTarget4 = num3 + num4 * 1.5f;
				AdjustAnimationTarget(val, field5[0], newTarget);
				AdjustAnimationTarget(val2, field5[1], newTarget2);
				AdjustAnimationTarget(val3, field5[2], newTarget3);
				AdjustAnimationTarget(component, field5[2], newTarget4);
			}
			AllIcons = GetField<NamedSpriteList>(component, "abilityIcons");
			SlotsByBox[((Object)box).GetInstanceID()] = component;
			BoxesBySlot[((Object)component).GetInstanceID()] = box;
			((SelectableMonoBehaviour)component).Select(val3.SelectedIndex);
			InstallFourthSlotPointer(box, component);
			Log.LogInfo((object)("Added fourth ability choice to character select box " + ((Object)box).GetInstanceID() + "."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not create the fourth character-select slot: " + ex));
		}
	}

	internal static bool RawFourthInputHeld(Player player)
	{
		if (player == null || player.ignoreAllInputs)
		{
			return false;
		}
		if (!player.IsLocalPlayer)
		{
			return false;
		}
		EnsureFourthBinding(player);
		InputControl val = FourthBindingFor(player);
		ButtonControl val2 = (ButtonControl)(object)((val is ButtonControl) ? val : null);
		bool flag = val2 != null && val2.isPressed;
		if (flag && VerifiedInputPlayers.Add(player.Id))
		{
			Log.LogInfo((object)("Fourth-slot input detected for local player " + player.Id + "."));
		}
		return flag;
	}

	internal static bool HasFourMidGameRows(MidGameAbilitySelect selector)
	{
		if ((Object)(object)selector == (Object)null)
		{
			return false;
		}
		Player field = GetField<Player>(selector, "player");
		RectTransform[] field2 = GetField<RectTransform[]>(selector, "Circles");
		if (field != null && field.Abilities != null && field.Abilities.Count > 3 && field2 != null)
		{
			return field2.Length > 3;
		}
		return false;
	}

	internal static void InstallMidGamePointer(MidGameAbilitySelect selector, RectTransform circle)
	{
		if ((Object)(object)selector == (Object)null || (Object)(object)circle == (Object)null)
		{
			return;
		}
		bool flag = false;
		CallOnHover[] componentsInChildren = ((Component)circle).GetComponentsInChildren<CallOnHover>(true);
		foreach (CallOnHover val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && EventCalls(val.onHover, "HoverCircle"))
			{
				GameObject gameObject = ((Component)val).gameObject;
				Object.Destroy((Object)(object)val);
				MidGameFourthPointer midGameFourthPointer = gameObject.GetComponent<MidGameFourthPointer>();
				if ((Object)(object)midGameFourthPointer == (Object)null)
				{
					midGameFourthPointer = gameObject.AddComponent<MidGameFourthPointer>();
				}
				midGameFourthPointer.Selector = selector;
				flag = true;
			}
		}
		if (!flag)
		{
			MidGameFourthPointer midGameFourthPointer2 = ((Component)circle).GetComponent<MidGameFourthPointer>();
			if ((Object)(object)midGameFourthPointer2 == (Object)null)
			{
				midGameFourthPointer2 = ((Component)circle).gameObject.AddComponent<MidGameFourthPointer>();
			}
			midGameFourthPointer2.Selector = selector;
		}
	}

	internal static void EnsureMidGameFourthCircle(MidGameAbilitySelect selector)
	{
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: 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_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: 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_0138: 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)
		if ((Object)(object)selector == (Object)null)
		{
			return;
		}
		RectTransform[] field = GetField<RectTransform[]>(selector, "Circles");
		if (field == null || field.Length < 3 || (Object)(object)field[2] == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)selector).GetInstanceID();
		if (!MidGameOriginalPositions.ContainsKey(instanceID))
		{
			Vector2[] array = (Vector2[])(object)new Vector2[3];
			for (int i = 0; i < 3; i++)
			{
				ref Vector2 reference = ref array[i];
				reference = (((Object)(object)field[i] == (Object)null) ? Vector2.zero : field[i].anchoredPosition);
			}
			MidGameOriginalPositions[instanceID] = array;
		}
		RectTransform val;
		if (field.Length > 3 && (Object)(object)field[3] != (Object)null)
		{
			val = field[3];
		}
		else
		{
			GameObject val2 = Object.Instantiate<GameObject>(((Component)field[2]).gameObject, ((Transform)field[2]).parent);
			((Object)val2).name = "Fourth Between-Round Ability Circle";
			val2.transform.SetSiblingIndex(((Transform)field[2]).GetSiblingIndex() + 1);
			val = val2.GetComponent<RectTransform>();
			if ((Object)(object)val == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return;
			}
			Vector2 val3 = (((Object)(object)field[1] == (Object)null) ? (Vector2.down * GetField<float>(selector, "circleDistance")) : (field[2].anchoredPosition - field[1].anchoredPosition));
			val.anchoredPosition = field[2].anchoredPosition + val3;
			RectTransform[] array2 = (RectTransform[])(object)new RectTransform[4];
			for (int j = 0; j < 3; j++)
			{
				array2[j] = field[j];
			}
			array2[3] = val;
			SetField(selector, "Circles", array2);
		}
		InstallMidGamePointer(selector, val);
		LayoutMidGameRows(selector);
	}

	internal static void LayoutMidGameRows(MidGameAbilitySelect selector)
	{
		//IL_0044: 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_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_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: 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_0087: 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_008d: 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)
		//IL_009a: 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)
		//IL_00ac: 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_00c0: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)selector == (Object)null)
		{
			return;
		}
		RectTransform[] field = GetField<RectTransform[]>(selector, "Circles");
		if (field == null || field.Length < 4 || !MidGameOriginalPositions.TryGetValue(((Object)selector).GetInstanceID(), out var value) || value == null || value.Length < 3)
		{
			return;
		}
		Vector2 val = (value[0] + value[2]) * 0.5f;
		Vector2 val2 = (value[2] - value[0]) * 0.5f;
		Vector2 val3 = val2 * 0.72f;
		val += Vector2.up * Mathf.Abs(val2.y) * 0.16f;
		for (int i = 0; i < 4; i++)
		{
			if (!((Object)(object)field[i] == (Object)null))
			{
				field[i].anchoredPosition = val + val3 * ((float)i - 1.5f);
				((Transform)field[i]).localScale = Vector3.one * 0.9f;
				((Component)field[i]).gameObject.SetActive(true);
			}
		}
		SyncAbilitySelectControllerLayout(selector, field);
	}

	internal static void SyncAbilitySelectControllerLayout(MidGameAbilitySelect selector, RectTransform[] circles)
	{
		//IL_004b: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)selector == (Object)null || circles == null || circles.Length < 4)
		{
			return;
		}
		AbilitySelectController componentInParent = ((Component)selector).GetComponentInParent<AbilitySelectController>();
		if (!((Object)(object)componentInParent == (Object)null))
		{
			Vector2[] array = (Vector2[])(object)new Vector2[4];
			for (int i = 0; i < 4; i++)
			{
				ref Vector2 reference = ref array[i];
				reference = (((Object)(object)circles[i] == (Object)null) ? Vector2.zero : circles[i].anchoredPosition);
			}
			SetField(componentInParent, "abilityListOriginalPositions", array);
			Log.LogInfo((object)("Repaired four-row between-round animation targets for local player " + componentInParent.GetPlayerId() + "."));
		}
	}

	internal static void EnsureAbilitySelectAnimationTargets(AbilitySelectController controller)
	{
		//IL_0077: 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_007c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		MidGameAbilitySelect field = GetField<MidGameAbilitySelect>(controller, "abilityCirclesParent");
		RectTransform[] array = (((Object)(object)field == (Object)null) ? null : GetField<RectTransform[]>(field, "Circles"));
		if (array == null)
		{
			return;
		}
		Vector2[] field2 = GetField<Vector2[]>(controller, "abilityListOriginalPositions");
		if (field2 == null || field2.Length != array.Length)
		{
			Vector2[] array2 = (Vector2[])(object)new Vector2[array.Length];
			for (int i = 0; i < array2.Length; i++)
			{
				ref Vector2 reference = ref array2[i];
				reference = (((Object)(object)array[i] == (Object)null) ? Vector2.zero : array[i].anchoredPosition);
			}
			SetField(controller, "abilityListOriginalPositions", array2);
		}
	}

	internal static int IconIndexForAbility(NamedSpriteList icons, GameObject ability)
	{
		if ((Object)(object)icons == (Object)null || icons.sprites == null || (Object)(object)ability == (Object)null)
		{
			return 1;
		}
		int num = icons.IndexOf(((Object)ability).name);
		if (num > 0 && num < icons.sprites.Count)
		{
			return num;
		}
		return 1;
	}

	internal static void PrepareMidGameSelector(MidGameAbilitySelect selector)
	{
		if (!HasFourMidGameRows(selector))
		{
			return;
		}
		Player field = GetField<Player>(selector, "player");
		RectTransform[] field2 = GetField<RectTransform[]>(selector, "Circles");
		NamedSpriteList field3 = GetField<NamedSpriteList>(selector, "localAbilityIcons");
		if (field != null && field2 != null && !((Object)(object)field2[3] == (Object)null) && !((Object)(object)field3 == (Object)null))
		{
			Image[] field4 = GetField<Image[]>(selector, "CircleImages");
			int[] field5 = GetField<int[]>(selector, "XPos");
			Image[] array = (Image[])(object)new Image[4];
			int[] array2 = new int[4];
			for (int i = 0; i < 3; i++)
			{
				array[i] = ((field4 != null && field4.Length > i) ? field4[i] : null);
				array2[i] = ((field5 == null || field5.Length <= i) ? 1 : field5[i]);
			}
			((Component)field2[3]).gameObject.SetActive(true);
			array[3] = ((((Transform)field2[3]).childCount > 0) ? ((Component)((Transform)field2[3]).GetChild(0)).GetComponent<Image>() : null);
			array2[3] = IconIndexForAbility(field3, field.Abilities[3]);
			if ((Object)(object)array[3] != (Object)null)
			{
				array[3].sprite = field3.GetSprite(array2[3]);
			}
			SetField(selector, "CircleImages", array);
			SetField(selector, "XPos", array2);
			LayoutMidGameRows(selector);
			selector.SyncArrowPositionToCurrentYPos();
		}
	}

	internal static bool MoveMidGameRow(MidGameAbilitySelect selector, int direction)
	{
		if (!HasFourMidGameRows(selector))
		{
			return false;
		}
		AudioManager.Get().Play("navigateMenu");
		int field = GetField<int>(selector, "YPos");
		SetField(selector, "YPos", (field + direction + 4) % 4);
		return true;
	}

	internal static void SaveMidGameFourthChoice(MidGameAbilitySelect selector)
	{
		if (!HasFourMidGameRows(selector) || GetField<int>(selector, "YPos") != 3)
		{
			return;
		}
		Player field = GetField<Player>(selector, "player");
		int[] field2 = GetField<int[]>(selector, "XPos");
		if (field != null && field.IsLocalPlayer && field2 != null && field2.Length >= 4)
		{
			int num = field2[3];
			int playerKey = GetPlayerKey(field);
			if (playerKey != int.MinValue)
			{
				Choices[playerKey] = num;
			}
			if (IsOnline())
			{
				OnlineChoices[field.Id] = num;
				SendChoice(field.Id, num);
			}
			Log.LogInfo((object)("Updated fourth ability from the between-round loss selector for player " + field.Id + "."));
		}
	}

	internal static bool FourthInputHeld(Player player)
	{
		if (player == null || player.ignoreAllInputs)
		{
			return false;
		}
		if (IsOnline() || GameLobby.isPlayingAReplay)
		{
			return player.SelectButton_isDown();
		}
		return RawFourthInputHeld(player);
	}

	internal static void PutFourthInputInPacket(int playerId, ref InputPacket packet)
	{
		if (IsOnline())
		{
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null && val2.IsLocalPlayer)
			{
				packet.select = RawFourthInputHeld(val2);
			}
		}
	}

	internal static void AddFourthToPlayers(List<Player> players)
	{
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		if (players == null)
		{
			return;
		}
		if ((Object)(object)AllIcons == (Object)null)
		{
			foreach (SelectAbility value2 in SlotsByBox.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					AllIcons = GetField<NamedSpriteList>(value2, "abilityIcons");
					if ((Object)(object)AllIcons != (Object)null)
					{
						break;
					}
				}
			}
		}
		if ((Object)(object)AllIcons == (Object)null || AllIcons.sprites == null || AllIcons.sprites.Count <= 1)
		{
			Log.LogError((object)"The ability icon list was unavailable; the fourth loadout ability was not added.");
			return;
		}
		for (int i = 0; i < players.Count; i++)
		{
			Player val = players[i];
			if (val == null)
			{
				continue;
			}
			if (val.IsLocalPlayer)
			{
				EnsureFourthBinding(val);
			}
			int num = 1;
			if (val.IsLocalPlayer && Choices.TryGetValue(GetPlayerKey(val), out var value))
			{
				num = value;
			}
			else if (IsOnline() && OnlineChoices.TryGetValue(val.Id, out value))
			{
				num = value;
			}
			if (num <= 0 || num >= AllIcons.sprites.Count)
			{
				num = 1;
			}
			if (IsOnline())
			{
				if (val.IsLocalPlayer)
				{
					OnlineChoices[val.Id] = num;
					SendChoice(val.Id, num);
				}
				else if (!OnlineChoices.ContainsKey(val.Id))
				{
					Log.LogWarning((object)("No fourth-ability selection was received yet for online player " + val.Id + "; using the default until the next selection screen."));
				}
			}
			NamedSprite val2 = AllIcons.sprites[num];
			if (!((Object)(object)val2.associatedGameObject == (Object)null))
			{
				if (val.Abilities == null)
				{
					val.Abilities = new List<GameObject>();
				}
				if (val.AbilityIcons == null)
				{
					val.AbilityIcons = new List<Sprite>();
				}
				if (val.Abilities.Count > 3)
				{
					val.Abilities[3] = val2.associatedGameObject;
				}
				else
				{
					val.Abilities.Add(val2.associatedGameObject);
				}
				if (val.AbilityIcons.Count > 3)
				{
					val.AbilityIcons[3] = val2.sprite;
				}
				else
				{
					val.AbilityIcons.Add(val2.sprite);
				}
				Log.LogInfo((object)("Prepared fourth gameplay ability '" + val2.name + "' for player " + val.Id + " (loadout count " + val.Abilities.Count + ")."));
			}
		}
	}

	internal static void EnsureCooldownArray(SlimeController controller)
	{
		//IL_0066: 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_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		List<AbilityMonoBehaviour> field = GetField<List<AbilityMonoBehaviour>>(controller, "abilities");
		int num = ((field == null) ? 4 : Math.Max(4, field.Count));
		Fix[] field2 = GetField<Fix[]>(controller, "abilityCooldownTimers");
		if (field2 == null || field2.Length < num)
		{
			Fix[] array = (Fix[])(object)new Fix[num];
			int num2 = ((field2 != null) ? field2.Length : 0);
			for (int i = 0; i < num2; i++)
			{
				ref Fix reference = ref array[i];
				reference = field2[i];
			}
			for (int j = num2; j < array.Length; j++)
			{
				ref Fix reference2 = ref array[j];
				reference2 = (Fix)(-1.5f);
			}
			SetField(controller, "abilityCooldownTimers", array);
		}
	}

	internal static void AppendFourthIndicator(SlimeController controller, Sprite sprite)
	{
		//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)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: 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_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_008e: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: 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_0112: 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_011b: 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_00c2: 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_018e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		AbilityReadyIndicator[] field = GetField<AbilityReadyIndicator[]>(controller, "AbilityReadyIndicators");
		if (field == null || field.Length < 3 || (Object)(object)field[2] == (Object)null)
		{
			return;
		}
		AbilityReadyIndicator val = field[2];
		FollowTransform component = ((Component)val).GetComponent<FollowTransform>();
		Vector3 val2 = ((Component)val).transform.localPosition;
		if ((Object)(object)component != (Object)null && GetField<bool>(component, "initializedPosition"))
		{
			val2 = GetField<Vector3>(component, "PositionOffset");
		}
		AbilityReadyIndicator val3 = ((field.Length > 3) ? field[3] : null);
		Vector3 val4 = (((Object)(object)val3 == (Object)null) ? val2 : ((val2 + IndicatorOffset(val3)) * 0.5f));
		float num = 0.32f;
		if ((Object)(object)field[0] != (Object)null && (Object)(object)field[1] != (Object)null)
		{
			Vector3 val5 = IndicatorOffset(field[0]);
			num = Mathf.Max(0.28f, Mathf.Abs(IndicatorOffset(field[1]).x - val5.x) * 0.22f);
		}
		Vector3 offset = val4 + Vector3.right * num;
		Vector3 offset2 = val4 + Vector3.left * num;
		SetIndicatorOffset(val, controller, offset);
		AbilityReadyIndicator val6 = val3;
		GameObject val7 = (((Object)(object)val6 == (Object)null) ? Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent) : ((Component)val6).gameObject);
		if ((Object)(object)val6 == (Object)null)
		{
			((Object)val7).name = "Fourth Ability Ready Indicator";
			val6 = val7.GetComponent<AbilityReadyIndicator>();
			if ((Object)(object)val6 != (Object)null)
			{
				val6.Init();
			}
		}
		if ((Object)(object)val6 != (Object)null)
		{
			SetIndicatorOffset(val6, controller, offset2);
			if ((Object)(object)sprite != (Object)null)
			{
				val6.SetSprite(sprite, true);
			}
			((Component)val6).gameObject.SetActive(true);
		}
		AbilityReadyIndicator[] array = (AbilityReadyIndicator[])(object)new AbilityReadyIndicator[Math.Max(4, field.Length)];
		for (int i = 0; i < field.Length; i++)
		{
			array[i] = field[i];
		}
		array[3] = val6;
		SetField(controller, "AbilityReadyIndicators", array);
	}

	internal static Vector3 IndicatorOffset(AbilityReadyIndicator indicator)
	{
		//IL_0009: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)indicator == (Object)null)
		{
			return Vector3.zero;
		}
		FollowTransform component = ((Component)indicator).GetComponent<FollowTransform>();
		if ((Object)(object)component != (Object)null && GetField<bool>(component, "initializedPosition"))
		{
			return GetField<Vector3>(component, "PositionOffset");
		}
		return ((Component)indicator).transform.localPosition;
	}

	internal static void SetIndicatorOffset(AbilityReadyIndicator indicator, SlimeController controller, Vector3 offset)
	{
		//IL_0010: 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)
		if (!((Object)(object)indicator == (Object)null))
		{
			((Component)indicator).transform.localPosition = offset;
			FollowTransform component = ((Component)indicator).GetComponent<FollowTransform>();
			if (!((Object)(object)component == (Object)null))
			{
				component.Leader = ((Component)controller).transform;
				SetField(component, "PositionOffset", offset);
			}
		}
	}

	internal static void FinishSpawn(GameSessionHandler handler)
	{
		if ((Object)(object)handler == (Object)null)
		{
			return;
		}
		SlimeController[] field = GetField<SlimeController[]>(handler, "slimeControllers");
		PlayerHandler val = PlayerHandler.Get();
		if (field == null || val == null)
		{
			return;
		}
		foreach (SlimeController val2 in field)
		{
			if (!((Object)(object)val2 == (Object)null))
			{
				List<AbilityMonoBehaviour> field2 = GetField<List<AbilityMonoBehaviour>>(val2, "abilities");
				if (field2 == null || field2.Count < 4)
				{
					Log.LogError((object)("Player " + val2.GetPlayerId() + " spawned with " + (field2?.Count ?? 0) + " abilities; fourth ability injection failed before SpawnPlayers."));
					continue;
				}
				Player player = val.GetPlayer(val2.GetPlayerId());
				Sprite sprite = ((player != null && player.AbilityIcons != null && player.AbilityIcons.Count > 3) ? player.AbilityIcons[3] : null);
				AppendFourthIndicator(val2, sprite);
				EnsureCooldownArray(val2);
				AbilityReadyIndicator[] field3 = GetField<AbilityReadyIndicator[]>(val2, "AbilityReadyIndicators");
				Fix[] field4 = GetField<Fix[]>(val2, "abilityCooldownTimers");
				Log.LogInfo((object)("Fourth gameplay slot ready for player " + val2.GetPlayerId() + ": abilities=" + field2.Count + ", indicators=" + ((field3 != null) ? field3.Length : 0) + ", cooldowns=" + ((field4 != null) ? field4.Length : 0) + "."));
			}
		}
	}

	internal static void AddFourthToClone(SlimeController clone, SlimeController source, Player player, AbilityReadyIndicator[] sourceIndicators)
	{
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_01a8: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)clone == (Object)null || (Object)(object)source == (Object)null)
		{
			return;
		}
		try
		{
			Sprite val = null;
			if (sourceIndicators != null && sourceIndicators.Length > 3 && (Object)(object)sourceIndicators[3] != (Object)null)
			{
				val = sourceIndicators[3].GetPrimarySprite();
			}
			if ((Object)(object)val == (Object)null && player != null && player.AbilityIcons != null && player.AbilityIcons.Count > 3)
			{
				val = player.AbilityIcons[3];
			}
			GameObject val2 = null;
			NamedSpriteList abilityIcons = source.abilityIcons;
			if ((Object)(object)abilityIcons != (Object)null && (Object)(object)val != (Object)null)
			{
				int num = abilityIcons.IndexOf(val);
				if (num >= 0 && num < abilityIcons.sprites.Count)
				{
					val2 = abilityIcons.sprites[num].associatedGameObject;
				}
			}
			if ((Object)(object)val2 == (Object)null && player != null && player.Abilities != null && player.Abilities.Count > 3)
			{
				val2 = player.Abilities[3];
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			GameObject val3 = FixTransform.InstantiateFixed(val2, Vec2.zero);
			val3.SetActive(false);
			AbilityMonoBehaviour component = val3.GetComponent<AbilityMonoBehaviour>();
			List<AbilityMonoBehaviour> list = GetField<List<AbilityMonoBehaviour>>(clone, "abilities");
			if (list == null)
			{
				list = new List<AbilityMonoBehaviour>();
				SetField(clone, "abilities", list);
			}
			list.Add(component);
			AppendFourthIndicator(clone, val);
			EnsureCooldownArray(clone);
			Revive val4 = (((Object)(object)component == (Object)null) ? null : ((Component)component).GetComponent<Revive>());
			if ((Object)(object)val4 != (Object)null && player != null && (Object)(object)player.ReviveInstance != (Object)null && ((Object)val4).GetInstanceID() == ((Object)player.ReviveInstance).GetInstanceID())
			{
				Fix[] field = GetField<Fix[]>(clone, "abilityCooldownTimers");
				if (field != null && field.Length > 3)
				{
					ref Fix reference = ref field[3];
					reference = Fix.Zero;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not restore the fourth ability on a clone: " + ex));
		}
	}

	internal static PickupState BeginVanillaPickup(SlimeController controller)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return null;
		}
		List<AbilityMonoBehaviour> field = GetField<List<AbilityMonoBehaviour>>(controller, "abilities");
		AbilityReadyIndicator[] field2 = GetField<AbilityReadyIndicator[]>(controller, "AbilityReadyIndicators");
		Fix[] field3 = GetField<Fix[]>(controller, "abilityCooldownTimers");
		if (field == null || field.Count < 4 || field2 == null || field2.Length < 4 || field3 == null || field3.Length < 4)
		{
			return null;
		}
		PickupState pickupState = new PickupState();
		pickupState.FourthAbility = field[3];
		pickupState.FourthIndicator = field2[3];
		pickupState.FourthCooldown = field3[3];
		pickupState.Active = true;
		List<AbilityMonoBehaviour> list = new List<AbilityMonoBehaviour>();
		for (int i = 0; i < 3; i++)
		{
			list.Add(field[i]);
		}
		AbilityReadyIndicator[] array = (AbilityReadyIndicator[])(object)new AbilityReadyIndicator[3];
		Fix[] array2 = (Fix[])(object)new Fix[3];
		for (int j = 0; j < 3; j++)
		{
			array[j] = field2[j];
			ref Fix reference = ref array2[j];
			reference = field3[j];
		}
		SetField(controller, "abilities", list);
		SetField(controller, "AbilityReadyIndicators", array);
		SetField(controller, "abilityCooldownTimers", array2);
		return pickupState;
	}

	internal static void EndVanillaPickup(SlimeController controller, PickupState state)
	{
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)controller == (Object)null) && state != null && state.Active)
		{
			state.Active = false;
			List<AbilityMonoBehaviour> list = GetField<List<AbilityMonoBehaviour>>(controller, "abilities");
			if (list == null)
			{
				list = new List<AbilityMonoBehaviour>();
			}
			while (list.Count > 3)
			{
				list.RemoveAt(list.Count - 1);
			}
			while (list.Count < 3)
			{
				list.Add(null);
			}
			list.Add(state.FourthAbility);
			SetField(controller, "abilities", list);
			AbilityReadyIndicator[] field = GetField<AbilityReadyIndicator[]>(controller, "AbilityReadyIndicators");
			AbilityReadyIndicator[] array = (AbilityReadyIndicator[])(object)new AbilityReadyIndicator[4];
			for (int i = 0; i < 3; i++)
			{
				array[i] = ((field != null && field.Length > i) ? field[i] : null);
			}
			array[3] = state.FourthIndicator;
			SetField(controller, "AbilityReadyIndicators", array);
			Fix[] field2 = GetField<Fix[]>(controller, "abilityCooldownTimers");
			Fix[] array2 = (Fix[])(object)new Fix[4];
			for (int j = 0; j < 3; j++)
			{
				ref Fix reference = ref array2[j];
				reference = ((field2 != null && field2.Length > j) ? field2[j] : ((Fix)(-1.5f)));
			}
			ref Fix reference2 = ref array2[3];
			reference2 = state.FourthCooldown;
			SetField(controller, "abilityCooldownTimers", array2);
			Log.LogInfo((object)"Ability pickup replaced slot 3 and preserved fourth slot.");
		}
	}
}
[HarmonyPatch(typeof(KeyBindButton), "Awake")]
internal static class KeyBindAwakePatch
{
	private static void Prefix(KeyBindButton __instance)
	{
		FourthAbilityRuntime.PrepareKeyBindMenu(__instance);
	}

	private static void Postfix(KeyBindButton __instance)
	{
		FourthAbilityRuntime.FinishKeyBindMenu(__instance);
	}
}
[HarmonyPatch(typeof(KeyBindButton), "SetToPlayerChoices")]
internal static class KeyBindPlayerChoicesPatch
{
	internal sealed class BindingState
	{
		internal Player Player;

		internal InputControl[] Canonical;
	}

	private static void Prefix(Player player, ref BindingState __state)
	{
		FourthAbilityRuntime.EnsureFourthBinding(player);
		if (player != null)
		{
			__state = new BindingState();
			__state.Player = player;
			__state.Canonical = player.CustomKeyBinding;
			player.CustomKeyBinding = FourthAbilityRuntime.ToBindingMenuOrder(player);
		}
	}

	private static void Postfix(BindingState __state)
	{
		if (__state != null && __state.Player != null)
		{
			__state.Player.CustomKeyBinding = __state.Canonical;
		}
	}

	private static Exception Finalizer(Exception __exception, BindingState __state)
	{
		if (__state != null && __state.Player != null)
		{
			__state.Player.CustomKeyBinding = __state.Canonical;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(KeyBindButton), "UpdateKeybind")]
internal static class KeyBindUpdatePatch
{
	private static bool Prefix(KeyBindButton __instance)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		CharacterSelectBox field = FourthAbilityRuntime.GetField<CharacterSelectBox>(__instance, "charSelectBox");
		if ((Object)(object)field == (Object)null)
		{
			return true;
		}
		bool field2 = FourthAbilityRuntime.GetField<bool>(field, "UseskeyboardMouse");
		InputControl[] field3 = FourthAbilityRuntime.GetField<InputControl[]>(__instance, field2 ? "newBinding_keyboardMouse" : "newBinding_gamepad");
		if (field3 == null || field3.Length <= 8)
		{
			return true;
		}
		int boxKey = FourthAbilityRuntime.GetBoxKey(field);
		if (boxKey != int.MinValue)
		{
			FourthAbilityRuntime.FourthBindings[boxKey] = field3[0];
		}
		InputControl[] keybindOverride = FourthAbilityRuntime.ToVanillaBindingOrder(field3);
		PlayerInit field4 = FourthAbilityRuntime.GetField<PlayerInit>(field, "playerInit");
		field4.keybindOverride = keybindOverride;
		FourthAbilityRuntime.SetField(field, "playerInit", field4);
		FourthAbilityRuntime.Log.LogInfo((object)"Saved A4 binding without changing Bopl's fixed eight-control local-start data.");
		return false;
	}
}
[HarmonyPatch(typeof(InputUpdater), "Init")]
internal static class InputUpdaterInitPatch
{
	internal sealed class BindingState
	{
		internal Player Player;

		internal InputControl[] FullBinding;
	}

	private static void Prefix(int __0, ref BindingState __state)
	{
		PlayerHandler val = PlayerHandler.Get();
		Player val2 = ((val == null) ? null : val.GetPlayer(__0));
		if (val2 != null)
		{
			InputControl[] array = FourthAbilityRuntime.HideFourthBinding(val2);
			if (array != null)
			{
				__state = new BindingState();
				__state.Player = val2;
				__state.FullBinding = array;
			}
		}
	}

	private static void Postfix(BindingState __state)
	{
		if (__state != null && __state.Player != null && __state.FullBinding != null)
		{
			__state.Player.CustomKeyBinding = __state.FullBinding;
		}
	}

	private static Exception Finalizer(BindingState __state, Exception __exception)
	{
		if (__state != null && __state.Player != null && __state.FullBinding != null)
		{
			__state.Player.CustomKeyBinding = __state.FullBinding;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(SlimeController), "AddAdditionalAbility")]
internal static class AbilityPickupPatch
{
	private static void Prefix(SlimeController __instance, ref FourthAbilityRuntime.PickupState __state)
	{
		__state = FourthAbilityRuntime.BeginVanillaPickup(__instance);
	}

	private static void Postfix(SlimeController __instance, FourthAbilityRuntime.PickupState __state)
	{
		FourthAbilityRuntime.EndVanillaPickup(__instance, __state);
	}

	private static Exception Finalizer(SlimeController __instance, Exception __exception, FourthAbilityRuntime.PickupState __state)
	{
		FourthAbilityRuntime.EndVanillaPickup(__instance, __state);
		return __exception;
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "Awake")]
internal static class CharacterSelectAwakePatch
{
	private static void Postfix(CharacterSelectBox __instance)
	{
		FourthAbilityRuntime.CreateFourthSlot(__instance);
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "UpdatePlayerInit")]
internal static class CharacterSelectSavePatch
{
	private static void Postfix(CharacterSelectBox __instance)
	{
		FourthAbilityRuntime.SaveChoice(__instance);
	}
}
[HarmonyPatch(typeof(SelectAbility), "Select")]
internal static class FourthSelectPatch
{
	private static void Postfix(SelectAbility __instance)
	{
		if (FourthAbilityRuntime.BoxesBySlot.TryGetValue(((Object)__instance).GetInstanceID(), out var value))
		{
			FourthAbilityRuntime.SaveChoice(value);
		}
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "LateUpdate")]
internal static class FourthSlotEnterPatch
{
	private static bool Prefix(CharacterSelectBox __instance)
	{
		object field = FourthAbilityRuntime.GetField<object>(__instance, "menuState");
		if (field == null || Convert.ToInt32(field) != 1)
		{
			return true;
		}
		if (!FourthAbilityRuntime.SlotsByBox.TryGetValue(((Object)__instance).GetInstanceID(), out var value) || (Object)(object)value == (Object)null)
		{
			return true;
		}
		List<SelectableMonoBehaviour> field2 = FourthAbilityRuntime.GetField<List<SelectableMonoBehaviour>>(__instance, "selectables");
		int field3 = FourthAbilityRuntime.GetField<int>(__instance, "selectedIndex");
		if (field2 == null || field3 != field2.IndexOf((SelectableMonoBehaviour)(object)value))
		{
			return true;
		}
		bool flag = false;
		if (FourthAbilityRuntime.GetField<bool>(__instance, "UseskeyboardMouse"))
		{
			Keyboard current = Keyboard.current;
			flag = current != null && ((ButtonControl)current.enterKey).wasPressedThisFrame;
		}
		else
		{
			Gamepad field4 = FourthAbilityRuntime.GetField<Gamepad>(__instance, "currentGamePad");
			flag = field4 != null && field4.aButton.wasPressedThisFrame;
		}
		if (!flag)
		{
			return true;
		}
		FourthAbilityRuntime.SaveChoice(__instance);
		__instance.EnterAbilityGrid();
		return false;
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "SetSelected")]
internal static class CharacterSelectArrowPatch
{
	private static void Postfix(CharacterSelectBox __instance, int __0)
	{
		//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_0045: Unknown result type (might be due to invalid IL or missing references)
		List<SelectableMonoBehaviour> field = FourthAbilityRuntime.GetField<List<SelectableMonoBehaviour>>(__instance, "selectables");
		if (field != null && __0 == field.Count - 1)
		{
			RectTransform field2 = FourthAbilityRuntime.GetField<RectTransform>(__instance, "arrows");
			if (!((Object)(object)field2 == (Object)null))
			{
				Vector2 anchoredPosition = field2.anchoredPosition;
				anchoredPosition.y = -1024f;
				field2.anchoredPosition = anchoredPosition;
			}
		}
	}
}
[HarmonyPatch(typeof(MidGameAbilitySelect), "SetPlayer")]
internal static class MidGameSetPlayerPatch
{
	private static void Prefix(MidGameAbilitySelect __instance, ref RectTransform[] __state)
	{
		RectTransform[] field = FourthAbilityRuntime.GetField<RectTransform[]>(__instance, "Circles");
		if (field != null && field.Length > 3)
		{
			__state = field;
			RectTransform[] array = (RectTransform[])(object)new RectTransform[3];
			for (int i = 0; i < 3; i++)
			{
				array[i] = field[i];
			}
			if ((Object)(object)field[3] != (Object)null)
			{
				((Component)field[3]).gameObject.SetActive(false);
			}
			FourthAbilityRuntime.SetField(__instance, "Circles", array);
		}
	}

	private static void Postfix(MidGameAbilitySelect __instance, RectTransform[] __state)
	{
		if (__state != null)
		{
			FourthAbilityRuntime.SetField(__instance, "Circles", __state);
		}
		FourthAbilityRuntime.EnsureMidGameFourthCircle(__instance);
		FourthAbilityRuntime.PrepareMidGameSelector(__instance);
	}

	private static Exception Finalizer(MidGameAbilitySelect __instance, Exception __exception, RectTransform[] __state)
	{
		if (__state != null)
		{
			FourthAbilityRuntime.SetField(__instance, "Circles", __state);
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(MidGameAbilitySelect), "TotalYOffset")]
internal static class MidGameTotalOffsetPatch
{
	private static void Postfix(MidGameAbilitySelect __instance, ref float __result)
	{
	}
}
[HarmonyPatch(typeof(MidGameAbilitySelect), "Down")]
internal static class MidGameDownPatch
{
	private static bool Prefix(MidGameAbilitySelect __instance)
	{
		return !FourthAbilityRuntime.MoveMidGameRow(__instance, 1);
	}
}
[HarmonyPatch(typeof(MidGameAbilitySelect), "Up")]
internal static class MidGameUpPatch
{
	private static bool Prefix(MidGameAbilitySelect __instance)
	{
		return !FourthAbilityRuntime.MoveMidGameRow(__instance, -1);
	}
}
[HarmonyPatch(typeof(MidGameAbilitySelect), "UpdatePlayerAbilityChoices")]
internal static class MidGameChoicePatch
{
	private static void Postfix(MidGameAbilitySelect __instance)
	{
		FourthAbilityRuntime.SaveMidGameFourthChoice(__instance);
	}
}
[HarmonyPatch(typeof(AbilitySelectController), "UpdateAnimation")]
internal static class AbilitySelectAnimationPatch
{
	private static void Prefix(AbilitySelectController __instance)
	{
		FourthAbilityRuntime.EnsureAbilitySelectAnimationTargets(__instance);
	}
}
[HarmonyPatch(typeof(Player), "AbilityButtonIsDown")]
internal static class FourthAbilityInputPatch
{
	private static bool Prefix(Player __instance, int index012, ref bool __result)
	{
		if (index012 != 3)
		{
			return true;
		}
		__result = FourthAbilityRuntime.FourthInputHeld(__instance);
		return false;
	}
}
[HarmonyPatch(typeof(Host), "CurrentInputAsPacket")]
internal static class FourthAbilityPacketPatch
{
	private static void Postfix(int __0, ref InputPacket __result)
	{
		FourthAbilityRuntime.PutFourthInputInPacket(__0, ref __result);
	}
}
[HarmonyPatch(typeof(GameSessionHandler), "SpawnPlayers")]
internal static class SpawnPlayersPatch
{
	private static void Prefix()
	{
		PlayerHandler val = PlayerHandler.Get();
		if (val != null)
		{
			FourthAbilityRuntime.AddFourthToPlayers(val.PlayerList());
		}
	}

	private static void Postfix(GameSessionHandler __instance)
	{
		FourthAbilityRuntime.FinishSpawn(__instance);
	}
}
[HarmonyPatch(typeof(SlimeController), "Init")]
internal static class SlimeInitPatch
{
	private static void Postfix(SlimeController __instance)
	{
		List<AbilityMonoBehaviour> field = FourthAbilityRuntime.GetField<List<AbilityMonoBehaviour>>(__instance, "abilities");
		if (field != null && field.Count > 3)
		{
			FourthAbilityRuntime.EnsureCooldownArray(__instance);
		}
	}
}
[HarmonyPatch(typeof(PlayerCollision), "SpawnClone")]
internal static class SpawnClonePatch
{
	internal sealed class CloneState
	{
		internal SlimeController Source;

		internal List<AbilityMonoBehaviour> Abilities;

		internal AbilityReadyIndicator[] Indicators;
	}

	private static void Prefix(SlimeController slimeContToRevive, ref CloneState __state)
	{
		if ((Object)(object)slimeContToRevive == (Object)null)
		{
			return;
		}
		List<AbilityMonoBehaviour> field = FourthAbilityRuntime.GetField<List<AbilityMonoBehaviour>>(slimeContToRevive, "abilities");
		AbilityReadyIndicator[] field2 = FourthAbilityRuntime.GetField<AbilityReadyIndicator[]>(slimeContToRevive, "AbilityReadyIndicators");
		if (field != null && field.Count >= 4 && field2 != null && field2.Length >= 4)
		{
			__state = new CloneState();
			__state.Source = slimeContToRevive;
			__state.Abilities = field;
			__state.Indicators = field2;
			List<AbilityMonoBehaviour> list = new List<AbilityMonoBehaviour>();
			for (int i = 0; i < 3; i++)
			{
				list.Add(field[i]);
			}
			AbilityReadyIndicator[] array = (AbilityReadyIndicator[])(object)new AbilityReadyIndicator[3];
			for (int j = 0; j < 3; j++)
			{
				array[j] = field2[j];
			}
			FourthAbilityRuntime.SetField(slimeContToRevive, "abilities", list);
			FourthAbilityRuntime.SetField(slimeContToRevive, "AbilityReadyIndicators", array);
		}
	}

	private static void Postfix(Player player, SlimeController slimeContToRevive, ref SlimeController __result, CloneState __state)
	{
		if (__state != null)
		{
			FourthAbilityRuntime.SetField(slimeContToRevive, "abilities", __state.Abilities);
			FourthAbilityRuntime.SetField(slimeContToRevive, "AbilityReadyIndicators", __state.Indicators);
			if ((Object)(object)__result != (Object)null)
			{
				FourthAbilityRuntime.AddFourthToClone(__result, __state.Source, player, __state.Indicators);
			}
		}
	}

	private static Exception Finalizer(SlimeController slimeContToRevive, Exception __exception, CloneState __state)
	{
		if (__state != null && (Object)(object)slimeContToRevive != (Object)null)
		{
			FourthAbilityRuntime.SetField(slimeContToRevive, "abilities", __state.Abilities);
			FourthAbilityRuntime.SetField(slimeContToRevive, "AbilityReadyIndicators", __state.Indicators);
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(SteamSocket), "OnMessage")]
internal static class FourthAbilityNetworkReceivePatch
{
	private static bool Prefix(NetIdentity identity, IntPtr data, int size)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		if (size < 5 || data == IntPtr.Zero)
		{
			return true;
		}
		byte[] array = new byte[size];
		Marshal.Copy(data, array, 0, size);
		if (!FourthAbilityRuntime.IsOurPacket(array))
		{
			return true;
		}
		FourthAbilityRuntime.ReceivePacket(array, identity);
		return false;
	}
}

BepInEx\plugins\FourthAbility\FourthAbilitySlotStableRepair.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FourthAbilitySlotStableRepair;

[BepInPlugin("com.openai.boplbattle.fourthabilityslot.stablerepair", "Fourth Ability Slot Stable Repair", "1.1.18")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class StableRepairPlugin : BaseUnityPlugin
{
	internal const string PluginGuid = "com.openai.boplbattle.fourthabilityslot.stablerepair";

	internal const string PluginVersion = "1.1.18";

	internal const string BasePluginGuid = "com.openai.boplbattle.fourthabilityslot";

	private Harmony harmony;

	private void Awake()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		RepairRuntime.Log = ((BaseUnityPlugin)this).Logger;
		RepairRuntime.InitializeBaseReflection();
		harmony = new Harmony("com.openai.boplbattle.fourthabilityslot.stablerepair");
		RepairRuntime.RemoveBrokenBaseUiHooks(harmony);
		harmony.PatchAll();
		bool flag = RepairRuntime.PatchBaseRawInput(harmony);
		bool flag2 = RepairRuntime.PatchBaseIndicatorCreation(harmony);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Stable Repair v1.1.18 active on Fourth Ability Slot v1.1.3.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Loss selector now preserves Bopl's three vanilla animation targets exactly and only extrapolates a fourth target after SetPlayer.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Gameplay HUD now leaves v1.1.3's proven diamond layout untouched on spawn; a one-shot A3 visibility gate prevents the early A4 flash without coupling cooldown visuals.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Player 2 A4 direct-input repair=" + flag + "; indicator creation repair=" + flag2 + "."));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"F6 HUD layout hotkey is polled from both the plugin frame loop and Host.CurrentInputAsPacket using Win32, Input System, and BepInEx KeyboardShortcut detection.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"No NumberOfAbilities selector patch, Settings save, forced lobby setting, or layout-picker UI is installed.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"v1.1.18 changes only the loss-screen vertical offsets again: the live four ability circles are now lifted +105px and the arrow is +95px, putting the stack closer to directly above the losing-player portrait. All other behavior is unchanged.");
	}

	private void Update()
	{
		RepairRuntime.PollLayoutHotkey();
	}
}
[DefaultExecutionOrder(20000)]
internal sealed class MidGameFourthFollower : MonoBehaviour
{
	internal RectTransform Third;

	internal RectTransform Fourth;

	internal Image ThirdImage;

	internal Image FourthImage;

	private void LateUpdate()
	{
		if ((Object)(object)Third == (Object)null || (Object)(object)Fourth == (Object)null)
		{
			return;
		}
		bool activeSelf = ((Component)Third).gameObject.activeSelf;
		if (((Component)Fourth).gameObject.activeSelf != activeSelf)
		{
			((Component)Fourth).gameObject.SetActive(activeSelf);
		}
		if (activeSelf)
		{
			RepairRuntime.CopyUiTreeAppearance((Component)(object)Third, (Component)(object)Fourth, ThirdImage, FourthImage);
			CanvasGroup component = ((Component)Third).GetComponent<CanvasGroup>();
			CanvasGroup component2 = ((Component)Fourth).GetComponent<CanvasGroup>();
			if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
			{
				component2.alpha = component.alpha;
				component2.interactable = component.interactable;
				component2.blocksRaycasts = component.blocksRaycasts;
			}
		}
	}
}
[DefaultExecutionOrder(25000)]
internal sealed class GameplayFourthVisualFollower : MonoBehaviour
{
	internal AbilityReadyIndicator Source;

	internal AbilityReadyIndicator Target;

	private bool released;

	internal void SyncNow()
	{
		if (released || (Object)(object)Source == (Object)null || (Object)(object)Target == (Object)null)
		{
			return;
		}
		SpriteRenderer[] componentsInChildren = ((Component)Source).GetComponentsInChildren<SpriteRenderer>(true);
		SpriteRenderer[] componentsInChildren2 = ((Component)Target).GetComponentsInChildren<SpriteRenderer>(true);
		int num = Math.Min(componentsInChildren.Length, componentsInChildren2.Length);
		bool flag = false;
		foreach (SpriteRenderer val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && ((Component)Source).gameObject.activeInHierarchy && ((Renderer)val).enabled)
			{
				flag = true;
				break;
			}
		}
		for (int j = 0; j < num; j++)
		{
			if (!((Object)(object)componentsInChildren[j] == (Object)null) && !((Object)(object)componentsInChildren2[j] == (Object)null))
			{
				((Renderer)componentsInChildren2[j]).enabled = ((Component)Source).gameObject.activeInHierarchy && ((Renderer)componentsInChildren[j]).enabled;
			}
		}
		if (flag)
		{
			released = true;
			Object.Destroy((Object)(object)this);
		}
	}

	private void LateUpdate()
	{
		SyncNow();
	}
}
internal sealed class IndicatorLayoutState : MonoBehaviour
{
	internal SlimeController Controller;

	internal Vector3 First;

	internal Vector3 Second;

	internal Vector3 Third;

	internal bool Ready;

	internal void Initialize(SlimeController controller, Vector3[] original)
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: 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_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		if (Ready || (Object)(object)controller == (Object)null)
		{
			return;
		}
		AbilityReadyIndicator[] field = RepairRuntime.GetField<AbilityReadyIndicator[]>(controller, "AbilityReadyIndicators");
		if (field != null && field.Length >= 4 && !((Object)(object)field[0] == (Object)null) && !((Object)(object)field[1] == (Object)null) && !((Object)(object)field[2] == (Object)null) && !((Object)(object)field[3] == (Object)null))
		{
			Controller = controller;
			if (original != null && original.Length >= 3)
			{
				First = original[0];
				Second = original[1];
				Third = original[2];
			}
			else
			{
				First = RepairRuntime.IndicatorOffset(field[0]);
				Second = RepairRuntime.IndicatorOffset(field[1]);
				Third = (RepairRuntime.IndicatorOffset(field[2]) + RepairRuntime.IndicatorOffset(field[3])) * 0.5f;
			}
			Ready = true;
		}
	}
}
internal sealed class MidGameState
{
	internal Settings Settings;

	internal FieldInfo RawAbilityCountField;

	internal int RawAbilityCount;

	internal bool ChangedRawAbilityCount;

	internal RectTransform[] FullCircles;
}
internal sealed class LossArrowCounterLiftState : MonoBehaviour
{
	internal RectTransform ArrowRoot;

	internal Vector2 ArrowBase;

	internal Vector2 ArrowShifted;

	internal bool Applied;

	internal bool Logged;
}
internal sealed class LossAbilityVisualLiftState : MonoBehaviour
{
	internal RectTransform[] Circles;

	internal Vector2[] BasePositions;

	internal Vector2[] ShiftedPositions;

	internal bool Applied;

	internal bool Logged;
}
internal static class RepairRuntime
{
	private const int VkF6 = 117;

	internal static ManualLogSource Log;

	private static bool previousF6;

	private static int lastF6PollFrame = -1;

	private static bool loggedF6Poller;

	private static readonly KeyboardShortcut LayoutShortcut = new KeyboardShortcut((KeyCode)287, (KeyCode[])(object)new KeyCode[0]);

	private static Type baseRuntimeType;

	private static MethodInfo baseInstallMidGamePointer;

	private static MethodInfo baseFourthBindingFor;

	private static MethodInfo baseRawFourthInputHeld;

	private static MethodInfo baseAppendFourthIndicator;

	private static FieldInfo baseSlotsByBox;

	private static readonly Dictionary<int, Vector3[]> PendingIndicatorOriginals = new Dictionary<int, Vector3[]>();

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

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

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

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

	private static readonly string[] LayoutNames = new string[5] { "A4 left / A3 right", "A4 below A3", "A3 left / A4 right", "A4 above A3", "single row" };

	internal static int CurrentLayout => Mathf.Clamp(PlayerPrefs.GetInt("FourthAbilitySlot.LayoutPreset", 0), 0, 4);

	[DllImport("user32.dll")]
	private static extern short GetAsyncKeyState(int virtualKey);

	internal static void PollLayoutHotkey()
	{
		//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)
		int frameCount = Time.frameCount;
		if (lastF6PollFrame == frameCount)
		{
			return;
		}
		lastF6PollFrame = frameCount;
		bool flag = false;
		bool flag2 = false;
		try
		{
			short asyncKeyState = GetAsyncKeyState(117);
			if ((asyncKeyState & 0x8000) != 0)
			{
				flag = true;
			}
			if ((asyncKeyState & 1) != 0)
			{
				flag2 = true;
			}
		}
		catch
		{
		}
		try
		{
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				if (((ButtonControl)current.f6Key).isPressed)
				{
					flag = true;
				}
				if (((ButtonControl)current.f6Key).wasPressedThisFrame)
				{
					flag2 = true;
				}
			}
		}
		catch
		{
		}
		try
		{
			KeyboardShortcut layoutShortcut = LayoutShortcut;
			if (((KeyboardShortcut)(ref layoutShortcut)).IsDown())
			{
				flag2 = true;
			}
		}
		catch
		{
		}
		if (!loggedF6Poller)
		{
			loggedF6Poller = true;
			Log.LogInfo((object)"F6 layout hotkey poller is running (frame loop + gameplay packet hook).");
		}
		if (flag2 || (flag && !previousF6))
		{
			CycleLayout();
		}
		previousF6 = flag;
	}

	internal static void InitializeBaseReflection()
	{
		baseRuntimeType = AccessTools.TypeByName("FourthAbilitySlotMod.FourthAbilityRuntime");
		if (baseRuntimeType == null)
		{
			Log.LogError((object)"Could not find FourthAbilitySlotMod.FourthAbilityRuntime. Refusing to guess an unknown base implementation.");
			return;
		}
		baseInstallMidGamePointer = AccessTools.Method(baseRuntimeType, "InstallMidGamePointer", new Type[2]
		{
			typeof(MidGameAbilitySelect),
			typeof(RectTransform)
		}, (Type[])null);
		baseFourthBindingFor = AccessTools.Method(baseRuntimeType, "FourthBindingFor", new Type[1] { typeof(Player) }, (Type[])null);
		baseRawFourthInputHeld = AccessTools.Method(baseRuntimeType, "RawFourthInputHeld", new Type[1] { typeof(Player) }, (Type[])null);
		baseAppendFourthIndicator = AccessTools.Method(baseRuntimeType, "AppendFourthIndicator", new Type[2]
		{
			typeof(SlimeController),
			typeof(Sprite)
		}, (Type[])null);
		baseSlotsByBox = AccessTools.Field(baseRuntimeType, "SlotsByBox");
	}

	internal static T GetField<T>(object instance, string name)
	{
		if (instance == null)
		{
			return default(T);
		}
		FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), name);
		if (fieldInfo == null)
		{
			return default(T);
		}
		object value = fieldInfo.GetValue(instance);
		if (value == null)
		{
			return default(T);
		}
		return (T)value;
	}

	internal static void SetField(object instance, string name, object value)
	{
		if (instance != null)
		{
			FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), name);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(instance, value);
			}
		}
	}

	internal static void CopyImageAppearance(Image source, Image target)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)source == (Object)null) && !((Object)(object)target == (Object)null))
		{
			((Graphic)target).color = ((Graphic)source).color;
			((Graphic)target).material = ((Graphic)source).material;
			((Behaviour)target).enabled = ((Behaviour)source).enabled;
			((Graphic)target).canvasRenderer.SetAlpha(((Graphic)source).canvasRenderer.GetAlpha());
		}
	}

	internal static void CopyUiTreeAppearance(Component sourceRoot, Component targetRoot, Image sourceAbilityImage, Image targetAbilityImage)
	{
		if ((Object)(object)sourceRoot == (Object)null || (Object)(object)targetRoot == (Object)null)
		{
			return;
		}
		Image[] componentsInChildren = sourceRoot.GetComponentsInChildren<Image>(true);
		Image[] componentsInChildren2 = targetRoot.GetComponentsInChildren<Image>(true);
		int num = Math.Min(componentsInChildren.Length, componentsInChildren2.Length);
		for (int i = 0; i < num; i++)
		{
			Image val = componentsInChildren[i];
			Image val2 = componentsInChildren2[i];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				Sprite sprite = val2.sprite;
				CopyImageAppearance(val, val2);
				if ((Object)(object)val2 == (Object)(object)targetAbilityImage || (Object)(object)val == (Object)(object)sourceAbilityImage)
				{
					val2.sprite = sprite;
				}
			}
		}
	}

	internal static void RemoveBrokenBaseUiHooks(Harmony harmony)
	{
		if (harmony != null)
		{
			UnpatchBase(harmony, typeof(MidGameAbilitySelect), "SetPlayer");
			UnpatchBase(harmony, typeof(MidGameAbilitySelect), "TotalYOffset");
			UnpatchBase(harmony, typeof(CharacterSelectBox), "SetSelected");
			UnpatchBase(harmony, typeof(MidGameAbilitySelect), "Update");
			UnpatchBase(harmony, typeof(AbilitySelectController), "UpdateAnimation");
			Log.LogInfo((object)"Replaced only the broken v1.1.3 UI lifecycle hooks; gameplay, pickups, clones, keybind menu, online packets, and A4 navigation remain on the base mod.");
		}
	}

	private static void UnpatchBase(Harmony harmony, Type type, string methodName)
	{
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		if (methodInfo != null)
		{
			harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)0, "com.openai.boplbattle.fourthabilityslot");
		}
	}

	internal static bool PatchBaseRawInput(Harmony harmony)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		if (harmony == null || baseRawFourthInputHeld == null)
		{
			return false;
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(RepairRuntime), "RawFourthInputPrefix", (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			return false;
		}
		harmony.Patch((MethodBase)baseRawFourthInputHeld, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		return true;
	}

	internal static bool PatchBaseIndicatorCreation(Harmony harmony)
	{
		//IL_005b: 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_006e: Expected O, but got Unknown
		//IL_006e: Expected O, but got Unknown
		if (harmony == null || baseAppendFourthIndicator == null)
		{
			return false;
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(RepairRuntime), "AppendFourthIndicatorPrefix", (Type[])null, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(typeof(RepairRuntime), "AppendFourthIndicatorPostfix", (Type[])null, (Type[])null);
		if (methodInfo == null || methodInfo2 == null)
		{
			return false;
		}
		harmony.Patch((MethodBase)baseAppendFourthIndicator, new HarmonyMethod(methodInfo), new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		return true;
	}

	internal static bool RawFourthInputPrefix(Player __0, ref bool __result)
	{
		if (__0 == null || __0.ignoreAllInputs || !__0.IsLocalPlayer)
		{
			return true;
		}
		InputControl val = ControlForPlayer(__0);
		ButtonControl val2 = (ButtonControl)(object)((val is ButtonControl) ? val : null);
		__result = val2 != null && val2.isPressed;
		if (__result && LoggedInputConfirmed.Add(__0.Id))
		{
			Log.LogInfo((object)("A4 input confirmed for local player " + __0.Id + " via " + DescribeControl(val) + "."));
		}
		return false;
	}

	private static InputControl ControlForPlayer(Player player)
	{
		if (player == null)
		{
			return null;
		}
		InputControl val = null;
		if (baseFourthBindingFor != null)
		{
			try
			{
				object? obj = baseFourthBindingFor.Invoke(null, new object[1] { player });
				val = (InputControl)((obj is InputControl) ? obj : null);
			}
			catch
			{
			}
		}
		if (player.UsesKeyboardAndMouse)
		{
			if (val != null)
			{
				return val;
			}
			Mouse current = Mouse.current;
			if (current != null)
			{
				return (InputControl)(object)current.middleButton;
			}
			return null;
		}
		Gamepad val2 = ResolvePlayerGamepad(player);
		if (val2 != null)
		{
			if (val != null && (object)val.device == val2)
			{
				return val;
			}
			return (InputControl)(object)val2.rightTrigger;
		}
		return val;
	}

	private static Gamepad ResolvePlayerGamepad(Player player)
	{
		if (player == null)
		{
			return null;
		}
		InputDevice inputDevice = player.inputDevice;
		Gamepad val = (Gamepad)(object)((inputDevice is Gamepad) ? inputDevice : null);
		if (val != null)
		{
			return val;
		}
		InputControl[] customKeyBinding = player.CustomKeyBinding;
		if (customKeyBinding != null)
		{
			foreach (InputControl val2 in customKeyBinding)
			{
				if (val2 != null)
				{
					InputDevice device = val2.device;
					Gamepad val3 = (Gamepad)(object)((device is Gamepad) ? device : null);
					if (val3 != null)
					{
						return val3;
					}
				}
			}
		}
		return null;
	}

	private static string DescribeControl(InputControl control)
	{
		if (control == null)
		{
			return "no control";
		}
		try
		{
			string text = ((control.device == null) ? "unknown device" : ((InputControl)control.device).displayName);
			return text + " " + control.path;
		}
		catch
		{
			return ((object)control).ToString();
		}
	}

	internal static void AppendFourthIndicatorPrefix(SlimeController __0)
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__0 == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)__0).GetInstanceID();
		IndicatorLayoutState component = ((Component)__0).GetComponent<IndicatorLayoutState>();
		if ((!((Object)(object)component != (Object)null) || !component.Ready) && !PendingIndicatorOriginals.ContainsKey(instanceID))
		{
			AbilityReadyIndicator[] field = GetField<AbilityReadyIndicator[]>(__0, "AbilityReadyIndicators");
			if (field != null && field.Length >= 3 && !((Object)(object)field[0] == (Object)null) && !((Object)(object)field[1] == (Object)null) && !((Object)(object)field[2] == (Object)null))
			{
				PendingIndicatorOriginals[instanceID] = (Vector3[])(object)new Vector3[3]
				{
					IndicatorOffset(field[0]),
					IndicatorOffset(field[1]),
					IndicatorOffset(field[2])
				};
			}
		}
	}

	internal static void AppendFourthIndicatorPostfix(SlimeController __0, Sprite __1)
	{
		AttachGameplayHud(__0);
	}

	internal static void BeforeMidGameSetPlayer(MidGameAbilitySelect selector, ref MidGameState state)
	{
		state = new MidGameState();
		if ((Object)(object)selector != (Object)null)
		{
			LossSelectorLiftApplied.Remove(((Object)selector).GetInstanceID());
		}
		try
		{
			Settings val = Settings.Get();
			FieldInfo fieldInfo = (((Object)(object)val == (Object)null) ? null : AccessTools.Field(((object)val).GetType(), "numberOfAbilities"));
			if ((Object)(object)val != (Object)null && fieldInfo != null)
			{
				int num = (int)fieldInfo.GetValue(val);
				state.Settings = val;
				state.RawAbilityCountField = fieldInfo;
				state.RawAbilityCount = num;
				if (num > 3)
				{
					fieldInfo.SetValue(val, 3);
					state.ChangedRawAbilityCount = true;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not temporarily vanilla-size SetPlayer's raw ability count: " + ex.Message));
		}
		RectTransform[] field = GetField<RectTransform[]>(selector, "Circles");
		if (field != null && field.Length > 3)
		{
			state.FullCircles = field;
			RectTransform[] array = (RectTransform[])(object)new RectTransform[3];
			for (int i = 0; i < 3; i++)
			{
				array[i] = field[i];
			}
			if ((Object)(object)field[3] != (Object)null)
			{
				((Component)field[3]).gameObject.SetActive(false);
			}
			SetField(selector, "Circles", array);
		}
	}

	internal static void RestoreMidGameSetPlayer(MidGameAbilitySelect selector, MidGameState state)
	{
		if (state == null)
		{
			return;
		}
		if (state.FullCircles != null)
		{
			SetField(selector, "Circles", state.FullCircles);
		}
		if (!state.ChangedRawAbilityCount || !((Object)(object)state.Settings != (Object)null) || !(state.RawAbilityCountField != null))
		{
			return;
		}
		try
		{
			state.RawAbilityCountField.SetValue(state.Settings, state.RawAbilityCount);
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not restore raw NumberOfAbilities after SetPlayer: " + ex.Message));
		}
	}

	internal static void SetupSafeMidGameSelector(MidGameAbilitySelect selector)
	{
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: 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_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)selector == (Object)null)
		{
			return;
		}
		Player field = GetField<Player>(selector, "player");
		if (field == null || field.Abilities == null || field.Abilities.Count < 4)
		{
			return;
		}
		RectTransform[] array = GetField<RectTransform[]>(selector, "Circles");
		if (array == null || array.Length < 3 || (Object)(object)array[1] == (Object)null || (Object)(object)array[2] == (Object)null)
		{
			return;
		}
		RectTransform val = ((array.Length > 3) ? array[3] : null);
		if ((Object)(object)val == (Object)null)
		{
			GameObject val2 = Object.Instantiate<GameObject>(((Component)array[2]).gameObject, ((Transform)array[2]).parent);
			((Object)val2).name = "Fourth Between-Round Ability Circle";
			val2.transform.SetSiblingIndex(((Transform)array[2]).GetSiblingIndex() + 1);
			val = val2.GetComponent<RectTransform>();
			if ((Object)(object)val == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return;
			}
			RectTransform[] array2 = (RectTransform[])(object)new RectTransform[4];
			for (int i = 0; i < 3; i++)
			{
				array2[i] = array[i];
			}
			array2[3] = val;
			array = array2;
			SetField(selector, "Circles", array);
		}
		Vector2 val3 = array[2].anchoredPosition - array[1].anchoredPosition;
		if (((Vector2)(ref val3)).sqrMagnitude < 0.0001f)
		{
			float field2 = GetField<float>(selector, "circleDistance");
			val3 = Vector2.down * ((Mathf.Abs(field2) > 0.01f) ? Mathf.Abs(field2) : 60f);
		}
		val.anchoredPosition = array[2].anchoredPosition + val3;
		((Transform)val).localScale = ((Transform)array[2]).localScale;
		((Component)val).gameObject.SetActive(((Component)array[2]).gameObject.activeSelf);
		if (baseInstallMidGamePointer != null)
		{
			try
			{
				baseInstallMidGamePointer.Invoke(null, new object[2] { selector, val });
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not install the proven v1.1.3 A4 loss-selector pointer: " + ex.Message));
			}
		}
		PrepareSafeMidGameSelector(selector);
		AbilitySelectController componentInParent = ((Component)selector).GetComponentInParent<AbilitySelectController>();
		EnsureAbilitySelectAnimationTargets(componentInParent);
		LiftLossSelectorSlightly(selector, componentInParent);
		Image[] field3 = GetField<Image[]>(selector, "CircleImages");
		MidGameFourthFollower midGameFourthFollower = ((Component)selector).GetComponent<MidGameFourthFollower>();
		if ((Object)(object)midGameFourthFollower == (Object)null)
		{
			midGameFourthFollower = ((Component)selector).gameObject.AddComponent<MidGameFourthFollower>();
		}
		midGameFourthFollower.Third = array[2];
		midGameFourthFollower.Fourth = array[3];
		midGameFourthFollower.ThirdImage = ((field3 != null && field3.Length > 2) ? field3[2] : null);
		midGameFourthFollower.FourthImage = ((field3 != null && field3.Length > 3) ? field3[3] : null);
		int instanceID = ((Object)selector).GetInstanceID();
		if (LoggedMidGameSelectors.Add(instanceID))
		{
			Log.LogInfo((object)("Loss selector repaired for player " + field.Id + ": vanilla A1-A3 targets preserved; A4 appended after SetPlayer."));
		}
	}

	private static void LayoutSafeMidGameRows(MidGameAbilitySelect selector, Vector2[] originals)
	{
	}

	private static void PrepareSafeMidGameSelector(MidGameAbilitySelect selector)
	{
		Player field = GetField<Player>(selector, "player");
		RectTransform[] field2 = GetField<RectTransform[]>(selector, "Circles");
		NamedSpriteList field3 = GetField<NamedSpriteList>(selector, "localAbilityIcons");
		if (field != null && field.Abilities != null && field.Abilities.Count >= 4 && field2 != null && field2.Length >= 4 && !((Object)(object)field2[3] == (Object)null) && !((Object)(object)field3 == (Object)null))
		{
			Image[] field4 = GetField<Image[]>(selector, "CircleImages");
			int[] field5 = GetField<int[]>(selector, "XPos");
			Image[] array = (Image[])(object)new Image[4];
			int[] array2 = new int[4];
			for (int i = 0; i < 3; i++)
			{
				array[i] = ((field4 != null && field4.Length > i) ? field4[i] : null);
				array2[i] = ((field5 == null || field5.Length <= i) ? 1 : field5[i]);
			}
			Image sourceImage = ((field4 != null && field4.Length > 2) ? field4[2] : null);
			array[3] = MatchingClonedCircleImage(field2[2], field2[3], sourceImage);
			int num = field3.IndexOf(((Object)field.Abilities[3]).name);
			if (num <= 0 || field3.sprites == null || num >= field3.sprites.Count)
			{
				num = 1;
			}
			array2[3] = num;
			if ((Object)(object)array[3] != (Object)null)
			{
				array[3].sprite = field3.GetSprite(num);
			}
			SetField(selector, "CircleImages", array);
			SetField(selector, "XPos", array2);
			selector.SyncArrowPositionToCurrentYPos();
		}
	}

	private static Image MatchingClonedCircleImage(RectTransform sourceCircle, RectTransform cloneCircle, Image sourceImage)
	{
		if ((Object)(object)sourceCircle == (Object)null || (Object)(object)cloneCircle == (Object)null)
		{
			return null;
		}
		if (((Transform)cloneCircle).childCount > 0)
		{
			Image component = ((Component)((Transform)cloneCircle).GetChild(0)).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
		}
		Image[] componentsInChildren = ((Component)sourceCircle).GetComponentsInChildren<Image>(true);
		Image[] componentsInChildren2 = ((Component)cloneCircle).GetComponentsInChildren<Image>(true);
		if ((Object)(object)sourceImage != (Object)null)
		{
			int num = Math.Min(componentsInChildren.Length, componentsInChildren2.Length);
			for (int i = 0; i < num; i++)
			{
				if ((Object)(object)componentsInChildren[i] == (Object)(object)sourceImage)
				{
					return componentsInChildren2[i];
				}
			}
		}
		Image component2 = ((Component)cloneCircle).GetComponent<Image>();
		if ((Object)(object)component2 != (Object)null)
		{
			return component2;
		}
		if (componentsInChildren2.Length != 0)
		{
			return componentsInChildren2[0];
		}
		return null;
	}

	private static void LiftLossSelectorSlightly(MidGameAbilitySelect selector, AbilitySelectController owner)
	{
		//IL_0040: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)selector == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)selector).GetInstanceID();
		if (!LossSelectorLiftApplied.Add(instanceID))
		{
			return;
		}
		RectTransform[] field = GetField<RectTransform[]>(selector, "Circles");
		if (field != null)
		{
			for (int i = 0; i < field.Length; i++)
			{
				if (!((Object)(object)field[i] == (Object)null))
				{
					Vector2 anchoredPosition = field[i].anchoredPosition;
					anchoredPosition.y += 34f;
					field[i].anchoredPosition = anchoredPosition;
				}
			}
		}
		if (!((Object)(object)owner != (Object)null))
		{
			return;
		}
		Vector2[] field2 = GetField<Vector2[]>(owner, "abilityListOriginalPositions");
		if (field2 != null)
		{
			for (int j = 0; j < field2.Length; j++)
			{
				ref Vector2 reference = ref field2[j];
				reference.y += 34f;
			}
			SetField(owner, "abilityListOriginalPositions", field2);
		}
	}

	internal static void LiftOpenLossSelectorArrowOnly(AbilitySelectController controller)
	{
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_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_010b: 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_013a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		bool field = GetField<bool>(controller, "isOpen");
		RectTransform field2 = GetField<RectTransform>(controller, "arrow");
		MidGameAbilitySelect field3 = GetField<MidGameAbilitySelect>(controller, "abilityCirclesParent");
		RectTransform[] array = (((Object)(object)field3 == (Object)null) ? null : GetField<RectTransform[]>(field3, "Circles"));
		LossArrowCounterLiftState lossArrowCounterLiftState = ((Component)controller).GetComponent<LossArrowCounterLiftState>();
		if ((Object)(object)lossArrowCounterLiftState == (Object)null)
		{
			lossArrowCounterLiftState = ((Component)controller).gameObject.AddComponent<LossArrowCounterLiftState>();
		}
		if ((Object)(object)field2 == (Object)null)
		{
			lossArrowCounterLiftState.Applied = false;
			lossArrowCounterLiftState.ArrowRoot = null;
			return;
		}
		Vector3[] array2 = null;
		if (array != null)
		{
			array2 = (Vector3[])(object)new Vector3[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null)
				{
					ref Vector3 reference = ref array2[i];
					reference = ((Transform)array[i]).position;
				}
			}
		}
		Vector2 anchoredPosition = field2.anchoredPosition;
		if (!field)
		{
			if (lossArrowCounterLiftState.Applied && (Object)(object)lossArrowCounterLiftState.ArrowRoot == (Object)(object)field2)
			{
				Vector2 val = anchoredPosition - lossArrowCounterLiftState.ArrowShifted;
				if (((Vector2)(ref val)).sqrMagnitude < 0.25f)
				{
					field2.anchoredPosition = lossArrowCounterLiftState.ArrowBase;
				}
			}
			if (array != null && array2 != null)
			{
				for (int j = 0; j < array.Length; j++)
				{
					if ((Object)(object)array[j] != (Object)null)
					{
						((Transform)array[j]).position = array2[j];
					}
				}
			}
			lossArrowCounterLiftState.Applied = false;
			lossArrowCounterLiftState.ArrowRoot = field2;
			return;
		}
		Vector2 val2 = anchoredPosition;
		if (lossArrowCounterLiftState.Applied && (Object)(object)lossArrowCounterLiftState.ArrowRoot == (Object)(object)field2)
		{
			Vector2 val3 = anchoredPosition - lossArrowCounterLiftState.ArrowShifted;
			if (((Vector2)(ref val3)).sqrMagnitude < 0.25f)
			{
				val2 = lossArrowCounterLiftState.ArrowBase;
			}
		}
		Vector2 val4 = val2;
		val4.y += 95f;
		field2.anchoredPosition = val4;
		if (array != null && array2 != null)
		{
			for (int k = 0; k < array.Length; k++)
			{
				if ((Object)(object)array[k] != (Object)null)
				{
					((Transform)array[k]).position = array2[k];
				}
			}
		}
		lossArrowCounterLiftState.ArrowRoot = field2;
		lossArrowCounterLiftState.ArrowBase = val2;
		lossArrowCounterLiftState.ArrowShifted = val4;
		lossArrowCounterLiftState.Applied = true;
		if (!lossArrowCounterLiftState.Logged && Log != null)
		{
			lossArrowCounterLiftState.Logged = true;
			Log.LogInfo((object)"Arrow +95px active; live ability circles are independently lifted +105px after vanilla animation.");
		}
	}

	internal static void LiftOpenLossAbilityCircles(AbilitySelectController controller)
	{
		//IL_0106: 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_014b: 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_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		bool field = GetField<bool>(controller, "isOpen");
		MidGameAbilitySelect field2 = GetField<MidGameAbilitySelect>(controller, "abilityCirclesParent");
		RectTransform[] array = (((Object)(object)field2 == (Object)null) ? null : GetField<RectTransform[]>(field2, "Circles"));
		LossAbilityVisualLiftState lossAbilityVisualLiftState = ((Component)controller).GetComponent<LossAbilityVisualLiftState>();
		if ((Object)(object)lossAbilityVisualLiftState == (Object)null)
		{
			lossAbilityVisualLiftState = ((Component)controller).gameObject.AddComponent<LossAbilityVisualLiftState>();
		}
		if (array == null || array.Length < 4)
		{
			lossAbilityVisualLiftState.Applied = false;
			lossAbilityVisualLiftState.Circles = array;
			return;
		}
		if (!field)
		{
			lossAbilityVisualLiftState.Applied = false;
			lossAbilityVisualLiftState.Circles = array;
			return;
		}
		if (lossAbilityVisualLiftState.Circles != array || lossAbilityVisualLiftState.BasePositions == null || lossAbilityVisualLiftState.ShiftedPositions == null || lossAbilityVisualLiftState.BasePositions.Length != array.Length || lossAbilityVisualLiftState.ShiftedPositions.Length != array.Length)
		{
			lossAbilityVisualLiftState.Circles = array;
			lossAbilityVisualLiftState.BasePositions = (Vector2[])(object)new Vector2[array.Length];
			lossAbilityVisualLiftState.ShiftedPositions = (Vector2[])(object)new Vector2[array.Length];
			lossAbilityVisualLiftState.Applied = false;
		}
		for (int i = 0; i < array.Length; i++)
		{
			RectTransform val = array[i];
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Vector2 anchoredPosition = val.anchoredPosition;
			if (lossAbilityVisualLiftState.Applied)
			{
				Vector2 val2 = anchoredPosition - lossAbilityVisualLiftState.ShiftedPositions[i];
				if (!(((Vector2)(ref val2)).sqrMagnitude > 0.25f))
				{
					goto IL_0152;
				}
			}
			lossAbilityVisualLiftState.BasePositions[i] = anchoredPosition;
			goto IL_0152;
			IL_0152:
			Vector2 val3 = lossAbilityVisualLiftState.BasePositions[i];
			val3.y += 105f;
			val.anchoredPosition = val3;
			lossAbilityVisualLiftState.ShiftedPositions[i] = val3;
		}
		lossAbilityVisualLiftState.Applied = true;
		if (!lossAbilityVisualLiftState.Logged && Log != null)
		{
			lossAbilityVisualLiftState.Logged = true;
			Log.LogInfo((object)"Loss-selector LIVE circles lifted +180px after vanilla animation; all four abilities should fully clear the losing-player portrait.");
		}
	}

	internal static void EnsureAbilitySelectAnimationTargets(AbilitySelectController controller)
	{
		//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_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: 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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: 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)
		//IL_013c: 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_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		MidGameAbilitySelect field = GetField<MidGameAbilitySelect>(controller, "abilityCirclesParent");
		RectTransform[] array = (((Object)(object)field == (Object)null) ? null : GetField<RectTransform[]>(field, "Circles"));
		if (array == null || array.Length < 4)
		{
			return;
		}
		Vector2[] field2 = GetField<Vector2[]>(controller, "abilityListOriginalPositions");
		if (field2 != null && field2.Length >= array.Length)
		{
			return;
		}
		Vector2[] array2 = (Vector2[])(object)new Vector2[array.Length];
		int num = ((field2 != null) ? Math.Min(field2.Length, array2.Length) : 0);
		for (int i = 0; i < num; i++)
		{
			ref Vector2 reference = ref array2[i];
			reference = field2[i];
		}
		for (int j = num; j < array2.Length; j++)
		{
			if (j >= 3 && j - 1 >= 0 && j - 2 >= 0)
			{
				Vector2 val = array2[j - 1];
				Vector2 val2 = array2[j - 2];
				Vector2 val3 = val - val2;
				if (((Vector2)(ref val3)).sqrMagnitude < 0.0001f && (Object)(object)array[j - 1] != (Object)null && (Object)(object)array[j - 2] != (Object)null)
				{
					val3 = array[j - 1].anchoredPosition - array[j - 2].anchoredPosition;
				}
				ref Vector2 reference2 = ref array2[j];
				reference2 = val + val3;
			}
			else
			{
				ref Vector2 reference3 = ref array2[j];
				reference3 = (((Object)(object)array[j] == (Object)null) ? Vector2.zero : array[j].anchoredPosition);
			}
		}
		SetField(controller, "abilityListOriginalPositions", array2);
	}

	internal static void MaintainCharacterFourth(CharacterSelectBox box)
	{
		//IL_00e6: 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_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)box == (Object)null || baseSlotsByBox == null || !(baseSlotsByBox.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(((Object)box).GetInstanceID()))
		{
			return;
		}
		object? obj = dictionary[((Object)box).GetInstanceID()];
		SelectAbility val = (SelectAbility)((obj is SelectAbility) ? obj : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		List<SelectableMonoBehaviour> field = GetField<List<SelectableMonoBehaviour>>(box, "selectables");
		SelectAbility val2 = (SelectAbility)((field != null && field.Count > 4) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val2 == (Object)null)
		{
			return;
		}
		bool activeSelf = ((Component)val2).gameObject.activeSelf;
		if (((Component)val).gameObject.activeSelf != activeSelf)
		{
			((Component)val).gameObject.SetActive(activeSelf);
		}
		if (!activeSelf)
		{
			return;
		}
		RectTransform component = ((Component)val2).GetComponent<RectTransform>();
		RectTransform component2 = ((Component)val).GetComponent<RectTransform>();
		if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
		{
			float num = component2.anchoredPosition.y - component.anchoredPosition.y;
			float[] field2 = GetField<float[]>(box, "originalAbilitySelectPos");
			if (field2 != null && field2.Length >= 3)
			{
				float num2 = (field2[2] - field2[0]) * 0.5f;
				num = num2 * 0.78f;
			}
			Vector2 anchoredPosition = component.anchoredPosition;
			anchoredPosition.y += num;
			component2.anchoredPosition = anchoredPosition;
		}
		CanvasGroup component3 = ((Component)val2).GetComponent<CanvasGroup>();
		CanvasGroup component4 = ((Component)val).GetComponent<CanvasGroup>();
		if ((Object)(object)component3 != (Object)null && (Object)(object)component4 != (Object)null)
		{
			component4.alpha = component3.alpha;
			component4.interactable = component3.interactable;
			component4.blocksRaycasts = component3.blocksRaycasts;
		}
		Image field3 = GetField<Image>(val2, "abilityIconRenderer");
		Image field4 = GetField<Image>(val, "abilityIconRenderer");
		if ((Object)(object)field3 != (Object)null && (Object)(object)field4 != (Object)null)
		{
			Sprite sprite = field4.sprite;
			CopyImageAppearance(field3, field4);
			field4.sprite = sprite;
		}
		Image field5 = GetField<Image>(val2, "BorderRenderer");
		Image field6 = GetField<Image>(val, "BorderRenderer");
		CopyImageAppearance(field5, field6);
		Image field7 = GetField<Image>(val2, "circlesRenderer");
		Image field8 = GetField<Image>(val, "circlesRenderer");
		CopyImageAppearance(field7, field8);
	}

	internal static void FixCharacterArrow(CharacterSelectBox box, int selectedIndex)
	{
		//IL_007c: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)box == (Object)null)
		{
			return;
		}
		List<SelectableMonoBehaviour> field = GetField<List<SelectableMonoBehaviour>>(box, "selectables");
		if (field == null || selectedIndex < 0 || selectedIndex >= field.Count)
		{
			return;
		}
		SelectableMonoBehaviour obj = field[selectedIndex];
		SelectAbility val = (SelectAbility)(object)((obj is SelectAbility) ? obj : null);
		if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).gameObject).name != "Fourth Ability Slot"))
		{
			RectTransform field2 = GetField<RectTransform>(box, "arrows");
			RectTransform component = ((Component)val).GetComponent<RectTransform>();
			if (!((Object)(object)field2 == (Object)null) && !((Object)(object)component == (Object)null))
			{
				Vector2 anchoredPosition = field2.anchoredPosition;
				anchoredPosition.y = component.anchoredPosition.y;
				field2.anchoredPosition = anchoredPosition;
			}
		}
	}

	internal static Vector3 IndicatorOffset(AbilityReadyIndicator indicator)
	{
		//IL_0009: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)indicator == (Object)null)
		{
			return Vector3.zero;
		}
		FollowTransform component = ((Component)indicator).GetComponent<FollowTransform>();
		if ((Object)(object)component != (Object)null && GetField<bool>(component, "initializedPosition"))
		{
			return GetField<Vector3>(component, "PositionOffset");
		}
		return ((Component)indicator).transform.localPosition;
	}

	private static void SetIndicatorOffset(AbilityReadyIndicator indicator, SlimeController controller, Vector3 offset)
	{
		//IL_0019: 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)
		if (!((Object)(object)indicator == (Object)null) && !((Object)(object)controller == (Object)null))
		{
			((Component)indicator).transform.localPosition = offset;
			FollowTransform component = ((Component)indicator).GetComponent<FollowTransform>();
			if ((Object)(object)component != (Object)null)
			{
				component.Leader = ((Component)controller).transform;
				SetField(component, "PositionOffset", offset);
			}
		}
	}

	internal static void AttachGameplayHud(SlimeController controller)
	{
		if ((Object)(object)controller == (Object)null)
		{
			return;
		}
		AbilityReadyIndicator[] field = GetField<AbilityReadyIndicator[]>(controller, "AbilityReadyIndicators");
		if (field != null && field.Length >= 4 && !((Object)(object)field[0] == (Object)null) && !((Object)(object)field[1] == (Object)null) && !((Object)(object)field[2] == (Object)null) && !((Object)(object)field[3] == (Object)null))
		{
			GameplayFourthVisualFollower gameplayFourthVisualFollower = ((Component)controller).GetComponent<GameplayFourthVisualFollower>();
			if ((Object)(object)gameplayFourthVisualFollower == (Object)null)
			{
				gameplayFourthVisualFollower = ((Component)controller).gameObject.AddComponent<GameplayFourthVisualFollower>();
			}
			gameplayFourthVisualFollower.Source = field[2];
			gameplayFourthVisualFollower.Target = field[3];
			gameplayFourthVisualFollower.SyncNow();
			IndicatorLayoutState indicatorLayoutState = ((Component)controller).GetComponent<IndicatorLayoutState>();
			if ((Object)(object)indicatorLayoutState == (Object)null)
			{
				indicatorLayoutState = ((Component)controller).gameObject.AddComponent<IndicatorLayoutState>();
			}
			Vector3[] value = null;
			PendingIndicatorOriginals.TryGetValue(((Object)controller).GetInstanceID(), out value);
			indicatorLayoutState.Initialize(controller, value);
			PendingIndicatorOriginals.Remove(((Object)controller).GetInstanceID());
		}
	}

	internal static void AttachGameplayHudForSession(GameSessionHandler handler)
	{
		if ((Object)(object)handler == (Object)null)
		{
			return;
		}
		SlimeController[] field = GetField<SlimeController[]>(handler, "slimeControllers");
		if (field != null)
		{
			for (int i = 0; i < field.Length; i++)
			{
				AttachGameplayHud(field[i]);
			}
		}
		LogLocalInputRoutes();
	}

	private static void LogLocalInputRoutes()
	{
		PlayerHandler val = PlayerHandler.Get();
		List<Player> list = ((val == null) ? null : val.PlayerList());
		if (list == null)
		{
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			Player val2 = list[i];
			if (val2 != null && val2.IsLocalPlayer && LoggedInputRoutes.Add(val2.Id))
			{
				InputControl control = ControlForPlayer(val2);
				Log.LogInfo((object)("A4 route for local player " + val2.Id + ": keyboardMouse=" + val2.UsesKeyboardAndMouse + ", inputDevice=" + ((val2.inputDevice == null) ? "null" : ((InputControl)val2.inputDevice).displayName) + ", control=" + DescribeControl(control) + "."));
			}
		}
	}

	internal static void ApplyIndicatorLayout(IndicatorLayoutState state)
	{
		//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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: 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_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_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: 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_0114: 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_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: 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)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: 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_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: 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_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)state == (Object)null || !state.Ready || (Object)(object)state.Controller == (Object)null)
		{
			return;
		}
		AbilityReadyIndicator[] field = GetField<AbilityReadyIndicator[]>(state.Controller, "AbilityReadyIndicators");
		if (field != null && field.Length >= 4 && !((Object)(object)field[0] == (Object)null) && !((Object)(object)field[1] == (Object)null) && !((Object)(object)field[2] == (Object)null) && !((Object)(object)field[3] == (Object)null))
		{
			Vector3 val = state.First;
			Vector3 val2 = state.Second;
			Vector3 val3 = state.Third;
			Vector3 val4 = (val + val2) * 0.5f;
			float num = Mathf.Max(0.9f, Mathf.Abs(val2.x - val.x));
			float num2 = Mathf.Max(0.38f, num * 0.25f);
			float num3 = ((val4.y >= val3.y) ? 1f : (-1f));
			float num4 = Mathf.Max(0.7f, Mathf.Abs(val4.y - val3.y) * 0.92f);
			Vector3 offset;
			switch (CurrentLayout)
			{
			case 1:
				offset = val3 + Vector3.up * num3 * num4;
				break;
			case 2:
				val3 += Vector3.left * num2;
				offset = state.Third + Vector3.right * num2;
				break;
			case 3:
				offset = val3 - Vector3.up * num3 * num4;
				break;
			case 4:
			{
				Vector3 val5 = (val4 + val3) * 0.5f;
				float num5 = num * 0.4f;
				val = val5 + Vector3.left * num5 * 1.5f;
				offset = val5 + Vector3.left * num5 * 0.5f;
				val3 = val5 + Vector3.right * num5 * 0.5f;
				val2 = val5 + Vector3.right * num5 * 1.5f;
				break;
			}
			default:
				val3 += Vector3.right * num2;
				offset = state.Third + Vector3.left * num2;
				break;
			}
			SetIndicatorOffset(field[0], state.Controller, val);
			SetIndicatorOffset(field[1], state.Controller, val2);
			SetIndicatorOffset(field[2], state.Controller, val3);
			SetIndicatorOffset(field[3], state.Controller, offset);
		}
	}

	internal static void CycleLayout()
	{
		//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)
		int num = (CurrentLayout + 1) % 5;
		PlayerPrefs.SetInt("FourthAbilitySlot.LayoutPreset", num);
		PlayerPrefs.Save();
		SlimeController[] array = Resources.FindObjectsOfTypeAll<SlimeController>();
		int num2 = 0;
		foreach (SlimeController val in array)
		{
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
			{
				continue;
			}
			Scene scene = ((Component)val).gameObject.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				AttachGameplayHud(val);
				IndicatorLayoutState component = ((Component)val).GetComponent<IndicatorLayoutState>();
				if ((Object)(object)component != (Object)null && component.Ready)
				{
					ApplyIndicatorLayout(component);
					num2++;
				}
			}
		}
		Log.LogInfo((object)("F6 detected from active gameplay poller. Fourth ability HUD layout " + (num + 1) + "/5: " + LayoutNames[num] + ". Applied to " + num2 + " live slime HUD(s)."));
	}
}
[HarmonyPriority(800)]
[HarmonyPatch(typeof(MidGameAbilitySelect), "SetPlayer")]
internal static class SafeMidGameSetPlayerPatch
{
	private static void Prefix(MidGameAbilitySelect __instance, ref MidGameState __state)
	{
		RepairRuntime.BeforeMidGameSetPlayer(__instance, ref __state);
	}

	private static void Postfix(MidGameAbilitySelect __instance, MidGameState __state)
	{
		RepairRuntime.RestoreMidGameSetPlayer(__instance, __state);
		RepairRuntime.SetupSafeMidGameSelector(__instance);
	}

	private static Exception Finalizer(MidGameAbilitySelect __instance, Exception __exception, MidGameState __state)
	{
		RepairRuntime.RestoreMidGameSetPlayer(__instance, __state);
		return __exception;
	}
}
[HarmonyPatch(typeof(AbilitySelectController), "UpdateAnimation")]
[HarmonyPriority(800)]
internal static class SafeAbilitySelectAnimationPatch
{
	private static void Prefix(AbilitySelectController __instance)
	{
		RepairRuntime.EnsureAbilitySelectAnimationTargets(__instance);
	}
}
[HarmonyPriority(0)]
[HarmonyPatch(typeof(AbilitySelectController), "UpdateAnimation")]
internal static class LossArrowOnlyCounterLiftPatch
{
	private static void Postfix(AbilitySelectController __instance)
	{
		RepairRuntime.LiftOpenLossAbilityCircles(__instance);
		RepairRuntime.LiftOpenLossSelectorArrowOnly(__instance);
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "LateUpdate")]
[HarmonyPriority(0)]
internal static class CharacterFourthLifecyclePatch
{
	private static void Postfix(CharacterSelectBox __instance)
	{
		RepairRuntime.MaintainCharacterFourth(__instance);
	}
}
[HarmonyPatch(typeof(CharacterSelectBox), "SetSelected")]
internal static class CharacterSelectArrowRepairPatch
{
	private static void Postfix(CharacterSelectBox __instance, int __0)
	{
		RepairRuntime.FixCharacterArrow(__instance, __0);
	}
}
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Host), "CurrentInputAsPacket")]
internal static class LayoutHotkeyGameplayTickPatch
{
	private static void Postfix()
	{
		RepairRuntime.PollLayoutHotkey();
	}
}
[HarmonyPriority(0)]
[HarmonyPatch(typeof(GameSessionHandler), "SpawnPlayers")]
internal static class GameplayHudRepairPatch
{
	private static void Postfix(GameSessionHandler __instance)
	{
		RepairRuntime.AttachGameplayHudForSession(__instance);
	}
}
[HarmonyPriority(0)]
[HarmonyPatch(typeof(SlimeController), "Init")]
internal static class SlimeHudRepairPatch
{
	private static void Postfix(SlimeController __instance)
	{
		RepairRuntime.AttachGameplayHud(__instance);
	}
}