Decompiled source of RoundWithBots v3.0.1

RoundsWithBots.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using CardChoiceSpawnUniqueCardPatch.CustomCategories;
using HarmonyLib;
using InControl;
using ModdingUtils.AIMinion;
using ModdingUtils.AIMinion.Extensions;
using ModdingUtils.GameModes;
using ModdingUtils.Utils;
using Photon.Pun;
using RWF;
using RWF.UI;
using RoundsWithBots.CardPickerAIs;
using RoundsWithBots.Extensions;
using RoundsWithBots.Menu;
using RoundsWithBots.Patches;
using RoundsWithBots.Utils;
using TMPro;
using UnboundLib;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnboundLib.Utils;
using UnboundLib.Utils.UI;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RoundsWithBots")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.0.1")]
[assembly: AssemblyInformationalVersion("1.0.0+52309c635c694dc1f9f06c2eff04e49b991e9b2a")]
[assembly: AssemblyProduct("RoundsWithBots")]
[assembly: AssemblyTitle("RoundsWithBots")]
[assembly: AssemblyVersion("3.0.1.0")]
namespace RoundsWithBots
{
	public class BotAIManager : MonoBehaviour, IPlayerPickStartHookHandler, IGameStartHookHandler, IPointStartHookHandler, IRoundEndHookHandler
	{
		internal static class StalemateHandler
		{
			public static bool IsStalemate => !PlayerManager.instance.players.Any((Player player) => !player.data.GetAdditionalData().IsBot && !CharacterDataExtension.GetAdditionalData(player.data).isAIMinion && PlayerStatus.PlayerAliveAndSimulated(player));

			public static IEnumerator HandleStalemate()
			{
				if (!PhotonNetwork.IsMasterClient && !PhotonNetwork.OfflineMode)
				{
					yield break;
				}
				yield return (object)new WaitForSeconds(2f);
				while (!IsStalemate)
				{
					yield return (object)new WaitForSeconds(0.5f);
				}
				yield return (object)new WaitForSeconds(RWBMenu.StalemateTimer.Value);
				while (IsStalemate)
				{
					yield return (object)new WaitForSeconds(RWBMenu.StalemateDamageCooldown.Value);
					Player[] array = PlayerManager.instance.players.Where((Player player) => PlayerStatus.PlayerAliveAndSimulated(player)).ToArray();
					if (array.Length == 0)
					{
						break;
					}
					Player val = array[Random.Range(0, array.Length)];
					NetworkingManager.RPC(typeof(StalemateHandler), "RPCA_SendTakeDamageOverTime", new object[4]
					{
						val.data.view.ControllerActorNr,
						val.playerID,
						val.data.maxHealth,
						RWBMenu.StalemateDamageDuration.Value
					});
				}
			}

			[UnboundRPC]
			public static void RPCA_SendTakeDamageOverTime(int actorID, int playerID, float damage, float duration)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				Player playerWithActorAndPlayerIDs = FindPlayer.GetPlayerWithActorAndPlayerIDs(actorID, playerID);
				playerWithActorAndPlayerIDs.data.healthHandler.TakeDamageOverTime(damage * Vector2.down, Vector2.op_Implicit(((Component)playerWithActorAndPlayerIDs).gameObject.transform.position), duration, 0.5f, Color.white, (GameObject)null, (Player)null, true);
			}
		}

		public static BotAIManager Instance;

		public Dictionary<int, CardPickerAI> PickerAIs = new Dictionary<int, CardPickerAI>();

		private Coroutine stalemateHandlerCoroutine;

		private void Start()
		{
			InterfaceGameModeHooksManager.instance.RegisterHooks((object)this);
			Object.DontDestroyOnLoad((Object)(object)this);
			Instance = this;
		}

		public void SetBotsId()
		{
			LoggingUtils.Log("Getting bots player.");
			PickerAIs.Clear();
			List<int> list = (from player in PlayerManager.instance.players
				where player.data.GetAdditionalData().IsBot
				select player.playerID).ToList();
			PickerAIs = list.ToDictionary((int id) => id, (int id) => new CardPickerAI());
			list.ForEach(delegate(int id)
			{
				LoggingUtils.Log($"Bot '{id}' has been added to the list of bots id.");
			});
			LoggingUtils.Log("Successfully get list of bots player.");
		}

		public void OnPlayerPickStart()
		{
			((MonoBehaviour)this).StartCoroutine(Instance.AiPickCard());
		}

