Decompiled source of OpenLib v0.2.12

OpenLib.dll

Decompiled 15 hours 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 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.Menus;
using TerminalStuff;
using TerminalStuff.EventSub;
using TwoRadarMaps;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering.HighDefinition;

[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.2.12")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.12.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
{
	[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(StartOfRound), "PassTimeToNextDay")]
	public class NextDayPatch
	{
		public static void Postfix()
		{
			EventManager.NextDayEvent.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(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.2.12")]
	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.2.12";
		}

		public static Plugin instance;

		internal static ManualLogSource Log;

		public bool TerminalStuff = false;

		public bool LobbyCompat = false;

		public bool TerminalFormatter = 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<TerminalKeyword> keywordsAdded = new List<TerminalKeyword>();

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

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

		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.2.12!");
			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.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 NextDayEvent = 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 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 class EventUsage
	{
		public static List<ConfigFile> configsToReload = new List<ConfigFile>();

		public static void Subscribers()
		{
			EventManager.TerminalAwake.AddListener(OnTerminalAwake);
			EventManager.TerminalStart.AddListener(OnTerminalStart);
			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);
		}

		public static void OnTerminalAwake(Terminal instance)
		{
			Plugin.instance.Terminal = instance;
			Plugin.MoreLogs("Setting Plugin.instance.Terminal");
			CommandRegistry.GetCommandsToAdd(ConfigSetup.defaultManaged, ConfigSetup.defaultListing);
		}

		public static void OnTerminalDisable()
		{
			if (Plugin.instance.OpenBodyCamsMod)
			{
				OpenBodyCamFuncs.ResidualCamsCheck();
			}
			RemoveThings.OnTerminalDisable();
			TerminalStart.delayStartEnum = false;
			ListManagement.ClearLists();
			foreach (ConfigFile item in configsToReload)
			{
				Plugin.Spam("reloading config from list");
				item.Save();
				item.Reload();
			}
			configsToReload.Clear();
		}

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

		public static void OnKeyPress()
		{
			if (AllInteractiveMenus.AllMenus.Count != 0)
			{
				AllInteractiveMenus.AllMenus.FirstOrDefault((InteractiveMenu x) => x.inMenu && x.isMenuEnabled)?.HandleInput();
			}
		}

		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 (LogicHandling.GetNewDisplayText(ConfigSetup.defaultListing, ref node))
			{
				Plugin.MoreLogs("node 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.CoreMethods
{
	public class AddingThings
	{
		private static readonly char[] NewLineChars = Environment.NewLine.ToCharArray();

		public static void AddKeywordToExistingNode(string keyWord, TerminalNode existingNode, bool addToList = true)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			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");
				}
			}
		}

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

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

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

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

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

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

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

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

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

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

		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)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			TerminalKeyword val = ScriptableObject.CreateInstance<TerminalKeyword>();
			((Object)val).name = name;
			val.word = keyword;
			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 = "", 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 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;
		}

		public static bool AnyMenuActive()
		{
			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)
			{
				Plugin.Spam("params are null");
				return;
			}
			Plugin.Spam($"listing count: {listingName.Listing.Count}");
			foreach (ManagedConfig managedBool in managedBools)
			{
				if (managedBool.BoolValue)
				{
					Plugin.Spam("configvalue is true");
					TerminalMenuItem terminalMenuItem = MenuBuild.MakeMenuItem(managedBool);
					if (terminalMenuItem != null)
					{
						managedBool.menuItem = terminalMenuItem;
					}
					Plugin.MoreLogs(managedBool.ConfigItemName + " found in managed bools and is active");
					if (managedBool.KeywordList == null)
					{
						continue;
					}
					AddCommandKeyword(managedBool, listingName);
					if (managedBool.categoryText.ToLower() == "other")
					{
						if (!LogicHandling.TryGetFromAllNodes("OtherCommands", out TerminalNode outNode))
						{
							Plugin.WARNING("Unable to add " + managedBool.configDescription + " to OtherCommands\nOtherCommands TerminalNode could not be found!");
						}
						else
						{
							AddingThings.AddToExistingNodeText("\n" + managedBool.configDescription, ref outNode);
						}
					}
				}
				else
				{
					Plugin.Spam("configvalue is false, deleting menuItem if not null");
					managedBool.menuItem?.Delete();
				}
			}
		}

		public static void AddCommandKeyword(ManagedConfig managedBool, MainListing listingName)
		{
			if (managedBool == null)
			{
				Plugin.ERROR("managedBool is null @AddCommandKeyword()");
				return;
			}
			if (managedBool.KeywordList.Count == 0)
			{
				Plugin.Spam("KeywordList Count = 0 for " + managedBool.ConfigItemName);
				return;
			}
			Plugin.Spam("AddCommandKeyword starting:");
			foreach (string keyword in managedBool.KeywordList)
			{
				Plugin.Spam("adding " + keyword);
				GenerateInfoText(managedBool);
				managedBool.TerminalNode = AddingThings.CreateNode(managedBool, keyword, listingName);
				if (DynamicBools.TryGetKeyword("info", out TerminalKeyword terminalKeyword))
				{
					AddingThings.InfoText(managedBool, keyword, terminalKeyword, listingName);
				}
				if (managedBool.specialNum != -1 && !listingName.specialListNum.ContainsKey(managedBool.TerminalNode))
				{
					listingName.specialListNum.Add(managedBool.TerminalNode, managedBool.specialNum);
					listingName.ListNumToString.Add(managedBool.specialNum, managedBool.specialString);
					Plugin.MoreLogs($"Added viewnode types to dictionaries, {managedBool.specialNum}");
				}
				else if (managedBool.specialString.Length > 1)
				{
					listingName.specialListString.Add(keyword, managedBool.TerminalNode);
					Plugin.MoreLogs("mapping keyword" + keyword + " for " + managedBool.specialString + " node");
				}
			}
		}

		public static void GenerateInfoText(ManagedConfig managedBool)
		{
			if (managedBool == null)
			{
				Plugin.ERROR("managedBool is null @GenerateInfoText()");
			}
			else if (managedBool.KeywordList.Count == 0)
			{
				Plugin.Spam("KeywordList Count = 0 for " + managedBool.ConfigItemName);
			}
			else if (managedBool.InfoAction == null && managedBool.InfoText.Length <= 0)
			{
				if (managedBool.menuItem == null)
				{
					Plugin.Spam("no menu items to grab description from");
				}
				else
				{
					managedBool.DefaultInfoText();
				}
			}
		}

		public static void AddSpecialListString(ref MainListing listingName, TerminalNode node, string special)
		{
			if (listingName.Listing.ContainsKey(node))
			{
				if (listingName.specialListString.ContainsKey(special))
				{
					Plugin.WARNING("Listing already contains special string key " + special);
					return;
				}
				listingName.specialListString.Add(special, node);
				Plugin.Spam(((Object)node).name + " added to special string listing with key " + special);
			}
		}
	}
	public class DynamicBools
	{
		public static bool UseMatchingNode(string nodeName, out TerminalNode returnNode)
		{
			TerminalNode[] array = Object.FindObjectsOfType<TerminalNode>();
			TerminalNode[] array2 = array;
			foreach (TerminalNode val in array2)
			{
				if (((Object)val).name.ToLower().Equals(nodeName.ToLower()))
				{
					returnNode = val;
					Plugin.Spam("Existing terminalNode [" + nodeName + "] found, using it rather than making a new one for this command");
					return true;
				}
			}
			returnNode = null;
			return false;
		}

		public static bool TryGetKeyword(string keyWord)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			foreach (TerminalKeyword item in list)
			{
				if (item.word.ToLower().Equals(keyWord.ToLower()))
				{
					return true;
				}
			}
			return false;
		}

		public static bool TryGetKeyword(string keyWord, out TerminalKeyword terminalKeyword)
		{
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			foreach (TerminalKeyword item in list)
			{
				if (item.word.ToLower().Equals(keyWord.ToLower()))
				{
					Plugin.Spam("Keyword: [" + keyWord + "] found!");
					terminalKeyword = item;
					return true;
				}
			}
			terminalKeyword = null;
			return false;
		}

		public static bool TryGetAndReturnUnlockable(string unlockableName, out UnlockableItem itemOut)
		{
			List<UnlockableItem> list = StartOfRound.Instance.unlockablesList.unlockables.ToList();
			foreach (UnlockableItem item in list)
			{
				if (item.unlockableName.Equals(unlockableName))
				{
					itemOut = item;
					return true;
				}
			}
			itemOut = null;
			return false;
		}

		public static bool TryGetAndReturnItem(string unlockableName, out Item itemOut)
		{
			List<Item> list = Plugin.instance.Terminal.buyableItemsList.ToList();
			foreach (Item item in list)
			{
				if (item.itemName.ToLower().Equals(unlockableName.ToLower()))
				{
					itemOut = item;
					return true;
				}
			}
			itemOut = null;
			return false;
		}

		public static bool IsCommandCreatedAlready(string keyWord, string displayText, List<TerminalKeyword> terminalKeywords)
		{
			foreach (TerminalKeyword terminalKeyword in terminalKeywords)
			{
				if (terminalKeyword.word.ToLower() == keyWord.ToLower() && terminalKeyword.specialKeywordResult.displayText == displayText)
				{
					Plugin.Spam("word: " + keyWord + " found with valid node: " + ((Object)terminalKeyword.specialKeywordResult).name);
					return true;
				}
			}
			return false;
		}

		public static bool IsCommandCreatedAlready(Dictionary<TerminalNode, Func<string>> MainCommandListing, string keyWord, Func<string> commandAction, List<TerminalKeyword> terminalKeywords)
		{
			if (MainCommandListing.Count == 0)
			{
				return false;
			}
			foreach (KeyValuePair<TerminalNode, Func<string>> item in MainCommandListing)
			{
				if (!((Delegate?)item.Value == (Delegate?)commandAction))
				{
					continue;
				}
				foreach (TerminalKeyword terminalKeyword in terminalKeywords)
				{
					if (terminalKeyword.word.ToLower() == keyWord.ToLower() && (Object)(object)terminalKeyword.specialKeywordResult == (Object)(object)item.Key)
					{
						Plugin.Spam("word: " + keyWord + " found with valid node: " + ((Object)terminalKeyword.specialKeywordResult).name);
						return true;
					}
				}
			}
			return false;
		}

		public static bool IsCommandCreatedAlready(Dictionary<TerminalNode, Func<string>> MainCommandListing, string keyWord, Func<string> commandAction, List<TerminalKeyword> terminalKeywords, out TerminalKeyword outKeyword)
		{
			outKeyword = null;
			if (MainCommandListing.Count == 0)
			{
				return false;
			}
			foreach (KeyValuePair<TerminalNode, Func<string>> item in MainCommandListing)
			{
				if (!((Delegate?)item.Value == (Delegate?)commandAction))
				{
					continue;
				}
				foreach (TerminalKeyword terminalKeyword in terminalKeywords)
				{
					if (terminalKeyword.word.ToLower() == keyWord.ToLower() && (Object)(object)terminalKeyword.specialKeywordResult == (Object)(object)item.Key)
					{
						Plugin.Spam("word: " + keyWord + " found with valid node: " + ((Object)terminalKeyword.specialKeywordResult).name);
						outKeyword = terminalKeyword;
						return true;
					}
				}
			}
			return false;
		}

		public static bool DoesNodeExist(Dictionary<TerminalNode, Func<string>> MainCommandListing, Func<string> commandAction, out TerminalNode node)
		{
			node = null;
			if (MainCommandListing.Count == 0)
			{
				return false;
			}
			foreach (KeyValuePair<TerminalNode, Func<string>> item in MainCommandListing)
			{
				if ((Object)(object)item.Key == (Object)null || !((Delegate?)item.Value == (Delegate?)commandAction))
				{
					continue;
				}
				node = item.Key;
				return true;
			}
			return false;
		}
	}
	public class RemoveThings
	{
		public static void OnTerminalDisable()
		{
			Plugin.Spam("OnTerminalDisable called");
			DeleteAllNodes(ref Plugin.nodesAdded);
			DeleteAllNouns(ref Plugin.nounsAdded);
			DeleteCams();
			ConfigSetup.defaultListing.DeleteAll();
		}

		private static void DeleteCams()
		{
			if ((Object)(object)CamStuff.CameraData != (Object)null)
			{
				Object.Destroy((Object)(object)CamStuff.CameraData);
			}
			if ((Object)(object)CamStuff.ObcCameraHolder != (Object)null)
			{
				Object.Destroy((Object)(object)CamStuff.ObcCameraHolder);
			}
			if ((Object)(object)CamStuff.ObcCameraHolder != (Object)null)
			{
				Object.Destroy((Object)(object)CamStuff.ObcCameraHolder);
			}
		}

		[Obsolete("Probably dont need to do this anymore")]
		public static void DeleteNounWord(ref TerminalKeyword keyWord, string terminalKeyword)
		{
			List<CompatibleNoun> list = keyWord.compatibleNouns.ToList();
			List<CompatibleNoun> list2 = new List<CompatibleNoun>();
			foreach (CompatibleNoun item in list)
			{
				if (item.noun.word.ToLower() == terminalKeyword.ToLower())
				{
					list2.Add(item);
				}
			}
			for (int num = list2.Count - 1; num >= 0; num--)
			{
				Plugin.Spam("Deleting noun: " + list2[num].noun.word + " from word: " + keyWord.word);
				Object.Destroy((Object)(object)list2[num].noun);
			}
			keyWord.compatibleNouns = list.ToArray();
		}

		[Obsolete("This doesn't really work right at the moment")]
		public static void RemoveCompatibleNoun(ref TerminalKeyword mainWord, TerminalKeyword wordToRemove)
		{
			bool flag = false;
			if (mainWord.compatibleNouns == null)
			{
				return;
			}
			List<CompatibleNoun> list = new List<CompatibleNoun>();
			CompatibleNoun[] compatibleNouns = mainWord.compatibleNouns;
			foreach (CompatibleNoun val in compatibleNouns)
			{
				if ((Object)(object)val.noun != (Object)(object)wordToRemove)
				{
					list.Add(val);
					continue;
				}
				flag = true;
				Plugin.Spam("Removing " + wordToRemove.word);
			}
			mainWord.compatibleNouns = list.ToArray();
			Plugin.Spam($"DeleteCompatibleNoun of {wordToRemove.word} from {mainWord.word} complete, word removed: {flag}");
		}

		[Obsolete("This doesn't really work right at the moment")]
		public static void RemoveCompatibleNoun(ref TerminalKeyword mainWord, string nounToRemove)
		{
			bool flag = false;
			if (mainWord.compatibleNouns == null)
			{
				return;
			}
			List<CompatibleNoun> list = new List<CompatibleNoun>();
			CompatibleNoun[] compatibleNouns = mainWord.compatibleNouns;
			foreach (CompatibleNoun val in compatibleNouns)
			{
				if (val.noun.word.ToLower() != nounToRemove.ToLower())
				{
					list.Add(val);
					continue;
				}
				flag = true;
				Plugin.Spam("Removing " + nounToRemove);
			}
			mainWord.compatibleNouns = list.ToArray();
			Plugin.Spam($"DeleteCompatibleNoun of {nounToRemove} from {mainWord.word} complete, word removed: {flag}");
		}

		public static void DeleteAllNouns(ref List<CompatibleNoun> nounsToDelete)
		{
			if (nounsToDelete.Count == 0)
			{
				Plugin.Spam("no nouns detected to delete");
				DeleteAllKeywords(ref Plugin.keywordsAdded);
				return;
			}
			List<TerminalKeyword> list = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			foreach (CompatibleNoun noun in nounsToDelete)
			{
				if (list.Any((TerminalKeyword k) => k.compatibleNouns != null && k.compatibleNouns.Contains(noun)))
				{
					List<TerminalKeyword> list2 = list.FindAll((TerminalKeyword k) => k.compatibleNouns != null && k.compatibleNouns.Contains(noun));
					foreach (TerminalKeyword item in list2)
					{
						List<CompatibleNoun> list3 = item.compatibleNouns.ToList();
						if (list3.Remove(noun))
						{
							item.compatibleNouns = list3.ToArray();
							Plugin.Spam(noun.noun.word + " removed from word: " + item.word);
						}
						else
						{
							Plugin.WARNING("Unable to remove compatible noun: " + noun.noun.word + " from word: " + item.word);
						}
					}
				}
				else
				{
					Plugin.WARNING("Unable to find any words " + noun.noun.word + " is associated to");
				}
			}
			Plugin.nounsAdded.Clear();
			Plugin.Spam("DeleteAllNouns Completed");
			DeleteAllKeywords(ref Plugin.keywordsAdded);
		}

		public static void DeleteAllKeywords(ref List<TerminalKeyword> keywordList)
		{
			if (keywordList.Count == 0)
			{
				return;
			}
			List<TerminalKeyword> list = keywordList;
			List<TerminalKeyword> list2 = Plugin.instance.Terminal.terminalNodes.allKeywords.ToList();
			foreach (TerminalKeyword keyword in keywordList)
			{
				for (int num = list2.Count - 1; num >= 0; num--)
				{
					if ((Object)(object)list2[num] == (Object)(object)keyword)
					{
						Plugin.Spam("Removing " + keyword.word + " from all keywords list");
						list2.RemoveAt(num);
						break;
					}
				}
			}
			for (int num2 = list.Count - 1; num2 >= 0; num2--)
			{
				Plugin.Spam("Deleting keyword Object: " + list[num2].word);
				Object.Destroy((Object)(object)list[num2]);
			}
			keywordList.Clear();
			Plugin.instance.Terminal.terminalNodes.allKeywords = list2.ToArray();
		}

		public static void DeleteAllNodes(ref Dictionary<TerminalNode, int> nodeDictionary)
		{
			List<TerminalNode> list = new List<TerminalNode>();
			foreach (KeyValuePair<TerminalNode, int> item in nodeDictionary)
			{
				list.Add(item.Key);
			}
			nodeDictionary.Clear();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				Plugin.Spam("Deleting node: " + ((Object)list[num]).name);
				Object.Destroy((Object)(object)list[num]);
			}
		}

		public static void DeleteAllNodes(ref Dictionary<TerminalNode, Func<string>> nodeDictionary)
		{
			if (nodeDictionary.Count == 0)
			{
				return;
			}
			List<TerminalNode> list = new List<TerminalNode>();
			foreach (KeyValuePair<TerminalNode, Func<string>> item in nodeDictionary)
			{
				list.Add(item.Key);
			}
			nodeDictionary.Clear();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				Plugin.Spam("Deleting node: " + ((Object)list[num]).name);
				Object.Destroy((Object)(object)list[num]);
			}
		}

		public static void DeleteAllNodes(ref List<TerminalNode> nodeList)
		{
			if (nodeList.Count == 0)
			{
				return;
			}
			List<TerminalNode> list = new List<TerminalNode>();
			foreach (TerminalNode node in nodeList)
			{
				list.Add(node);
			}
			nodeList.Clear();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				Plugin.Spam("Deleting node: " + ((Object)list[num]).name);
				Object.Destroy((Object)(object)list[num]);
			}
		}

		public static void DeleteMatchingNode(string nodeName)
		{
			List<TerminalNode> allNodes = LogicHandling.GetAllNodes();
			for (int num = allNodes.Count - 1; num >= 0; num--)
			{
				if (((Object)allNodes[num]).name.Equals(nodeName))
				{
					Object.Destroy((Object)(object)allNodes[num]);
					Plugin.Spam("Node: [" + nodeName + "] removed");
					break;
				}
			}
		}

		public static bool TryGetAndDeleteUnlockableName(string unlockableName, out int indexPos)
		{
			List<UnlockableItem> list = StartOfRound.Instance.unlockablesList.unlockables.ToList();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].unlockableName.Equals(unlockableName))
				{
					Plugin.Spam("Unlockable: [" + unlockableName + "] found! Removing unlockable and noting index position");
					StartOfRound.Instance.unlockablesList.unlockables.Remove(list[num]);
					indexPos = num;
					return true;
				}
			}
			indexPos = -1;
			return false;
		}
	}
	public class LogicHandling
	{
		public static bool GetNewDisplayText(MainListing providedListing, ref TerminalNode node)
		{
			if (providedListing.Listing.Count == 0)
			{
				return false;
			}
			Dictionary<TerminalNode, Func<string>> listing = providedListing.Listing;
			if (listing.Count < 1)
			{
				return false;
			}
			Plugin.Spam("command dictionary is not null in provided listing");
			if ((Object)(object)node == (Object)null)
			{
				return false;
			}
			if (EventManager.GetNewDisplayText.Listeners > 0)
			{
				node = EventManager.GetNewDisplayText.NodeInvoke(ref node);
			}
			if (listing.TryGetValue(node, out var value))
			{
				CommonTerminal.parseNode = node;
				Plugin.Spam("Func<string> found for " + ((Object)node).name);
				node.displayText = value();
				return true;
			}
			Plugin.Spam("Not in special nodeListing dictionary");
			return false;
		}

		public static bool GetNewDisplayText(List<MainListing> providedListing, ref TerminalNode node)
		{
			if (providedListing.Count == 0)
			{
				return false;
			}
			if ((Object)(object)node == (Object)null)
			{
				return false;
			}
			bool result = false;
			int num = 0;
			foreach (MainListing item in providedListing)
			{
				if (item.Listing.Count >= 1)
				{
					Dictionary<TerminalNode, Func<string>> listing = item.Listing;
					num++;
					Plugin.Spam($"command dictionary in this listing is not empty ({num})");
					if (EventManager.GetNewDisplayText.Listeners > 0)
					{
						node = EventManager.GetNewDisplayText.NodeInvoke(ref node);
					}
					if (listing.TryGetValue(node, out var value))
					{
						CommonTerminal.parseNode = node;
						Plugin.MoreLogs("Func<string> found for " + ((Object)node).name + " in one of provided listings");
						node.displayText = value();
						result = true;
						break;
					}
					Plugin.Spam("Not in special nodeListing dictionary");
				}
			}
			Plugin.MoreLogs("provided listings do not contain this node");
			return result;
		}

		public static bool GetDisplayFromFaux(List<FauxKeyword> fauxWords, string words, ref TerminalNode node)
		{
			Plugin.Spam("GetDisplayFromFaux " + words);
			string text = words.Split(new char[1] { ' ' })[0];
			foreach (FauxKeyword fauxWord in fauxWords)
			{
				if (fauxWord.ResultFunc == null || fauxWord.Keyword == null || (Object)(object)fauxWord.MainPage == (Object)null)
				{
					continue;
				}
				fauxWord.thisNode.displayText = "";
				if (words.StartsWith(fauxWord.Keyword.Substring(0, 3), ignoreCase: true, CultureInfo.InvariantCulture) && (Object)(object)Plugin.instance.Terminal.currentNode == (Object)(object)fauxWord.MainPage)
				{
					if (fauxWord.requireExact && words.ToLower() != fauxWord.Keyword.ToLower())
					{
						return false;
					}
					Plugin.Spam("Using faux word associated with MainPage");
					if (fauxWord.ConfirmFunc != null && !fauxWord.GetConfirm)
					{
						fauxWord.GetConfirm = true;
					}
					fauxWord.thisNode.displayText = fauxWord.ResultFunc();
					node = fauxWord.thisNode;
					return true;
				}
				if ((Object)(object)Plugin.instance.Terminal.currentNode == (Object)(object)fauxWord.thisNode && fauxWord.GetConfirm)
				{
					Plugin.Spam("getting confirmation for this faux word");
					if (words.StartsWith("c", ignoreCase: false, null))
					{
						fauxWord.thisNode.displayText = fauxWord.ConfirmFunc();
						node = fauxWord.thisNode;
						fauxWord.GetConfirm = false;
					}
					else if (words.StartsWith("d", ignoreCase: false, null))
					{
						fauxWord.thisNode.displayText = fauxWord.DenyFunc();
						node = fauxWord.thisNode;
						fauxWord.GetConfirm = false;
					}
					else
					{
						if (!words.StartsWith(fauxWord.Keyword, ignoreCase: false, null))
						{
							return false;
						}
						fauxWord.thisNode.displayText = fauxWord.ResultFunc();
						node = fauxWord.thisNode;
					}
					return true;
				}
				if (!words.StartsWith(fauxWord.Keyword.Substring(0, 3), ignoreCase: true, CultureInfo.InvariantCulture) || !fauxWords.Any((FauxKeyword f) => (Object)(object)f.thisNode == (Object)(object)Plugin.instance.Terminal.currentNode && f.AllowOtherFauxWords))
				{
					continue;
				}
				if (fauxWord.requireExact && words.ToLower() != fauxWord.Keyword.ToLower())
				{
					return false;
				}
				Plugin.Spam("Using faux word that can be called from other fauxwords");
				if (fauxWord.ConfirmFunc != null && !fauxWord.GetConfirm)
				{
					fauxWord.GetConfirm = true;
				}
				fauxWord.thisNode.displayText = fauxWord.ResultFunc();
				node = fauxWord.thisNode;
				return true;
			}
			return false;
		}

		public static bool TryGetFuncFromNode(List<MainListing> providedListing, ref TerminalNode node, out Func<string> returnFunc)
		{
			if ((Object)(object)node == (Object)null || providedListing.Count == 0)
			{
				Plugin.WARNING("node is null or listings do not exist");
				returnFunc = null;
				return false;
			}
			int num = 0;
			foreach (MainListing item in providedListing)
			{
				Dictionary<TerminalNode, Func<string>> listing = item.Listing;
				if (listing.Count >= 1)
				{
					num++;
					Plugin.Spam($"command dictionary in this listing is not null ({num})");
					if (listing.TryGetValue(node, out var value))
					{
						Plugin.MoreLogs("Func<string> found for " + ((Object)node).name + " in one of provided listings");
						returnFunc = value;
						return true;
					}
					Plugin.Spam("Not in this special nodeListing dictionary");
				}
			}
			Plugin.MoreLogs("provided listings do not contain this node");
			returnFunc = null;
			return false;
		}

		public static bool TryGetFromAllNodes(string nodeName, out TerminalNode outNode)
		{
			List<TerminalNode> allNodes = GetAllNodes();
			outNode = null;
			foreach (TerminalNode item in allNodes)
			{
				if ((Object)(object)item == (Object)null || !(((Object)item).name == nodeName))
				{
					continue;
				}
				Plugin.Spam(nodeName + " found!");
				outNode = item;
				return true;
			}
			Plugin.Spam(nodeName + " could not be found, result set to null.");
			return false;
		}

		public static List<TerminalNode> GetAllNodes()
		{
			return Resources.FindObjectsOfTypeAll<TerminalNode>().ToList();
		}

		public static void SetTerminalInput(string terminalInput)
		{
			Plugin.instance.Terminal.TextChanged(Plugin.instance.Terminal.currentText.Substring(0, Plugin.instance.Terminal.currentText.Length - Plugin.instance.Terminal.textAdded) + terminalInput);
			Plugin.instance.Terminal.screenText.text = Plugin.instance.Terminal.currentText;
			Plugin.instance.Terminal.textAdded = terminalInput.Length;
		}

		[Obsolete("Use TryGetFuncFromNode instead to avoid getting NULL funcs")]
		public static Func<string> GetFuncFromNode(List<MainListing> providedListing, ref TerminalNode node)
		{
			if ((Object)(object)node == (Object)null || providedListing.Count == 0)
			{
				Plugin.WARNING("node is null or listings do not exist");
				return null;
			}
			int num = 0;
			foreach (MainListing item in providedListing)
			{
				Dictionary<TerminalNode, Func<string>> listing = item.Listing;
				if (listing.Count >= 1)
				{
					num++;
					Plugin.Spam($"command dictionary in this listing is not null ({num})");
					if (listing.TryGetValue(node, out var value))
					{
						Plugin.MoreLogs("Func<string> found for " + ((Object)node).name + " in one of provided listings");
						return value;
					}
					Plugin.Spam("Not in this special nodeListing dictionary");
				}
			}
			Plugin.MoreLogs("provided listings do not contain this node");
			return null;
		}

		[Obsolete("Use TryGetFromAllNodes instead to avoid getting NULL funcs")]
		public static TerminalNode GetFromAllNodes(string nodeName)
		{
			List<TerminalNode> allNodes = GetAllNodes();
			foreach (TerminalNode item in allNodes)
			{
				if ((Object)(object)item == (Object)null || !(((Object)item).name == nodeName))
				{
					continue;
				}
				Plugin.Spam(nodeName + " found!");
				return item;
			}
			Plugin.Spam(nodeName + " could not be found, result set to null.");
			return null;
		}
	}
}
namespace OpenLib.ConfigManager
{
	public class ConfigHelper
	{
		public static List<string> GetAcceptableValues(AcceptableValueBase acceptableValueBase)
		{
			List<string> result = new List<string>();
			if (acceptableValueBase == null)
			{
				return result;
			}
			string text = acceptableValueBase.ToDescriptionString();
			text = text.Replace("# Acceptable values:", "").Replace(" ", "");
			return CommonStringStuff.GetKeywordsPerConfigItem(text, ',');
		}

