Decompiled source of OpenLib v0.3.2

OpenLib.dll

Decompiled 2 weeks ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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 TerminalStuff;
using TerminalStuff.EventSub;
using TwoRadarMaps;
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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("OpenLib")]
[assembly: AssemblyDescription("https://github.com/darmuh/OpenLib")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OpenLib")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e2700abc-7bc7-4bd0-b787-effe68445b6a")]
[assembly: AssemblyFileVersion("0.3.2")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.2.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;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace OpenLib
{
	public class NodeInfo
	{
		[CompilerGenerated]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		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;
			InfoAction = null;
			terminalNode = null;
			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);
				});
				Plugin.Spam("info node created and assigned to command!");
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	public class StartRoundAwake
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundAwake.Invoke();
		}
	}
	[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(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(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(TimeOfDay), "SetNewProfitQuota")]
	public class NewQuotaPatch
	{
		public static void Postfix()
		{
			EventManager.NewQuota.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ChangeLevel")]
	public class RouteEvent
	{
		public static void Postfix()
		{
			EventManager.StartOfRoundChangeLevel.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(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 : MonoBehaviour
		{
			private static void Postfix()
			{
				EventManager.PlayerSpawn.Invoke();
			}
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter), "Awake")]
	public class TeleporterInit : ShipTeleporter
	{
		private static void Postfix(ShipTeleporter __instance)
		{
			EventManager.TeleporterAwake.Invoke(__instance);
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "Start")]
	public class GameStartPatch
	{
		public static void Postfix()
		{
			EventManager.GameNetworkManagerStart.Invoke();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
	public class OnClientConnectPatch
	{
		public static void Postfix()
		{
			EventManager.OnClientConnect.Invoke();
		}
	}
	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(Terminal), "Awake")]
	public class AwakeTermPatch : Terminal
	{
		private static void Postfix(Terminal __instance)
		{
			EventManager.TerminalAwake.Invoke(__instance);
		}
	}
	[HarmonyPatch(typeof(Terminal), "OnDisable")]
	public class DisableTermPatch : Terminal
	{
		private static void Postfix()
		{
			EventManager.TerminalDisable.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "QuitTerminal")]
	public class QuitTerminalPatch : Terminal
	{
		private static void Postfix()
		{
			EventManager.TerminalQuit.Invoke();
		}
	}
	[HarmonyPatch(typeof(Terminal), "LoadNewNode")]
	public class LoadNewNodePatch : Terminal
	{
		private static void Postfix(TerminalNode node)
		{
			EventManager.TerminalLoadNewNode.Invoke(node);
		}
	}
	[HarmonyPatch(typeof(Terminal), "Start")]
	public class TerminalStartPatch : Terminal
	{
		private static void Postfix()
		{
			EventManager.TerminalStart.Invoke();
		}
	}
	[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;

		private static void Postfix(Terminal __instance)
		{
			if (usePatch)
			{
				if (__instance.placeableObject.inUse != inUse)
				{
					inUse = __instance.placeableObject.inUse;
					EventManager.SetTerminalInUse.Invoke();
				}
				if (((ButtonControl)Keyboard.current.anyKey).wasPressedThisFrame && __instance.terminalInUse)
				{
					EventManager.TerminalKeyPressed.Invoke();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")]
	public class AffordableNodePatch
	{
		private static void Postfix(TerminalNode node)
		{
			EventManager.TerminalLoadIfAffordable.Invoke(node);
		}
	}
	[BepInPlugin("darmuh.OpenLib", "OpenLib", "0.3.2")]
	public class Plugin : BaseUnityPlugin
	{
		public static class PluginInfo
		{
			public const string PLUGIN_GUID = "darmuh.OpenLib";

			public const string PLUGIN_NAME = "OpenLib";

			public const string PLUGIN_VERSION = "0.3.2";
		}

		public static Plugin instance;

		internal static ManualLogSource Log;

		public bool TerminalStuff = false;

		public bool LobbyCompat = false;

		public bool TerminalFormatter = false;

		public bool ITAPI = false;

		public bool LethalConfig = false;

		public bool OpenBodyCamsMod = false;

		public bool TwoRadarMapsMod = false;

		public bool ModelReplacement = false;

		public bool TooManyEmotes = false;

		public bool MirrorDecor = false;

		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>();

		private void Awake()
		{
			instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"OpenLib is loading with version 0.3.2!");
			ConfigSetup.defaultManaged = new List<ManagedConfig>();
			ConfigSetup.defaultListing = new MainListing();
			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>();
			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);
		}

		internal static void MoreLogs(string message)
		{
			if (ConfigSetup.ExtensiveLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		internal static void Spam(string message)
		{
			if (ConfigSetup.DeveloperLogging.Value)
			{
				Log.LogDebug((object)message);
			}
		}

		internal static void ERROR(string message)
		{
			Log.LogError((object)message);
		}

		internal static void WARNING(string message)
		{
			Log.LogWarning((object)message);
		}
	}
}
namespace OpenLib.Properties
{
	[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
	[DebuggerNonUserCode]
	[CompilerGenerated]
	internal class Resources
	{
		private static ResourceManager resourceMan;

		private static CultureInfo resourceCulture;

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static ResourceManager ResourceManager
		{
			get
			{
				if (resourceMan == null)
				{
					ResourceManager resourceManager = new ResourceManager("OpenLib.Properties.Resources", typeof(Resources).Assembly);
					resourceMan = resourceManager;
				}
				return resourceMan;
			}
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static CultureInfo Culture
		{
			get
			{
				return resourceCulture;
			}
			set
			{
				resourceCulture = value;
			}
		}

		internal Resources()
		{
		}
	}
}
namespace OpenLib.Menus
{
	public class TerminalMenu
	{
		public string MenuName;

		public string MainMenuText;

		public string setKeyword;

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

		public string currentCategory;

		public bool isActive;

		public bool isNextEnabled;

		public int nextCount = 1;

		public List<TerminalMenuItem> menuItems;

		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 void Delete()
		{
			MenuBuild.allMenus.Remove(this);
			menuItems.Clear();
			categoryLists.Clear();
			Categories.Clear();
			terminalNodePerCategory.Clear();
			terminalNodes.Clear();
		}
	}
	public class TerminalMenuItem
	{
		public string ItemName;

		public string Category;

		public List<string> itemKeywords;

		public string itemDescription;

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

		public string CatDescription;
	}
	public class MenuBuild
	{
		public static bool isNextEnabled = false;

		public static int nextCount = 1;

		public static string currentCategory = "";

		public static TerminalMenu currentMenu;

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

		public static List<TerminalMenuCategory> InitCategories(Dictionary<string, string> CategoryItems)
		{
			Plugin.Spam("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);
			}
			Plugin.Spam("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);
				}
			}
			Plugin.Spam("\n\n\n");
			Plugin.Spam($"myMenuItems count: {list.Count}");
			Plugin.Spam("\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)
			{
				Plugin.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 = "";
				Plugin.Spam("In main menu of " + terminalMenu.MenuName);
				return true;
			}
			if (terminalMenu.isNextEnabled && terminalMenu.terminalNodes.Contains(terminalNode))
			{
				Plugin.Spam("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)
			{
				Plugin.Spam("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)
		{
			List<Dictionary<string, List<string>>> list = new List<Dictionary<string, List<string>>>();
			foreach (TerminalMenuCategory category in terminalMenu.Categories)
			{
				Plugin.Spam("checking category in terminalMenu.categories");
				Dictionary<string, List<string>> item = MakeCategoryList(category, terminalMenu.menuItems);
				if (!list.Contains(item))
				{
					list.Add(item);
				}
				FauxKeyword fauxKeyword = new FauxKeyword("more", category.CatName, GetFirstInList);
				fauxKeyword.AllowOtherFauxWords = true;
				fauxKeyword.requireExact = true;
				AddingThings.AddToFauxListing(fauxKeyword, yourModListing);
			}
			terminalMenu.categoryLists = list;
			FauxKeyword fauxKeyword2 = new FauxKeyword("more", "next", NextInList);
			fauxKeyword2.AllowOtherFauxWords = true;
			AddingThings.AddToFauxListing(fauxKeyword2, 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)
			{
				Plugin.Spam("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)
		{
			Plugin.Spam("2.1");
			List<string> result = new List<string>();
			foreach (TerminalMenu allMenu in allMenus)
			{
				Plugin.Spam("2.2");
				if (!allMenu.isActive)
				{
					continue;
				}
				for (int i = 0; i < allMenu.Categories.Count; i++)
				{
					Plugin.Spam("2.3");
					foreach (KeyValuePair<string, List<string>> item in allMenu.categoryLists[i])
					{
						if (item.Key.ToLower() == catName.ToLower())
						{
							Plugin.Spam("categorylist found!!!");
							menuName = allMenu;
							return item.Value;
						}
					}
				}
			}
			Plugin.Spam("2.1 FAIL");
			menuName = null;
			return result;
		}

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

		public static string NextInList()
		{
			if (!isNextEnabled)
			{
				return "Not currently in any menus...\r\n\r\n";
			}
			Plugin.Spam("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);
			Plugin.Spam($"currentCategory:{currentCategory} nextCount: {nextCount} isNextEnabled: {isNextEnabled}");
			menuName.isNextEnabled = isNextEnabled;
			return nextPage;
		}

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

		public static string GetCategoryFromString(string input)
		{
			string input2 = input;
			Plugin.Spam("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) => d.Key.ToLower() == input2.ToLower())))
				{
					Plugin.Spam("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) => d.Key.ToLower() == input2.ToLower()));
					return allMenu.categoryLists[index].First<KeyValuePair<string, List<string>>>((KeyValuePair<string, List<string>> d) => d.Key.ToLower() == input2.ToLower()).Key;
				}
				Plugin.Spam("menu does not contain string " + input2);
				allMenu.isActive = false;
			}
			return "CategoryNameFailure";
		}

		public static string GetCategoryFromNode(TerminalNode givenNode)
		{
			Plugin.Spam("1.1");
			if ((Object)(object)givenNode == (Object)null)
			{
				Plugin.ERROR("givenNode is null!!!!");
				return "";
			}
			foreach (TerminalMenu allMenu in allMenus)
			{
				if (!allMenu.terminalNodePerCategory.ContainsValue(givenNode))
				{
					Plugin.Spam("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)
					{
						Plugin.Spam("FOUND NODE AND PAIR " + item.Key);
						allMenu.isActive = true;
						return item.Key;
					}
				}
			}
			Plugin.ERROR("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
				};
			}
			Plugin.WARNING("Empty categoryText, Unable to create TerminalMenuItem! (null return)");
			return null;
		}
	}
}
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)
			{
				Plugin.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)
			{
				Plugin.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 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 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 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.TerminalKeyPressed.AddListener(OnKeyPress);
		}

		private static void OnTerminalAwake(Terminal instance)
		{
			Plugin.instance.Terminal = instance;
			Plugin.MoreLogs("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)
			{
				Plugin.Spam("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 OnKeyPress()
		{
			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();
			}
		}

		public static void OnUsingTerminal()
		{
			Plugin.MoreLogs("Start Using Terminal Postfix");
		}

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

		public static void OnLoadNewNode(TerminalNode node)
		{
			Plugin.Spam($"listing count: {ConfigSetup.defaultListing.Listing.Count}");
			if (!((Object)(object)node == (Object)null))
			{
				Plugin.Spam(((Object)node).name + " has been loaded");
				if (node.acceptAnything && node.terminalOptions.Length < 1)
				{
					node.acceptAnything = false;
					Plugin.Spam("fixing node property to avoid errors! (eg. LLL route locked)");
				}
			}
		}
	}
}
namespace OpenLib.InteractiveMenus
{
	public abstract class BetterMenuBase
	{
		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 class BetterMenu<T> : BetterMenuBase
	{
		private string _name = "";

		private bool _inMenu = false;

		private MenuItem _mainMenu = null;

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

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

		public TerminalNode MenuNode;

		public TerminalNode ExitPage = null;

		public OpenLib.Events.Events.CustomEvent OnExit = 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 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 = false;

		public bool AcceptAnything = false;

		public int ActiveSelection = 0;

		public int CurrentPage = 1;

		public int PageSize = 8;

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

		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 BetterMenu(string name, Dictionary<Key, Action> MoreMenuActions = null)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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);
			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
			{
				Load();
			}
		}

		private IEnumerator DelayUpdateText()
		{
			yield return (object)new WaitForEndOfFrame();
			if (!AcceptAnything)
			{
				MenuNode.displayText = GetPageText();
			}
			yield return (object)new WaitForEndOfFrame();
			CommonTerminal.LoadNewNode(MenuNode);
			yield return (object)new WaitForEndOfFrame();
		}

		public string GetPageText()
		{
			StringBuilder stringBuilder = new StringBuilder();
			MenuItem current = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (current == null)
			{
				Plugin.WARNING("Unable to get current menu page!!");
				return "Unable to get current page!\r\n\r\n";
			}
			if (current == null)
			{
				Plugin.WARNING("Unable to get current menu page!!");
			}
			else
			{
				stringBuilder.Append(current.Header() ?? "");
			}
			DisplayMenuItemsOfType = AllMenuItemsOfType.FindAll((MenuItem x) => current.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 (current != null)
				{
					stringBuilder.Append(current.Footer() ?? "");
				}
				return stringBuilder.ToString();
			}
			CurrentPage = Misc.CycleIndex(CurrentPage, 1, Mathf.CeilToInt((float)DisplayMenuItemsOfType.Count / (float)PageSize));
			int num = (CurrentPage - 1) * PageSize;
			int num2 = Mathf.Min(num + PageSize, DisplayMenuItemsOfType.Count);
			ActiveSelection = Misc.CycleIndex(ActiveSelection, num, num2 - 1);
			Plugin.Spam($"{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 < num2; 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 num3 = num2 - num - PageSize;
			if (num3 < 0)
			{
				for (int j = num3; j < 0; j++)
				{
					stringBuilder.Append("\n");
				}
			}
			if (current == null)
			{
				Plugin.WARNING("Unable to select current menu item!!");
			}
			else
			{
				stringBuilder.Append(current.Footer() ?? "");
			}
			return stringBuilder.ToString();
		}

		public void SelectInMenu()
		{
			if (DisplayMenuItemsOfType.Count == 0)
			{
				return;
			}
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem == null)
			{
				Plugin.WARNING("Unable to select current menu item!!");
				return;
			}
			Plugin.Spam("Selecting Nested Menu Item!");
			MenuItem menuItem2 = DisplayMenuItemsOfType[ActiveSelection];
			menuItem2.SelectionEvent?.Invoke();
			if (menuItem2.NestedMenus.Count > 0)
			{
				Plugin.Spam("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 ExitInTerminal()
		{
			MenuItem menuItem = AllMenuItemsOfType.FirstOrDefault((MenuItem x) => x.IsActive);
			if (menuItem == null)
			{
				Plugin.WARNING("Unable to get current menu page!!");
			}
			if (menuItem == null)
			{
				ExitMenu(enableInput: true);
			}
			else if (menuItem.Parent != null)
			{
				Plugin.Spam("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)
		{
			OnExit.Invoke();
			((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());
		}

		internal IEnumerator MenuClose(bool enableInput)
		{
			yield return (object)new WaitForEndOfFrame();
			InMenu = false;
			AcceptAnything = false;
			CollectionExtensions.Do<MenuItem>((IEnumerable<MenuItem>)AllMenuItemsOfType, (Action<MenuItem>)delegate(MenuItem x)
			{
				x.IsActive = false;
			});
			yield return (object)new WaitForEndOfFrame();
			if ((Object)(object)ExitPage == (Object)null)
			{
				ExitPage = Plugin.instance.Terminal.terminalNodes.specialNodes.ToArray()[1];
			}
			CommonTerminal.LoadNewNode(ExitPage);
			yield return (object)new WaitForEndOfFrame();
			CommonTerminal.ChangeCaretColor(CommonTerminal.CaretOriginal, saveOriginal: false);
			if (enableInput)
			{
				Plugin.instance.Terminal.screenText.ActivateInputField();
				((Selectable)Plugin.instance.Terminal.screenText).interactable = true;
			}
		}

		internal IEnumerator MenuStart(MenuItem Start = null)
		{
			if (!InMenu)
			{
				if (Start == null)
				{
					Start = MainMenu;
				}
				Start.IsActive = true;
				AcceptAnything = false;
				yield return (object)new WaitForEndOfFrame();
				InMenu = true;
				CommonTerminal.ChangeCaretColor(CommonTerminal.transparent, saveOriginal: true);
				ActiveSelection = 0;
				CurrentPage = 1;
				yield return (object)new WaitForEndOfFrame();
				Plugin.instance.Terminal.screenText.DeactivateInputField(false);
				((Selectable)Plugin.instance.Terminal.screenText).interactable = false;
				yield return (object)new WaitForEndOfFrame();
				Start.SelectionEvent?.Invoke();
				if (Start.LoadPageOnSelect)
				{
					LoadPage.Invoke();
				}
			}
		}

		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
	{
		private string _prefix = string.Empty;

		private string _suffix = string.Empty;

		private bool _isActive = false;

		private bool _LoadOnSelect = true;

		private MenuItem _parent = null;

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

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

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

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

		public virtual void AddNestedItem(MenuItem parent)
		{
			if (parent != null && !parent.NestedMenus.Contains(this))
			{
				parent.NestedMenus.Add(this);
			}
		}
	}
	public class MenusContainer
	{
		public static List<BetterMenuBase> AllMenus = new List<BetterMenuBase>();

		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()
		{
			bool flag = false;
			if (Plugin.instance.ITAPI)
			{
				flag = InteractiveTermAPI.ApplicationInUse();
			}
			if (flag)
			{
				return true;
			}
			if (AllInteractiveMenus.AnyInteractiveMenuActive())
			{
				return true;
			}
			if (AllMenus.Count == 0)
			{
				return false;
			}
			if (AllMenus.Any((BetterMenuBase x) => x.InMenu))
			{
				return true;
			}
			return false;
		}
	}
}
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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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();
				Plugin.Spam(((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);
			}
			Plugin.Spam("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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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();
				Plugin.Spam(((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);
			}
			Plugin.Spam("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))
			{
				Plugin.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;
			}
			Plugin.Spam($"oldtext length {existingNode.displayText.Length}");
			Plugin.Spam(existingNode.displayText);
			string text = existingNode.displayText.TrimEnd(NewLineChars);
			text = text + "\n" + textToAdd + "\r\n\r\n";
			existingNode.displayText = text;
			Plugin.Spam(((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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if (!LogicHandling.TryGetFromAllNodes("OtherCommands", out TerminalNode outNode) && category.ToLower() == "other")
			{
				Plugin.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 (category.ToLower() == "other" && (Object)(object)outNode != (Object)null)
				{
					AddToExistingNodeText(keywordDescription ?? "", ref outNode);
					Plugin.Spam("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)
			{
				Plugin.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)
			{
				Plugin.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();
			Plugin.Spam(nodeName ?? "");
			Plugin.Spam(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;
			Plugin.Spam("node created");
			TerminalKeyword val2 = BasicTerminal.CreateNewTerminalKeyword(nodeName + "_keyword", keyWord.ToLower());
			val2.isVerb = false;
			val2.specialKeywordResult = val;
			Plugin.Spam("keyword created");
			yourModListing.Listing.Add(val, commandAction);
			Plugin.Spam("func added to listing");
			if (!isNextPageCommand)
			{
				terminalMenu.terminalNodePerCategory.Add(keyWord, val);
				Plugin.Spam("added terminalNode to menus nodelisting");
			}
			list.Add(val2);
			Plugin.keywordsAdded.Add(val2);
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
			Plugin.Spam("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);
				Plugin.Spam("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);
				Plugin.Spam("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;
				Plugin.Spam("managedBool nodename is blank, using configitemname");
			}
			else
			{
				text = managedBool.nodeName;
				Plugin.Spam("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)
			{
				Plugin.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)
			{
				Plugin.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
			{
				Plugin.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)
			{
				Plugin.ERROR("node is null when adding store command!!!");
				confirm = null;
				deny = null;
			}
			else if (ConfirmAction != null)
			{
				AddConfirm(nodeName, price, ConfirmAction, DenyAction, confirmText, denyText, mainListing.Listing, out confirm, out deny);
				StoreStuff(nodeName, storeName, ref keyword, ref node, price, alwaysInStock, maxStock, ref confirm, ref deny);
			}
			else
			{
				Plugin.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 StoreStuff(string nodeName, string storeName, ref TerminalKeyword keyword, ref TerminalNode node, int price, bool alwaysInStock, int maxStock, ref CompatibleNoun confirm, ref CompatibleNoun deny)
		{
			node.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[2] { confirm, deny };
			UnlockableItem item = AddUnlockable(nodeName, node, alwaysInStock, maxStock);
			if (!StartOfRound.Instance.unlockablesList.unlockables.Contains(item))
			{
				StartOfRound.Instance.unlockablesList.unlockables.Add(item);
			}
			int shipUnlockableID = StartOfRound.Instance.unlockablesList.unlockables.IndexOf(item);
			node.creatureName = storeName;
			node.shipUnlockableID = shipUnlockableID;
			confirm.result.shipUnlockableID = shipUnlockableID;
			confirm.result.buyUnlockable = false;
			confirm.result.itemCost = price;
			if (DynamicBools.TryGetKeyword("buy", out TerminalKeyword terminalKeyword))
			{
				AddToBuyWord(ref terminalKeyword, ref keyword, item);
			}
			Plugin.ShopNodes.Add(node);
			Plugin.Spam("Store nodes created for " + nodeName);
		}

		public static UnlockableItem AddUnlockable(string storeName, TerminalNode node, bool alwaysInStock, int maxStock)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			if (DynamicBools.TryGetAndReturnUnlockable(storeName, out UnlockableItem itemOut))
			{
				Plugin.Spam("found matching item for " + storeName);
				itemOut.unlockableType = 1;
				itemOut.shopSelectionNode = node;
				itemOut.alwaysInStock = alwaysInStock;
				itemOut.IsPlaceable = false;
				itemOut.spawnPrefab = false;
				itemOut.maxNumber = maxStock;
				return itemOut;
			}
			Plugin.Spam("Creating unlockable item manually for item: " + storeName);
			return new UnlockableItem
			{
				unlockableType = 1,
				unlockableName = storeName,
				shopSelectionNode = node,
				alwaysInStock = alwaysInStock,
				IsPlaceable = false,
				spawnPrefab = false,
				maxNumber = maxStock
			};
		}

		public static void AddToBuyWord(ref TerminalKeyword buyKeyword, ref TerminalKeyword terminalKeyword, UnlockableItem item)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			terminalKeyword.defaultVerb = buyKeyword;
			Plugin.Spam("Added buy verb to " + buyKeyword.word);
			CompatibleNoun item2 = new CompatibleNoun
			{
				noun = terminalKeyword,
				result = item.shopSelectionNode
			};
			List<CompatibleNoun> list = buyKeyword.compatibleNouns.ToList();
			list.Add(item2);
			Plugin.nounsAdded.Add(item2);
			buyKeyword.compatibleNouns = list.ToArray();
		}

		[Obsolete("Use AddCompatibleNoun instead")]
		public static void AddToKeyword(ref TerminalKeyword originalKeyword, ref TerminalKeyword newWord)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (!originalKeyword.isVerb)
			{
				Plugin.Log.LogWarning((object)"AddToKeyword called on non-verb");
				return;
			}
			newWord.defaultVerb = originalKeyword;
			Plugin.Spam("Added verb " + originalKeyword.word + " to " + newWord.word);
			CompatibleNoun item = new CompatibleNoun
			{
				noun = newWord,
				result = newWord.specialKeywordResult
			};
			List<CompatibleNoun> list = originalKeyword.compatibleNouns.ToList();
			list.Add(item);
			Plugin.nounsAdded.Add(item);
			originalKeyword.compatibleNouns = list.ToArray();
		}

		public static void AddCompatibleNoun(ref TerminalKeyword originalWord, string word, TerminalNode resultNode)
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			if (!originalWord.isVerb)
			{
				Plugin.WARNING(originalWord.word + " is NOT a verb");
				return;
			}
			List<CompatibleNoun> list = originalWord.compatibleNouns.ToList();
			foreach (CompatibleNoun item in list)
			{
				if (item.noun.word.ToLower() == word.ToLower())
				{
					Plugin.WARNING("NOUN: " + item.noun.word + " already exists for WORD: " + originalWord.word);
					return;
				}
			}
			if (DynamicBools.TryGetKeyword(word, out TerminalKeyword terminalKeyword))
			{
				CompatibleNoun val = new CompatibleNoun();
				val.noun = terminalKeyword;
				val.result = resultNode;
				list.Add(val);
				originalWord.compatibleNouns = list.ToArray();
				Plugin.Spam("Added NOUN: " + val.noun.word + " to WORD: " + originalWord.word + " compatible nouns");
				Plugin.nounsAdded.Add(val);
			}
			else
			{
				Plugin.WARNING("word: " + word + " does not exist, unable to add as compatible noun");
			}
		}

		[Obsolete("use CommandManager class, if equivalent method does not exist will exist in the future")]
		public static TerminalNode BaseCommandCreation(string nodeName, string keyWord, Func<string> commandAction, bool clearText, int CommandType, MainListing yourModListing, int price, Func<string> ConfirmAction, Func<string> DenyAction, string confirmText, string denyText, bool alwaysInStock, int maxStock, string storeName, bool reuseFunc, string itemList)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			if (DynamicBools.IsCommandCreatedAlready(yourModListing.Listing, keyWord, commandAction, list, out TerminalKeyword outKeyword) && !reuseFunc)
			{
				return outKeyword.specialKeywordResult;
			}
			CommonThings.CheckForAndDeleteKeyWord(keyWord.ToLower());
			if (DynamicBools.DoesNodeExist(yourModListing.Listing, commandAction, out TerminalNode node) && !reuseFunc)
			{
				AddKeywordToExistingNode(keyWord, node);
				Plugin.Spam("existing node found " + ((Object)node).name + ", reusing associated func and adding additional keyword " + keyWord);
				return node;
			}
			TerminalNode node2 = BasicTerminal.CreateNewTerminalNode();
			((Object)node2).name = nodeName;
			node2.displayText = nodeName;
			node2.clearPreviousText = clearText;
			node2.buyUnlockable = false;
			TerminalKeyword keyword = BasicTerminal.CreateNewTerminalKeyword(nodeName + "_keyword", keyWord.ToLower());
			keyword.isVerb = false;
			keyword.specialKeywordResult = node2;
			CompatibleNoun confirm = null;
			CompatibleNoun deny = null;
			switch (CommandType)
			{
			case 1:
				AddConfirm(nodeName, price, ConfirmAction, DenyAction, confirmText, denyText, yourModListing.Listing, out confirm, out deny);
				node2.acceptAnything = false;
				Plugin.Spam("command type 1 detected, adding basic confirmation");
				break;
			case 2:
				AddStoreCommand(nodeName, storeName, ref keyword, ref node2, price, ConfirmAction, DenyAction, confirmText, denyText, yourModListing, alwaysInStock, maxStock, out confirm, out deny);
				Plugin.Spam("command type 2 detected, adding store logic");
				node2.acceptAnything = false;
				yourModListing.shopNodes.Add(confirm.result);
				yourModListing.shopNodes.Add(node2);
				yourModListing.shopNodes.Add(deny.result);
				if (itemList.Length > 1)
				{
					confirm.result.buyUnlockable = false;
					yourModListing.storePacks.Add(node2, itemList);
					Plugin.Spam("storepack detected, adding itemlist");
				}
				break;
			}
			if (confirm != null && deny != null)
			{
				list.Add(confirm.noun);
				Plugin.keywordsAdded.Add(confirm.noun);
				list.Add(deny.noun);
				Plugin.keywordsAdded.Add(deny.noun);
				node2.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[2] { confirm, deny };
				node2.overrideOptions = true;
			}
			else
			{
				Plugin.Spam("no confirmation logic added for " + keyWord);
			}
			yourModListing.Listing.Add(node2, commandAction);
			list.Add(keyword);
			if (!Plugin.nodesAdded.Contains(node2))
			{
				Plugin.nodesAdded.Add(node2);
			}
			if (!Plugin.keywordsAdded.Contains(keyword))
			{
				Plugin.keywordsAdded.Add(keyword);
			}
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
			return node2;
		}

		[Obsolete("use AddCompatibleNoun")]
		public static void AddNounWordSimple(string originalVerb, string nodeName, string keyWord, string displayText, bool clearText)
		{
		}
	}
	public class BasicTerminal
	{
		public static TerminalKeyword CreateNewTerminalKeyword(string name, string keyword, bool checkForExisting = false)
		{
			if (checkForExisting)
			{
				CheckForAndDeleteKeyWord(keyword);
			}
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			TerminalKeyword val = ScriptableObject.CreateInstance<TerminalKeyword>();
			((Object)val).name = name;
			val.word = keyword;
			val.isVerb = false;
			val.compatibleNouns = Array.Empty<CompatibleNoun>();
			val.defaultVerb = null;
			list.Add(val);
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
			return val;
		}

		public static TerminalNode CreateNewTerminalNode()
		{
			TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>();
			((Object)val).name = "OpenLibTerminalNode";
			val.displayText = string.Empty;
			val.terminalEvent = string.Empty;
			val.maxCharactersToType = 25;
			val.buyItemIndex = -1;
			val.buyRerouteToMoon = -1;
			val.displayPlanetInfo = -1;
			val.shipUnlockableID = -1;
			val.creatureFileID = -1;
			val.storyLogFileID = -1;
			val.playSyncedClip = -1;
			val.terminalOptions = Array.Empty<CompatibleNoun>();
			return val;
		}

		public static CompatibleNoun CreateCompatibleNoun(string nodeName, string word, string displayText = "")
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			CompatibleNoun val = new CompatibleNoun();
			TerminalKeyword terminalKeyword;
			if (word.ToLower() == "deny" || word.ToLower() == "confirm")
			{
				val.noun = CreateNewTerminalKeyword(nodeName + "_" + word, word);
			}
			else if (DynamicBools.TryGetKeyword(word, out terminalKeyword))
			{
				val.noun = terminalKeyword;
			}
			else
			{
				val.noun = CreateNewTerminalKeyword(nodeName + "_" + word, word);
			}
			val.result = CreateNewTerminalNode();
			((Object)val.result).name = nodeName + "_" + word;
			val.result.displayText = displayText;
			val.result.clearPreviousText = true;
			val.noun.specialKeywordResult = val.result;
			return val;
		}

		public static CompatibleNoun CreateCompatibleNoun(string nodeName, string word, string displayText = "", int price = 0, Func<string> thisAction = null, Dictionary<TerminalNode, Func<string>> nodeListing = null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			CompatibleNoun val = new CompatibleNoun();
			TerminalKeyword terminalKeyword;
			if (word.ToLower() == "deny" || word.ToLower() == "confirm")
			{
				val.noun = CreateNewTerminalKeyword(nodeName + "_" + word, word);
			}
			else if (DynamicBools.TryGetKeyword(word, out terminalKeyword))
			{
				val.noun = terminalKeyword;
			}
			else
			{
				val.noun = CreateNewTerminalKeyword(nodeName + "_" + word, word);
			}
			val.result = CreateNewTerminalNode();
			((Object)val.result).name = nodeName + "_" + word;
			val.result.displayText = displayText;
			val.result.clearPreviousText = true;
			val.result.itemCost = price;
			val.noun.specialKeywordResult = val.result;
			if (thisAction != null)
			{
				nodeListing?.Add(val.result, thisAction);
			}
			return val;
		}

		public static void CheckForAndDeleteKeyWord(string keyWord)
		{
			Plugin.Spam("Checking for " + keyWord);
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].word.Equals(keyWord))
				{
					Plugin.Spam("removing " + list[num].word);
					list.RemoveAt(num);
					break;
				}
			}
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
		}
	}
	public class CommandManager
	{
		public string Name = string.Empty;

		public ConfigWatch<bool> IsEnabled;

		public ConfigEntry<string> KeywordsConfig;

		public List<string> KeywordList;

		public Func<string> MainAction;

		public bool ClearText = true;

		public bool AddAtAwake = true;

		public bool AcceptAdditionalText = false;

		public int CommandType = 0;

		public NodeInfo InfoBase;

		public NodeConfirmation ConfirmBase;

		public NodeSpecial SpecialBase;

		public NodeStore StoreBase;

		public TerminalNode terminalNode;

		public List<TerminalKeyword> terminalKeywords = new List<TerminalKeyword>();

		public CommandManager(string commandName, ConfigEntry<bool> CommandBool, ConfigEntry<string> keywords, Func<string> commandFunc, int type = 0, bool addToMain = true)
		{
			Name = commandName;
			IsEnabled = new ConfigWatch<bool>(CommandBool);
			KeywordList = CommonStringStuff.GetKeywordsPerConfigItem(keywords.Value);
			MainAction = commandFunc;
			CommandType = Mathf.Clamp(type, 0, 2);
			if (addToMain)
			{
				Plugin.AllCommands.Add(this);
			}
		}

		public CommandManager(string commandName, ConfigEntry<bool> CommandBool, List<string> manualWords, Func<string> commandFunc, int type = 0, bool addToMain = true)
		{
			Name = commandName;
			IsEnabled = new ConfigWatch<bool>(CommandBool);
			KeywordList = manualWords;
			MainAction = commandFunc;
			CommandType = Mathf.Clamp(type, 0, 2);
			if (addToMain)
			{
				Plugin.AllCommands.Add(this);
			}
		}

		public CommandManager(string commandName, List<string> manualWords, Func<string> commandFunc, ConfigEntry<bool> CommandBool = null, int type = 0, bool addToMain = true)
		{
			Name = commandName;
			KeywordList = manualWords;
			MainAction = commandFunc;
			CommandType = Mathf.Clamp(type, 0, 2);
			if (CommandBool != null)
			{
				IsEnabled = new ConfigWatch<bool>(CommandBool);
			}
			if (addToMain)
			{
				Plugin.AllCommands.Add(this);
			}
		}

		public bool IsCommandEnabled()
		{
			if (IsEnabled == null)
			{
				return true;
			}
			if (!IsEnabled.NetworkingReq || IsEnabled.networkingConfig == null)
			{
				return IsEnabled.ConfigItem.Value;
			}
			if (IsEnabled.NetworkingReq && IsEnabled.networkingConfig.Value)
			{
				return IsEnabled.ConfigItem.Value;
			}
			return false;
		}

		public void SetInfoText(string infoText)
		{
			if (InfoBase == null)
			{
				InfoBase = new NodeInfo(this);
			}
			InfoBase.InfoText = infoText;
		}

		public void SetInfoAction(Func<string> action)
		{
			if (InfoBase == null)
			{
				InfoBase = new NodeInfo(this);
			}
			InfoBase.InfoAction = action;
		}

		public void AddToDefaultListing()
		{
			if (!Plugin.AllCommands.Contains(this))
			{
				Plugin.AllCommands.Add(this);
			}
		}

		internal static void AddAllCommandsToTerminal()
		{
			if (Plugin.AllCommands.Count != 0)
			{
				CollectionExtensions.DoIf<CommandManager>((IEnumerable<CommandManager>)Plugin.AllCommands, (Func<CommandManager, bool>)((CommandManager x) => x.AddAtAwake), (Action<CommandManager>)delegate(CommandManager x)
				{
					x.RegisterCommand();
				});
			}
		}

		internal void GetInfo()
		{
			if (InfoBase == null)
			{
				InfoBase = new NodeInfo(this);
				InfoBase.GetDefaultInfo(this);
			}
			else if (InfoBase.InfoAction == null && InfoBase.InfoText.Length < 1)
			{
				InfoBase.GetDefaultInfo(this);
			}
		}

		public void TerminalDisabled()
		{
			terminalKeywords = new List<TerminalKeyword>();
			terminalNode = null;
		}

		public void RegisterCommand()
		{
			if (!IsCommandEnabled())
			{
				return;
			}
			terminalNode = BasicTerminal.CreateNewTerminalNode();
			((Object)terminalNode).name = Name;
			terminalNode.displayText = string.Empty;
			terminalNode.clearPreviousText = ClearText;
			GetInfo();
			CollectionExtensions.Do<string>((IEnumerable<string>)KeywordList, (Action<string>)delegate(string w)
			{
				AddKeyword(w);
			});
			if (CommandType > 0)
			{
				ConfirmBase.CreateConfirmation();
			}
			if (CommandType == 2)
			{
				if (StoreBase == null)
				{
					Plugin.WARNING("UNABLE TO ADD STORE ITEM, StoreBase is undefined!");
					return;
				}
				StoreBase.AddToStore();
			}
			InfoBase.CreateInfoNode();
		}

		internal void AddKeyword(string keyword)
		{
			Plugin.Spam("adding " + keyword);
			TerminalKeyword item = BasicTerminal.CreateNewTerminalKeyword(Name + "_keyword", keyword, checkForExisting: true);
			terminalKeywords.Add(item);
		}
	}
	public class CommonThings
	{
		public static void CheckForAndDeleteKeyWord(string keyWord)
		{
			Plugin.Spam("Checking for " + keyWord);
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].word.Equals(keyWord))
				{
					Plugin.Spam("removing " + list[num].word);
					list.RemoveAt(num);
					break;
				}
			}
			Plugin.instance.Terminal.terminalNodes.allKeywords = list.ToArray();
		}
	}
	public class FauxKeyword
	{
		public TerminalNode MainPage;

		public TerminalNode thisNode = BasicTerminal.CreateNewTerminalNode();

		public string Keyword;

		public Func<string> ResultFunc;

		public Func<string> ConfirmFunc;

		public Func<string> DenyFunc;

		public string ConfirmText;

		public string DenyText;

		public bool GetConfirm;

		public bool AllowOtherFauxWords = false;

		public bool requireExact = false;

		public FauxKeyword(string mainWord, string keyword, Func<string> resultFunc)
		{
			TerminalKeyword terminalKeyword;
			if (keyword.Length < 3)
			{
				Plugin.WARNING("Unable to create FauxKeyword for {keyword}! It's too short!");
			}
			else if (DynamicBools.TryGetKeyword(mainWord, out terminalKeyword))
			{
				MainPage = terminalKeyword.specialKeywordResult;
				Keyword = keyword;
				ResultFunc = resultFunc;
				thisNode.clearPreviousText = true;
				((Object)thisNode).name = keyword;
				Plugin.Spam("FauxKeyword - " + keyword + " created!");
			}
			else
			{
				Plugin.WARNING("Could not find main page at word - " + mainWord);
				MainPage = null;
				Keyword = keyword;
			}
		}

		public void AddConfirm(Func<string> confirmFunc, Func<string> denyFunc = null)
		{
			GetConfirm = false;
			ConfirmFunc = confirmFunc;
			if (denyFunc != null)
			{
				DenyFunc = denyFunc;
			}
		}

		public void AddText(string denyText, string confirmText = "")
		{
			GetConfirm = false;
			ConfirmText = confirmText;
			DenyText = denyText;
		}
	}
	public class InteractiveMenu
	{
		public string MenuName = "";

		public Action LoadPage;

		public Action EnterMenu;

		public Action LeaveMenu;

		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 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 = false;

		public bool inMenu = false;

		public bool acceptAnything = false;

		public int activeSelection = 0;

		public int currentPage = 1;

		public InteractiveMenu(string name, Action pageLoader, Action enter, Action leave, Dictionary<Key, Action> MoreMenuActions = null)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!TerminalUpdatePatch.usePatch)
			{
				TerminalUpdatePatch.usePatch = true;
			}
			MenuName = name;
			LoadPage = pageLoader;
			EnterMenu = enter;
			LeaveMenu = leave;
			SetupMainActions();
			if (MoreMenuActions != null)
			{
				OtherActions = MoreMenuActions;
			}
			AllInteractiveMenus.AllMenus.Add(this);
		}

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

		internal void SetupMainActions()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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, EnterMenu.Invoke);
			MainActions.Add(leaveMenu, LeaveMenu.Invoke);
		}

		internal void HandleInput()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (!inMenu)
			{
				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 UpMenu()
		{
			if (inMenu)
			{
				if (activeSelection > 0)
				{
					activeSelection--;
				}
				LoadPage();
				UpMenuEvent.Invoke();
			}
		}

		public void DownMenu()
		{
			if (inMenu)
			{
				activeSelection++;
				LoadPage();
				DownMenuEvent.Invoke();
			}
		}

		public void LeftMenu()
		{
			if (inMenu)
			{
				if (currentPage > 1)
				{
					currentPage--;
				}
				LoadPage();
				LeftMenuEvent.Invoke();
			}
		}

		public void RightMenu()
		{
			if (inMenu)
			{
				currentPage++;
				LoadPage();
				RightMenuEvent.Invoke();
			}
		}
	}
	public static class AllInteractiveMenus
	{
		public static List<InteractiveMenu> AllMenus { get; internal set; }

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

		[Obsolete("Use MenusContainer.AnyMenuActive instead")]
		public static bool AnyMenuActive()
		{
			if (MenusContainer.AnyMenuActive())
			{
				return true;
			}
			return false;
		}

		public static bool AnyInteractiveMenuActive()
		{
			if (AllMenus.Count == 0)
			{
				return false;
			}
			if (AllMenus.Any((InteractiveMenu x) => x.inMenu))
			{
				return true;
			}
			return false;
		}
	}
	public class ListManagement
	{
		public static void ClearLists()
		{
			Plugin.ShopNodes.Clear();
		}
	}
	public class MainListing
	{
		public List<TerminalNode> terminalNodes = new List<TerminalNode>();

		public List<TerminalKeyword> terminalKeywords = new List<TerminalKeyword>();

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

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

		public List<FauxKeyword> fauxKeywords = new List<FauxKeyword>();

		public Dictionary<TerminalNode, int> specialListNum = new Dictionary<TerminalNode, int>();

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

		public Dictionary<int, string> ListNumToString = new Dictionary<int, string>();

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

		public void DeleteAll()
		{
			terminalKeywords.Clear();
			terminalNodes.Clear();
			Listing.Clear();
			shopNodes.Clear();
			specialListNum.Clear();
			specialListString.Clear();
			ListNumToString.Clear();
			storePacks.Clear();
			fauxKeywords.Clear();
		}
	}
	public class CommandRegistry
	{
		public static void InitListing(ref MainListing listingName)
		{
			if (listingName == null)
			{
				listingName = new MainListing();
			}
			listingName.terminalNodes = new List<TerminalNode>();
			listingName.terminalKeywords = new List<TerminalKeyword>();
			listingName.Listing = new Dictionary<TerminalNode, Func<string>>();
			listingName.shopNodes = new List<TerminalNode>();
			listingName.specialListNum = new Dictionary<TerminalNode, int>();
			listingName.specialListString = new Dictionary<string, TerminalNode>();
			listingName.ListNumToString = new Dictionary<int, string>();
			if (listingName == null)
			{
				Plugin.ERROR("InitListing still null");
			}
		}

		public static void GetCommandsToAdd(List<ManagedConfig> managedBools, MainListing listingName)
		{
			Plugin.MoreLogs("GetCommandsToAdd");
			if (managedBools == null || listingName == null)
			{