		public void OnGameStart()
		{
			Instance.SetBotsId();
			foreach (KeyValuePair<int, CardPickerAI> bot in PickerAIs)
			{
				((TMP_Text)((Component)((Component)PlayerManager.instance.players.First((Player p) => p.playerID == bot.Key)).GetComponentInChildren<PlayerName>()).GetComponent<TextMeshProUGUI>()).text = "<#07e0f0>[BOT]";
			}
		}

		public void OnPointStart()
		{
			if (stalemateHandlerCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(stalemateHandlerCoroutine);
			}
			stalemateHandlerCoroutine = ((MonoBehaviour)this).StartCoroutine(StalemateHandler.HandleStalemate());
		}

		public void OnRoundEnd()
		{
			int maxRounds = (int)GameModeManager.CurrentHandler.Settings["roundsToWinGame"];
			int? num = PlayerManager.instance.players.Select((Player p) => p.teamID).Distinct().Select((Func<int, int?>)((int id) => id))
				.FirstOrDefault((int? id) => GameModeManager.CurrentHandler.GetTeamScore(id.Value).rounds >= maxRounds);
			bool flag = PlayerManager.instance.players.All((Player p) => p.data.GetAdditionalData().IsBot || CharacterDataExtension.GetAdditionalData(p.data).isAIMinion);
			if (num.HasValue && flag)
			{
				((MonoBehaviour)this).StartCoroutine(Rematch());
			}
		}