		public static List<float> GetAcceptableValueF(AcceptableValueBase acceptableValueBase)
		{
			List<float> result = new List<float>();
			if (acceptableValueBase == null)
			{
				return result;
			}
			string text = acceptableValueBase.ToDescriptionString();
			Plugin.Spam(text);
			text = text.Replace("# Acceptable value range: From ", "").Replace("to", "").Replace(" ", ",");
			return CommonStringStuff.GetFloatListFromStringList(CommonStringStuff.GetKeywordsPerConfigItem(text, ','));
		}

		public static void ChangeBool(ConfigFile ModConfig, ConfigEntryBase configItem, string newValue)
		{
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			if (newValue.Length != 0 && ModConfig.TryGetEntry<bool>(configItem.Definition, ref val))
			{
				if (newValue == "true")
				{
					val.Value = true;
				}
				else
				{
					val.Value = false;
				}
			}
		}

		public static void ChangeString(ConfigFile ModConfig, ConfigEntryBase configItem, string newValue)
		{
			ConfigEntry<string> val = default(ConfigEntry<string>);
			if (newValue.Length != 0 && ModConfig.TryGetEntry<string>(configItem.Definition, ref val))
			{
				val.Value = newValue;
			}
		}

		public static void ChangeInt(ConfigFile ModConfig, ConfigEntryBase configItem, string newValue)
		{
			ConfigEntry<int> val = default(ConfigEntry<int>);
			if (newValue.Length != 0 && ModConfig.TryGetEntry<int>(configItem.Definition, ref val))
			{
				val.Value = int.Parse(newValue);
			}
		}

