Decompiled source of TerminalGames v1.0.2

TerminalGames.dll

Decompiled 5 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GTFO.API;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TerminalGames")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TerminalGames")]
[assembly: AssemblyTitle("TerminalGames")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace TerminalGames
{
	public struct CommandDescriptor
	{
		public TERM_Command Type;

		public string Command;

		public string Description;

		public TERM_CommandRule Rule;
	}
	public class Game
	{
		public enum GameType
		{
			Tictactoe,
			Connect4,
			Othello
		}

		public enum GameMode
		{
			Solo,
			Multi,
			Local
		}

		public static ManualLogSource Log;

		public List<int> symbols = new List<int> { 1, 2 };

		private GameType type;

		private GameMode mode;

		private List<List<int>> board = new List<List<int>>();

		private static List<Tuple<int, int>> placed_tokens = new List<Tuple<int, int>>();

		private bool isActive;

		private int currentPlayer = 1;

		public string MakeAIMove()
		{
			if (!isActive)
			{
				return "";
			}
			List<(int, int)> emptySpots = GetEmptySpots();
			int value = ((currentPlayer != 1) ? 1 : 2);
			foreach (var item in emptySpots)
			{
				List<List<int>> list = CopyBoard();
				list[item.Item1][item.Item2] = currentPlayer;
				if (CheckForWin(list))
				{
					MakeMove(item.Item1, item.Item2, currentPlayer);
					return $"{(ushort)(item.Item2.ToString()[0] + 49)}{item.Item1 + 1}";
				}
			}
			foreach (var item2 in emptySpots)
			{
				List<List<int>> list2 = CopyBoard();
				list2[item2.Item1][item2.Item2] = value;
				if (CheckForWin(list2))
				{
					MakeMove(item2.Item1, item2.Item2, currentPlayer);
					return $"{(ushort)(item2.Item2.ToString()[0] + 49)}{item2.Item1 + 1}";
				}
			}
			int index = new Random().Next(emptySpots.Count);
			var (num, column) = emptySpots[index];
			MakeMove(num, column, currentPlayer);
			return $"{(ushort)(column.ToString()[0] + 49)}{num + 1}";
		}

		private List<(int row, int col)> GetEmptySpots()
		{
			List<(int, int)> list = new List<(int, int)>();
			for (int i = 0; i < board.Count; i++)
			{
				for (int j = 0; j < board[i].Count; j++)
				{
					if (IsValidMove(i, j))
					{
						list.Add((i, j));
					}
				}
			}
			return list;
		}

		private List<List<int>> CopyBoard()
		{
			List<List<int>> list = new List<List<int>>();
			foreach (List<int> item2 in board)
			{
				List<int> item = new List<int>(item2);
				list.Add(item);
			}
			return list;
		}

		public bool CheckForWin(List<List<int>>? board_used = null)
		{
			if (board_used == null)
			{
				board_used = board;
			}
			if (type == GameType.Connect4)
			{
				if (!CheckRows(4, board_used) && !CheckColumns(4, board_used))
				{
					return CheckDiagonals(4, board_used);
				}
				return true;
			}
			if (type == GameType.Tictactoe)
			{
				if (!CheckRows(3, board_used) && !CheckColumns(3, board_used))
				{
					return CheckDiagonals(3, board_used);
				}
				return true;
			}
			if (type == GameType.Othello)
			{
				bool flag = true;
				foreach (List<int> item in board)
				{
					foreach (int item2 in item)
					{
						if (item2 == 0)
						{
							flag = false;
						}
					}
				}
				bool flag2 = false;
				for (int i = 0; i < board.Count; i++)
				{
					for (int j = 0; j < board[0].Count; j++)
					{
						if (IsValidMove(i, j))
						{
							flag2 = true;
						}
					}
				}
				int num = CountPieces(1);
				int num2 = CountPieces(2);
				if (flag || !flag2)
				{
					return num != num2;
				}
				return false;
			}
			return false;
		}

		private bool CheckRows(int consecutiveSymbols, List<List<int>> board_used)
		{
			foreach (int symbol in symbols)
			{
				for (int i = 0; i < board_used.Count; i++)
				{
					for (int j = 0; j <= board_used[i].Count - consecutiveSymbols; j++)
					{
						bool flag = true;
						for (int k = 0; k < consecutiveSymbols; k++)
						{
							if (board_used[i][j + k] != symbol)
							{
								flag = false;
								break;
							}
						}
						if (flag)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private bool CheckColumns(int consecutiveSymbols, List<List<int>> board_used)
		{
			foreach (int symbol in symbols)
			{
				for (int i = 0; i < board_used[0].Count; i++)
				{
					for (int j = 0; j <= board_used.Count - consecutiveSymbols; j++)
					{
						bool flag = true;
						for (int k = 0; k < consecutiveSymbols; k++)
						{
							if (board_used[j + k][i] != symbol)
							{
								flag = false;
								break;
							}
						}
						if (flag)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private bool CheckDiagonals(int consecutiveSymbols, List<List<int>> board_used)
		{
			foreach (int symbol in symbols)
			{
				for (int i = 0; i <= board_used.Count - consecutiveSymbols; i++)
				{
					for (int j = 0; j <= board_used[i].Count - consecutiveSymbols; j++)
					{
						bool flag = true;
						for (int k = 0; k < consecutiveSymbols; k++)
						{
							if (board_used[i + k][j + k] != symbol)
							{
								flag = false;
								break;
							}
						}
						if (flag)
						{
							return true;
						}
					}
				}
				for (int l = 0; l <= board_used.Count - consecutiveSymbols; l++)
				{
					for (int m = consecutiveSymbols - 1; m < board_used[l].Count; m++)
					{
						bool flag2 = true;
						for (int n = 0; n < consecutiveSymbols; n++)
						{
							if (board_used[l + n][m - n] != symbol)
							{
								flag2 = false;
								break;
							}
						}
						if (flag2)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		public bool CheckForDraw(List<List<int>>? board_used = null)
		{
			if (board_used == null)
			{
				board_used = board;
			}
			if (type == GameType.Othello)
			{
				bool flag = true;
				foreach (List<int> item in board)
				{
					foreach (int item2 in item)
					{
						if (item2 == 0)
						{
							flag = false;
							break;
						}
					}
					if (!flag)
					{
						break;
					}
				}
				bool flag2 = false;
				for (int i = 0; i < board.Count; i++)
				{
					for (int j = 0; j < board[0].Count; j++)
					{
						if (IsValidMove(i, j))
						{
							flag2 = true;
							break;
						}
					}
					if (flag2)
					{
						break;
					}
				}
				int num = CountPieces(1);
				int num2 = CountPieces(2);
				if (flag || !flag2)
				{
					return num == num2;
				}
				return false;
			}
			for (int k = 0; k < board_used.Count; k++)
			{
				for (int l = 0; l < board_used[k].Count; l++)
				{
					if (board_used[k][l] == 0)
					{
						return false;
					}
				}
			}
			return true;
		}

		private int CountPieces(int player)
		{
			int num = 0;
			foreach (List<int> item in board)
			{
				foreach (int item2 in item)
				{
					if (item2 == player)
					{
						num++;
					}
				}
			}
			return num;
		}

		private void InitializeBoard(int rows, int columns)
		{
			board = new List<List<int>>(rows);
			for (int i = 0; i < rows; i++)
			{
				board.Add(new List<int>(columns));
				for (int j = 0; j < columns; j++)
				{
					board[i].Add(0);
				}
			}
		}

		public void StopGame()
		{
			currentPlayer = 1;
			isActive = false;
		}

		public string SetGameType(string input, string input2)
		{
			if (isActive)
			{
				return "A game is already being played.";
			}
			if (Enum.TryParse<GameType>(input, ignoreCase: true, out var result))
			{
				type = result;
				isActive = true;
				switch (type)
				{
				case GameType.Tictactoe:
					InitializeBoard(3, 3);
					break;
				case GameType.Connect4:
					InitializeBoard(6, 7);
					break;
				case GameType.Othello:
					InitializeBoard(8, 8);
					board[3][3] = 1;
					board[4][4] = 1;
					board[3][4] = 2;
					board[4][3] = 2;
					break;
				}
				if (Enum.TryParse<GameMode>(input2, ignoreCase: true, out var result2))
				{
					mode = result2;
				}
				else
				{
					mode = GameMode.Solo;
				}
				return "";
			}
			return "Invalid Game Type input.";
		}

		public static string ConvertCoordinate(string coordinate, out int row, out int column)
		{
			row = -1;
			column = -1;
			if (coordinate.Length < 1 || coordinate.Length > 2)
			{
				return "Invalid coordinate format. Please use a format like 'a2'.";
			}
			char c = coordinate[0];
			if (coordinate.Length == 2)
			{
				if (!int.TryParse(coordinate[1].ToString(), out row))
				{
					return "Invalid row coordinate. Please use a format like 'a2'.";
				}
				row--;
			}
			column = c - 97;
			return "";
		}

		public List<string> MakeMove(string coordinate, int terminalPlayer)
		{
			if (isActive && ConvertCoordinate(coordinate, out var row, out var column) == "")
			{
				return MakeMove(row, column, terminalPlayer);
			}
			return new List<string> { "Invalid move. Please try again." };
		}

		public List<string> MakeMove(int row, int column, int terminalPlayer)
		{
			if (terminalPlayer != currentPlayer)
			{
				return new List<string> { "This not your turn to play." };
			}
			if (type == GameType.Connect4)
			{
				while (row < board.Count - 1 && board[row + 1][column] == 0)
				{
					row++;
				}
			}
			if (IsValidMove(row, column))
			{
				placed_tokens = new List<Tuple<int, int>>
				{
					new Tuple<int, int>(row, column)
				};
				board[row][column] = currentPlayer;
				if (type == GameType.Othello)
				{
					int num = ((currentPlayer != 1) ? 1 : 2);
					for (int i = -1; i <= 1; i++)
					{
						for (int j = -1; j <= 1; j++)
						{
							if (i == 0 && j == 0)
							{
								continue;
							}
							int num2 = row + i;
							int num3 = column + j;
							if (num2 < 0 || num2 >= board.Count || num3 < 0 || num3 >= board[0].Count || board[num2][num3] != num)
							{
								continue;
							}
							List<(int, int)> list = new List<(int, int)>();
							while (num2 >= 0 && num2 < board.Count && num3 >= 0 && num3 < board[0].Count && board[num2][num3] == num)
							{
								list.Add((num2, num3));
								num2 += i;
								num3 += j;
							}
							if (num2 < 0 || num2 >= board.Count || num3 < 0 || num3 >= board[0].Count || board[num2][num3] != currentPlayer)
							{
								continue;
							}
							foreach (var (num4, num5) in list)
							{
								board[num4][num5] = currentPlayer;
								placed_tokens.Add(new Tuple<int, int>(num4, num5));
							}
						}
					}
				}
				if (currentPlayer == 1)
				{
					currentPlayer = 2;
				}
				else
				{
					currentPlayer = 1;
				}
				return DisplayBoard();
			}
			return new List<string> { "Invalid move. Please try again." };
		}

		private bool IsValidMove(int row, int column)
		{
			bool flag = row >= 0 && row < board.Count && column >= 0 && column < board[row].Count && board[row][column] == 0;
			if (type == GameType.Connect4)
			{
				bool flag2 = row == board.Count - 1;
				bool flag3 = row < board.Count - 1 && board[row + 1][column] != 0;
				flag = flag && (flag2 || flag3);
			}
			else if (flag && type == GameType.Othello)
			{
				int num = ((currentPlayer != 1) ? 1 : 2);
				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						if (i == 0 && j == 0)
						{
							continue;
						}
						int num2 = row + i;
						int num3 = column + j;
						if (num2 >= 0 && num2 < board.Count && num3 >= 0 && num3 < board[0].Count && board[num2][num3] == num)
						{
							while (num2 >= 0 && num2 < board.Count && num3 >= 0 && num3 < board[0].Count && board[num2][num3] == num)
							{
								num2 += i;
								num3 += j;
							}
							if (num2 >= 0 && num2 < board.Count && num3 >= 0 && num3 < board[0].Count && board[num2][num3] == currentPlayer)
							{
								return true;
							}
						}
					}
				}
				return false;
			}
			return flag;
		}

		public bool IsGameActive()
		{
			return isActive;
		}

		public GameMode GetGameMode()
		{
			return mode;
		}

		public GameType GetGameType()
		{
			return type;
		}

		public int GetCurrentPlayer()
		{
			return currentPlayer;
		}

		public Game Copy()
		{
			Game game = new Game
			{
				type = type,
				mode = mode,
				isActive = isActive,
				currentPlayer = currentPlayer,
				board = new List<List<int>>(board.Count)
			};
			for (int i = 0; i < board.Count; i++)
			{
				game.board.Add(new List<int>(board[i]));
			}
			return game;
		}

		public List<string> DisplayBoard()
		{
			List<string> list = new List<string>
			{
				"",
				"   " + string.Join(" ", GetColumnLetters(board[0].Count))
			};
			for (int i = 0; i < board.Count; i++)
			{
				list.Add($"{i + 1} |{string.Join(" ", GetRowSymbols(board[i], i))}|");
			}
			list.Add("");
			return list;
		}

		private static string[] GetRowSymbols(List<int> row, int rowIndex)
		{
			string[] array = new string[row.Count];
			for (int i = 0; i < row.Count; i++)
			{
				string text = GetPlayerColor(row[i]);
				for (int j = 0; j < placed_tokens.Count; j++)
				{
					if (placed_tokens[j].Item1 == rowIndex && placed_tokens[j].Item2 == i)
					{
						text = "<color=green>";
						break;
					}
				}
				array[i] = text + GetSymbol(row[i]) + "</color>";
			}
			return array;
		}

		private static char[] GetColumnLetters(int columnCount)
		{
			char[] array = new char[columnCount];
			for (int i = 0; i < columnCount; i++)
			{
				array[i] = (char)(97 + i);
			}
			return array;
		}

		private static string GetSymbol(int player)
		{
			return player switch
			{
				1 => "X", 
				2 => "O", 
				_ => " ", 
			};
		}

		public static string GetPlayerColor(int player)
		{
			return player switch
			{
				1 => "<color=purple>", 
				2 => "<color=yellow>", 
				_ => "", 
			};
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "ReceiveCommand")]
	internal class Inject_Terminal_ReceiveCmd
	{
		public static ManualLogSource Log;

		public static event Action<LG_ComputerTerminalCommandInterpreter, TERM_Command, string, string, string> OnCmdUsed_LevelInstanced;

		static Inject_Terminal_ReceiveCmd()
		{
			LevelAPI.OnLevelCleanup += delegate
			{
				Inject_Terminal_ReceiveCmd.OnCmdUsed_LevelInstanced = null;
			};
		}

		private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, TERM_Command cmd, string inputLine, string param1, string param2)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Inject_Terminal_ReceiveCmd.OnCmdUsed_LevelInstanced?.Invoke(__instance, cmd, inputLine, param1, param2);
		}
	}
	internal static class Patch
	{
		public class MonoPatch : MonoBehaviour
		{
			public static ManualLogSource? Log;

			public static List<EnrichedTerminal> enriched_terminals = new List<EnrichedTerminal>();

			public static void Initialize()
			{
				List<LG_Zone> zones = Builder.Current.m_currentFloor.MainDimension.Layers[0].m_zones;
				for (int i = 0; i < zones.Count; i++)
				{
					List<LG_ComputerTerminal> terminalsSpawnedInZone = zones[i].TerminalsSpawnedInZone;
					for (int j = 0; j < terminalsSpawnedInZone.Count; j++)
					{
						LG_ComputerTerminal val = terminalsSpawnedInZone[j];
						EnrichedTerminal enrichedTerminal = new EnrichedTerminal
						{
							ComputerTerminal = val,
							CmdProcessor = val.m_command,
							Interaction = ((Component)val).GetComponentInChildren<Interact_ComputerTerminal>(true)
						};
						enrichedTerminal.SetTerminalListIndex(enriched_terminals.Count);
						enrichedTerminal.Setup();
						enriched_terminals.Add(enrichedTerminal);
					}
				}
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("TerminalGames", "TerminalGames", "1.0.2")]
	public class Plugin : BasePlugin
	{
		private Harmony _Harmony;

		public override void Load()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			_Harmony = new Harmony("TerminalGames");
			_Harmony.PatchAll();
			Patch.MonoPatch.Log = ((BasePlugin)this).Log;
			EnrichedTerminal.Log = ((BasePlugin)this).Log;
			Game.Log = ((BasePlugin)this).Log;
			((BasePlugin)this).AddComponent<Patch.MonoPatch>();
			EventAPI.OnExpeditionStarted += Patch.MonoPatch.Initialize;
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(35, 0, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin TerminalGames is now loaded.");
			}
			log.LogInfo(val);
		}
	}
	public class EnrichedTerminal
	{
		public static ManualLogSource Log;

		private LocalizedText _GCTextHolder;

		private Game current_game = new Game();

		private int player = 1;

		private int TerminalListIndex;

		private int OtherTerminalListIndex = -1;

		public const TERM_Command COMMAND_PLAY = 255;

		public const TERM_Command COMMAND_PLACE = 254;

		public const TERM_Command COMMAND_STOP = 253;

		public const TERM_Command COMMAND_JOIN = 252;

		public LG_ComputerTerminal ComputerTerminal { get; set; }

		public LG_ComputerTerminalCommandInterpreter CmdProcessor { get; set; }

		public Interact_ComputerTerminal Interaction { get; set; }

		public event Action<TERM_Command, string, string, string> OnCmdUsed;

		public void AddCommand(CommandDescriptor descriptor, Action<LG_ComputerTerminalCommandInterpreter, string, string>? onCommandUsed = null)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Action<LG_ComputerTerminalCommandInterpreter, string, string> onCommandUsed2 = onCommandUsed;
			if (CmdProcessor.HasRegisteredCommand(descriptor.Type))
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Command Type: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<TERM_Command>(descriptor.Type);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is Already Added!!");
				}
				log.LogError(val);
				return;
			}
			_GCTextHolder = new LocalizedText
			{
				UntranslatedText = descriptor.Description,
				Id = 0u
			};
			CmdProcessor.AddCommand(descriptor.Type, descriptor.Command, _GCTextHolder, descriptor.Rule);
			OnCmdUsed += delegate(TERM_Command cmdType, string cmdStr, string param1, string param2)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				if (cmdType == descriptor.Type)
				{
					onCommandUsed2?.Invoke(CmdProcessor, param1, param2);
				}
			};
		}

		public void AddPlayCommand(string cmd, string helpText, Action<LG_ComputerTerminalCommandInterpreter>? onCommandUsed = null)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Action<LG_ComputerTerminalCommandInterpreter> onCommandUsed2 = onCommandUsed;
			string cmd2 = cmd;
			CommandDescriptor commandDescriptor = default(CommandDescriptor);
			commandDescriptor.Type = (TERM_Command)255;
			commandDescriptor.Command = cmd2;
			commandDescriptor.Description = helpText;
			commandDescriptor.Rule = (TERM_CommandRule)0;
			CommandDescriptor descriptor = commandDescriptor;
			AddCommand(descriptor, delegate(LG_ComputerTerminalCommandInterpreter interpreter, string param1, string param2)
			{
				onCommandUsed2?.Invoke(interpreter);
				interpreter.AddOutput((TerminalLineType)0, $"Desired Action: <color=orange>{cmd2}</color> <color=yellow>{param1}</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				if (param1 != null && param1.Length > 0)
				{
					string text = current_game.SetGameType(param1, param2);
					if (text.Length > 0)
					{
						interpreter.AddOutput((TerminalLineType)0, "<color=red>" + text + "</color>", 0.65f, (TerminalSoundType)0, (TerminalSoundType)0);
					}
					else
					{
						interpreter.AddOutput((TerminalLineType)4, "Preparing game..", 0.85f, (TerminalSoundType)0, (TerminalSoundType)0);
						interpreter.AddOutput((TerminalLineType)0, "<color=green>New game created!</color> " + Game.GetPlayerColor(player) + "You</color><color=green> can start playing!</color>", 0.65f, (TerminalSoundType)0, (TerminalSoundType)0);
						List<string> list = current_game.DisplayBoard();
						list.Add("<color=green>PLACE {coordinates}</color> to place a move.");
						foreach (string item in list)
						{
							interpreter.AddOutput((TerminalLineType)0, item, 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
						}
						if (current_game.GetGameMode() == Game.GameMode.Multi)
						{
							OtherTerminalListIndex = -1;
							interpreter.AddOutput((TerminalLineType)0, $"The other player can join the game with <color=green>JOIN Terminal_{ComputerTerminal.m_serialNumber}</color>", 0.65f, (TerminalSoundType)0, (TerminalSoundType)0);
						}
					}
				}
				else
				{
					interpreter.AddOutput((TerminalLineType)0, "<color=red>You have to specify a game to play.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
			});
		}

		public void AddPlaceCommand(string cmd, string helpText, Action<LG_ComputerTerminalCommandInterpreter>? onCommandUsed = null)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Action<LG_ComputerTerminalCommandInterpreter> onCommandUsed2 = onCommandUsed;
			string cmd2 = cmd;
			CommandDescriptor commandDescriptor = default(CommandDescriptor);
			commandDescriptor.Type = (TERM_Command)254;
			commandDescriptor.Command = cmd2;
			commandDescriptor.Description = helpText;
			commandDescriptor.Rule = (TERM_CommandRule)0;
			CommandDescriptor descriptor = commandDescriptor;
			AddCommand(descriptor, delegate(LG_ComputerTerminalCommandInterpreter interpreter, string param1, string param2)
			{
				LG_ComputerTerminalCommandInterpreter interpreter2 = interpreter;
				onCommandUsed2?.Invoke(interpreter2);
				if (!current_game.IsGameActive())
				{
					interpreter2.AddOutput((TerminalLineType)0, "<color=red>There is no active game yet.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
				else if (current_game.GetGameMode() == Game.GameMode.Multi && OtherTerminalListIndex == -1)
				{
					interpreter2.AddOutput((TerminalLineType)0, "<color=red>You have to wait for a player to join the game.</color>", 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
				else
				{
					interpreter2.AddOutput((TerminalLineType)0, $"Desired Action: <color=orange>{cmd2}</color> <color=yellow>{param1}</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					List<string> list = current_game.MakeMove(param1, player);
					if (list.Count == 1)
					{
						interpreter2.AddOutput((TerminalLineType)0, "<color=red>" + list[0] + "</color>", 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
					}
					else
					{
						if (IsMultiJoined())
						{
							Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].current_game.MakeMove(param1, player);
						}
						foreach (string item in list)
						{
							interpreter2.AddOutput((TerminalLineType)0, item, 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
							if (IsMultiJoined())
							{
								Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)0, item, 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
							}
						}
						if (current_game.CheckForWin())
						{
							interpreter2.AddOutput((TerminalLineType)0, $"<color=green>Hurray! The {Game.GetPlayerColor(player)}player {player}</color> <color=green>won! </color></color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
							if (IsMultiJoined())
							{
								Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)0, $"<color=green>Hurray! The {Game.GetPlayerColor(player)}player {player}</color> <color=green>won! </color></color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
								StopMultiGame();
							}
							player = 1;
							current_game.StopGame();
						}
						else if (current_game.CheckForDraw())
						{
							interpreter2.AddOutput((TerminalLineType)0, "<color=orange>No one won... Game's over.</color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
							if (IsMultiJoined())
							{
								Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)0, "<color=orange>No one won... Game's over.</color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
								StopMultiGame();
							}
							player = 1;
							current_game.StopGame();
						}
						else
						{
							if (current_game.GetGameMode() == Game.GameMode.Local)
							{
								SetEndOfQueue(delegate
								{
									interpreter2.AddOutput((TerminalLineType)5, Game.GetPlayerColor(player) + "Player " + player + "</color>'s turn.", 1.2f, (TerminalSoundType)0, (TerminalSoundType)0);
								});
							}
							else if (IsMultiJoined())
							{
								SetEndOfQueue(delegate
								{
									interpreter2.AddOutput((TerminalLineType)5, Game.GetPlayerColor(current_game.GetCurrentPlayer()) + "Other player</color>'s turn.", 1.2f, (TerminalSoundType)0, (TerminalSoundType)0);
								});
								Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].SetEndOfQueue(delegate
								{
									Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)5, Game.GetPlayerColor(current_game.GetCurrentPlayer()) + "Your turn</color>.", 1.2f, (TerminalSoundType)0, (TerminalSoundType)0);
								});
							}
							if (current_game.GetGameMode() == Game.GameMode.Solo)
							{
								Random random = new Random();
								interpreter2.AddOutput((TerminalLineType)4, Game.GetPlayerColor((player != 1) ? 1 : 2) + "AI</color> is thinking..", (float)(0.4 + random.NextDouble()), (TerminalSoundType)0, (TerminalSoundType)0);
								string text = current_game.MakeAIMove().ToUpper();
								interpreter2.AddOutput((TerminalLineType)0, Game.GetPlayerColor((player != 1) ? 1 : 2) + "AI placed on</color> <color=orange>" + text + "</color>", 0.1f, (TerminalSoundType)0, (TerminalSoundType)0);
								foreach (string item2 in current_game.DisplayBoard())
								{
									interpreter2.AddOutput((TerminalLineType)0, item2, 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
								}
								interpreter2.AddOutput((TerminalLineType)0, Game.GetPlayerColor(player) + "Your turn.</color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
								if (current_game.CheckForWin())
								{
									interpreter2.AddOutput((TerminalLineType)0, "<color=red>The AI won.</color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
									player = 1;
									current_game.StopGame();
								}
								else if (current_game.CheckForDraw())
								{
									interpreter2.AddOutput((TerminalLineType)0, "<color=orange>No one won... Game's over.</color>", 0.7f, (TerminalSoundType)0, (TerminalSoundType)0);
									player = 1;
									current_game.StopGame();
								}
							}
							if (current_game.GetGameMode() == Game.GameMode.Local)
							{
								if (player == 1)
								{
									player = 2;
								}
								else
								{
									player = 1;
								}
							}
						}
					}
				}
			});
		}

		public void AddStopCommand(string cmd, string helpText, Action<LG_ComputerTerminalCommandInterpreter>? onCommandUsed = null)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Action<LG_ComputerTerminalCommandInterpreter> onCommandUsed2 = onCommandUsed;
			string cmd2 = cmd;
			CommandDescriptor commandDescriptor = default(CommandDescriptor);
			commandDescriptor.Type = (TERM_Command)253;
			commandDescriptor.Command = cmd2;
			commandDescriptor.Description = helpText;
			commandDescriptor.Rule = (TERM_CommandRule)0;
			CommandDescriptor descriptor = commandDescriptor;
			AddCommand(descriptor, delegate(LG_ComputerTerminalCommandInterpreter interpreter, string param1, string param2)
			{
				onCommandUsed2?.Invoke(interpreter);
				interpreter.AddOutput((TerminalLineType)0, "Desired Action: <color=orange>" + cmd2 + "</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				if (current_game.IsGameActive())
				{
					if (IsMultiJoined())
					{
						Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)4, "Stopping game from remote terminal..", 0.85f, (TerminalSoundType)0, (TerminalSoundType)0);
						Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].CmdProcessor.AddOutput((TerminalLineType)0, "<color=orange>The game has been stopped.</color>", 0.65f, (TerminalSoundType)0, (TerminalSoundType)0);
						StopMultiGame();
					}
					interpreter.AddOutput((TerminalLineType)4, "Stopping game..", 0.85f, (TerminalSoundType)0, (TerminalSoundType)0);
					interpreter.AddOutput((TerminalLineType)0, "<color=orange>The game has been stopped.</color>", 0.65f, (TerminalSoundType)0, (TerminalSoundType)0);
					player = 1;
					current_game.StopGame();
				}
				else
				{
					interpreter.AddOutput((TerminalLineType)0, "<color=red>There is no game currently played.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
			});
		}

		public void AddJoinCommand(string cmd, string helpText, Action<LG_ComputerTerminalCommandInterpreter>? onCommandUsed = null)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Action<LG_ComputerTerminalCommandInterpreter> onCommandUsed2 = onCommandUsed;
			string cmd2 = cmd;
			CommandDescriptor commandDescriptor = default(CommandDescriptor);
			commandDescriptor.Type = (TERM_Command)252;
			commandDescriptor.Command = cmd2;
			commandDescriptor.Description = helpText;
			commandDescriptor.Rule = (TERM_CommandRule)0;
			CommandDescriptor descriptor = commandDescriptor;
			AddCommand(descriptor, delegate(LG_ComputerTerminalCommandInterpreter interpreter, string param1, string param2)
			{
				LG_ComputerTerminalCommandInterpreter interpreter2 = interpreter;
				onCommandUsed2?.Invoke(interpreter2);
				interpreter2.AddOutput((TerminalLineType)0, "Desired Action: <color=orange>" + cmd2 + "</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				if (current_game.IsGameActive())
				{
					interpreter2.AddOutput((TerminalLineType)0, "<color=red>There is already a game currently being played.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
				else
				{
					interpreter2.AddOutput((TerminalLineType)4, "Finding game..", 0.85f, (TerminalSoundType)0, (TerminalSoundType)0);
					if (param1 != null)
					{
						param1 = param1.ToLower();
					}
					if (param1 != null && param1.Length > 0 && param1.Contains("terminal_"))
					{
						param1 = param1.Split("terminal_")[1];
						if (param1 == ComputerTerminal.m_serialNumber.ToString())
						{
							interpreter2.AddOutput((TerminalLineType)0, "<color=red>You cannot play as the other player on the same terminal.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
						}
						else
						{
							OtherTerminalListIndex = -1;
							for (int i = 0; i < Patch.MonoPatch.enriched_terminals.Count; i++)
							{
								EnrichedTerminal enrichedTerminal = Patch.MonoPatch.enriched_terminals[i];
								if (i != TerminalListIndex && enrichedTerminal.ComputerTerminal.m_serialNumber.ToString() == param1)
								{
									if (enrichedTerminal.OtherTerminalListIndex != -1)
									{
										interpreter2.AddOutput((TerminalLineType)0, "<color=red>A player has already joined the game on this terminal.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
									}
									else
									{
										if (enrichedTerminal.current_game.IsGameActive() && enrichedTerminal.current_game.GetGameMode() == Game.GameMode.Multi)
										{
											current_game = enrichedTerminal.current_game.Copy();
											if (enrichedTerminal.player == 1)
											{
												player = 2;
											}
											else
											{
												player = 2;
											}
											OtherTerminalListIndex = i;
											enrichedTerminal.OtherTerminalListIndex = TerminalListIndex;
											enrichedTerminal.CmdProcessor.AddOutput((TerminalLineType)0, $"<color=orange>A player has joined you from </color><color=green>Terminal_{ComputerTerminal.m_serialNumber}</color><color=orange>!</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
											enrichedTerminal.CmdProcessor.AddOutput((TerminalLineType)5, Game.GetPlayerColor(current_game.GetCurrentPlayer()) + "Your turn</color>.", 1.2f, (TerminalSoundType)0, (TerminalSoundType)0);
											break;
										}
										interpreter2.AddOutput((TerminalLineType)0, "<color=red>No multiplayer game found on that terminal.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
									}
									return;
								}
							}
							if (OtherTerminalListIndex == -1)
							{
								interpreter2.AddOutput((TerminalLineType)0, "<color=red>No other terminal found with that ID.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
							}
							else
							{
								interpreter2.AddOutput((TerminalLineType)4, "Fetching board..", 0.85f, (TerminalSoundType)0, (TerminalSoundType)0);
								foreach (string item in current_game.DisplayBoard())
								{
									interpreter2.AddOutput((TerminalLineType)0, item, 0.02f, (TerminalSoundType)0, (TerminalSoundType)0);
								}
								SetEndOfQueue(delegate
								{
									interpreter2.AddOutput((TerminalLineType)5, Game.GetPlayerColor(current_game.GetCurrentPlayer()) + "Other player</color>'s turn.", 1.2f, (TerminalSoundType)0, (TerminalSoundType)0);
								});
							}
						}
					}
					else
					{
						interpreter2.AddOutput((TerminalLineType)0, "<color=red>Wrong syntax for JOIN command.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					}
				}
			});
		}

		public void Setup()
		{
			Inject_Terminal_ReceiveCmd.OnCmdUsed_LevelInstanced += OnReceiveCommand;
			AddPlayCommand("play", "{<color=orange>TICTACTOE</color>, <color=orange>CONNECT4</color>, <color=orange>OTHELLO</color>}</color> {<color=green>SOLO</color>, <color=green>MULTI</color>, <color=green>LOCAL</color>}");
			AddPlaceCommand("place", "Once a game is started, place on given <color=orange>{coordinates}</color>. <color=blue> Ex: PLACE A2</color>");
			AddStopCommand("stop", "Once a game is started, <color=red>stops</color> the current game");
			AddJoinCommand("join", "Joins the game from its {<color=orange>Terminal ID</color>}. <color=blue> Ex: JOIN Terminal_284</color>");
		}

		private void OnReceiveCommand(LG_ComputerTerminalCommandInterpreter interpreter, TERM_Command cmd, string inputLine, string param1, string param2)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (interpreter.m_terminal.m_syncID == ComputerTerminal.m_syncID)
			{
				this.OnCmdUsed?.Invoke(cmd, inputLine, param1, param2);
			}
		}

		public void SetEndOfQueue(Action onEndOfQueue)
		{
			CmdProcessor.OnEndOfQueue = Action.op_Implicit(onEndOfQueue);
		}

		public bool IsMultiJoined()
		{
			if (OtherTerminalListIndex != -1)
			{
				return current_game.GetGameMode() == Game.GameMode.Multi;
			}
			return false;
		}

		public void StopMultiGame()
		{
			Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].current_game.StopGame();
			Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].OtherTerminalListIndex = -1;
			Patch.MonoPatch.enriched_terminals[OtherTerminalListIndex].player = 1;
			OtherTerminalListIndex = -1;
		}

		public void SetTerminalListIndex(int index)
		{
			TerminalListIndex = index;
		}
	}
	[GeneratedCode("VersionInfoGenerator", "2.0.0+git50a4b1a-master")]
	[CompilerGenerated]
	internal static class VersionInfo
	{
		public const string RootNamespace = "TerminalGames";

		public const string Version = "1.0.0";

		public const string VersionPrerelease = null;

		public const string VersionMetadata = null;

		public const string SemVer = "1.0.0";

		public const string GitRevShort = null;

		public const string GitRevLong = null;

		public const string GitBranch = null;

		public const string GitTag = null;

		public const bool GitIsDirty = false;
	}
}