		public IEnumerator Rematch()
		{
			yield return (object)new WaitForSeconds(1f);
			if (GameManager.instance.isPlaying)
			{
				Type type = AccessTools.TypeByName("RWF.RoundEndHandler");
				object value = type.GetField("instance", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
				type.GetMethod("OnGameOverChoose", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(value, new object[1] { "REMATCH" });
			}
		}

		public List<GameObject> GetSpawnCards()
		{
			LoggingUtils.Log("Getting spawn cards");
			return (List<GameObject>)AccessTools.Field(typeof(CardChoice), "spawnedCards").GetValue(CardChoice.instance);
		}

		public IEnumerator CycleThroughCards(float delay, List<GameObject> spawnedCards)
		{
			LoggingUtils.Log("Cycling through cards");
			CardInfo lastCardInfo = null;
			int index = 0;
			foreach (GameObject spawnedCard in spawnedCards)
			{
				CardInfo component = spawnedCard.GetComponent<CardInfo>();
				LoggingUtils.Log("Cycling through '$" + component.cardName + "' card");
				if ((Object)(object)lastCardInfo != (Object)null)
				{
					lastCardInfo.RPCA_ChangeSelected(false);
				}
				component.RPCA_ChangeSelected(true);
				AccessTools.Field(typeof(CardChoice), "currentlySelectedCard").SetValue(CardChoice.instance, index);
				lastCardInfo = component;
				index++;
				yield return (object)new WaitForSeconds(delay);
			}
			LoggingUtils.Log("Successfully gone through all cards");
		}

		public IEnumerator GoToCards(GameObject selectedCards, List<GameObject> spawnedCards, float delay)
		{
			LoggingUtils.Log($"Going to '${selectedCards}' card");
			int selectedCardIndex = spawnedCards.IndexOf(selectedCards);
			int handIndex = int.Parse(AccessTools.Field(typeof(CardChoice), "currentlySelectedCard").GetValue(CardChoice.instance).ToString());
			while (handIndex != selectedCardIndex)
			{
				CardInfo component = spawnedCards[handIndex].GetComponent<CardInfo>();
				component.RPCA_ChangeSelected(false);
				LoggingUtils.Log($"Currently on '${component}' card");
				if (handIndex > selectedCardIndex)
				{
					handIndex--;
				}
				else if (handIndex < selectedCardIndex)
				{
					handIndex++;
				}
				component = spawnedCards[handIndex].GetComponent<CardInfo>();
				component.RPCA_ChangeSelected(true);
				AccessTools.Field(typeof(CardChoice), "currentlySelectedCard").SetValue(CardChoice.instance, handIndex);
				yield return (object)new WaitForSeconds(delay);
			}
			LoggingUtils.Log($"Successfully got to '${selectedCards}' card");
		}

		public void PickCard(List<GameObject> spawnCards)
		{
			CardChoice.instance.Pick(spawnCards[(int)ExtensionMethods.GetFieldValue((object)CardChoice.instance, "currentlySelectedCard")], true);
		}

		public IEnumerator AiPickCard()
		{
			if (!PhotonNetwork.IsMasterClient && !PhotonNetwork.OfflineMode)
			{
				yield break;
			}
			yield return (object)new WaitUntil((Func<bool>)(() => CardChoice.instance.IsPicking && ((List<GameObject>)ExtensionMethods.GetFieldValue((object)CardChoice.instance, "spawnedCards")).Count == ((Transform[])ExtensionMethods.GetFieldValue((object)CardChoice.instance, "children")).Count() && !((List<GameObject>)ExtensionMethods.GetFieldValue((object)CardChoice.instance, "spawnedCards")).Any((GameObject card) => (Object)(object)card == (Object)null)));
			for (int i = 0; i < PlayerManager.instance.players.Count; i++)
			{
				_ = PlayerManager.instance.players[i];
				if (PickerAIs.ContainsKey(CardChoice.instance.pickrID))
				{
					LoggingUtils.Log("AI picking card");
					List<GameObject> spawnCards = GetSpawnCards();
					((Component)spawnCards[0].GetComponent<CardInfo>()).GetComponent<PhotonView>().RPC("RPCA_ChangeSelected", (RpcTarget)0, new object[1] { true });
					ICardPickerAI cardPickerAI = PickerAIs[CardChoice.instance.pickrID].cardPickerAI;
					StartCardsPicking(spawnCards, cardPickerAI, PickerAIs[CardChoice.instance.pickrID].pickerInfo);
					break;
				}
			}
		}

		public void StartCardsPicking(List<GameObject> spawnCards, ICardPickerAI botCardPickerAI, PickerInfo pickerInfo)
		{
			if (botCardPickerAI == null)
			{
				LoggingUtils.Log("Bot card picker AI is null, Skipping card picking");
				return;
			}
			List<CardInfo> list = spawnCards.Select((GameObject card) => card.GetComponent<CardInfo>()).ToList();
			List<CardInfo> list2 = botCardPickerAI.PickCard(list);
			CardInfo item = list2.ElementAt(Random.Range(0, list2.Count));
			int num = list.IndexOf(item);
			NetworkingManager.RPC(typeof(BotAIManager), "RPCA_PickCardsAtPosition", new object[5] { num, pickerInfo.CycleDelay, pickerInfo.PreCycleDelay, pickerInfo.GoToCardDelay, pickerInfo.PickDelay });
		}

		private IEnumerator PickCardsAtPosition(int position, float cycleDelay, float preCycleDelay, float goToCardDelay, float pickDelay)
		{
			List<GameObject> spawnCards = GetSpawnCards();
			yield return CycleThroughCards(cycleDelay, spawnCards);
			yield return (object)new WaitForSeconds(preCycleDelay);
			yield return GoToCards(spawnCards[position], spawnCards, goToCardDelay);
			yield return (object)new WaitForSeconds(pickDelay);
			PickCard(spawnCards);
		}

		[UnboundRPC]
		private static void RPCA_PickCardsAtPosition(int position, float cycleDelay, float preCycleDelay, float goToCardDelay, float pickDelay)
		{
			((MonoBehaviour)Instance).StartCoroutine(Instance.PickCardsAtPosition(position, cycleDelay, preCycleDelay, goToCardDelay, pickDelay));
		}
	}
	public class PickerInfo
	{
		public float CycleDelay;

		public float PreCycleDelay;

		public float GoToCardDelay;

		public float PickDelay;

		public PickerInfo(float cycleDelay, float preCycleDelay, float goToCardDelay, float pickDelay)
		{
			CycleDelay = cycleDelay;
			PreCycleDelay = preCycleDelay;
			GoToCardDelay = goToCardDelay;
			PickDelay = pickDelay;
		}

		public PickerInfo()
		{
			CycleDelay = RWBMenu.CycleDelay.Value;
			PreCycleDelay = RWBMenu.PreCycleDelay.Value;
			GoToCardDelay = RWBMenu.GoToCardDelay.Value;
			PickDelay = RWBMenu.PickDelay.Value;
		}
	}
	public class CardPickerAI
	{
		public ICardPickerAI cardPickerAI;

		public PickerInfo pickerInfo;

		public CardPickerAI(ICardPickerAI cardPickerAI, PickerInfo pickerInfo)
		{
			this.cardPickerAI = cardPickerAI;
			this.pickerInfo = pickerInfo;
		}

		public CardPickerAI()
		{
			cardPickerAI = new RarestCardPicker();
			pickerInfo = new PickerInfo();
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.aalund13.rounds.roundswithbots", "Rounds With Bots", "2.3.0")]
	[BepInProcess("Rounds.exe")]
	public class RoundsWithBots : BaseUnityPlugin
	{
		private const string ModId = "com.aalund13.rounds.roundswithbots";

		private const string ModName = "Rounds With Bots";

		public const string Version = "2.3.0";

		public const string ModInitials = "RWB";

		public bool IsPicking;

		public static RoundsWithBots Instance { get; private set; }

		private void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("com.aalund13.rounds.roundswithbots").PatchAll();
		}

		private void Start()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			RWBMenu.RegisterMenu("Rounds With Bots", ((BaseUnityPlugin)this).Config);
			Unbound.RegisterHandshake("com.aalund13.rounds.roundswithbots", (Action)OnHandShakeCompleted);
			CardExclusiveUtils.ExcludeCardsFromBots(CardManager.GetCardInfoWithName("Remote"));
			CardExclusiveUtils.ExcludeCardsFromBots(CardManager.GetCardInfoWithName("Teleport"));
			CardExclusiveUtils.ExcludeCardsFromBots(CardManager.GetCardInfoWithName("Shield Charge"));
			BotAIManager.Instance = new GameObject("RWB_BotAIManager").AddComponent<BotAIManager>();
		}

		private void OnHandShakeCompleted()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				NetworkingManager.RPC_Others(((object)this).GetType(), "RPCA_SyncSettings", new object[7]
				{
					RWBMenu.StalemateTimer.Value,
					RWBMenu.StalemateDamageCooldown.Value,
					RWBMenu.StalemateDamageDuration.Value,
					RWBMenu.CycleDelay.Value,
					RWBMenu.PreCycleDelay.Value,
					RWBMenu.GoToCardDelay.Value,
					RWBMenu.PickDelay.Value
				});
			}
		}