		public static void ChangeFloat(ConfigFile ModConfig, ConfigEntryBase configItem, string newValue)
		{
			ConfigEntry<float> val = default(ConfigEntry<float>);
			if (newValue.Length != 0 && ModConfig.TryGetEntry<float>(configItem.Definition, ref val))
			{
				val.Value = float.Parse(newValue);
			}
		}

		public static bool TryFindConfigItem(string query, ConfigFile ModConfig, out ConfigEntryBase configItem)
		{
			Dictionary<ConfigDefinition, ConfigEntryBase> dictionary = new Dictionary<ConfigDefinition, ConfigEntryBase>();
			ConfigEntryBase[] configEntries = ModConfig.GetConfigEntries();
			foreach (ConfigEntryBase val in configEntries)
			{
				dictionary.Add(val.Definition, val);
				Plugin.Spam($"added {val.Definition} to list of configItems to check");
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in dictionary)
			{
				if (item.Key.Key == query)
				{
					configItem = item.Value;
					return true;
				}
			}
			configItem = null;
			return false;
		}
	}
	public class ConfigMisc
	{
		public static bool CheckChangedConfigSetting(List<ManagedConfig> managedItems, ConfigEntryBase entryBase)
		{
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			ConfigEntry<string> val2 = default(ConfigEntry<string>);
			foreach (ManagedConfig managedItem in managedItems)
			{
				if (!(managedItem.configDescription == entryBase.Description.Description))
				{
					continue;
				}
				if (entryBase.BoxedValue.GetType() == typeof(bool))
				{
					if (entryBase.ConfigFile.TryGetEntry<bool>(entryBase.Definition, ref val))
					{
						if (managedItem.BoolValue != val.Value)
						{
							managedItem.ConfigChange(val.Value);
							Plugin.Spam("Updating config item: " + ((ConfigEntryBase)val).Definition.Key + " in managedItems");
							return true;
						}
						Plugin.Spam("item value matches config item: " + ((ConfigEntryBase)val).Definition.Key);
					}
				}
				else if (entryBase.BoxedValue.GetType() == typeof(string) && entryBase.ConfigFile.TryGetEntry<string>(entryBase.Definition, ref val2))
				{
					if (managedItem.StringValue != val2.Value)
					{
						managedItem.ConfigChange(val2.Value);
						Plugin.Spam("Updating config item: " + ((ConfigEntryBase)val2).Definition.Key + " in managedItems");
						List<string> keywordsPerConfigItem = CommonStringStuff.GetKeywordsPerConfigItem(val2.Value);
						managedItem.relatedConfigItem.KeywordList = keywordsPerConfigItem;
						return true;
					}
					Plugin.Spam("item value matches config item: " + ((ConfigEntryBase)val2).Definition.Key);
				}
			}
			Plugin.Spam("could not match changed config setting to any managed config items");
			return false;
		}

		public static bool ShouldReloadConfigNow(ConfigEntry<string> entry)
		{
			if ((Object)(object)Plugin.instance.Terminal != (Object)null)
			{
				if (!EventUsage.configsToReload.Contains(((ConfigEntryBase)entry).ConfigFile))
				{
					EventUsage.configsToReload.Add(((ConfigEntryBase)entry).ConfigFile);
				}
				return false;
			}
			return true;
		}
	}
	public class ConfigSync
	{
		public static void UpdateFromHost(string key, bool value, ConfigFile myConfig)
		{
			if (ConfigHelper.TryFindConfigItem(key, myConfig, out ConfigEntryBase configItem) && ((object)configItem).GetType() == typeof(bool))
			{
				ConfigEntry<bool> val = configItem as ConfigEntry<bool>;
				if (val.Value == value)
				{
					Plugin.Spam($"Config - {key} verified set to {value}");
					return;
				}
				val.Value = value;
				Plugin.WARNING($"Config sync has updated {key} to {value}");
			}
		}

		public static void UpdateFromH