Decompiled source of OpenLib v0.4.0

OpenLib.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using InteractiveTerminalAPI.UI;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using LobbyCompatibility.Enums;
using LobbyCompatibility.Features;
using Microsoft.CodeAnalysis;
using ModelReplacement;
using OpenBodyCams;
using OpenBodyCams.API;
using OpenLib.Common;
using OpenLib.Compat;
using OpenLib.ConfigManager;
using OpenLib.CoreMethods;
using OpenLib.Events;
using OpenLib.InteractiveMenus;
using OpenLib.Menus;
using TMPro;
using TerminalStuff;
using TerminalStuff.EventSub;
using TerminalStuff.SpecialStuff;
using TwoRadarMaps;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("darmuhsTerminalStuff")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("darmuh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.0")]
[assembly: AssemblyInformationalVersion("0.4.0+5f6d109a8b261753d1ec15b919a3c4d338c163af")]
[assembly: AssemblyProduct("OpenLib")]
[assembly: AssemblyTitle("OpenLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace OpenLib
{
	public class Loggers
	{
		public enum LoggingLevel
		{
			WarningsPlus = 4,
			Message = 8,
			Info = 0x10,
			Debug = 0x20
		}

		private static void Log(LogLevel bepLevel, object data)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected I4, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			int value = (int)ConfigSetup.LogLevel.Value;
			int num = (int)bepLevel;
			if (num <= value)
			{
				Plugin.Log.Log(bepLevel, data);
			}
		}

		internal static void LogDebug(object data)
		{
			Log((LogLevel)32, data);
		}

		internal static void LogInfo(object data)
		{
			Log((LogLevel)16, data);
		}

		internal static void LogMessage(object data)
		{
			Log((LogLevel)8, data);
		}

		internal static void WARNING(object data)
		{
			Log((LogLevel)4, data);
		}

		internal static void ERROR(object data)
		{
			Log((LogLevel)2, data);
		}

		internal static void FATAL(object data)
		{
			Log((LogLevel)1, data);
		}
	}
	public class PageBuilder
	{
		public StringBuilder? Content { get; set; }

		public int PageNumber { get; set; }
	}
	public class PageSplitter
	{
		public static List<PageBuilder> SplitTextIntoPages(string inputText, int maxLinesPerPage, string nextPageBlurb)
		{
			string[] array = inputText.Split(new string[1] { Environment.NewLine }, StringSplitOptions.None);
			List<PageBuilder> list = new List<PageBuilder>();
			int i = 0;
			int num = 1;
			while (i < array.Length)
			{
				PageBuilder pageBuilder = new PageBuilder
				{
					Content = new StringBuilder(),
					PageNumber = num
				};
				for (; i < array.Length && string.IsNullOrWhiteSpace(array[i]); i++)
				{
				}
				for (int j = 0; j < maxLinesPerPage; j++)
				{
					if (i >= array.Length)
					{
						break;
					}
					pageBuilder.Content.AppendLine(array[i]);
					i++;
				}
				if (i < array.Length - 2)
				{
					pageBuilder.Content.AppendLine(nextPageBlurb ?? "");
				}
				else
				{
					pageBuilder.Content.AppendLine("\r\n");
				}
				list.Add(pageBuilder);
				num++;
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "Start")]
	public class GameStartPatch
	{
		public static void Postfix()
		{
			EventManager.GameNetworkManagerStart.Invoke();
			NetworkClassBase.RegisterNetworkPrefabs();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	public class StartRoundAwake
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundAwake.Invoke();
			NetworkClassBase.SpawnNetworkPrefab();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	public class StartRoundPatch
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundStart.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "StartGame")]
	public class LandingPatch
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundStartGame.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
	public class ShipResetPatch
	{
		public static void Postfix()
		{
			EventManager.ShipReset.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "PassTimeToNextDay")]
	public class NextDayPatch
	{
		public static void Postfix()
		{
			EventManager.NextDayEvent.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
	public class OnShipLandedMiscPatch
	{
		public static void Postfix()
		{
			EventManager.OnShipLandedMiscPatch.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")]
	public class ShipLeftPatch
	{
		public static void Postfix()
		{
			EventManager.ShipLeft.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
	public class OnClientConnectPatch
	{
		public static void Postfix()
		{
			EventManager.OnClientConnect.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ChangeLevel")]
	public class RouteEvent
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundChangeLevel.Invoke();
		}
	}
	[HarmonyPatch(typeof(RoundManager), "SetBigDoorCodes")]
	public class SetBigDoorCodes
	{
		public static void Postfix()
		{
			EventManager.SetBigDoorCodes.Invoke();
		}
	}
	[HarmonyPatch(typeof(RoundManager), "SpawnMapObjects")]
	public class SpawnMapObjects
	{
		public static void Postfix()
		{
			EventManager.SpawnMapObjects.Invoke();
		}
	}
	[HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")]
	public class NewQuotaPatch
	{
		public static void Postfix()
		{
			EventManager.NewQuota.Invoke();
		}
	}
	[HarmonyPatch(typeof(AutoParentToShip), "Awake")]
	public class AutoParentGameObjectPatch
	{
		public static void Postfix(AutoParentToShip __instance)
		{
			if (!((Object)(object)((Component)__instance).gameObject == (Object)null))
			{
				EventManager.AutoParentEvent.Invoke(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(NetworkObject), "Spawn")]
	public class ObjectSpawnPatch
	{
		public static void Postfix(NetworkObject __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).gameObject == (Object)null))
			{
				EventManager.NetworkObjectSpawn.Invoke(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "StartPerformingEmoteServerRpc")]
	public class EmotePatch
	{
		public static void Postfix()
		{
			EventManager.PlayerEmote.Invoke();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	public class PlayerUpdatePatch
	{
		public static bool usePatch;

		public static bool inShip;

		public static bool spectate_inShip;

		public static bool isDead;

		public static void Postfix(PlayerControllerB __instance)
		{
			if (usePatch && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)StartOfRound.Instance.localPlayerController == (Object)null) && !((Object)(object)StartOfRound.Instance.localPlayerController != (Object)(object)__instance))
			{
				if (__instance.isInHangarShipRoom != inShip)
				{
					inShip = __instance.isInHangarShipRoom;
					EventManager.PlayerIsInShip.Invoke();
				}
				if (__instance.isPlayerDead != isDead)
				{
					isDead = __instance.isPlayerDead;
					EventManager.PlayerIsDead.Invoke();
				}
				if (__instance.isPlayerDead && (Object)(object)__instance.spectatedPlayerScript != (Object)null && __instance.spectatedPlayerScript.isInHangarShipRoom != spectate_inShip)
				{
					spectate_inShip = __instance.spectatedPlayerScript.isInHangarShipRoom;
					EventManager.SpecatingPlayerIsInShip.Invoke();
				}
			}
		}
	}
	public class SpectateNextPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "SpectateNextPlayer")]
		public class PlayerSpawnPatch : MonoBehaviour
		{
			private static void Postfix()
			{
				EventManager.SpecateNextPlayer.Invoke();
			}
		}
	}
	public class SpawnPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "SpawnPlayerAnimation")]
		public class PlayerSpawnPatch
		{
			private static void Postfix()
			{
				EventManager.PlayerSpawn.Invoke();
			}
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter), "Awake")]
	public class TeleporterInit
	{
		private static void Postfix(ShipTeleporter __instance)
		{
			EventManager.TeleporterAwake.Invoke(__instance);
		}
	}
	[HarmonyPatch(typeof(Terminal), "Awake")]
	public class AwakeTermPatch
	{
		private static void Postfix(Terminal __instance)
		{
			EventManager.TerminalAwake.Invoke(__instance);
		}
	}
	[HarmonyPatch(typeof(Terminal), "Start")]
	public class TerminalStartPatch
	{
		private static void Postfix()
		{
			EventManager.TerminalStart.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "OnDisable")]
	public class DisableTermPatch
	{
		private static void Postfix()
		{
			EventManager.TerminalDisable.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "QuitTerminal")]
	public class QuitTerminalPatch
	{
		private static void Postfix()
		{
			EventManager.TerminalQuit.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "LoadNewNode")]
	public class LoadNewNodePatch
	{
		private static void Postfix(TerminalNode node)
		{
			EventManager.TerminalLoadNewNode.Invoke(node);
		}
	}
	[HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")]
	public class AffordableNodePatch
	{
		private static void Postfix(TerminalNode node)
		{
			EventManager.TerminalLoadIfAffordable.Invoke(node);
		}
	}
	[HarmonyPatch(typeof(Terminal), "BeginUsingTerminal")]
	public class Terminal_Begin_Patch
	{
		private static void Postfix()
		{
			EventManager.TerminalBeginUsing.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	public class Terminal_ParsePlayerSentence_Patch
	{
		private static void Postfix(ref TerminalNode __result)
		{
			if (!((Object)(object)__result == (Object)null))
			{
				TerminalNode val = EventManager.TerminalParseSent.NodeInvoke(ref __result);
				__result = val;
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "Update")]
	public class TerminalUpdatePatch
	{
		public static bool inUse;

		public static bool usePatch;

		public static int menuIndex;

		private static void Postfix(Terminal __instance)
		{
			if (usePatch && __instance.placeableObject.inUse != inUse)
			{
				inUse = __instance.placeableObject.inUse;
				EventManager.SetTerminalInUse.Invoke();
			}
		}

		[HarmonyPrefix]
		private static bool Prefix(Terminal __instance)
		{
			if (!usePatch || !__instance.terminalInUse)
			{
				return true;
			}
			if (MenusContainer.AnyOpenLibMenuActive())
			{
				__instance.scrollBarCanvasGroup.alpha = 0f;
				((TMP_Text)__instance.topRightText).text = $"${__instance.groupCredits}";
				if (__instance.placeableObject.inUse != inUse)
				{
					inUse = __instance.placeableObject.inUse;
					EventManager.SetTerminalInUse.Invoke();
				}
				if (((ButtonControl)Keyboard.current.anyKey).wasPressedThisFrame)
				{
					EventManager.TerminalMenuKeyPressed.Invoke();
				}
				return false;
			}
			if (((ButtonControl)Keyboard.current.anyKey).wasPressedThisFrame)
			{
				EventManager.TerminalKeyPressed.Invoke();
			}
			return true;
		}
	}
	[BepInPlugin("darmuh.OpenLib", "OpenLib", "0.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static Plugin instance = null;

		internal static ManualLogSource Log = null;

		public bool TerminalStuff;

		public bool LobbyCompat;

		public bool TerminalFormatter;

		public bool ITAPI;

		public bool LethalConfig;

		public bool OpenBodyCamsMod;

		public bool TwoRadarMapsMod;

		public bool ModelReplacement;

		public bool TooManyEmotes;

		public bool MirrorDecor;

		public static List<CommandManager> AllCommands = new List<CommandManager>();

		public static List<TerminalKeyword> KeywordsAdded = new List<TerminalKeyword>();

		public static List<TerminalNode> NodesAdded = new List<TerminalNode>();

		public static List<CompatibleNoun> NounsAdded = new List<CompatibleNoun>();

		public static List<TerminalAccessibleObject> AllTerminalCodes = new List<TerminalAccessibleObject>();

		public Terminal Terminal;

		public static List<TerminalNode> ShopNodes = new List<TerminalNode>();

		public const string Id = "darmuh.OpenLib";

		public static string Name => "OpenLib";

		public static string Version => "0.4.0";

		public static List<CommandManager> GetActiveCommands()
		{
			if (AllCommands.Count == 0)
			{
				return new List<CommandManager>();
			}
			return AllCommands.FindAll((CommandManager x) => x.IsCreated);
		}

		private void Awake()
		{
			instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"OpenLib is loading with version 0.4.0!\nThis mod has been compiled for v73 of Lethal Company and may not work with earlier versions");
			ConfigSetup.defaultManaged = new List<ManagedConfig>();
			CommandRegistry.InitListing(ref ConfigSetup.defaultListing);
			ConfigSetup.BindConfigSettings();
			((BaseUnityPlugin)this).Config.ConfigReloaded += OnConfigReloaded;
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			EventUsage.Subscribers();
			AllInteractiveMenus.AllMenus = new List<InteractiveMenu>();
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "openlib.bundle");
			if (File.Exists(text))
			{
				AssetBundle val = AssetBundle.LoadFromFile(text);
				NetworkClassBase.Prefab = val.LoadAsset<GameObject>("Openlib Networker");
			}
			else
			{
				Log.LogError((object)("Openlib Networker asset cannot be found! Expected path: " + text));
			}
			Log.LogInfo((object)"OpenLib load complete!");
		}

		internal void OnConfigReloaded(object sender, EventArgs e)
		{
			Log.LogInfo((object)"Config has been reloaded!");
			ConfigSetup.ReadConfigAndAssignValues(((BaseUnityPlugin)instance).Config, ConfigSetup.defaultManaged);
		}
	}
	public class NodeInfo
	{
		[CompilerGenerated]
		private CommandManager <command>P;

		public string Name;

		public string InfoText;

		public Func<string> InfoAction;

		public TerminalNode terminalNode;

		public NodeInfo(CommandManager command)
		{
			<command>P = command;
			Name = <command>P.Name;
			InfoText = string.Empty;
			base..ctor();
		}

		public void GetDefaultInfo(CommandManager command)
		{
			string text = "[ " + CommonStringStuff.GetKeywordsForMenuItem(command.KeywordList) + " ]\r\n";
			text = ((command.IsEnabled == null) ? (text + "No further information on this command!\r\n\r\n") : (text + ((ConfigEntryBase)command.IsEnabled.ConfigItem).Description.Description + "\r\n\r\n"));
			InfoText = text;
		}

		public void CreateInfoNode()
		{
			if (!((Object)(object)CommonTerminal.InfoKeyword == (Object)null))
			{
				TerminalKeyword info = CommonTerminal.InfoKeyword;
				terminalNode = BasicTerminal.CreateNewTerminalNode();
				((Object)terminalNode).name = "info_" + Name;
				terminalNode.displayText = InfoText;
				terminalNode.clearPreviousText = true;
				CollectionExtensions.Do<string>((IEnumerable<string>)<command>P.KeywordList, (Action<string>)delegate(string Keyword)
				{
					AddingThings.AddCompatibleNoun(ref info, Keyword, terminalNode);
				});
				Loggers.LogDebug("info node created and assigned to command!");
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "OpenLib";

		public const string PLUGIN_NAME = "OpenLib";

		public const string PLUGIN_VERSION = "0.4.0";
	}
}
namespace OpenLib.Menus
{
	public class CommandsMenu
	{
		internal static CommandsMenuBase CommandMenu = null;

		internal static CommandMenuItem<CommandsMenuBase> MainMenuItem = null;

		internal static List<CommandMenuItem<CommandsMenuBase>> AllCommandMenuItems = new List<CommandMenuItem<CommandsMenuBase>>();

		internal static void Init()
		{
			CommandMenu = new CommandsMenuBase("Commands Menu")
			{
				MainMenu = MainMenuItem,
				PageSize = 10,
				AdjustScrollInMenu = false
			};
			MainMenuItem = CreateMainMenu(CommandMenu, "My Commands Menu", () => "=== My Commands Main Menu  ===\n\n", () => "Created by darmuh");
		}

		internal static void RuntimeSetup()
		{
			List<CommandManager> activeCommands = Plugin.GetActiveCommands();
			UpdateMenuListing(CommandMenu, MainMenuItem, activeCommands);
			CreateAndSetControlsFooter(CommandMenu, AllCommandMenuItems);
		}

		public static void UpdateMenuListing(CommandsMenuBase menuBase, CommandMenuItem<CommandsMenuBase> mainMenuItem, List<CommandManager> CommandList, string defaultCategory = "Other")
		{
			if (mainMenuItem.NestedMenus.Count == 0)
			{
				MakeCommandMenuItems(menuBase, CommandList, defaultCategory, mainMenuItem);
				return;
			}
			List<CommandMenuItem<CommandsMenuBase>> list = mainMenuItem.NestedMenus.ConvertAll((MenuItem x) => x as CommandMenuItem<CommandsMenuBase>);
			foreach (CommandMenuItem<CommandsMenuBase> item in list)
			{
				item.isEnabled = CommandList.Contains(item.Command);
				CommandList.Remove(item.Command);
				UpdateMenuVisibility(item);
			}
			if (CommandList.Count > 0)
			{
				MakeCommandMenuItems(menuBase, CommandList, defaultCategory, mainMenuItem);
			}
		}

		private static void UpdateMenuVisibility(CommandMenuItem<CommandsMenuBase> item)
		{
			if (item.isEnabled)
			{
				if (item.Parent == null)
				{
					if (item.CachedParent == null)
					{
						Loggers.WARNING("Unable to update " + item.Name + "'s parent. CachedParent is null!");
					}
					else
					{
						item.SetParentMenu(item.CachedParent);
					}
				}
			}
			else if (item.Parent != null)
			{
				item.CachedParent = item.Parent;
				item.SetParentMenu(null);
			}
		}

		internal static string EnterCommandMenu()
		{
			if (MainMenuItem == null)
			{
				return "This menu has not been created correctly";
			}
			CommandMenu.EnterAtPage(MainMenuItem);
			return "";
		}

		public static CommandMenuItem<CommandsMenuBase> CreateMainMenu(CommandsMenuBase menuBase, string menuName, Func<string> header = null, Func<string> footer = null)
		{
			if (header == null)
			{
				header = () => string.Empty;
			}
			if (footer == null)
			{
				footer = () => string.Empty;
			}
			CommandMenuItem<CommandsMenuBase> commandMenuItem = new CommandMenuItem<CommandsMenuBase>(menuBase, menuName)
			{
				Header = header,
				Footer = footer
			};
			AllCommandMenuItems.Add(commandMenuItem);
			return commandMenuItem;
		}

		public static List<CommandMenuItem<CommandsMenuBase>> MakeCommandMenuItems(CommandsMenuBase menuBase, List<CommandManager> commands, string DefaultCategory, CommandMenuItem<CommandsMenuBase> MainMenu)
		{
			CommandsMenuBase menuBase2 = menuBase;
			List<CommandMenuItem<CommandsMenuBase>> commandMenuItems = new List<CommandMenuItem<CommandsMenuBase>>();
			Dictionary<CommandManager, string> dictionary = new Dictionary<CommandManager, string>();
			if (commands.Count < 1)
			{
				return commandMenuItems;
			}
			foreach (CommandManager command in commands)
			{
				if (string.IsNullOrEmpty(command.Category))
				{
					dictionary.Add(command, DefaultCategory);
				}
				else
				{
					dictionary.Add(command, command.Category);
				}
			}
			foreach (KeyValuePair<CommandManager, string> category in dictionary)
			{
				MenuItem menuItem = MainMenu.NestedMenus.FirstOrDefault((MenuItem c) => Misc.CompareStringsInvariant(c.Name, category.Value));
				CommandMenuItem<CommandsMenuBase> cat = menuItem as CommandMenuItem<CommandsMenuBase>;
				if (cat == null)
				{
					cat = new CommandMenuItem<CommandsMenuBase>(menuBase2, category.Value.ToUpperInvariant());
					commandMenuItems.Add(cat);
					cat.SetParentMenu(MainMenu);
					cat.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.CategoryHeader, cat.Name);
				}
				CreateCommandMenuItems(menuBase2, cat, category.Key, ref commandMenuItems);
			}
			foreach (CommandMenuItem<CommandsMenuBase> item in commandMenuItems)
			{
				if (item.Command == null && item.Parent == null)
				{
					item.SetParentMenu(MainMenu);
				}
			}
			AllCommandMenuItems.AddRange(commandMenuItems);
			return commandMenuItems;
		}

		public static void CreateAndSetControlsFooter(CommandsMenuBase menuBase, List<CommandMenuItem<CommandsMenuBase>> MenuItems)
		{
			SetMenuItemsFooter(MenuItems, menuBase.Controls);
		}

		public static void SetMenuItemsFooter(List<CommandMenuItem<CommandsMenuBase>> MenuItems, Func<string> footer)
		{
			foreach (CommandMenuItem<CommandsMenuBase> MenuItem in MenuItems)
			{
				MenuItem.Footer = footer;
			}
		}

		public static void CreateCommandMenuItems(CommandsMenuBase menuBase, CommandMenuItem<CommandsMenuBase> parent, CommandManager command, ref List<CommandMenuItem<CommandsMenuBase>> commandMenuItems)
		{
			CommandsMenuBase menuBase2 = menuBase;
			CommandMenuItem<CommandsMenuBase> parent2 = parent;
			CommandManager command2 = command;
			CommandMenuItem<CommandsMenuBase> CommandName = TryCreate(menuBase2, command2);
			commandMenuItems.Add(CommandName);
			CommandName.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.CommandHeader, parent2.Name, CommandName.Name);
			CommandName.SetParentMenu(parent2);
			if (menuBase2.AddKeywordsMenu)
			{
				if (!TryGetChild(CommandName, command2.Name + " Keywords", out CommandMenuItem<CommandsMenuBase> item))
				{
					item = new CommandMenuItem<CommandsMenuBase>(menuBase2, command2.Name + " Keywords");
					commandMenuItems.Add(item);
					item.SetParentMenu(CommandName);
				}
				item.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.KeywordsHeader, parent2.Name, CommandName.Name);
				foreach (string keyword in command2.KeywordList)
				{
					if (!TryGetChild(item, keyword, out CommandMenuItem<CommandsMenuBase> item2))
					{
						item2 = new CommandMenuItem<CommandsMenuBase>(menuBase2, keyword);
						commandMenuItems.Add(item2);
						item2.SetParentMenu(item);
						item2.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.KeywordsHeader, parent2.Name, CommandName.Name);
					}
				}
			}
			if (command2.IsEnabled != null && menuBase2.AddInfoMenu)
			{
				if (!TryGetChild(CommandName, command2.Name + " Information", out CommandMenuItem<CommandsMenuBase> item3))
				{
					item3 = new CommandMenuItem<CommandsMenuBase>(menuBase2, command2.Name + " Information");
					commandMenuItems.Add(item3);
					item3.SetParentMenu(CommandName);
				}
				item3.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.InfoHeader, parent2.Name, CommandName.Name);
				if (!TryGetChild(item3, ((ConfigEntryBase)command2.IsEnabled.ConfigItem).Description.Description, out CommandMenuItem<CommandsMenuBase> item4))
				{
					item4 = new CommandMenuItem<CommandsMenuBase>(menuBase2, ((ConfigEntryBase)command2.IsEnabled.ConfigItem).Description.Description);
					commandMenuItems.Add(item4);
					item4.SetParentMenu(item3);
				}
				item4.Header = () => CommandsMenuBase.ConvertHeader(menuBase2.InfoHeader, parent2.Name, CommandName.Name);
			}
			if ((!command2.AcceptAdditionalText || !menuBase2.AddRunCommand) && !TryGetChild(CommandName, "Run " + command2.Name, out CommandMenuItem<CommandsMenuBase> item5))
			{
				item5 = new CommandMenuItem<CommandsMenuBase>(menuBase2, "Run " + command2.Name)
				{
					LoadPageOnSelect = false
				};
				commandMenuItems.Add(item5);
				item5.SetParentMenu(CommandName);
				OpenLib.Events.Events.CustomEvent customEvent = new OpenLib.Events.Events.CustomEvent();
				customEvent.AddListener(delegate
				{
					menuBase2.ExitPage = command2;
					menuBase2.ExitMenu(enableInput: true);
				});
				item5.SelectionEvent = customEvent;
			}
		}

		public static CommandMenuItem<CommandsMenuBase> TryCreate(CommandsMenuBase menuBase, CommandManager command)
		{
			CommandManager command2 = command;
			CommandMenuItem<CommandsMenuBase> commandMenuItem = AllCommandMenuItems.FirstOrDefault((CommandMenuItem<CommandsMenuBase> c) => c.Command == command2);
			if (commandMenuItem != null)
			{
				return commandMenuItem;
			}
			return new CommandMenuItem<CommandsMenuBase>(menuBase, command2.Name)
			{
				Command = command2
			};
		}

		public static bool TryGetChild(CommandMenuItem<CommandsMenuBase> Parent, string expectedName, out CommandMenuItem<CommandsMenuBase> item)
		{
			CommandMenuItem<CommandsMenuBase> Parent2 = Parent;
			string expectedName2 = expectedName;
			item = AllCommandMenuItems.FirstOrDefault((CommandMenuItem<CommandsMenuBase> c) => c.Parent == Parent2 && c.Name == expectedName2);
			return item != null;
		}

		public static bool TryGetCategoryMenuItem(string categoryName, out CommandMenuItem<CommandsMenuBase> match)
		{
			string categoryName2 = categoryName;
			List<CommandMenuItem<CommandsMenuBase>> source = AllCommandMenuItems.FindAll((CommandMenuItem<CommandsMenuBase> x) => x.Parent == MainMenuItem && x.Command == null);
			match = source.FirstOrDefault((CommandMenuItem<CommandsMenuBase> x) => x.Name == categoryName2);
			return match != null;
		}

		public static void SetCategoryHeader(string categoryName, Func<string> header)
		{
			if (TryGetCategoryMenuItem(categoryName, out CommandMenuItem<CommandsMenuBase> match))
			{
				match.Header = header;
			}
		}

		public static void SetCategoryFooter(string categoryName, Func<string> footer)
		{
			if (TryGetCategoryMenuItem(categoryName, out CommandMenuItem<CommandsMenuBase> match))
			{
				match.Footer = footer;
			}
		}
	}
	public class CommandsMenuBase : BetterMenu<CommandsMenuBase>
	{
		public bool AddKeywordsMenu = true;

		public bool AddInfoMenu = true;

		public bool AddRunCommand = true;

		public string CommandHeader = "======== {commandName} ========\n\n";

		public string KeywordsHeader = "======== {commandName} Keywords ========\n\n";

		public string CategoryHeader = "======== {catName>>} COMMANDS ========\n\n";

		public string InfoHeader = "====== {commandName} Information ======\n\n";

		public const string CategoryName = "catName";

		public const string CommandName = "commandName";

		public const string ToUpper = ">>";

		public const string ToLower = "<<";

		public static readonly List<string> AcceptableVariables = new List<string>(4) { "catName", "commandName", ">>", "<<" };

		public CommandManager ExitPage;

		public CommandsMenuBase(string name, Dictionary<Key, Action> MoreMenuActions = null)
			: base(name, MoreMenuActions)
		{
			ExitAction = CustomExitAction;
			OnEnter.AddListener(delegate
			{
				ExitPage = null;
			});
		}

		public void CustomExitAction()
		{
			if (ExitPage != null)
			{
				if (LogicHandling.GetDisplayTextFromCommand(ref ExitPage.terminalNode))
				{
					CommonTerminal.LoadNewNode(ExitPage.terminalNode);
				}
				else
				{
					CommonTerminal.LoadNewNode(CommonTerminal.HomePage);
				}
			}
			else
			{
				CommonTerminal.LoadNewNode(CommonTerminal.HomePage);
			}
		}

		public static string ConvertHeader(string query, string catName, string commandName = "")
		{
			if (string.IsNullOrEmpty(query))
			{
				return query;
			}
			List<string> substrings = Misc.GetSubstrings('{', '}', query);
			if (substrings.Count == 0)
			{
				return query;
			}
			foreach (string item in substrings)
			{
				string text = item.Replace("{", "").Replace("}", "");
				if (Misc.StringContainsInvariant(item, "catName"))
				{
					text = text.Replace("catName", catName);
				}
				if (Misc.StringContainsInvariant(item, "commandName"))
				{
					text = text.Replace("commandName", commandName);
				}
				if (Misc.StringContainsInvariant(item, ">>"))
				{
					text = text.Replace(">>", "").ToUpperInvariant();
				}
				if (Misc.StringContainsInvariant(item, "<<"))
				{
					text = text.Replace("<<", "").ToLowerInvariant();
				}
				query = query.Replace(item, text);
			}
			return query;
		}

		public string Controls()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append($"\r\n\r\nPage [{leftMenu}] < {CurrentPage}/{Mathf.CeilToInt((float)DisplayMenuItemsOfType.Count / (float)PageSize)} > [{rightMenu}]\r\n");
			stringBuilder.Append($"Back: [{leaveMenu}] Select: [{selectMenu}]\r\n");
			return stringBuilder.ToString();
		}
	}
	public class CommandMenuItem<TMenu> : MenuItem<TMenu> where TMenu : BetterMenuBase
	{
		private string _name;

		private bool _showEmpty;

		private OpenLib.Events.Events.CustomEvent _selection;

		private List<MenuItem> _nested;

		public bool isEnabled;

		public CommandManager Command;

		public MenuItem CachedParent;

		public TMenu MenuBase;

		public override string Name
		{
			get
			{
				return _name;
			}
			set
			{
				_name = value;
			}
		}

		public override bool ShowIfEmptyNest
		{
			get
			{
				return _showEmpty;
			}
			set
			{
				_showEmpty = value;
			}
		}

		public override OpenLib.Events.Events.CustomEvent SelectionEvent
		{
			get
			{
				return _selection;
			}
			set
			{
				_selection = value;
			}
		}

		public override List<MenuItem> NestedMenus
		{
			get
			{
				return _nested;
			}
			set
			{
				_nested = value;
			}
		}

		public CommandMenuItem(TMenu betterMenu, string name)
		{
			_name = name;
			_showEmpty = true;
			_selection = new OpenLib.Events.Events.CustomEvent();
			_nested = new List<MenuItem>();
			isEnabled = true;
			MenuBase = betterMenu;
			base..ctor(betterMenu);
		}
	}
	[Obsolete("Doing away with this style of Menu...")]
	public class MenuBuild
	{
		public static bool isNextEnabled = false;

		public static int nextCount = 1;

		public static string currentCategory = "";

		public static TerminalMenu currentMenu = null;

		public static List<TerminalMenu> allMenus = new List<TerminalMenu>();

		public static List<TerminalMenuCategory> InitCategories(Dictionary<string, string> CategoryItems)
		{
			Loggers.LogDebug("InitCategories START");
			List<TerminalMenuCategory> list = new List<TerminalMenuCategory>();
			if (CategoryItems.Count < 1)
			{
				return list;
			}
			foreach (KeyValuePair<string, string> CategoryItem in CategoryItems)
			{
				TerminalMenuCategory item = new TerminalMenuCategory
				{
					CatName = CategoryItem.Key,
					CatDescription = CategoryItem.Value
				};
				list.Add(item);
			}
			Loggers.LogDebug("InitCategories SUCCESS");
			return list;
		}

		public static bool ShouldAddCategoryNameToMainMenu(List<TerminalMenuItem> menuItems, string categoryName)
		{
			foreach (TerminalMenuItem menuItem in menuItems)
			{
				if (menuItem.Category == categoryName)
				{
					return true;
				}
			}
			return false;
		}

		public static List<TerminalMenuItem> TerminalMenuItems(List<ManagedConfig> managedBools)
		{
			List<TerminalMenuItem> list = new List<TerminalMenuItem>();
			managedBools.RemoveAll((ManagedConfig m) => m == null);
			foreach (ManagedConfig managedBool in managedBools)
			{
				if (managedBool.menuItem != null && managedBool.KeywordList != null && managedBool.KeywordList.Count > 0)
				{
					list.Add(managedBool.menuItem);
				}
			}
			Loggers.LogDebug("\n\n\n");
			Loggers.LogDebug($"myMenuItems count: {list.Count}");
			Loggers.LogDebug("\n\n\n");
			return list;
		}

		public static TerminalMenu AssembleMainMenu(string menuName, string keyword, string mainMenuText, List<TerminalMenuCategory> categoryList, List<TerminalMenuItem> menuItems, bool addToOther = false, string menuDescription = "")
		{
			TerminalMenu terminalMenu = new TerminalMenu
			{
				MenuName = menuName,
				setKeyword = keyword,
				Categories = categoryList,
				MainMenuText = mainMenuText,
				menuItems = menuItems,
				currentCategory = "",
				nextCount = 1,
				isNextEnabled = false
			};
			string displayText = AssembleMainMenuText(terminalMenu);
			if (addToOther)
			{
				AddingThings.AddBasicCommand(terminalMenu.MenuName + "_main", terminalMenu.setKeyword, displayText, isVerb: false, clearText: true, "other", menuDescription);
			}
			else
			{
				AddingThings.AddBasicCommand(terminalMenu.MenuName + "_main", terminalMenu.setKeyword, displayText, isVerb: false, clearText: true);
			}
			allMenus.Add(terminalMenu);
			return terminalMenu;
		}

		public static bool InMainMenu(TerminalNode terminalNode, TerminalMenu terminalMenu)
		{
			if (terminalMenu == null)
			{
				Loggers.ERROR("ERROR: OpenLib menu is NULL, most likely failed to create!");
				return false;
			}
			if (((Object)terminalNode).name.Contains(terminalMenu.MenuName))
			{
				terminalMenu.isActive = true;
				terminalMenu.nextCount = 1;
				terminalMenu.currentCategory = "";
				Loggers.LogDebug("In main menu of " + terminalMenu.MenuName);
				return true;
			}
			if (terminalMenu.isNextEnabled && terminalMenu.terminalNodes.Contains(terminalNode))
			{
				Loggers.LogDebug("Still in menus but not main, next is enabled");
				return false;
			}
			terminalMenu.isActive = false;
			return false;
		}

		public static string AssembleMainMenuText(TerminalMenu terminalMenu)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(terminalMenu.MainMenuText + "\r\n\r\n");
			if (terminalMenu.Categories.Count > 0)
			{
				foreach (TerminalMenuCategory category in terminalMenu.Categories)
				{
					stringBuilder.Append("[" + category.CatName.ToUpper() + "]\r\n" + category.CatDescription + "\r\n\r\n");
				}
			}
			return stringBuilder.ToString();
		}

		public static string AssembleMainMenuText(string MainMenuText, Dictionary<string, string> Categories)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(MainMenuText + "\r\n\r\n");
			if (Categories.Count > 0)
			{
				foreach (KeyValuePair<string, string> Category in Categories)
				{
					stringBuilder.Append("[" + Category.Key.ToUpper() + "]\r\n" + Category.Value + "\r\n\r\n");
				}
			}
			return stringBuilder.ToString();
		}

		public static void CreateCategoryCommands(TerminalMenu terminalMenu, MainListing yourModListing)
		{
			List<Dictionary<string, List<string>>> list = new List<Dictionary<string, List<string>>>();
			foreach (TerminalMenuCategory category in terminalMenu.Categories)
			{
				Loggers.LogDebug("checking category in terminalMenu.categories");
				Dictionary<string, List<string>> item = MakeCategoryList(category, terminalMenu.menuItems);
				if (!list.Contains(item))
				{
					list.Add(item);
				}
				TerminalNode item2 = AddingThings.CreateNode(terminalMenu, category.CatName ?? "", category.CatName.ToLower(), GetFirstInList, yourModListing);
				terminalMenu.terminalNodes.Add(item2);
			}
			terminalMenu.categoryLists = list;
			TerminalNode item3 = AddingThings.CreateNode(terminalMenu, "nextInMenu", "next", NextInList, yourModListing, isNextPageCommand: true);
			terminalMenu.terminalNodes.Add(item3);
		}

		public static void CreateCategoryFauxCommands(TerminalMenu terminalMenu, MainListing yourModListing)
		{
			CreateCategoryFauxCommands(terminalMenu, yourModListing, "more");
		}

		public static void CreateCategoryFauxCommands(TerminalMenu terminalMenu, MainListing yourModListing, string mainWord)
		{
			List<Dictionary<string, List<string>>> list = new List<Dictionary<string, List<string>>>();
			foreach (TerminalMenuCategory category in terminalMenu.Categories)
			{
				Loggers.LogDebug("checking category in terminalMenu.categories");
				Dictionary<string, List<string>> item = MakeCategoryList(category, terminalMenu.menuItems);
				if (!list.Contains(item))
				{
					list.Add(item);
				}
				FauxKeyword fauxWord = new FauxKeyword(mainWord, category.CatName, GetFirstInList)
				{
					AllowOtherFauxWords = true,
					requireExact = true
				};
				AddingThings.AddToFauxListing(fauxWord, yourModListing);
			}
			terminalMenu.categoryLists = list;
			FauxKeyword fauxWord2 = new FauxKeyword(mainWord, "next", NextInList)
			{
				AllowOtherFauxWords = true
			};
			AddingThings.AddToFauxListing(fauxWord2, yourModListing);
		}

		public static void UpdateCategories(TerminalMenu myMenu)
		{
			List<Dictionary<string, List<string>>> list = new List<Dictionary<string, List<string>>>();
			foreach (TerminalMenuCategory category in myMenu.Categories)
			{
				Loggers.LogDebug("checking category in myMenu.categories");
				Dictionary<string, List<string>> item = MakeCategoryList(category, myMenu.menuItems);
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			myMenu.categoryLists = list;
		}

		public static List<string> GetCategoryList(string catName, out TerminalMenu menuName)
		{
			Loggers.LogDebug("2.1");
			List<string> result = new List<string>();
			foreach (TerminalMenu allMenu in allMenus)
			{
				Loggers.LogDebug("2.2");
				if (!allMenu.isActive)
				{
					continue;
				}
				for (int i = 0; i < allMenu.Categories.Count; i++)
				{
					Loggers.LogDebug("2.3");
					foreach (KeyValuePair<string, List<string>> item in allMenu.categoryLists[i])
					{
						if (Misc.CompareStringsInvariant(item.Key, catName))
						{
							Loggers.LogDebug("categorylist found!!!");
							menuName = allMenu;
							return item.Value;
						}
					}
				}
			}
			Loggers.LogDebug("2.1 FAIL");
			menuName = null;
			return result;
		}

		public static Dictionary<string, List<string>> MakeCategoryList(TerminalMenuCategory category, List<TerminalMenuItem> terminalMenuItems)
		{
			Loggers.LogDebug("MakeCategoryList START");
			string catName = category.CatName;
			Loggers.LogDebug(catName);
			List<string> list = new List<string>();
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			Loggers.LogDebug($"count: {terminalMenuItems.Count}");
			foreach (TerminalMenuItem terminalMenuItem in terminalMenuItems)
			{
				Loggers.LogDebug("checking " + terminalMenuItem.ItemName);
				if (Misc.CompareStringsInvariant(terminalMenuItem.Category, catName))
				{
					list.Add("> " + CommonStringStuff.GetKeywordsForMenuItem(terminalMenuItem.itemKeywords) + "\r\n" + terminalMenuItem.itemDescription + "\r\n");
					Loggers.LogDebug(CommonStringStuff.GetKeywordsForMenuItem(terminalMenuItem.itemKeywords) + " added");
					Loggers.LogDebug(terminalMenuItem.itemDescription + " added too!");
				}
			}
			Loggers.LogDebug("setting catName list");
			dictionary.Add(catName, list);
			Loggers.LogDebug("MakeCategoryList END");
			return dictionary;
		}

		public static string NextInList()
		{
			if (!isNextEnabled)
			{
				return "Not currently in any menus...\r\n\r\n";
			}
			Loggers.LogDebug("currentCategory = " + currentCategory);
			nextCount++;
			GetCategoryFromString(currentCategory);
			TerminalMenu menuName;
			List<string> categoryList = GetCategoryList(currentCategory, out menuName);
			if (menuName == null)
			{
				return "ERROR: Unable to get current category!\r\n\r\n";
			}
			menuName.isActive = true;
			menuName.nextCount = nextCount;
			menuName.currentCategory = currentCategory;
			string nextPage = CommonStringStuff.GetNextPage(categoryList, currentCategory, 4, nextCount, out isNextEnabled);
			Loggers.LogDebug($"currentCategory:{currentCategory} nextCount: {nextCount} isNextEnabled: {isNextEnabled}");
			menuName.isNextEnabled = isNextEnabled;
			return nextPage;
		}

		public static string GetFirstInList()
		{
			Loggers.LogDebug("1");
			nextCount = 1;
			string text = Plugin.instance.Terminal.screenText.text;
			int textAdded = Plugin.instance.Terminal.textAdded;
			int length = text.Length;
			int num = length - textAdded;
			string input = text.Substring(num, length - num);
			currentCategory = GetCategoryFromString(input);
			Loggers.LogDebug("currentCategory detected as: [" + currentCategory + "]");
			Loggers.LogDebug("2");
			TerminalMenu menuName;
			List<string> categoryList = GetCategoryList(currentCategory, out menuName);
			menuName.isActive = true;
			menuName.nextCount = nextCount;
			menuName.currentCategory = currentCategory;
			Loggers.LogDebug("3");
			string nextPage = CommonStringStuff.GetNextPage(categoryList, currentCategory, 4, 1, out isNextEnabled);
			menuName.isNextEnabled = isNextEnabled;
			Loggers.LogDebug("4");
			return nextPage;
		}

		public static string GetCategoryFromString(string input)
		{
			string input2 = input;
			Loggers.LogDebug("Getting Category from string: [" + input2 + "]");
			foreach (TerminalMenu allMenu in allMenus)
			{
				if (allMenu.categoryLists.Any((Dictionary<string, List<string>> c) => c.Any((KeyValuePair<string, List<string>> d) => Misc.CompareStringsInvariant(d.Key, input2))))
				{
					Loggers.LogDebug("detected menu with categoryList containing string " + input2 + "!!");
					allMenu.isActive = true;
					int index = allMenu.categoryLists.FindIndex((Dictionary<string, List<string>> c) => c.Any<KeyValuePair<string, List<string>>>((KeyValuePair<string, List<string>> d) => Misc.CompareStringsInvariant(d.Key, input2)));
					return allMenu.categoryLists[index].First<KeyValuePair<string, List<string>>>((KeyValuePair<string, List<string>> d) => Misc.CompareStringsInvariant(d.Key, input2)).Key;
				}
				Loggers.LogDebug("menu does not contain string " + input2);
				allMenu.isActive = false;
			}
			return "CategoryNameFailure";
		}

		public static string GetCategoryFromNode(TerminalNode givenNode)
		{
			Loggers.LogDebug("1.1");
			if ((Object)(object)givenNode == (Object)null)
			{
				Loggers.ERROR("GetCategoryFromNode: givenNode is null!!!!");
				return "";
			}
			foreach (TerminalMenu allMenu in allMenus)
			{
				if (!allMenu.terminalNodePerCategory.ContainsValue(givenNode))
				{
					Loggers.LogDebug("menu does not contain node " + ((Object)givenNode).name);
					allMenu.isActive = false;
					continue;
				}
				foreach (KeyValuePair<string, TerminalNode> item in allMenu.terminalNodePerCategory)
				{
					if ((Object)(object)item.Value == (Object)(object)givenNode)
					{
						Loggers.LogDebug("FOUND NODE AND PAIR " + item.Key);
						allMenu.isActive = true;
						return item.Key;
					}
				}
			}
			Loggers.ERROR("GetCategoryFromNode FAILURE: COULD NOT FIND NODE???");
			return "";
		}

		public static TerminalMenuItem MakeMenuItem(ManagedConfig managedBool)
		{
			if (managedBool.categoryText != "")
			{
				return new TerminalMenuItem
				{
					itemKeywords = managedBool.KeywordList,
					itemDescription = managedBool.configDescription,
					ItemName = managedBool.ConfigItemName,
					Category = managedBool.categoryText
				};
			}
			return null;
		}

		public static TerminalMenuItem MakeMenuItem(string categoryText, List<string> keywordList, string configDescription, string itemName)
		{
			if (categoryText != "")
			{
				return new TerminalMenuItem
				{
					itemKeywords = keywordList,
					itemDescription = configDescription,
					ItemName = itemName,
					Category = categoryText
				};
			}
			Loggers.WARNING("Empty categoryText, Unable to create TerminalMenuItem! (null return)");
			return null;
		}
	}
	[Obsolete("This style of menu will be deleted in next major update to library, once all mods are confirmed not using this")]
	public class TerminalMenu
	{
		public string MenuName = string.Empty;

		public string MainMenuText = string.Empty;

		public string setKeyword = string.Empty;

		public List<TerminalMenuCategory> Categories = new List<TerminalMenuCategory>();

		public List<TerminalMenuItem> menuItems = new List<TerminalMenuItem>();

		public Dictionary<string, TerminalNode> terminalNodePerCategory = new Dictionary<string, TerminalNode>();

		public List<Dictionary<string, List<string>>> categoryLists = new List<Dictionary<string, List<string>>>();

		public List<TerminalNode> terminalNodes = new List<TerminalNode>();

		public string currentCategory { get; internal set; } = string.Empty;


		public bool isActive { get; internal set; }

		public bool isNextEnabled { get; internal set; }

		public int nextCount { get; internal set; } = 1;


		public void Delete()
		{
			MenuBuild.allMenus.Remove(this);
			menuItems.Clear();
			categoryLists.Clear();
			Categories.Clear();
			terminalNodePerCategory.Clear();
			terminalNodes.Clear();
		}
	}
	public class TerminalMenuItem
	{
		public string ItemName = string.Empty;

		public string Category = string.Empty;

		public List<string> itemKeywords;

		public string itemDescription = string.Empty;

		public void Delete()
		{
			itemDescription = "";
			Category = "";
			ItemName = "";
			if (itemKeywords.Count > 0)
			{
				itemKeywords.Clear();
			}
		}
	}
	public class TerminalMenuCategory
	{
		public string CatName { get; set; }

		public string CatDescription { get; set; }
	}
}
namespace OpenLib.InteractiveMenus
{
	public abstract class BetterMenuBase
	{
		public List<MenuItem> AllMenuItemsOfType = new List<MenuItem>();

		public abstract string Name { get; set; }

		public abstract Type MenuType { get; }

		public abstract object BoxedValue { get; }

		public abstract bool InMenu { get; set; }

		public abstract OpenLib.Events.Events.CustomEvent InputEvent { get; set; }

		public abstract OpenLib.Events.Events.CustomEvent ExitTerminal { get; set; }

		public abstract MenuItem MainMenu { get; set; }

		public List<T> GetMenuItemsOfType<T>() where T : MenuItem
		{
			return AllMenuItemsOfType.OfType<T>().ToList();
		}

		public override string ToString()
		{
			return Name;
		}
	}
	public class BetterMenu<T> : BetterMenuBase
	{
		[CompilerGenerated]
		private sealed class <DelayUpdateText>d__68 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public BetterMenu<T> <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayUpdateText>d__68(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected O, but got Unknown
				//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Expected O, but got Unknown
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Expected O, but got Unknown
				int num = <>1__state;
				BetterMenu<T> betterMenu = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (!betterMenu.AcceptAnything)
					{
						betterMenu.MenuNode.displayText = betterMenu.GetPageText();
					}
					if (string.IsNullOrEmpty(betterMenu.MenuNode.displayText))
					{
						betterMenu.ExitInTerminal();
					}
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					CommonTerminal.LoadNewNode(betterMenu.MenuNode);
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					if (betterMenu.AdjustScrollInMenu)
					{
						betterMenu.ScrollAdjust();
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <MenuClose>d__78 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public BetterMenu<T> <>4__this;

			public bool enableInput;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <MenuClose>d__78(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				//IL_0087: 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_009d: Expected O, but got Unknown
				int num = <>1__state;
				BetterMenu<T> betterMenu = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					betterMenu.OnExit.Invoke();
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					betterMenu.InMenu = false;
					betterMenu.AcceptAnything = false;
					CollectionExtensions.Do<MenuItem>((IEnumerable<MenuItem>)betterMenu.AllMenuItemsOfType, (Action<MenuItem>)delegate(MenuItem x)
					{
						x.IsActive = false;
					});
					CommonTerminal.ChangeCaretColor(CommonTerminal.CaretOriginal, saveOriginal: false);
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					if (betterMenu.ExitAction == null)
					{
						CommonTerminal.LoadNewNode(CommonTerminal.HomePage);
					}
					else
					{
						betterMenu.ExitAction();
					}
					if (enableInput)
					{
						Plugin.instance.Terminal.screenText.ActivateInputField();
						((Selectable)Plugin.instance.Terminal.screenText).interactable = true;
					}
					betterMenu.OnExitComplete.Invoke();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <MenuStart>d__79 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public BetterMenu<T> <>4__this;

			public MenuItem Start;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <MenuStart>d__79(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0080: 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_00a4: Expected O, but got Unknown
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Expected O, but got Unknown
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Expected O, but got Unknown
				int num = <>1__state;
				BetterMenu<T> betterMenu = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (betterMenu.InMenu)
					{
						return false;
					}
					if (Start == null)
					{
						Start = betterMenu.MainMenu;
					}
					Start.IsActive = true;
					betterMenu.AcceptAnything = false;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					betterMenu.InMenu = true;
					CommonTerminal.ChangeCaretColor(CommonTerminal.transparent, saveOriginal: true);
					betterMenu.ActiveSelection = 0;
					betterMenu.CurrentPage = 1;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					Plugin.instance.Terminal.screenText.DeactivateInputField(false);
					((Selectable)Plugin.instance.Terminal.screenText).interactable = false;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					Start.SelectionEvent?.Invoke();
					if (Start.LoadPageOnSelect)
					{
						betterMenu.LoadPage.Invoke();
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private string _name = "";

		private bool _inMenu;

		private MenuItem _mainMenu;

		private OpenLib.Events.Events.CustomEvent _inputEvent = new OpenLib.Events.Events.CustomEvent();

		private OpenLib.Events.Events.CustomEvent _exitEvent = new OpenLib.Events.Events.CustomEvent();

		public MenuItem CurrentMenuItem;

		public TerminalNode MenuNode;

		public Action ExitAction;

		public OpenLib.Events.Events.CustomEvent OnExit = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent OnExitComplete = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent OnEnter = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent OnLoad = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent LoadPage = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent UpMenuEvent = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent DownMenuEvent = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent LeftMenuEvent = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent RightMenuEvent = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEvent AcceptAnyKeyEvent = new OpenLib.Events.Events.CustomEvent();

		public OpenLib.Events.Events.CustomEventRef<List<MenuItem>> MenuItemList = new OpenLib.Events.Events.CustomEventRef<List<MenuItem>>();

		public Key upMenu = (Key)63;

		public Key downMenu = (Key)64;

		public Key leftMenu = (Key)61;

		public Key rightMenu = (Key)62;

		public Key selectMenu = (Key)2;

		public Key leaveMenu = (Key)65;

		public Dictionary<Key, Action> MainActions = new Dictionary<Key, Action>();

		public Dictionary<Key, Action> OtherActions = new Dictionary<Key, Action>();

		public bool IsMenuEnabled;

		public bool AcceptAnything;

		public bool AdjustScrollInMenu;

		private int _activeIndex;

		private int _endIndex;

		public int CurrentPage = 1;

		public int PageSize = 8;

		public List<MenuItem> DisplayMenuItemsOfType = new List<MenuItem>();

		public override string Name
		{
			get
			{
				return _name;
			}
			set
			{
				_name = value;
			}
		}

		public override Type MenuType => typeof(T);

		public override object BoxedValue => this;

		public override bool InMenu
		{
			get
			{
				return _inMenu;
			}
			set
			{
				_inMenu = value;
			}
		}

		public override MenuItem MainMenu
		{
			get
			{
				return _mainMenu;
			}
			set
			{
				_mainMenu = value;
			}
		}

		public override OpenLib.Events.Events.CustomEvent InputEvent
		{
			get
			{
				return _inputEvent;
			}
			set
			{
				_inputEvent = value;
			}
		}

		public override OpenLib.Events.Events.CustomEvent ExitTerminal
		{
			get
			{
				return _exitEvent;
			}
			set
			{
				_exitEvent = value;
			}
		}

		public int ActiveSelection
		{
			get
			{
				return _activeIndex;
			}
			set
			{
				_activeIndex = value;
			}
		}

		public int EndIndex
		{
			get
			{
				return _endIndex;
			}
			set
			{
				_endIndex = value;
			}
		}

		public override string ToString()
		{
			return Name;
		}

		public BetterMenu(string name, Dictionary<Key, Action> MoreMenuActions = null)
		{
			//IL_009d: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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)
			if (!TerminalUpdatePatch.usePatch)
			{
				TerminalUpdatePatch.usePatch = true;
			}
			Name = name;
			LoadPage.AddListener(Load);
			InputEvent.AddListener(HandleInput);
			ExitTerminal.AddListener(ExitTerminalLeave);
			AcceptAnyKeyEvent.AddListener(DefaultAcceptAnything);
			UpdateMainActions();
			if (MoreMenuActions != null)
			{
				OtherActions = MoreMenuActions;
			}
			MenusContainer.AllMenus.Add(this);
		}

		public void ReplaceEventAction(OpenLib.Events.Events.CustomEvent eventName, OpenLib.Events.Events.CustomEvent.Event newMethod)
		{
			if (eventName.Listeners > 0)
			{
				eventName.RemoveAllListeners();
			}
			eventName.AddListener(newMethod);
		}

		public void AddToOtherActions(Key key, Action action)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (OtherActions.ContainsKey(key))
			{
				OtherActions.Remove(key);
			}
			OtherActions.Add(key, action);
		}

		public void UpdateMainActions()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			MainActions.Clear();
			MainActions.Add(upMenu, UpMenu);
			MainActions.Add(downMenu, DownMenu);
			MainActions.Add(leftMenu, LeftMenu);
			MainActions.Add(rightMenu, RightMenu);
			MainActions.Add(selectMenu, SelectInMenu);
			MainActions.Add(leaveMenu, ExitInTerminal);
		}

		internal void HandleInput()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!InMenu || (Object)(object)MenuNode == (Object)null)
			{
				return;
			}
			if (AcceptAnything && AcceptAnyKeyEvent.HasListeners)
			{
				AcceptAnyKeyEvent.Invoke();
				return;
			}
			Key? main = MainActions.FirstOrDefault<KeyValuePair<Key, Action>>((KeyValuePair<Key, Action> x) => ((ButtonControl)Keyboard.current[x.Key]).isPressed).Key;
			if (main.HasValue)
			{
				MainActions.FirstOrDefault<KeyValuePair<Key, Action>>((KeyValuePair<Key, Action> x) => (Key?)x.Key == main).Value?.Invoke();
			}
			if (OtherActions.Count == 0)
			{
				return;
			}
			Key? other = OtherActions.FirstOrDefault<KeyValuePair<Key, Action>>((KeyValuePair<Key, Action> x) => ((ButtonControl)Keyboard.current[x.Key]).isPressed).Key;
			if (other.HasValue)
			{
				OtherActions.FirstOrDefault<KeyValuePair<Key, Action>>((KeyValuePair<Key, Action> x) => (Key?)x.Key == other).Value?.Invoke();
			}
		}

		public void Load()
		{
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem == null)
			{
				Loggers.ERROR("Unable to load current page! Nothing is active!");
				return;
			}
			if ((Object)(object)MenuNode == (Object)null)
			{
				Loggers.ERROR("NRE detected at MenuNode! This menu did not set it's terminal node correctly!");
				return;
			}
			menuItem.OnPageLoad?.Invoke();
			OnLoad.Invoke();
			((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(DelayUpdateText());
		}

		public void DefaultAcceptAnything()
		{
			AcceptAnything = false;
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem.NestedMenus.Count == 0)
			{
				ExitInTerminal();
			}
			else
			{
				LoadPage.Invoke();
			}
		}

		[IteratorStateMachine(typeof(BetterMenu<>.<DelayUpdateText>d__68))]
		private IEnumerator DelayUpdateText()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayUpdateText>d__68(0)
			{
				<>4__this = this
			};
		}

		private void ScrollAdjust()
		{
			float num = ((float)EndIndex - (float)ActiveSelection) / (float)EndIndex;
			if (num >= 1f)
			{
				((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(Plugin.instance.Terminal.forceScrollbarUp());
			}
			else if (num == 0f)
			{
				((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(Plugin.instance.Terminal.forceScrollbarDown());
			}
			else
			{
				Plugin.instance.Terminal.scrollBarVertical.value = num;
			}
		}

		public string GetPageText()
		{
			StringBuilder stringBuilder = new StringBuilder();
			CurrentMenuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (CurrentMenuItem == null)
			{
				Loggers.WARNING("Unable to get current menu page!!");
				return "";
			}
			stringBuilder.Append(CurrentMenuItem.Header() ?? "");
			DisplayMenuItemsOfType = AllMenuItemsOfType.FindAll((MenuItem x) => CurrentMenuItem.NestedMenus.Contains(x));
			DisplayMenuItemsOfType.RemoveAll((MenuItem x) => !x.ShowIfEmptyNest && x.NestedMenus.Count == 0);
			if (DisplayMenuItemsOfType.Count == 0)
			{
				stringBuilder.Append("\r\n\r\nThis menu listing is currently empty :(\r\n");
				if (CurrentMenuItem != null)
				{
					stringBuilder.Append(CurrentMenuItem.Footer() ?? "");
				}
				return stringBuilder.ToString();
			}
			CurrentMenuItem.AdjustNestedMenuList.Invoke(ref DisplayMenuItemsOfType);
			CurrentPage = Misc.CycleIndex(CurrentPage, 1, Mathf.CeilToInt((float)DisplayMenuItemsOfType.Count / (float)PageSize));
			int num = (CurrentPage - 1) * PageSize;
			int num3 = (EndIndex = Mathf.Min(num + PageSize, DisplayMenuItemsOfType.Count));
			ActiveSelection = Misc.CycleIndex(ActiveSelection, num, num3 - 1);
			Loggers.LogDebug($"{Name} menu activeselection: {ActiveSelection}");
			CollectionExtensions.DoIf<MenuItem>((IEnumerable<MenuItem>)DisplayMenuItemsOfType, (Func<MenuItem, bool>)((MenuItem x) => x.OnPageLoad != null), (Action<MenuItem>)delegate(MenuItem x)
			{
				x.OnPageLoad();
			});
			for (int i = num; i < num3; i++)
			{
				string text = string.Empty;
				if (ActiveSelection == i)
				{
					text = ">>> ";
				}
				text += DisplayMenuItemsOfType[i].Prefix;
				text += DisplayMenuItemsOfType[i].Name;
				text += DisplayMenuItemsOfType[i].Suffix;
				stringBuilder.Append(text + "\n");
			}
			int num4 = num3 - num - PageSize;
			if (num4 < 0)
			{
				for (int j = num4; j < 0; j++)
				{
					stringBuilder.Append('\n');
				}
			}
			if (CurrentMenuItem == null)
			{
				Loggers.WARNING("Unable to select current menu item!!");
			}
			else
			{
				stringBuilder.Append(CurrentMenuItem.Footer() ?? "");
			}
			return stringBuilder.ToString();
		}

		public void SelectInMenu()
		{
			if (DisplayMenuItemsOfType.Count == 0)
			{
				return;
			}
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem == null)
			{
				Loggers.WARNING("Unable to select current menu item!!");
				return;
			}
			Loggers.LogDebug("Selecting Nested Menu Item!");
			MenuItem menuItem2 = DisplayMenuItemsOfType[ActiveSelection];
			menuItem2.SelectionEvent?.Invoke();
			if (menuItem2.NestedMenus.Count > 0)
			{
				Loggers.LogDebug("Setting to nested menu item!");
				CurrentPage = 1;
				ActiveSelection = 0;
				CollectionExtensions.Do<MenuItem>((IEnumerable<MenuItem>)AllMenuItemsOfType, (Action<MenuItem>)delegate(MenuItem x)
				{
					x.IsActive = false;
				});
				menuItem2.IsActive = true;
			}
			if (menuItem2.LoadPageOnSelect)
			{
				LoadPage.Invoke();
			}
		}

		public void AddMenuItem(MenuItem menuItem)
		{
			if (!AllMenuItemsOfType.Contains(menuItem))
			{
				AllMenuItemsOfType.Add(menuItem);
			}
		}

		public void ExitInTerminal()
		{
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem == null)
			{
				Loggers.WARNING("Unable to get current menu page!!");
			}
			if (menuItem == null)
			{
				ExitMenu(enableInput: true);
			}
			else if (menuItem.Parent != null)
			{
				Loggers.LogDebug("Setting to ParentMenu!");
				ActiveSelection = 0;
				CurrentPage = 1;
				menuItem.IsActive = false;
				menuItem.Parent.IsActive = true;
				LoadPage.Invoke();
			}
			else
			{
				ExitMenu(enableInput: true);
			}
		}

		public void ExitTerminalLeave()
		{
			ExitMenu(enableInput: false);
		}

		public void ExitMenu(bool enableInput)
		{
			((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(MenuClose(enableInput));
		}

		public void EnterAtPage(MenuItem menuItem)
		{
			OnEnter.Invoke();
			((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(MenuStart(menuItem));
		}

		public void EnterMenu()
		{
			OnEnter.Invoke();
			((MonoBehaviour)Plugin.instance.Terminal).StartCoroutine(MenuStart());
		}

		[IteratorStateMachine(typeof(BetterMenu<>.<MenuClose>d__78))]
		internal IEnumerator MenuClose(bool enableInput)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MenuClose>d__78(0)
			{
				<>4__this = this,
				enableInput = enableInput
			};
		}

		[IteratorStateMachine(typeof(BetterMenu<>.<MenuStart>d__79))]
		internal IEnumerator MenuStart(MenuItem Start = null)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MenuStart>d__79(0)
			{
				<>4__this = this,
				Start = Start
			};
		}

		public void UpMenu()
		{
			if (InMenu)
			{
				ActiveSelection--;
				UpMenuEvent.Invoke();
				LoadPage.Invoke();
			}
		}

		public void DownMenu()
		{
			if (InMenu)
			{
				ActiveSelection++;
				DownMenuEvent.Invoke();
				LoadPage.Invoke();
			}
		}

		public void LeftMenu()
		{
			if (InMenu)
			{
				CurrentPage--;
				LeftMenuEvent.Invoke();
				LoadPage.Invoke();
			}
		}

		public void RightMenu()
		{
			if (InMenu)
			{
				CurrentPage++;
				RightMenuEvent.Invoke();
				LoadPage.Invoke();
			}
		}
	}
	public abstract class MenuItem<TMenu> : MenuItem where TMenu : BetterMenuBase
	{
		public new TMenu BetterMenu => (TMenu)base.BetterMenu;

		protected MenuItem(TMenu betterMenu)
			: base(betterMenu)
		{
		}
	}
	public abstract class MenuItem
	{
		private string _prefix = string.Empty;

		private string _suffix = string.Empty;

		private bool _isActive;

		private bool _LoadOnSelect = true;

		private MenuItem _parent;

		private Func<string> _header = () => string.Empty;

		private Func<string> _footer = () => string.Empty;

		protected BetterMenuBase? BetterMenu { get; }

		public abstract string Name { get; set; }

		public abstract bool ShowIfEmptyNest { get; set; }

		public virtual string Prefix
		{
			get
			{
				return _prefix;
			}
			set
			{
				_prefix = value;
			}
		}

		public virtual string Suffix
		{
			get
			{
				return _suffix;
			}
			set
			{
				_suffix = value;
			}
		}

		public virtual bool IsActive
		{
			get
			{
				return _isActive;
			}
			set
			{
				_isActive = value;
			}
		}

		public virtual bool LoadPageOnSelect
		{
			get
			{
				return _LoadOnSelect;
			}
			set
			{
				_LoadOnSelect = value;
			}
		}

		public virtual Action OnPageLoad { get; set; }

		public abstract OpenLib.Events.Events.CustomEvent SelectionEvent { get; set; }

		public virtual OpenLib.Events.Events.CustomEventRef<List<MenuItem>> AdjustNestedMenuList { get; set; } = new OpenLib.Events.Events.CustomEventRef<List<MenuItem>>();


		public abstract List<MenuItem> NestedMenus { get; set; }

		public virtual MenuItem Parent
		{
			get
			{
				return _parent;
			}
			set
			{
				_parent = value;
			}
		}

		public virtual Func<string> Header
		{
			get
			{
				return _header;
			}
			set
			{
				_header = value;
			}
		}

		public virtual Func<string> Footer
		{
			get
			{
				return _footer;
			}
			set
			{
				_footer = value;
			}
		}

		[Obsolete("Added for compatibility with older versions, please use the constructor with the bettermenubase")]
		protected MenuItem()
		{
			Loggers.LogInfo("MenuItem created from obsolete constructor! Please use constructor with BetterMenuBase!");
		}

		protected MenuItem(BetterMenuBase betterMenu)
		{
			if (betterMenu == null)
			{
				Loggers.ERROR("Unable to assign menu item to NULL betterMenu!");
				return;
			}
			BetterMenu = betterMenu;
			betterMenu.AllMenuItemsOfType.Add(this);
		}

		public override string ToString()
		{
			return Name;
		}

		public virtual void SetParentMenu(MenuItem parent)
		{
			Parent?.NestedMenus.RemoveAll((MenuItem m) => m == this);
			Parent = parent;
			if (parent != null && !parent.NestedMenus.Contains(this))
			{
				parent.NestedMenus.Add(this);
			}
		}

		public virtual void AddNestedItem(MenuItem child)
		{
			if (child != null)
			{
				child.Parent = this;
				if (!NestedMenus.Contains(child))
				{
					NestedMenus.Add(child);
				}
			}
		}

		public virtual void RemoveFromParent()
		{
			if (Parent != null)
			{
				Parent.NestedMenus.RemoveAll((MenuItem m) => m == this);
				Parent = null;
			}
		}

		public virtual void RemoveChild(MenuItem child)
		{
			if (child != null)
			{
				if (child.Parent != null)
				{
					child.Parent = null;
				}
				NestedMenus.Remove(child);
			}
		}
	}
	public class MenusContainer
	{
		public static List<BetterMenuBase> AllMenus = new List<BetterMenuBase>();

		private static int _activeIndex = 0;

		public static int StaticIndex
		{
			get
			{
				return _activeIndex;
			}
			set
			{
				_activeIndex = value;
			}
		}

		public static bool TryGetMenu(string menuName, out BetterMenuBase item)
		{
			string menuName2 = menuName;
			item = AllMenus.FirstOrDefault((BetterMenuBase x) => x.Name == menuName2);
			if (item == null)
			{
				return false;
			}
			return true;
		}

		public static bool AnyMenuActive()
		{
			if (AllInteractiveMenus.AnyInteractiveMenuActive())
			{
				return true;
			}
			bool flag = false;
			if (Plugin.instance.ITAPI)
			{
				flag = InteractiveTermAPI.ApplicationInUse();
			}
			if (flag)
			{
				return true;
			}
			if (AllMenus.Count == 0)
			{
				return false;
			}
			if (AllMenus.Any((BetterMenuBase x) => x.InMenu))
			{
				return true;
			}
			return false;
		}

		public static bool AnyBetterMenuActive()
		{
			if (AllMenus.Count == 0)
			{
				return false;
			}
			if (AllMenus.Any((BetterMenuBase x) => x.InMenu))
			{
				return true;
			}
			return false;
		}

		public static bool AnyOpenLibMenuActive()
		{
			if (AllInteractiveMenus.AnyInteractiveMenuActive())
			{
				return true;
			}
			if (AllMenus.Count == 0)
			{
				return false;
			}
			if (AllMenus.Any((BetterMenuBase x) => x.InMenu))
			{
				return true;
			}
			return false;
		}
	}
}
namespace OpenLib.Examples
{
	internal class Examples
	{
		public static void TestMyTAO()
		{
			TerminalCodeObject<PlayerControllerB> terminalCodeObject = new TerminalCodeObject<PlayerControllerB>(StartOfRound.Instance.localPlayerController, ((Component)StartOfRound.Instance.localPlayerController).gameObject, dynamicMapIcon: true);
			terminalCodeObject.OnCodeUsed.AddListener((UnityAction<TerminalAccessibleObject, PlayerControllerB>)TestCodeEvent);
			terminalCodeObject.OnCooldownComplete.AddListener((UnityAction<TerminalAccessibleObject, PlayerControllerB>)TestCoolDownEvent);
			terminalCodeObject.SetTimers(10f, 0f);
		}

		public static void TestCodeEvent(TerminalAccessibleObject Code, PlayerControllerB playerOfCode)
		{
			if ((Object)(object)Code == (Object)null)
			{
				Loggers.WARNING("Code is NULL!");
				return;
			}
			Plugin.Log.LogDebug((object)$"{Code.objectCode} activated! Status: isPoweredOn - {Code.isPoweredOn}, Cooldown: {Code.inCooldown}, Cooldown Timer: {Code.currentCooldownTimer}");
			playerOfCode.drunkness = 20f;
		}

		public static void TestCoolDownEvent(TerminalAccessibleObject Code, PlayerControllerB playerOfCode)
		{
			if ((Object)(object)Code == (Object)null)
			{
				Loggers.WARNING("Code is NULL!");
				return;
			}
			Plugin.Log.LogDebug((object)$"{Code.objectCode} cooldown reached! Status: isPoweredOn - {Code.isPoweredOn}, Cooldown: {Code.inCooldown}, Cooldown Timer: {Code.currentCooldownTimer}");
			playerOfCode.drunkness = 0f;
		}
	}
}
namespace OpenLib.Events
{
	public static class EventManager
	{
		public static Events.CustomEvent TerminalDisable = new Events.CustomEvent();

		public static Events.CustomEvent TerminalStart = new Events.CustomEvent();

		public static Events.CustomEvent TerminalBeginUsing = new Events.CustomEvent();

		public static Events.CustomEvent TerminalQuit = new Events.CustomEvent();

		public static Events.CustomEvent<Terminal> TerminalAwake = new Events.CustomEvent<Terminal>();

		public static Events.CustomEvent<TerminalNode> TerminalLoadIfAffordable = new Events.CustomEvent<TerminalNode>();

		public static Events.TerminalNodeEvent TerminalParseSent = new Events.TerminalNodeEvent();

		public static Events.CustomEvent<TerminalNode> TerminalLoadNewNode = new Events.CustomEvent<TerminalNode>();

		public static Events.TerminalNodeEvent GetNewDisplayText = new Events.TerminalNodeEvent();

		public static Events.CustomEvent StartOfRoundAwake = new Events.CustomEvent();

		public static Events.CustomEvent StartOfRoundStart = new Events.CustomEvent();

		public static Events.CustomEvent StartOfRoundStartGame = new Events.CustomEvent();

		public static Events.CustomEvent StartOfRoundChangeLevel = new Events.CustomEvent();

		public static Events.CustomEvent ShipReset = new Events.CustomEvent();

		public static Events.CustomEvent SetBigDoorCodes = new Events.CustomEvent();

		public static Events.CustomEvent SpawnMapObjects = new Events.CustomEvent();

		public static Events.CustomEvent NextDayEvent = new Events.CustomEvent();

		public static Events.CustomEvent OnShipLandedMiscPatch = new Events.CustomEvent();

		public static Events.CustomEvent ShipLeft = new Events.CustomEvent();

		public static Events.CustomEvent NewQuota = new Events.CustomEvent();

		public static Events.CustomEvent PlayerSpawn = new Events.CustomEvent();

		public static Events.CustomEvent PlayerEmote = new Events.CustomEvent();

		public static Events.CustomEvent<ShipTeleporter> TeleporterAwake = new Events.CustomEvent<ShipTeleporter>();

		public static Events.CustomEvent NormalTPFound = new Events.CustomEvent();

		public static Events.CustomEvent InverseTPFound = new Events.CustomEvent();

		public static Events.CustomEvent GameNetworkManagerStart = new Events.CustomEvent();

		public static Events.CustomEvent OnClientConnect = new Events.CustomEvent();

		public static Events.CustomEvent SpecateNextPlayer = new Events.CustomEvent();

		public static Events.CustomEvent TerminalDelayStart = new Events.CustomEvent();

		public static Events.CustomEvent SetTerminalInUse = new Events.CustomEvent();

		public static Events.CustomEvent TerminalKeyPressed = new Events.CustomEvent();

		public static Events.CustomEvent TerminalMenuKeyPressed = new Events.CustomEvent();

		public static Events.CustomEvent PlayerIsInShip = new Events.CustomEvent();

		public static Events.CustomEvent PlayerIsDead = new Events.CustomEvent();

		public static Events.CustomEvent SpecatingPlayerIsInShip = new Events.CustomEvent();

		public static Events.CustomEvent<GameObject> AutoParentEvent = new Events.CustomEvent<GameObject>();

		public static Events.CustomEvent<GameObject> NetworkObjectSpawn = new Events.CustomEvent<GameObject>();
	}
	public class Events
	{
		public class CustomEvent<T>
		{
			public delegate void ParameterEvent(T param);

			public bool HasListeners => Listeners != 0;

			public int Listeners { get; internal set; }

			private event ParameterEvent OnParameterEvent;

			public void Invoke(T param)
			{
				this.OnParameterEvent?.Invoke(param);
			}

			public void AddListener(ParameterEvent listener)
			{
				OnParameterEvent += listener;
				Listeners++;
			}

			public void RemoveListener(ParameterEvent listener)
			{
				OnParameterEvent -= listener;
				Listeners--;
			}
		}

		public class CustomEventRef<T>
		{
			public delegate void ParameterEvent(ref T param);

			public bool HasListeners => Listeners != 0;

			public int Listeners { get; internal set; }

			private event ParameterEvent OnParameterEvent;

			public void Invoke(ref T param)
			{
				this.OnParameterEvent?.Invoke(ref param);
			}

			public void AddListener(ParameterEvent listener)
			{
				OnParameterEvent += listener;
				Listeners++;
			}

			public void RemoveListener(ParameterEvent listener)
			{
				OnParameterEvent -= listener;
				Listeners--;
			}
		}

		public class TerminalNodeEvent
		{
			public delegate TerminalNode Event(ref TerminalNode original);

			public bool HasListeners => Listeners != 0;

			public int Listeners { get; internal set; }

			private event Event OnEvent;

			public TerminalNode NodeInvoke(ref TerminalNode original)
			{
				return this.OnEvent?.Invoke(ref original);
			}

			public void AddListener(Event listener)
			{
				OnEvent += listener;
				Listeners++;
			}

			public void RemoveListener(Event listener)
			{
				OnEvent -= listener;
				Listeners--;
			}
		}

		public class TerminalKeywordEvent
		{
			public delegate TerminalKeyword Event(ref TerminalKeyword original);

			public bool HasListeners => Listeners != 0;

			public int Listeners { get; internal set; }

			private event Event OnEvent;

			public TerminalKeyword WordInvoke(ref TerminalKeyword original)
			{
				return this.OnEvent?.Invoke(ref original);
			}

			public void AddListener(Event listener)
			{
				OnEvent += listener;
				Listeners++;
			}

			public void RemoveListener(Event listener)
			{
				OnEvent -= listener;
				Listeners--;
			}
		}

		public class CustomEvent
		{
			public delegate void Event();

			public bool HasListeners => Listeners != 0;

			public int Listeners { get; internal set; }

			private event Event OnEvent;

			public void Invoke()
			{
				if (HasListeners)
				{
					this.OnEvent?.Invoke();
				}
			}

			public void AddListener(Event listener)
			{
				OnEvent += listener;
				Listeners++;
			}

			public void RemoveListener(Event listener)
			{
				OnEvent -= listener;
				Listeners--;
			}

			public void RemoveAllListeners()
			{
				if (Listeners != 0)
				{
					List<Delegate> list = this.OnEvent.GetInvocationList().ToList();
					CollectionExtensions.Do<Delegate>((IEnumerable<Delegate>)list, (Action<Delegate>)delegate(Delegate x)
					{
						OnEvent -= (Event)x;
					});
					Listeners = 0;
				}
			}
		}
	}
	public class EventUsage
	{
		public static List<ConfigFile> configsToReload = new List<ConfigFile>();

		internal static void Subscribers()
		{
			EventManager.TerminalAwake.AddListener(OnTerminalAwake);
			EventManager.TerminalStart.AddListener(OnTerminalStart);
			EventManager.TerminalQuit.AddListener(OnTerminalQuit);
			EventManager.TerminalDisable.AddListener(OnTerminalDisable);
			EventManager.TerminalLoadNewNode.AddListener(OnLoadNewNode);
			EventManager.TerminalParseSent.AddListener(OnParseSent);
			EventManager.TerminalBeginUsing.AddListener(OnUsingTerminal);
			EventManager.GameNetworkManagerStart.AddListener(StartGame.OnGameStart);
			EventManager.TeleporterAwake.AddListener(Teleporter.CheckTeleporterTypeAndAssign);
			EventManager.TerminalMenuKeyPressed.AddListener(OnMenuKeyPress);
		}

		private static void OnTerminalAwake(Terminal instance)
		{
			Plugin.instance.Terminal = instance;
			Loggers.LogInfo("Setting Plugin.instance.Terminal");
			CommandRegistry.GetCommandsToAdd(ConfigSetup.defaultManaged, ConfigSetup.defaultListing);
			CommandManager.AddAllCommandsToTerminal();
		}

		private static void OnTerminalDisable()
		{
			if (Plugin.instance.OpenBodyCamsMod)
			{
				OpenBodyCamFuncs.ResidualCamsCheck();
			}
			RemoveThings.OnTerminalDisable();
			TerminalStart.delayStartEnum = false;
			ListManagement.ClearLists();
			CollectionExtensions.Do<CommandManager>((IEnumerable<CommandManager>)Plugin.AllCommands, (Action<CommandManager>)delegate(CommandManager x)
			{
				x.TerminalDisabled();
			});
			foreach (ConfigFile item in configsToReload)
			{
				Loggers.LogDebug("reloading config from list");
				item.Save();
				item.Reload();
			}
			configsToReload.Clear();
		}

		private static void OnTerminalStart()
		{
			TerminalStart.TerminalStartGroupDelay();
		}

		private static void OnTerminalQuit()
		{
			if (MenusContainer.AllMenus.Count != 0)
			{
				MenusContainer.AllMenus.FirstOrDefault((BetterMenuBase x) => x.InMenu)?.ExitTerminal.Invoke();
			}
		}

		internal static void OnMenuKeyPress()
		{
			if (AllInteractiveMenus.AllMenus.Count != 0)
			{
				AllInteractiveMenus.AllMenus.FirstOrDefault((InteractiveMenu x) => x.inMenu && x.isMenuEnabled)?.HandleInput();
			}
			if (MenusContainer.AllMenus.Count != 0)
			{
				MenusContainer.AllMenus.FirstOrDefault((BetterMenuBase x) => x.InMenu)?.InputEvent.Invoke();
			}
			CommonTerminal.TrySyncNodeOnly(Plugin.instance.Terminal.currentNode);
		}

		public static void OnUsingTerminal()
		{
			Loggers.LogInfo("Start Using Terminal Postfix");
		}

		public static TerminalNode OnParseSent(ref TerminalNode node)
		{
			Loggers.LogDebug("parsing sentence");
			if ((Object)(object)node == (Object)null)
			{
				Loggers.WARNING("node detected as NULL, returning...");
				return node;
			}
			string text = Plugin.instance.Terminal.screenText.text;
			int textAdded = Plugin.instance.Terminal.textAdded;
			int length = text.Length;
			int num = length - textAdded;
			string text2 = text.Substring(num, length - num);
			if (text2.Length > 0)
			{
				if (LogicHandling.GetDisplayFromFaux(ConfigSetup.defaultListing.fauxKeywords, text2, ref node))
				{
					Loggers.LogInfo("faux word detected on current node!");
				}
				if (CommonTerminal.TryGetNodeFromList(text2, ConfigSetup.defaultListing.specialListString, out TerminalNode returnNode))
				{
					node = returnNode;
					Loggers.LogDebug("node found matching specialListString in text - " + text2);
				}
				if (CommonTerminal.TryGetCommand(text2, out TerminalNode returnNode2))
				{
					node = returnNode2;
					Loggers.LogDebug("node found matching CommandManager listing in text - " + text2);
				}
			}
			if (LogicHandling.GetNewDisplayText(ConfigSetup.defaultListing, ref node))
			{
				Loggers.LogInfo("node found: " + ((Object)node).name);
			}
			if (LogicHandling.GetDisplayTextFromCommand(ref node))
			{
				Loggers.LogInfo("command found: " + ((Object)node).name);
			}
			return node;
		}

		public static void OnLoadNewNode(TerminalNode node)
		{
			if (!((Object)(object)node == (Object)null))
			{
				Loggers.LogDebug(((Object)node).name + " has been loaded");
				if (node.acceptAnything && node.terminalOptions.Length < 1)
				{
					node.acceptAnything = false;
					Loggers.LogDebug("fixing node property to avoid errors! (eg. LLL route locked)");
				}
			}
		}
	}
}
namespace OpenLib.CoreMethods
{
	public class AddingThings
	{
		private static readonly char[] NewLineChars = Environment.NewLine.ToCharArray();

		public static void AddKeywordToExistingNode(string keyWord, TerminalNode existingNode, bool addToList = true)
		{
			//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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			List<CompatibleNoun> list2 = new List<CompatibleNoun>();
			TerminalKeyword val = BasicTerminal.CreateNewTerminalKeyword(keyWord + "_keyword", keyWord.ToLower());
			val.isVerb = false;
			val.specialKeywordResult = existingNode;
			if (existingNode.terminalOptions != null)
			{
				list2 = existingNode.terminalOptions.ToList();
				Loggers.LogDebug(((Object)existingNode).name + " has existing terminalOptions");
			}
			CompatibleNoun item = new CompatibleNoun
			{
				noun = val,
				result = existingNode
			};
			list2.Add(item);
			existingNode.terminalOptions = list2.ToArray();
			list.Add(val);
			if (addToList)
			{
				Plugin.KeywordsAdded.Add(val);
			}
			Loggers.LogDebug("Adding " + keyWord + " to existing node " + ((Object)existingNode).name);
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
		}

		public static TerminalKeyword AddKeywordToNode(string keyWord, TerminalNode existingNode, bool addToList = true)
		{
			//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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			List<CompatibleNoun> list2 = new List<CompatibleNoun>();
			TerminalKeyword val = BasicTerminal.CreateNewTerminalKeyword(keyWord + "_keyword", keyWord.ToLower());
			val.isVerb = false;
			val.specialKeywordResult = existingNode;
			if (existingNode.terminalOptions != null)
			{
				list2 = existingNode.terminalOptions.ToList();
				Loggers.LogDebug(((Object)existingNode).name + " has existing terminalOptions");
			}
			CompatibleNoun item = new CompatibleNoun
			{
				noun = val,
				result = existingNode
			};
			list2.Add(item);
			existingNode.terminalOptions = list2.ToArray();
			list.Add(val);
			if (addToList)
			{
				Plugin.KeywordsAdded.Add(val);
			}
			Loggers.LogDebug("Adding " + keyWord + " to existing node " + ((Object)existingNode).name);
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
			return val;
		}

		public static void AddToHelpCommand(string textToAdd)
		{
			TerminalNode val = Plugin.instance.Terminal.terminalNodes.specialNodes[13];
			if (val.displayText.Contains(textToAdd))
			{
				Loggers.WARNING("Help command already contains this text: " + textToAdd);
				return;
			}
			int startIndex = val.displayText.LastIndexOf('[');
			val.displayText = val.displayText.Insert(startIndex, textToAdd + "\r\n\r\n");
		}

		public static void AddToExistingNodeText(string textToAdd, ref TerminalNode existingNode)
		{
			if (existingNode.displayText.Contains(textToAdd))
			{
				Plugin.Log.LogWarning((object)("Unable to add below text to " + ((Object)existingNode).name + ", it already has this text in it"));
				return;
			}
			Loggers.LogDebug($"oldtext length {existingNode.displayText.Length}");
			Loggers.LogDebug(existingNode.displayText);
			string text = existingNode.displayText.TrimEnd(NewLineChars);
			text = text + "\n" + textToAdd + "\r\n\r\n";
			existingNode.displayText = text;
			Loggers.LogDebug(((Object)existingNode).name + " text updated!!!");
		}

		public static TerminalNode CreateDummyNode(string nodeName, bool clearPrevious, string displayText)
		{
			if (DynamicBools.UseMatchingNode(nodeName, out TerminalNode returnNode))
			{
				returnNode.displayText = displayText;
				returnNode.clearPreviousText = clearPrevious;
			}
			else
			{
				returnNode = BasicTerminal.CreateNewTerminalNode();
				((Object)returnNode).name = nodeName;
				returnNode.displayText = displayText;
				returnNode.clearPreviousText = clearPrevious;
			}
			return returnNode;
		}

		public static void AddBasicCommand(string nodeName, string keyWord, string displayText, bool isVerb, bool clearText, string category = "", string keywordDescription = "")
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (!LogicHandling.TryGetFromAllNodes("OtherCommands", out TerminalNode outNode) && Misc.CompareStringsInvariant(category, "other"))
			{
				Loggers.WARNING("Unable to add " + keyWord + " to " + category + "\n" + category + " TerminalNode could not be found!");
				return;
			}
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			if (!DynamicBools.IsCommandCreatedAlready(keyWord, displayText, list))
			{
				CommonThings.CheckForAndDeleteKeyWord(keyWord.ToLower());
				TerminalNode val = BasicTerminal.CreateNewTerminalNode();
				((Object)val).name = nodeName;
				val.displayText = displayText;
				val.clearPreviousText = clearText;
				TerminalKeyword val2 = BasicTerminal.CreateNewTerminalKeyword(nodeName + "_keyword", keyWord.ToLower());
				((Object)val2).name = nodeName + "_keyword";
				val2.word = keyWord.ToLower();
				val2.isVerb = isVerb;
				val2.specialKeywordResult = val;
				new CompatibleNoun
				{
					noun = val2,
					result = val
				};
				list.Add(val2);
				Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
				if (!Plugin.NodesAdded.Contains(val))
				{
					Plugin.NodesAdded.Add(val);
				}
				if (!Plugin.KeywordsAdded.Contains(val2))
				{
					Plugin.KeywordsAdded.Add(val2);
				}
				if (Misc.CompareStringsInvariant(category, "other") && (Object)(object)outNode != (Object)null)
				{
					AddToExistingNodeText(keywordDescription ?? "", ref outNode);
					Loggers.LogDebug("adding node to other listing");
				}
			}
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static TerminalNode AddNodeManual(string nodeName, string stringValue, Func<string> commandAction, bool clearText, int CommandType, MainListing yourModListing, int price = 0, Func<string> ConfirmAction = null, Func<string> DenyAction = null, string confirmText = "", string denyText = "", bool alwaysInStock = false, int maxStock = 1, string storeName = "", bool reuseFunc = false, string itemList = "")
		{
			TerminalNode val = null;
			List<string> list = new List<string>();
			if (stringValue != null)
			{
				list = CommonStringStuff.GetKeywordsPerConfigItem(stringValue);
			}
			foreach (string item in list)
			{
				val = BaseCommandCreation(nodeName, item, commandAction, clearText, CommandType, yourModListing, price, ConfirmAction, DenyAction, confirmText, denyText, alwaysInStock, maxStock, storeName, reuseFunc, itemList);
			}
			if ((Object)(object)val == (Object)null)
			{
				Loggers.WARNING("Returning NULL terminal node @AddNodeManual!!!");
			}
			return val;
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static TerminalNode AddNodeManual(string nodeName, ConfigEntry<string> stringValue, Func<string> commandAction, bool clearText, int CommandType, MainListing yourModListing, List<ManagedConfig> managedBools, string category = "", string description = "", int price = 0, Func<string> ConfirmAction = null, Func<string> DenyAction = null, string confirmText = "", string denyText = "", bool alwaysInStock = false, int maxStock = 1, string storeName = "", bool reuseFunc = false, string itemList = "")
		{
			TerminalNode val = null;
			List<string> list = new List<string>();
			bool flag = true;
			if (stringValue != null)
			{
				flag = false;
				list = CommonStringStuff.GetKeywordsPerConfigItem(stringValue.Value);
			}
			foreach (string item in list)
			{
				val = BaseCommandCreation(nodeName, item, commandAction, clearText, CommandType, yourModListing, price, ConfirmAction, DenyAction, confirmText, denyText, alwaysInStock, maxStock, storeName, reuseFunc, itemList);
			}
			if ((Object)(object)val == (Object)null)
			{
				Loggers.WARNING("Returning NULL terminal node @AddNodeManual!!!");
			}
			if (ManagedBoolGet.CanAddToManagedBoolList(managedBools, nodeName))
			{
				TerminalMenuItem menuItem = new TerminalMenuItem
				{
					Category = category,
					itemDescription = description,
					ItemName = nodeName,
					itemKeywords = list
				};
				ManagedConfig managedConfig = new ManagedConfig
				{
					TerminalNode = val,
					menuItem = menuItem,
					ConfigItemName = nodeName
				};
				managedBools.Add(managedConfig);
				if (!flag)
				{
					ConfigSetup.AddManagedString(stringValue, ref managedBools, managedConfig);
				}
			}
			return val;
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static TerminalNode CreateNode(TerminalMenu terminalMenu, string nodeName, string keyWord, Func<string> commandAction, MainListing yourModListing, bool isNextPageCommand = false)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			Loggers.LogDebug(nodeName ?? "");
			Loggers.LogDebug(keyWord);
			bool clearPreviousText = true;
			CommonThings.CheckForAndDeleteKeyWord(keyWord.ToLower());
			TerminalNode val = BasicTerminal.CreateNewTerminalNode();
			((Object)val).name = nodeName;
			val.displayText = nodeName;
			val.clearPreviousText = clearPreviousText;
			val.buyUnlockable = false;
			Loggers.LogDebug("node created");
			TerminalKeyword val2 = BasicTerminal.CreateNewTerminalKeyword(nodeName + "_keyword", keyWord.ToLower());
			val2.isVerb = false;
			val2.specialKeywordResult = val;
			Loggers.LogDebug("keyword created");
			yourModListing.Listing.Add(val, commandAction);
			Loggers.LogDebug("func added to listing");
			if (!isNextPageCommand)
			{
				terminalMenu.terminalNodePerCategory.Add(keyWord, val);
				Loggers.LogDebug("added terminalNode to menus nodelisting");
			}
			list.Add(val2);
			Plugin.KeywordsAdded.Add(val2);
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
			Loggers.LogDebug("added to all keyword lists");
			return val;
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static void InfoText(ManagedConfig managedBool, string keyWord, TerminalKeyword infoWord, MainListing yourModListing)
		{
			if (managedBool.InfoAction != null)
			{
				TerminalNode val = BasicTerminal.CreateNewTerminalNode();
				((Object)val).name = "info_" + keyWord;
				val.displayText = "infoAction should replace this";
				yourModListing.Listing.Add(val, managedBool.InfoAction);
				val.clearPreviousText = true;
				AddCompatibleNoun(ref infoWord, keyWord, val);
				Loggers.LogDebug("info node created with infoAction!");
			}
			else if (managedBool.InfoText.Length > 1)
			{
				TerminalNode val2 = BasicTerminal.CreateNewTerminalNode();
				((Object)val2).name = "info_" + keyWord;
				val2.displayText = managedBool.InfoText;
				val2.clearPreviousText = true;
				AddCompatibleNoun(ref infoWord, keyWord, val2);
				Loggers.LogDebug("info node created");
			}
		}

		public static void AddToFauxListing(FauxKeyword fauxWord, MainListing yourListing)
		{
			if (fauxWord != null && fauxWord.Keyword != null && (Object)(object)fauxWord.MainPage != (Object)null)
			{
				yourListing.fauxKeywords.Add(fauxWord);
			}
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static TerminalNode CreateNode(ManagedConfig managedBool, string keyWord, MainListing yourModListing)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			Func<string> mainAction = managedBool.MainAction;
			string text;
			if (managedBool.nodeName.Length < 2)
			{
				text = managedBool.ConfigItemName;
				Loggers.LogDebug("managedBool nodename is blank, using configitemname");
			}
			else
			{
				text = managedBool.nodeName;
				Loggers.LogDebug("using nodeName: " + text);
			}
			bool clearText = managedBool.clearText;
			TerminalNode val = BaseCommandCreation(text, keyWord, mainAction, managedBool.clearText, managedBool.CommandType, yourModListing, managedBool.price, managedBool.ConfirmAction, managedBool.DenyAction, managedBool.confirmText, managedBool.denyText, managedBool.alwaysInStock, managedBool.maxStock, managedBool.storeName, managedBool.reuseFunc, managedBool.itemList);
			if ((Object)(object)val == (Object)null)
			{
				Loggers.WARNING("terminalNode is NULL at CreateNode!!!");
			}
			return val;
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static void AddConfirm(string nodeName, ManagedConfig managedBool, Dictionary<TerminalNode, Func<string>> nodeListing, out CompatibleNoun confirm, out CompatibleNoun deny)
		{
			confirm = BasicTerminal.CreateCompatibleNoun(nodeName, "confirm", managedBool.confirmText, managedBool.price, managedBool.ConfirmAction, nodeListing);
			deny = BasicTerminal.CreateCompatibleNoun(nodeName, "deny", managedBool.denyText, managedBool.price, managedBool.DenyAction, nodeListing);
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static void AddConfirm(string nodeName, int price, Func<string> ConfirmAction, Func<string> DenyAction, string confirmText, string denyText, Dictionary<TerminalNode, Func<string>> nodeListing, out CompatibleNoun confirm, out CompatibleNoun deny)
		{
			confirm = BasicTerminal.CreateCompatibleNoun(nodeName, "confirm", confirmText, price, ConfirmAction, nodeListing);
			deny = BasicTerminal.CreateCompatibleNoun(nodeName, "deny", denyText, price, DenyAction, nodeListing);
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static void AddStoreCommand(string nodeName, ref TerminalKeyword keyword, ManagedConfig managedBool, MainListing mainListing, out CompatibleNoun confirm, out CompatibleNoun deny)
		{
			if ((Object)(object)managedBool.TerminalNode == (Object)null)
			{
				Loggers.ERROR("node is null when adding store command!!!");
				confirm = null;
				deny = null;
			}
			else if (managedBool.ConfirmAction != null)
			{
				AddConfirm(nodeName, managedBool, mainListing.Listing, out confirm, out deny);
				StoreStuff(nodeName, managedBool.storeName, ref keyword, ref managedBool.TerminalNode, managedBool.price, managedBool.alwaysInStock, managedBool.maxStock, ref confirm, ref deny);
			}
			else
			{
				Loggers.ERROR("Shop nodes NEED confirmation, but confirmAction is null for " + nodeName + "!");
				confirm = null;
				deny = null;
			}
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static void AddStoreCommand(string nodeName, string storeName, ref TerminalKeyword keyword, ref TerminalNode node, int price, Func<string> ConfirmAction, Func<string> DenyAction, string confirmText, string denyText, MainListing mainListing, bool alwaysInStock, int maxStock, out CompatibleNoun confirm, out CompatibleNoun deny)
		{
			if ((Object)(object)node == (Object)null)
			{
				Loggers.ERROR("node is null when adding store command!!!");
				confirm = null;
				deny = null;
			}
			else if (ConfirmAction != null)
			{
				AddConfir