		[UnboundRPC]
		private static void RPCA_SyncSettings(float stalemateTimer, float stalemateDamageCooldown, float stalemateDamageDuration, float cycleDelay, float preCycleDelay, float goToCardDelay, float pickDelay)
		{
			RWBMenu.StalemateTimer.Value = stalemateTimer;
			RWBMenu.StalemateDamageCooldown.Value = stalemateDamageCooldown;
			RWBMenu.StalemateDamageDuration.Value = stalemateDamageDuration;
			RWBMenu.CycleDelay.Value = cycleDelay;
			RWBMenu.PreCycleDelay.Value = preCycleDelay;
			RWBMenu.GoToCardDelay.Value = goToCardDelay;
			RWBMenu.PickDelay.Value = pickDelay;
		}
	}
}
namespace RoundsWithBots.Utils
{
	public class CardExclusiveUtils
	{
		public static CardCategory NotBotCategory = CustomCardCategories.instance.CardCategory("NotForBots");

		public static void ExcludeCardsFromBots(CardInfo card)
		{
			card.blacklistedCategories = CollectionExtensions.AddToArray<CardCategory>(card.blacklistedCategories, NotBotCategory);
		}
	}
	public static class LoggingUtils
	{
		public static void Log(string message)
		{
			if (RWBMenu.DebugMode.Value)
			{
				Debug.Log((object)message);
			}
		}

		public static void LogWarning(string message)
		{
			if (RWBMenu.DebugMode.Value)
			{
				Debug.LogWarning((object)message);
			}
		}

		public static void Error(string message)
		{
			if (RWBMenu.DebugMode.Value)
			{
				Debug.LogError((object)message);
			}
		}
	}
}
namespace RoundsWithBots.Patches
{
	[HarmonyPatch(typeof(PlayerAIPhilip))]
	internal class PlayerAIPhilipPatch
	{
		private const float maxDistance = 1f;

		public static List<Collider2D> DamageBoxesColliders = new List<Collider2D>();

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		public static void UpdatePostfix(PlayerAIPhilip __instance)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0089: 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_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_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)
			//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)
			GeneralInput val = (GeneralInput)AccessTools.Field(typeof(PlayerAPI), "input").GetValue(((Component)__instance).GetComponentInParent<PlayerAPI>());
			OutOfBoundsHandler obj = Object.FindObjectOfType<OutOfBoundsHandler>();
			Vector3 val2 = (Vector3)AccessTools.Method(typeof(OutOfBoundsHandler), "GetPoint", (Type[])null, (Type[])null).Invoke(obj, new object[1] { ((Component)__instance).transform.position });
			float num = Mathf.Abs(((Component)__instance).transform.position.x - val2.x);
			float num2 = Mathf.Abs(((Component)__instance).transform.position.y - val2.y);
			if ((num <= 1f || num2 <= 1f) && (num >= 1f || num2 >= 1f))
			{
				val.shieldWasPressed = true;
			}
			foreach (Collider2D damageBoxesCollider in DamageBoxesColliders)
			{
				if (!((Object)(object)damageBoxesCollider == (Object)null))
				{
					Bounds bounds = damageBoxesCollider.bounds;
					if (Vector2.Distance(Vector2.op_Implicit(((Bounds)(ref bounds)).ClosestPoint(((Component)__instance).transform.position)), Vector2.op_Implicit(((Component)__instance).transform.position)) <= 1f)
					{
						val.shieldWasPressed = true;
						break;
					}
				}
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch("CanSee")]
		public static IEnumerable<CodeInstruction> CanSeeTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ApplyLayerMaskToRaycast(instructions);
		}

		[HarmonyTranspiler]
		[HarmonyPatch("CheckGround")]
		public static IEnumerable<CodeInstruction> CheckGroundTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ApplyLayerMaskToRaycast(instructions);
		}

		private static IEnumerable<CodeInstruction> ApplyLayerMaskToRaycast(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo raycastMethod = AccessTools.Method(typeof(Physics2D), "Raycast", new Type[4]
			{
				typeof(Vector2),
				typeof(Vector2),
				typeof(float),
				typeof(int)
			}, (Type[])null);
			int num = LayerMask.NameToLayer("BackgroundObject");
			int layerMask = ~(1 << num);
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Call && instruction.operand is MethodInfo methodInfo && methodInfo.Name == "Raycast")
				{
					yield return new CodeInstruction(OpCodes.Ldc_I4, (object)layerMask);
					yield return new CodeInstruction(OpCodes.Call, (object)raycastMethod);
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
}
namespace RoundsWithBots.Pacthes
{
	[HarmonyPatch(typeof(CharacterSelectionInstance))]
	internal class CharacterSelectionInstancePatch
	{
		[HarmonyPatch("StartPicking")]
		[HarmonyBefore(new string[] { "io.olavim.rounds.rwf" })]
		public static void Postfix(CharacterSelectionInstance __instance, Player pickingPlayer)
		{
			if (((Behaviour)((Component)pickingPlayer).GetComponent<PlayerAPI>()).enabled)
			{
				if (RWBMenu.RandomizationFace.Value)
				{
					__instance.currentlySelectedFace = Random.Range(0, 7);
				}
				else
				{
					__instance.currentlySelectedFace = RWBMenu.SelectedFace.Value;
				}
			}
		}

		[HarmonyPatch("Update")]
		[HarmonyBefore(new string[] { "io.olavim.rounds.rwf" })]
		public static bool Prefix(CharacterSelectionInstance __instance)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			if ((Object)(object)__instance.currentPlayer == (Object)null)
			{
				return false;
			}
			if (((Behaviour)((Component)__instance.currentPlayer).GetComponent<PlayerAPI>()).enabled)
			{
				ExtensionMethods.SetFieldValue((object)__instance.currentPlayer.data.playerVel, "simulated", (object)false);
				if (__instance.currentPlayer.data.playerActions == null)
				{
					__instance.currentPlayer.data.playerActions = new PlayerActions();
					((PlayerActionSet)__instance.currentPlayer.data.playerActions).Device = InputDevice.Null;
				}
				if (Input.GetKeyDown((KeyCode)114))
				{
					AccessTools.Method(typeof(CharacterSelectionInstance), "ReadyUp", (Type[])null, (Type[])null).Invoke(__instance, null);
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Map))]
	internal class MapPatch
	{
		[HarmonyPatch("StartMatch")]
		public static void Postfix()
		{
			((MonoBehaviour)RoundsWithBots.Instance).StartCoroutine(SetDamageBoxesColliders());
		}

		public static IEnumerator SetDamageBoxesColliders()
		{
			yield return null;
			List<DamageBox> list = Object.FindObjectsOfType<DamageBox>().ToList();
			PlayerAIPhilipPatch.DamageBoxesColliders.Clear();
			foreach (DamageBox item in list)
			{
				PlayerAIPhilipPatch.DamageBoxesColliders.Add(((Component)item).GetComponent<Collider2D>());
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAssigner))]
	internal class PlayerAssignerPatch
	{
		[HarmonyPatch("CreatePlayer")]
		public static bool Prefix(bool isAI, ref IEnumerator __result)
		{
			if (GameManager.instance.isPlaying && !AIMinionHandler.sandbox)
			{
				__result = EmptyEnumerator();
				return false;
			}
			if (isAI)
			{
				((MonoBehaviour)RoundsWithBots.Instance).StartCoroutine(DelayedAIReplacement());
			}
			return true;
		}

		private static IEnumerator DelayedAIReplacement()
		{
			yield return null;
			Player val = PlayerManager.instance.players.Last();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError("Player could not be found.");
				yield break;
			}
			MonoBehaviour val2 = (MonoBehaviour)(((object)((Component)val).GetComponentInChildren<PlayerAI>()) ?? ((object)((Component)val).GetComponentInChildren<PlayerAIZorro>()));
			if ((Object)(object)val2 != (Object)null)
			{
				PlayerAIZorro val3 = (PlayerAIZorro)(object)((val2 is PlayerAIZorro) ? val2 : null);
				if (val3 != null)
				{
					HealthHandler healthHandler = val.data.healthHandler;
					healthHandler.delayedReviveAction = (Action)Delegate.Remove(healthHandler.delayedReviveAction, new Action(val3.Init));
				}
				((Component)val2).gameObject.AddComponent<PlayerAIPhilip>();
				val.data.GetAdditionalData().IsBot = true;
				Object.Destroy((Object)(object)val2);
			}
		}

		private static IEnumerator EmptyEnumerator()
		{
			yield break;
		}
	}
}
namespace RoundsWithBots.Pacthes.RWF
{
	[HarmonyPatch(typeof(KeybindHints))]
	internal class KeybindHintsPatch
	{
		[HarmonyPatch("CreateLocalHints")]
		public static void Postfix()
		{
			if (PlayerPrefs.GetInt(RWFMod.GetCustomPropertyKey("ShowKeybinds"), 1) != 0)
			{
				KeybindHints.AddHint("to ready up all bots", "[R]", (Vector2?)null);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerSpotlight))]
	internal class RWFAddSpotToPlayerPatch
	{
		[HarmonyPatch("AddSpotToPlayer")]
		public static bool Prefix(Player player)
		{
			return !((Behaviour)((Component)player).GetComponent<PlayerAPI>()).enabled;
		}
	}
}
namespace RoundsWithBots.Pacthes.ModdingUtils
{
	[HarmonyPatch(typeof(Cards))]
	internal class PlayerIsAllowedCard
	{
		[HarmonyPatch("PlayerIsAllowedCard")]
		[HarmonyPostfix]
		public static void Postfix(Player player, CardInfo card, ref bool __result, Cards __instance)
		{
			if (((Behaviour)((Component)player).GetComponent<PlayerAPI>()).enabled && card.blacklistedCategories.Contains(CustomCardCategories.instance.CardCategory("NotForBots")))
			{
				__result = false;
			}
		}
	}
}
namespace RoundsWithBots.Menu
{
	internal static class RWBMenu
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__4_0;

			public static UnityAction<float> <>9__4_1;

			public static UnityAction<float> <>9__4_2;

			public static UnityAction<float> <>9__4_3;

			public static UnityAction<float> <>9__4_4;

			public static UnityAction <>9__8_0;

			public static UnityAction<bool> <>9__8_1;

			public static UnityAction<float> <>9__8_2;

			public static UnityAction <>9__10_0;

			public static UnityAction<bool> <>9__11_0;

			public static UnityAction <>9__16_0;

			public static UnityAction<float> <>9__16_1;

			public static UnityAction<float> <>9__16_2;

			public static UnityAction<float> <>9__16_3;

			internal void <CreateCardsPickerMenu>b__4_0()
			{
			}

			internal void <CreateCardsPickerMenu>b__4_1(float value)
			{
				CycleDelay.Value = value;
			}

			internal void <CreateCardsPickerMenu>b__4_2(float value)
			{
				PreCycleDelay.Value = value;
			}

			internal void <CreateCardsPickerMenu>b__4_3(float value)
			{
				GoToCardDelay.Value = value;
			}

			internal void <CreateCardsPickerMenu>b__4_4(float value)
			{
				PickDelay.Value = value;
			}

			internal void <CreateDetailsMenu>b__8_0()
			{
			}

			internal void <CreateDetailsMenu>b__8_1(bool value)
			{
				RandomizationFace.Value = value;
				SelectedFaceObject.SetActive(!value);
			}

			internal void <CreateDetailsMenu>b__8_2(float value)
			{
				SelectedFace.Value = (int)value;
			}

			internal void <RegisterMenu>b__10_0()
			{
			}

			internal void <CreateRWBMenu>b__11_0(bool value)
			{
				DebugMode.Value = value;
			}

			internal void <CreateStalemateMenu>b__16_0()
			{
			}

			internal void <CreateStalemateMenu>b__16_1(float value)
			{
				StalemateTimer.Value = value;
			}

			internal void <CreateStalemateMenu>b__16_2(float value)
			{
				StalemateDamageCooldown.Value = value;
			}

			internal void <CreateStalemateMenu>b__16_3(float value)
			{
				StalemateDamageDuration.Value = value;
			}
		}

		public static ConfigEntry<float> CycleDelay;

		public static ConfigEntry<float> PreCycleDelay;

		public static ConfigEntry<float> GoToCardDelay;

		public static ConfigEntry<float> PickDelay;

		public static GameObject SelectedFaceObject;

		public static ConfigEntry<bool> RandomizationFace;

		public static ConfigEntry<int> SelectedFace;

		public static ConfigEntry<bool> DebugMode;

		public static ConfigEntry<float> StalemateTimer;

		public static ConfigEntry<float> StalemateDamageCooldown;

		public static ConfigEntry<float> StalemateDamageDuration;

		private static void CreateCardsPickerMenu(GameObject mainMenu)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			object obj = <>c.<>9__4_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
				};
				<>c.<>9__4_0 = val;
				obj = (object)val;
			}
			GameObject val2 = MenuHandler.CreateMenu("Cards Picker", (UnityAction)obj, mainMenu, 40, true, true, ((Component)mainMenu.transform.parent).gameObject, true, -1);
			TextMeshProUGUI val3 = default(TextMeshProUGUI);
			MenuHandler.CreateText("<b>Rounds With Bots | Cards Picker", val2, ref val3, 70, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 50);
			Slider val4 = default(Slider);
			MenuHandler.CreateSlider("Cycle Delay", val2, 30, 0f, 1f, CycleDelay.Value, (UnityAction<float>)delegate(float value)
			{
				CycleDelay.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			MenuHandler.CreateSlider("Pre-Cycle Delay", val2, 30, 0f, 5f, PreCycleDelay.Value, (UnityAction<float>)delegate(float value)
			{
				PreCycleDelay.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			MenuHandler.CreateSlider("Go To Card Delay", val2, 30, 0f, 1f, GoToCardDelay.Value, (UnityAction<float>)delegate(float value)
			{
				GoToCardDelay.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			MenuHandler.CreateSlider("Pick Delay", val2, 30, 0f, 5f, PickDelay.Value, (UnityAction<float>)delegate(float value)
			{
				PickDelay.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
		}

		private static void CreateDetailsMenu(GameObject mainMenu)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			object obj = <>c.<>9__8_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
				};
				<>c.<>9__8_0 = val;
				obj = (object)val;
			}
			GameObject val2 = MenuHandler.CreateMenu("Bot Details", (UnityAction)obj, mainMenu, 40, true, true, ((Component)mainMenu.transform.parent).gameObject, true, -1);
			TextMeshProUGUI val3 = default(TextMeshProUGUI);
			MenuHandler.CreateText("<b>Rounds With Bots | Bot Details", val2, ref val3, 70, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 50);
			MenuHandler.CreateToggle(RandomizationFace.Value, "Randomize Bot Faces", val2, (UnityAction<bool>)delegate(bool value)
			{
				RandomizationFace.Value = value;
				SelectedFaceObject.SetActive(!value);
			}, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			Slider val4 = default(Slider);
			SelectedFaceObject = MenuHandler.CreateSlider("Selected Bot Face", val2, 30, 0f, 7f, (float)SelectedFace.Value, (UnityAction<float>)delegate(float value)
			{
				SelectedFace.Value = (int)value;
			}, ref val4, true, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			SelectedFaceObject.SetActive(!RandomizationFace.Value);
		}

		public static void RegisterMenu(string modName, ConfigFile config)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			object obj = <>c.<>9__10_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
				};
				<>c.<>9__10_0 = val;
				obj = (object)val;
			}
			Unbound.RegisterMenu(modName, (UnityAction)obj, (Action<GameObject>)CreateRWBMenu, (GameObject)null, false);
			DebugMode = config.Bind<bool>(modName, "DebugMode", false, "Enable or disable debug mode for additional logging and debugging features.");
			RandomizationFace = config.Bind<bool>(modName, "RandomizationFace", true, "Enable or disable randomization of bot faces.");
			SelectedFace = config.Bind<int>(modName, "SelectedFace", 0, "Select a specific bot face when Randomize Bot Faces is disabled.");
			StalemateTimer = config.Bind<float>(modName, "StalemateTimer", 10f, "The time in seconds before a stalemate is declared.");
			StalemateDamageCooldown = config.Bind<float>(modName, "StalemateDamageCooldown", 1f, "The time in seconds before a player can take damage again after a stalemate.");
			StalemateDamageDuration = config.Bind<float>(modName, "StalemateDamageDuration", 10f, "The time in seconds that a player takes damage after a stalemate.");
			CycleDelay = config.Bind<float>(modName, "CycleDelay", 0.3f, "The delay between cycling through cards.");
			PreCycleDelay = config.Bind<float>(modName, "PreCycleDelay", 1f, "The delay before cycling through cards.");
			GoToCardDelay = config.Bind<float>(modName, "GoToCardDelay", 0.2f, "The delay between going to a specific card.");
			PickDelay = config.Bind<float>(modName, "PickDelay", 0.5f, "The delay before picking a card.");
		}

		private static void CreateRWBMenu(GameObject mainMenu)
		{
			TextMeshProUGUI val = default(TextMeshProUGUI);
			MenuHandler.CreateText("<b>Rounds With Bots", mainMenu, ref val, 70, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(mainMenu, 50);
			CreateDetailsMenu(mainMenu);
			AddBlank(mainMenu, 20);
			CreateStalemateMenu(mainMenu);
			AddBlank(mainMenu, 20);
			CreateCardsPickerMenu(mainMenu);
			AddBlank(mainMenu, 20);
			MenuHandler.CreateToggle(DebugMode.Value, "<#c41010>Debug Mode", mainMenu, (UnityAction<bool>)delegate(bool value)
			{
				DebugMode.Value = value;
			}, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
		}

		private static void AddBlank(GameObject menu, int size = 30)
		{
			TextMeshProUGUI val = default(TextMeshProUGUI);
			MenuHandler.CreateText(" ", menu, ref val, size, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
		}

		private static void CreateStalemateMenu(GameObject mainMenu)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			object obj = <>c.<>9__16_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
				};
				<>c.<>9__16_0 = val;
				obj = (object)val;
			}
			GameObject val2 = MenuHandler.CreateMenu("Stalemate Options", (UnityAction)obj, mainMenu, 40, true, true, ((Component)mainMenu.transform.parent).gameObject, true, -1);
			TextMeshProUGUI val3 = default(TextMeshProUGUI);
			MenuHandler.CreateText("<b>Rounds With Bots | Stalemate Options", val2, ref val3, 70, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 50);
			Slider val4 = default(Slider);
			MenuHandler.CreateSlider("Stalemate Timer", val2, 30, 0f, 60f, StalemateTimer.Value, (UnityAction<float>)delegate(float value)
			{
				StalemateTimer.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			MenuHandler.CreateSlider("Stalemate Damage Cooldown", val2, 30, 0f, 60f, StalemateDamageCooldown.Value, (UnityAction<float>)delegate(float value)
			{
				StalemateDamageCooldown.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			AddBlank(val2, 20);
			MenuHandler.CreateSlider("Stalemate Damage Duration", val2, 30, 0f, 60f, StalemateDamageDuration.Value, (UnityAction<float>)delegate(float value)
			{
				StalemateDamageDuration.Value = value;
			}, ref val4, false, (Color?)null, (Direction)0, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
		}
	}
}
namespace RoundsWithBots.Extensions
{
	[Serializable]
	public class CharacterDataAdditionalData
	{
		public bool IsBot { get; set; }

		public CharacterDataAdditionalData()
		{
			IsBot = false;
		}
	}
	public static class CharacterDataExtension
	{
		public static readonly ConditionalWeakTable<CharacterData, CharacterDataAdditionalData> data = new ConditionalWeakTable<CharacterData, CharacterDataAdditionalData>();

		public static CharacterDataAdditionalData GetAdditionalData(this CharacterData characterData)
		{
			return data.GetOrCreateValue(characterData);
		}

		public static void AddData(this CharacterData characterData, CharacterDataAdditionalData value)
		{
			try
			{
				data.Add(characterData, value);
			}
			catch (Exception)
			{
			}
		}
	}
}
namespace RoundsWithBots.CardPickerAIs
{
	public interface ICardPickerAI
	{
		List<CardInfo> PickCard(List<CardInfo> cards);
	}
	public class RarestCardPicker : ICardPickerAI
	{
		public List<CardInfo> PickCard(List<CardInfo> cards)
		{
			return (from card in cards
				group card by card.rarity into @group
				orderby @group.Key
				select @group).LastOrDefault()?.ToList();
		}
	}
}