Decompiled source of LethalAccess v1.0.5

BepInEx/plugins/Lethal Access/LethalAccess Remake.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using Green.LethalAccess;
using Green.LethalAccess.Patches;
using GreenBean.LethalSpeechOutput;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LethalAccess Remake")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LethalAccess Remake")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("921084e6-f5ac-4a1f-9d36-75ba292096cd")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[HarmonyPatch(typeof(GrabbableObject), "ItemInteractLeftRightOnClient")]
internal class ItemInteractLeftRightOnClientPatch
{
	private static void Prefix(PlayerControllerB __instance, ref bool __state)
	{
		__state = ((Behaviour)__instance).enabled;
		((Behaviour)__instance).enabled = true;
	}

	private static void Postfix(PlayerControllerB __instance, bool __state)
	{
		((Behaviour)__instance).enabled = __state;
	}
}
[HarmonyPatch(typeof(StartOfRound), "StartGame")]
internal class StartOfRoundNavMeshPatch
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		Pathfinder.RemoveNavMeshAgentFromPlayer();
	}
}
[HarmonyPatch(typeof(PlayerControllerB))]
internal class PlayerControllerBFallDamagePatch
{
	[HarmonyPrefix]
	[HarmonyPatch("PlayerHitGroundEffects")]
	private static bool Prefix(PlayerControllerB __instance, ref float ___fallValue)
	{
		if (Pathfinder.ShouldPreventFallDamage)
		{
			__instance.takingFallDamage = false;
			___fallValue = 0f;
			return false;
		}
		return true;
	}
}
public class UnityMainThreadDispatcher : MonoBehaviour
{
	private static UnityMainThreadDispatcher _instance;

	private readonly Queue<Action> _executionQueue = new Queue<Action>();

	public static UnityMainThreadDispatcher Instance()
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		if (!Object.op_Implicit((Object)(object)_instance))
		{
			_instance = Object.FindObjectOfType(typeof(UnityMainThreadDispatcher)) as UnityMainThreadDispatcher;
			if (!Object.op_Implicit((Object)(object)_instance))
			{
				GameObject val = new GameObject("UnityMainThreadDispatcher");
				_instance = val.AddComponent<UnityMainThreadDispatcher>();
			}
		}
		return _instance;
	}

	private void Update()
	{
		lock (_executionQueue)
		{
			while (_executionQueue.Count > 0)
			{
				_executionQueue.Dequeue()();
			}
		}
	}

	public void Enqueue(Action action)
	{
		lock (_executionQueue)
		{
			_executionQueue.Enqueue(action);
		}
	}

	public Task EnqueueAsync(Action action)
	{
		TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
		Enqueue(delegate
		{
			try
			{
				action();
				tcs.SetResult(result: true);
			}
			catch (Exception exception)
			{
				tcs.SetException(exception);
			}
		});
		return tcs.Task;
	}
}
namespace Green.LethalAccess
{
	[BepInPlugin("Green.LethalAccess.NavMesh", "NavMesh", "1.0.0")]
	public class CompanyNavMesh : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(DepositItemsDesk), "Start")]
		internal class DepositItemsDeskPatch
		{
			[HarmonyPostfix]
			internal static void StartPatch(DepositItemsDesk __instance)
			{
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					GameObject[] array = GameObject.FindGameObjectsWithTag("OutsideAINode");
					GameObject[] array2 = array;
					foreach (GameObject val in array2)
					{
						Object.Destroy((Object)(object)val);
					}
					GameObject[] array3 = GameObject.FindGameObjectsWithTag("AINode");
					GameObject[] array4 = array3;
					foreach (GameObject val2 in array4)
					{
						Object.Destroy((Object)(object)val2);
					}
					Debug.Log((object)"Instantiating Company Navigation!");
					Transform transform = Object.Instantiate<GameObject>(navPrefab, ((Component)__instance).transform.parent, true).transform;
					transform.position = Vector3.zero;
					transform.rotation = Quaternion.identity;
					transform.localScale = Vector3.one;
					Transform child = transform.GetChild(0);
					RoundManager.Instance.outsideAINodes = (GameObject[])(object)new GameObject[child.childCount];
					for (int k = 0; k < child.childCount; k++)
					{
						RoundManager.Instance.outsideAINodes[k] = ((Component)child.GetChild(k)).gameObject;
					}
					Transform child2 = transform.GetChild(1);
					RoundManager.Instance.insideAINodes = (GameObject[])(object)new GameObject[child2.childCount];
					for (int l = 0; l < child2.childCount; l++)
					{
						RoundManager.Instance.insideAINodes[l] = ((Component)child2.GetChild(l)).gameObject;
					}
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		private static GameObject navPrefab;

		private void Awake()
		{
			AssetBundle val = AssetBundle.LoadFromStream(ResourceUtils.Get(".bundle"));
			if ((Object)(object)val != (Object)null)
			{
				navPrefab = val.LoadAsset<GameObject>("CompanyNavSurface.prefab");
				val.Unload(false);
			}
			else
			{
				Debug.LogError((object)"Failed to load asset bundle.");
			}
			Harmony.CreateAndPatchAll(typeof(DepositItemsDeskPatch), (string)null);
		}
	}
	public static class ResourceUtils
	{
		public static Stream Get(string name)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			if (manifestResourceNames.Length == 0)
			{
				throw new FileNotFoundException("Assembly does not contain any resource stream names.");
			}
			string text = manifestResourceNames.FirstOrDefault((string n) => n.EndsWith(name));
			if (string.IsNullOrEmpty(text))
			{
				throw new FileNotFoundException("Assembly does not contain a resource stream ending with '" + name + "'");
			}
			return executingAssembly.GetManifestResourceStream(text);
		}
	}
	public class NavMenu : MonoBehaviour
	{
		public struct CategoryItemIndices
		{
			public int categoryIndex;

			public int itemIndex;

			public CategoryItemIndices(int categoryIndex, int itemIndex)
			{
				this.categoryIndex = categoryIndex;
				this.itemIndex = itemIndex;
			}
		}

		private const float ScanRadius = 80f;

		private const string ItemsCategoryName = "Items";

		private const string UnlabeledCategoryName = "Unlabeled Nearby Objects";

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

		private Dictionary<string, string> displayNames = new Dictionary<string, string>();

		private Dictionary<string, string> sceneNames = new Dictionary<string, string>();

		private Dictionary<string, Vector3> registeredCoordinates = new Dictionary<string, Vector3>();

		public List<string> categories = new List<string>();

		private Dictionary<string, bool> categoryVisibility = new Dictionary<string, bool>();

		public CategoryItemIndices currentIndices = new CategoryItemIndices(0, 0);

		private List<string> ignoreKeywords = new List<string>
		{
			"Floor", "Wall", "Ceiling", "Terrain", "Collider", "collider", "scannode", "cube", "plane", "trigger",
			"placementcollider", "volume", "outofbounds", "mesh", "pipe", "hanginglight", "terrainmap", "cylinder", "bone", "elbow",
			"arm", "thigh", "spine", "playerphysicsbox", "shin", "player", "body", "placement", "tree", "road",
			"rock", "optimized", "wall", "container", "lineofsight2", "audio", "anomaly"
		};

		private Dictionary<string, bool> previousCategoryVisibility = new Dictionary<string, bool>();

		public void Initialize()
		{
			try
			{
				Debug.Log((object)"NavMenu: Initializing input actions.");
				LethalAccess.Instance.RegisterKeybind("MoveToNextItem", (Key)12, MoveToNextItem);
				LethalAccess.Instance.RegisterKeybind("MoveToPreviousItem", (Key)11, MoveToPreviousItem);
				LethalAccess.Instance.RegisterKeybind("MoveToNextCategory", (Key)14, MoveToNextCategory);
				LethalAccess.Instance.RegisterKeybind("MoveToPreviousCategory", (Key)13, MoveToPreviousCategory);
				LethalAccess.Instance.RegisterKeybind("RefreshCurrentCategory", (Key)6, RefreshCurrentCategory);
				menuItems["Items"] = new List<string>();
				categories.Add("Items");
				categoryVisibility["Items"] = true;
				menuItems["Unlabeled Nearby Objects"] = new List<string>();
				categories.Add("Unlabeled Nearby Objects");
				categoryVisibility["Unlabeled Nearby Objects"] = true;
				Debug.Log((object)"NavMenu: Input actions are registered.");
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("NavMenu: Error during initialization: " + ex.Message));
			}
		}

		public void RemoveItem(string gameObjectName, string category)
		{
			if (menuItems.TryGetValue(category, out var value))
			{
				value.Remove(gameObjectName);
				Debug.Log((object)("Removed item '" + gameObjectName + "' from category '" + category + "'"));
			}
		}

		public void RefreshMenu()
		{
			currentIndices.itemIndex = 0;
			SpeakCategoryAndFirstItem();
		}

		public void RegisterMenuItem(string gameObjectName, string displayName, string category, string sceneName = "", Vector3? coordinates = null)
		{
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (string.IsNullOrWhiteSpace(gameObjectName))
				{
					Debug.LogError((object)"NavMenu: gameObjectName cannot be null or empty.");
					return;
				}
				if (string.IsNullOrWhiteSpace(displayName))
				{
					Debug.LogError((object)"NavMenu: displayName cannot be null or empty.");
					return;
				}
				if (string.IsNullOrWhiteSpace(category))
				{
					Debug.LogError((object)"NavMenu: category cannot be null or empty.");
					return;
				}
				gameObjectName = gameObjectName.Trim();
				displayName = displayName.Trim();
				category = category.Trim();
				displayNames[gameObjectName] = displayName;
				if (!string.IsNullOrWhiteSpace(sceneName))
				{
					sceneNames[gameObjectName] = sceneName.Trim();
				}
				if (!menuItems.ContainsKey(category))
				{
					menuItems[category] = new List<string>();
					if (category == "Unlabeled Nearby Objects")
					{
						categories.Add(category);
					}
					else
					{
						int num = categories.IndexOf("Unlabeled Nearby Objects");
						if (num != -1)
						{
							categories.Insert(num, category);
						}
						else
						{
							categories.Add(category);
						}
					}
					categoryVisibility[category] = true;
					Debug.Log((object)("NavMenu: Added new category: " + category));
				}
				if (menuItems[category].Contains(gameObjectName))
				{
					Debug.LogWarning((object)("NavMenu: Item '" + gameObjectName + "' already exists in category '" + category + "'. Skipping addition."));
					return;
				}
				menuItems[category].Add(gameObjectName);
				if (coordinates.HasValue)
				{
					registeredCoordinates[gameObjectName] = coordinates.Value;
					Debug.Log((object)$"NavMenu: Registered new item '{displayName}' ({gameObjectName}) at coordinates {coordinates.Value} in category '{category}'. Total items in this category: {menuItems[category].Count}");
				}
				else
				{
					Debug.Log((object)$"NavMenu: Registered new item '{displayName}' ({gameObjectName}) in category '{category}'. Total items in this category: {menuItems[category].Count}");
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("NavMenu: Error registering menu item: " + ex.Message));
			}
		}

		private void MoveToNextItem()
		{
			if (categories.Count <= 0)
			{
				return;
			}
			string text = categories[currentIndices.categoryIndex];
			List<string> list = menuItems[text];
			if (list.Count > 0)
			{
				currentIndices.itemIndex = (currentIndices.itemIndex + 1) % list.Count;
				string gameObjectName = list[currentIndices.itemIndex];
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					GameObject val = FindGameObjectByName(gameObjectName);
					string displayNameForObject = GetDisplayNameForObject(val);
					if ((Object)(object)val != (Object)null)
					{
						LethalAccess.currentLookTarget = val;
						Utilities.SpeakText(displayNameForObject);
					}
					else
					{
						Utilities.SpeakText(gameObjectName + ", Not found nearby");
					}
				});
			}
			else
			{
				Utilities.SpeakText("No items in category " + text);
			}
		}

		private void MoveToPreviousItem()
		{
			if (categories.Count <= 0)
			{
				return;
			}
			string text = categories[currentIndices.categoryIndex];
			List<string> list = menuItems[text];
			if (list.Count > 0)
			{
				currentIndices.itemIndex = (currentIndices.itemIndex - 1 + list.Count) % list.Count;
				string gameObjectName = list[currentIndices.itemIndex];
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					GameObject val = FindGameObjectByName(gameObjectName);
					string displayNameForObject = GetDisplayNameForObject(val);
					if ((Object)(object)val != (Object)null)
					{
						LethalAccess.currentLookTarget = val;
						Utilities.SpeakText(displayNameForObject);
					}
					else
					{
						Utilities.SpeakText(gameObjectName + ", Not found nearby");
					}
				});
			}
			else
			{
				Utilities.SpeakText("No items in category " + text);
			}
		}

		private async void MoveToNextCategory()
		{
			if (categories.Count > 0)
			{
				do
				{
					currentIndices.categoryIndex = (currentIndices.categoryIndex + 1) % categories.Count;
				}
				while (!categoryVisibility[categories[currentIndices.categoryIndex]]);
				currentIndices.itemIndex = 0;
				string currentCategory = categories[currentIndices.categoryIndex];
				if (currentCategory == "Items" || currentCategory == "Unlabeled Nearby Objects")
				{
					await RefreshCategory(currentCategory);
				}
				AnnounceCategoryAndFirstItem();
			}
		}

		private async void MoveToPreviousCategory()
		{
			if (categories.Count > 0)
			{
				do
				{
					currentIndices.categoryIndex = (currentIndices.categoryIndex - 1 + categories.Count) % categories.Count;
				}
				while (!categoryVisibility[categories[currentIndices.categoryIndex]]);
				currentIndices.itemIndex = 0;
				string currentCategory = categories[currentIndices.categoryIndex];
				if (currentCategory == "Items" || currentCategory == "Unlabeled Nearby Objects")
				{
					await RefreshCategory(currentCategory);
				}
				AnnounceCategoryAndFirstItem();
			}
		}

		private void AnnounceCategoryAndFirstItem()
		{
			if (categories.Count <= 0)
			{
				return;
			}
			string text = categories[currentIndices.categoryIndex];
			List<string> list = menuItems[text];
			if (list.Count > 0)
			{
				string text2 = list[0];
				GameObject val = FindGameObjectByName(text2);
				string displayNameForObject = GetDisplayNameForObject(val);
				if ((Object)(object)val != (Object)null)
				{
					Utilities.SpeakText(text + ", " + displayNameForObject);
					SetCurrentLookTarget(val);
				}
				else
				{
					Utilities.SpeakText(text + ", " + text2 + ", Not found nearby");
				}
			}
			else
			{
				Utilities.SpeakText(text + ", No items");
			}
		}

		private void SetCurrentLookTarget(GameObject target)
		{
			if ((Object)(object)target != (Object)null)
			{
				LethalAccess.currentLookTarget = target;
			}
		}

		private async void RefreshCurrentCategory()
		{
			if (categories.Count > 0)
			{
				string currentCategory = categories[currentIndices.categoryIndex];
				await RefreshCategory(currentCategory);
				currentIndices.itemIndex = 0;
				SpeakCategoryAndFirstItem();
				SetCurrentLookTargetToFirstItem();
			}
		}

		public async Task RefreshCategory(string category)
		{
			List<string> items = new List<string>();
			List<string> existingItems;
			if (category == "Items")
			{
				items = await ScanForItemsAsync();
			}
			else if (category == "Unlabeled Nearby Objects")
			{
				items = await ScanForUnlabeledObjectsAsync();
			}
			else if (menuItems.TryGetValue(category, out existingItems))
			{
				items = new List<string>(existingItems);
			}
			await UnityMainThreadDispatcher.Instance().EnqueueAsync(delegate
			{
				menuItems[category] = items;
				currentIndices.itemIndex = 0;
				Debug.Log((object)$"Refreshed category '{category}' with {items.Count} items.");
			});
		}

		private async Task<List<string>> ScanForItemsAsync()
		{
			return await Task.Run(delegate
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				List<string> list = new List<string>();
				Collider[] source = Physics.OverlapSphere(LethalAccess.PlayerTransform.position, 80f);
				DepositItemsDesk depositItemsDesk = Object.FindObjectOfType<DepositItemsDesk>();
				List<Collider> list2 = (from c in source.Where(delegate(Collider c)
					{
						GrabbableObject component2 = ((Component)c).GetComponent<GrabbableObject>();
						return (Object)(object)component2 != (Object)null && !component2.isHeld && !component2.isPocketed && !component2.deactivated && ((Object)(object)depositItemsDesk == (Object)null || !depositItemsDesk.itemsOnCounter.Contains(component2));
					})
					orderby Vector3.Distance(LethalAccess.PlayerTransform.position, ((Component)c).transform.position)
					select c).ToList();
				foreach (Collider item in list2)
				{
					GrabbableObject component = ((Component)item).GetComponent<GrabbableObject>();
					if ((Object)(object)component != (Object)null)
					{
						string itemName = component.itemProperties.itemName;
						if (!string.IsNullOrEmpty(itemName))
						{
							string gameObjectName = ((Object)((Component)item).gameObject).name;
							list.Add(gameObjectName);
							UnityMainThreadDispatcher.Instance().Enqueue(delegate
							{
								RegisterMenuItem(gameObjectName, itemName, "Items");
							});
						}
						else
						{
							list.Add(((Object)((Component)item).gameObject).name);
						}
					}
				}
				return list;
			});
		}

		private async Task<List<string>> ScanForUnlabeledObjectsAsync()
		{
			return await Task.Run(delegate
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				List<string> list = new List<string>();
				Collider[] source = Physics.OverlapSphere(LethalAccess.PlayerTransform.position, 80f);
				List<Collider> list2 = (from c in source
					where !ignoreKeywords.Any((string keyword) => ((Object)((Component)c).gameObject).name.ToLower().Contains(keyword.ToLower()))
					orderby Vector3.Distance(LethalAccess.PlayerTransform.position, ((Component)c).transform.position)
					select c).ToList();
				foreach (Collider item in list2)
				{
					string gameObjectName = ((Object)((Component)item).gameObject).name;
					list.Add(gameObjectName);
					UnityMainThreadDispatcher.Instance().Enqueue(delegate
					{
						RegisterMenuItem(gameObjectName, gameObjectName, "Unlabeled Nearby Objects");
					});
				}
				return list;
			});
		}

		private void SpeakCategoryAndFirstItem()
		{
			if (categories.Count <= 0)
			{
				return;
			}
			string text = categories[currentIndices.categoryIndex];
			List<string> list = menuItems[text];
			if (list.Count > 0)
			{
				string text2 = list[0];
				GameObject val = FindGameObjectByName(text2);
				string displayNameForObject = GetDisplayNameForObject(val);
				if ((Object)(object)val != (Object)null)
				{
					Utilities.SpeakText(text + ", " + displayNameForObject);
				}
				else
				{
					Utilities.SpeakText(text + ", " + text2 + ", Not found nearby");
				}
			}
			else
			{
				Utilities.SpeakText(text + ", No items");
			}
		}

		private void SetCurrentLookTargetToFirstItem()
		{
			if (categories.Count <= 0)
			{
				return;
			}
			string text = categories[currentIndices.categoryIndex];
			if (menuItems.ContainsKey(text) && menuItems[text].Count > 0)
			{
				string gameObjectName = menuItems[text][0];
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					GameObject val = FindGameObjectByName(gameObjectName);
					if ((Object)(object)val != (Object)null)
					{
						LethalAccess.currentLookTarget = val;
						string displayNameForObject = GetDisplayNameForObject(val);
					}
				});
			}
			else
			{
				Utilities.SpeakText("No items in " + text);
			}
		}

		private GameObject FindGameObjectByName(string gameObjectName)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (sceneNames.TryGetValue(gameObjectName, out var value))
				{
					Scene sceneByName = SceneManager.GetSceneByName(value);
					if (((Scene)(ref sceneByName)).isLoaded)
					{
						GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
						GameObject[] array = rootGameObjects;
						foreach (GameObject val in array)
						{
							Transform obj = val.transform.Find(gameObjectName);
							GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null);
							if ((Object)(object)val2 != (Object)null)
							{
								return val2;
							}
						}
					}
				}
				GameObject[] array2 = Object.FindObjectsOfType<GameObject>();
				GameObject[] array3 = array2;
				foreach (GameObject val3 in array3)
				{
					if (((Object)val3).name == gameObjectName)
					{
						return val3;
					}
				}
				if (registeredCoordinates.TryGetValue(gameObjectName, out var value2))
				{
					GameObject val4 = new GameObject(gameObjectName);
					val4.transform.position = value2;
					Debug.Log((object)$"Created new GameObject '{gameObjectName}' at coordinates {value2}");
					return val4;
				}
				Debug.LogWarning((object)("GameObject with name '" + gameObjectName + "' not found in the scene."));
				return null;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("NavMenu: Error finding GameObject: " + ex.Message));
				return null;
			}
		}

		public string GetDisplayNameForObject(GameObject gameObject)
		{
			if ((Object)(object)gameObject != (Object)null)
			{
				string name = ((Object)gameObject).name;
				switch (name)
				{
				case "EntranceTeleportA":
					return "Enter Factory";
				case "EntranceTeleportA(Clone)":
					return "Exit Factory";
				case "EntranceTeleportB":
					return "Enter Fire Escape";
				case "EntranceTeleportB(Clone)":
					return "Exit Fire Escape";
				default:
				{
					if (displayNames.TryGetValue(name, out var value))
					{
						return value;
					}
					return name;
				}
				}
			}
			if (currentIndices.categoryIndex < categories.Count)
			{
				string key = categories[currentIndices.categoryIndex];
				if (currentIndices.itemIndex < menuItems[key].Count)
				{
					string text = menuItems[key][currentIndices.itemIndex];
					if (displayNames.TryGetValue(text, out var value2))
					{
						return value2;
					}
					return text;
				}
			}
			return "Unknown Object";
		}

		public void HideCategory(string category)
		{
			if (categoryVisibility.ContainsKey(category))
			{
				categoryVisibility[category] = false;
			}
		}

		public void UnhideCategory(string category)
		{
			if (categoryVisibility.ContainsKey(category))
			{
				categoryVisibility[category] = true;
			}
		}

		public void UpdateCategoriesVisibility(bool isShipLanded, string currentPlanetName)
		{
			if (isShipLanded)
			{
				UpdateCategoryVisibility("Factory", currentPlanetName != "71 Gordion");
				UpdateCategoryVisibility("Company Building", currentPlanetName == "71 Gordion");
			}
			else
			{
				UpdateCategoryVisibility("Factory", shouldBeVisible: false);
				UpdateCategoryVisibility("Company Building", shouldBeVisible: false);
			}
		}

		private void UpdateCategoryVisibility(string category, bool shouldBeVisible)
		{
			if (!previousCategoryVisibility.ContainsKey(category) || previousCategoryVisibility[category] != shouldBeVisible)
			{
				if (shouldBeVisible)
				{
					UnhideCategory(category);
					Utilities.SpeakText(category + " category is now available.");
				}
				else
				{
					HideCategory(category);
					Utilities.SpeakText(category + " category is now hidden.");
				}
				previousCategoryVisibility[category] = shouldBeVisible;
			}
		}
	}
	public class NorthSoundManager : MonoBehaviour
	{
		private AudioSource audioSource;

		public bool isEnabled = false;

		private float playInterval = 1.5f;

		private float volume = 0.15f;

		private float normalFrequency = 440f;

		private float behindFrequency = 220f;

		private static ConfigEntry<float> configPlayInterval;

		private void Start()
		{
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.spatialize = true;
			audioSource.spatialBlend = 1f;
			audioSource.volume = volume;
			audioSource.loop = false;
			audioSource.playOnAwake = false;
			audioSource.dopplerLevel = 0f;
			audioSource.rolloffMode = (AudioRolloffMode)1;
			audioSource.maxDistance = 1000f;
			configPlayInterval = ((BaseUnityPlugin)LethalAccess.Instance).Config.Bind<float>("Values", "NorthSoundPlayInterval", 1.5f, "The delay in seconds between North sound plays");
			playInterval = configPlayInterval.Value;
		}

		private void Update()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (isEnabled)
			{
				Vector3 forward = Vector3.forward;
				((Component)this).transform.position = LethalAccess.PlayerTransform.position + forward * 10f;
				((Component)this).transform.LookAt(LethalAccess.PlayerTransform);
			}
		}

		public void ToggleNorthSound()
		{
			isEnabled = !isEnabled;
			if (isEnabled)
			{
				((MonoBehaviour)this).StartCoroutine(PlayNorthSoundRoutine());
				return;
			}
			((MonoBehaviour)this).StopAllCoroutines();
			audioSource.Stop();
		}

		private IEnumerator PlayNorthSoundRoutine()
		{
			while (isEnabled)
			{
				bool isBehindPlayer = IsSoundBehindPlayer();
				audioSource.clip = GenerateNorthSound(isBehindPlayer);
				audioSource.Play();
				yield return (object)new WaitForSeconds(playInterval);
			}
		}

		private AudioClip GenerateNorthSound(bool isBehindPlayer)
		{
			int num = 44100;
			float num2 = (isBehindPlayer ? behindFrequency : normalFrequency);
			float num3 = 0.2f;
			int num4 = Mathf.CeilToInt((float)num * num3);
			float[] array = new float[num4];
			for (int i = 0; i < num4; i++)
			{
				float num5 = (float)i / (float)num;
				array[i] = Mathf.Sin((float)Math.PI * 2f * num2 * num5);
			}
			AudioClip val = AudioClip.Create("NorthSound", num4, 1, num, false);
			val.SetData(array, 0);
			return val;
		}

		private bool IsSoundBehindPlayer()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 forward = LethalAccess.PlayerTransform.forward;
			Vector3 val = ((Component)this).transform.position - LethalAccess.PlayerTransform.position;
			float num = Vector3.Dot(forward, ((Vector3)(ref val)).normalized);
			return num < 0f;
		}

		public void UpdatePlayInterval(float newInterval)
		{
			playInterval = newInterval;
			configPlayInterval.Value = newInterval;
		}
	}
	[HarmonyPatch(typeof(SaveFileUISlot))]
	public static class SaveFileUISlotPatch
	{
		[HarmonyPatch("SetFileToThis")]
		[HarmonyPostfix]
		public static void SetFileToThisPostfix(SaveFileUISlot __instance)
		{
			if (__instance.fileNum != -1)
			{
				string text = ((TMP_Text)__instance.fileStatsText).text;
				string text2;
				if (string.IsNullOrWhiteSpace(text))
				{
					text2 = $"Set to File {__instance.fileNum + 1}, empty file.";
				}
				else
				{
					string[] array = text.Split(new char[1] { '\n' });
					string arg = ((array.Length != 0) ? array[0] : "");
					string arg2 = ((array.Length > 1) ? array[1] : "");
					text2 = $"Set to File {__instance.fileNum + 1}, Balance: {arg}, {arg2}";
				}
				Utilities.SpeakText(text2);
			}
		}
	}
	internal class Pathfinder : MonoBehaviour
	{
		private NavMeshAgent agent;

		public bool isPathfinding = false;

		private Vector3 lastPosition;

		private Vector3 currentDestination;

		private float lastPositionUpdateTime = 0f;

		public float stoppingRadius = 1.5f;

		private float baseSpeed = 1.75f;

		public static bool ShouldPreventFallDamage = false;

		private LineRenderer lineRenderer;

		private Vector3 lastFootstepPosition;

		private const float FootstepDistanceThreshold = 3f;

		private AudioSource audioSource;

		private static readonly string reachedPositionAudioFilePath = "LethalAccessAssets\\ReachedPosition.wav";

		private List<string> obstacleNames = new List<string> { "Landmine", "Center", "Collider (6)" };

		public PlayerControllerB playerController;

		public bool IsPathfinding => isPathfinding;

		public static Pathfinder Instance { get; private set; }

		private void Awake()
		{
			try
			{
				Instance = this;
				playerController = ((Component)this).GetComponent<PlayerControllerB>();
				CreateOrRecreateAgent();
				audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				((MonoBehaviour)this).StartCoroutine(LoadAudioClip(reachedPositionAudioFilePath));
				((MonoBehaviour)this).InvokeRepeating("EnsureNavMeshAgentIsRemoved", 0.5f, 0.5f);
				lineRenderer = ((Component)this).gameObject.GetComponent<LineRenderer>();
				if ((Object)(object)lineRenderer == (Object)null)
				{
					lineRenderer = ((Component)this).gameObject.AddComponent<LineRenderer>();
				}
				SetupLineRenderer();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Pathfinder: Error during Awake: " + ex.Message));
			}
		}

		private void SetupLineRenderer()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0044: 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)
			lineRenderer.startWidth = 0.15f;
			lineRenderer.endWidth = 0.15f;
			((Renderer)lineRenderer).material = new Material(Shader.Find("Sprites/Default"));
			lineRenderer.startColor = Color.red;
			lineRenderer.endColor = Color.red;
			lineRenderer.positionCount = 0;
		}

		private void EnsureNavMeshAgentIsRemoved()
		{
			if (!isPathfinding && (Object)(object)agent != (Object)null)
			{
				Object.Destroy((Object)(object)agent);
				agent = null;
				Debug.Log((object)"NavMeshAgent removed from the player.");
			}
		}

		private void Start()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			lastPosition = ((Component)this).transform.position;
			lastPositionUpdateTime = Time.time;
		}

		public void NavigateTo(GameObject targetObject)
		{
			try
			{
				if ((Object)(object)StartOfRound.Instance == (Object)null || !StartOfRound.Instance.shipHasLanded)
				{
					Utilities.SpeakText("The ship has not landed yet. Pathfinding is not allowed.");
					return;
				}
				if ((Object)(object)targetObject == (Object)null)
				{
					Utilities.SpeakText("Selected object not found at current location.");
					Debug.LogError((object)"Pathfinder.NavigateTo: targetObject is null.");
					return;
				}
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					//IL_003f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0076: Unknown result type (might be due to invalid IL or missing references)
					//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)agent == (Object)null)
					{
						Debug.LogError((object)"Pathfinder.NavigateTo: NavMeshAgent is null.");
						CreateOrRecreateAgent();
					}
					NavMeshHit val = default(NavMeshHit);
					if (!NavMesh.SamplePosition(((Component)agent).transform.position, ref val, 1f, -1))
					{
						Utilities.SpeakText("Could not Pathfind! No NavMesh available at current position.");
					}
					else
					{
						agent.Warp(((NavMeshHit)(ref val)).position);
						if (FindAndAvoidObstacles())
						{
							Debug.Log((object)"Avoiding Landmines.");
						}
						if (agent.SetDestination(targetObject.transform.position))
						{
							agent.isStopped = false;
							isPathfinding = true;
							ShouldPreventFallDamage = true;
							string text = LethalAccess.Instance?.navMenu?.GetDisplayNameForObject(targetObject) ?? ((Object)targetObject).name;
							Utilities.SpeakText("Starting pathfinding to " + text);
						}
						else
						{
							Utilities.SpeakText("Could not Pathfind! Object is not on NavMesh.");
							StopPathfinding();
						}
					}
				});
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Pathfinder: Error during NavigateTo: " + ex.Message));
				StopPathfinding();
			}
		}

		private bool FindAndAvoidObstacles()
		{
			IEnumerable<GameObject> enumerable = from obj in Object.FindObjectsOfType<GameObject>()
				where obstacleNames.Contains(((Object)obj).name) && Vector3.Distance(((Component)this).transform.position, obj.transform.position) <= 50f
				select obj;
			if (enumerable.Any())
			{
				foreach (GameObject item in enumerable)
				{
					NavMeshObstacle component = item.GetComponent<NavMeshObstacle>();
					if ((Object)(object)component == (Object)null)
					{
						component = item.AddComponent<NavMeshObstacle>();
						component.carving = true;
						component.shape = (NavMeshObstacleShape)0;
						component.radius = 2f;
						component.height = 2f;
					}
				}
				return true;
			}
			return false;
		}

		private void FixedUpdate()
		{
			try
			{
				if ((Object)(object)playerController != (Object)null && playerController.isPlayerDead)
				{
					if (isPathfinding)
					{
						StopPathfinding();
						Utilities.SpeakText("Pathfinding stopped because the player is dead.");
					}
					return;
				}
				if (isPathfinding && (Object)(object)agent != (Object)null && agent.isOnNavMesh && !agent.pathPending)
				{
					if (agent.remainingDistance <= agent.stoppingDistance)
					{
						OnReachedDestination();
					}
					else
					{
						UpdateAgentSpeed();
					}
				}
				DetectAndSpeakDoor();
				if (isPathfinding)
				{
					HandleStuckDetection();
					CheckAndPlayFootstepSound();
				}
				if (isPathfinding && (Object)(object)agent != (Object)null && agent.path != null)
				{
					DrawPath(agent.path);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Pathfinder: Error during FixedUpdate: " + ex.Message));
				StopPathfinding();
			}
		}

		private void OnReachedDestination()
		{
			agent.isStopped = true;
			isPathfinding = false;
			if ((Object)(object)audioSource.clip != (Object)null)
			{
				audioSource.Play();
			}
			string text = "Unknown Object";
			if ((Object)(object)LethalAccess.Instance != (Object)null && (Object)(object)LethalAccess.Instance.navMenu != (Object)null)
			{
				text = LethalAccess.Instance.navMenu.GetDisplayNameForObject(LethalAccess.currentLookTarget);
			}
			((MonoBehaviour)this).StartCoroutine(ResetFallDamageImmunityAfterDelay());
			RemoveAgent();
		}

		private void HandleStuckDetection()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time - lastPositionUpdateTime > 3f)
			{
				if (Vector3.Distance(((Component)this).transform.position, lastPosition) < 1f)
				{
					TeleportAlongPath(5f);
				}
				lastPosition = ((Component)this).transform.position;
				lastPositionUpdateTime = Time.time;
			}
		}

		private void DrawPath(NavMeshPath path)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			if (path.corners.Length >= 2)
			{
				lineRenderer.positionCount = path.corners.Length;
				for (int i = 0; i < path.corners.Length; i++)
				{
					Vector3 val = path.corners[i] + Vector3.up * 1f;
					lineRenderer.SetPosition(i, val);
				}
			}
		}

		private void CheckAndPlayFootstepSound()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)LethalAccess.PlayerTransform == (Object)null))
			{
				Vector3 position = LethalAccess.PlayerTransform.position;
				if (Vector3.Distance(new Vector3(position.x, 0f, position.z), new Vector3(lastFootstepPosition.x, 0f, lastFootstepPosition.z)) >= 3f && (Object)(object)playerController != (Object)null)
				{
					playerController.PlayFootstepLocal();
					playerController.PlayFootstepServer();
					lastFootstepPosition = position;
				}
			}
		}

		private void UpdateAgentSpeed()
		{
			if ((Object)(object)playerController != (Object)null)
			{
				float num = playerController.carryWeight - 1f;
				num = Mathf.Clamp(num, 0f, 1.4f);
				num *= 1.5f;
				num = Mathf.Min(num, 1.4f);
				float num2 = Mathf.Lerp(1f, 0.15f, num / 1.4f);
				agent.speed = baseSpeed * 3.5f * num2;
			}
		}

		private void TeleportAlongPath(float distance)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if (agent.path == null || agent.path.corners.Length < 2)
			{
				return;
			}
			currentDestination = agent.destination;
			Vector3 val = agent.path.corners[1] - ((Component)this).transform.position;
			Vector3 val2 = ((Component)this).transform.position + ((Vector3)(ref val)).normalized * distance;
			Vector3 val3;
			if (TryTeleportTo(val2))
			{
				val3 = val2;
				Debug.Log((object)("Teleported player to " + ((object)(Vector3)(ref val3)).ToString()));
				ContinuePathfinding();
				return;
			}
			for (int i = 0; i < 10; i++)
			{
				Vector3 val4 = ((Component)this).transform.position + Random.insideUnitSphere * 2f;
				if (TryTeleportTo(val4))
				{
					val3 = val4;
					Debug.Log((object)("Teleported player to nearby random point: " + ((object)(Vector3)(ref val3)).ToString()));
					ContinuePathfinding();
					return;
				}
			}
			val3 = val2;
			Debug.LogError((object)("Failed to teleport player: No valid NavMesh point found near " + ((object)(Vector3)(ref val3)).ToString()));
		}

		private bool TryTeleportTo(Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(point, ref val, 1f, -1))
			{
				agent.Warp(((NavMeshHit)(ref val)).position);
				return true;
			}
			return false;
		}

		private void ContinuePathfinding()
		{
			//IL_0010: 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)
			if ((Object)(object)agent != (Object)null)
			{
				_ = currentDestination;
				if (true)
				{
					agent.SetDestination(currentDestination);
					isPathfinding = true;
				}
			}
		}

		private IEnumerator LoadAudioClip(string relativeFilePath)
		{
			string modDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string fullPath = Path.Combine(modDirectory, relativeFilePath);
			string fileURL = "file://" + fullPath;
			UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileURL, (AudioType)20);
			try
			{
				yield return uwr.SendWebRequest();
				if ((int)uwr.result == 2 || (int)uwr.result == 3)
				{
					Debug.LogError((object)("Error While Loading Audio Clip: " + uwr.error));
				}
				else
				{
					audioSource.clip = DownloadHandlerAudioClip.GetContent(uwr);
				}
			}
			finally
			{
				((IDisposable)uwr)?.Dispose();
			}
		}

		private void DetectAndSpeakDoor()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			float num = 2.25f;
			DoorLock val = null;
			float num2 = num;
			DoorLock[] array = Object.FindObjectsOfType<DoorLock>();
			foreach (DoorLock val2 in array)
			{
				float num3 = Vector3.Distance(((Component)this).transform.position, ((Component)val2).transform.position);
				if (num3 < num2)
				{
					num2 = num3;
					val = val2;
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				AnimatedObjectTrigger component = ((Component)val).GetComponent<AnimatedObjectTrigger>();
				if ((Object)(object)component != (Object)null && !component.boolValue)
				{
					val.OpenOrCloseDoor(playerController);
				}
			}
		}

		private IEnumerator ResetFallDamageImmunityAfterDelay()
		{
			yield return (object)new WaitForSeconds(0.1f);
			ShouldPreventFallDamage = false;
		}

		private void CreateOrRecreateAgent()
		{
			RemoveAgent();
			agent = ((Component)this).gameObject.AddComponent<NavMeshAgent>();
			agent.speed = baseSpeed * 3f;
			agent.angularSpeed = 1200f;
			agent.acceleration = 12f;
			agent.radius = 0.3f;
			agent.baseOffset = 0.4f;
			agent.stoppingDistance = stoppingRadius;
			agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			agent.areaMask = -1;
			agent.autoRepath = true;
			agent.autoTraverseOffMeshLink = true;
		}

		public void StopPathfinding()
		{
			try
			{
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					if ((Object)(object)agent != (Object)null)
					{
						agent.isStopped = true;
						Object.Destroy((Object)(object)agent);
						agent = null;
					}
					isPathfinding = false;
					((MonoBehaviour)this).StartCoroutine(ResetFallDamageImmunityAfterDelay());
					ClearPath();
				});
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Pathfinder: Error during StopPathfinding: " + ex.Message));
			}
		}

		private void ClearPath()
		{
			lineRenderer.positionCount = 0;
		}

		private void RemoveAgent()
		{
			if ((Object)(object)agent != (Object)null)
			{
				Object.Destroy((Object)(object)agent);
				agent = null;
			}
		}

		public static void RemoveNavMeshAgentFromPlayer()
		{
			Pathfinder pathfinder = Object.FindObjectOfType<Pathfinder>();
			if ((Object)(object)pathfinder != (Object)null)
			{
				pathfinder.RemoveAgent();
			}
		}
	}
	[BepInPlugin("Green.LethalAccess", "LethalAccess", "1.0.0.0")]
	public class LethalAccess : BaseUnityPlugin
	{
		private const string modGUID = "Green.LethalAccess";

		private const string modName = "LethalAccess";

		private const string modVersion = "1.0.0.0";

		public static Transform playerTransform;

		public static Transform cameraTransform;

		public static readonly string reachedPositionAudioFilePath = "LethalAccessAssets\\ReachedPosition.wav";

		private static Dictionary<string, ConfigEntry<Key>> keybindConfigEntries = new Dictionary<string, ConfigEntry<Key>>();

		private static Dictionary<string, Action> registeredActions = new Dictionary<string, Action>();

		public static Dictionary<string, List<Func<string>>> overriddenTexts = new Dictionary<string, List<Func<string>>>();

		private List<GameObject> previouslyFocusedUIElements = new List<GameObject>();

		public static GameObject currentLookTarget;

		private static GameObject lastAnnouncedObject;

		public static bool enableCustomKeybinds = true;

		private bool hasPlayedReachedSound = false;

		private bool isNavigatingWithPrevKey = false;

		private bool mainMenuActivated = false;

		private bool quickMenuActivated = false;

		private Dictionary<string, Dictionary<string, string>> customUINavigation = new Dictionary<string, Dictionary<string, string>>();

		private ControlTipAccessPatch controlTipAccessPatch;

		private ProfitQuotaPatch profitQuotaPatch;

		private PlayerHealthPatch playerHealthPatch;

		private TimeOfDayPatch timeOfDayPatch;

		public NavMenu navMenu;

		private Pathfinder pathfinder;

		private NorthSoundManager northSoundManager;

		private const float MAX_DISTANCE_TO_OBJECT = 15f;

		private const float DEFAULT_STOPPING_RADIUS = 1.5f;

		public static LethalAccess Instance { get; private set; }

		public static Transform PlayerTransform
		{
			get
			{
				if ((Object)(object)playerTransform == (Object)null)
				{
					PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
					if ((Object)(object)val != (Object)null)
					{
						playerTransform = ((Component)val).transform;
					}
					else
					{
						Debug.LogWarning((object)"LocalPlayerController is null. Cannot get PlayerTransform.");
					}
				}
				return playerTransform;
			}
		}

		public static Transform CameraTransform
		{
			get
			{
				if ((Object)(object)cameraTransform == (Object)null)
				{
					PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
					if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null)
					{
						cameraTransform = ((Component)val.gameplayCamera).transform;
					}
					else
					{
						Debug.LogWarning((object)"LocalPlayerController or gameplayCamera is null. Cannot get CameraTransform.");
					}
				}
				return cameraTransform;
			}
		}

		private void Awake()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
				controlTipAccessPatch = new ControlTipAccessPatch();
				controlTipAccessPatch.Initialize();
				profitQuotaPatch = new ProfitQuotaPatch();
				profitQuotaPatch.Initialize();
				playerHealthPatch = new PlayerHealthPatch();
				playerHealthPatch.Initialize();
				timeOfDayPatch = new TimeOfDayPatch();
				timeOfDayPatch.Initialize();
				navMenu = new NavMenu();
				navMenu.Initialize();
				pathfinder = new Pathfinder();
				northSoundManager = ((Component)this).gameObject.AddComponent<NorthSoundManager>();
				Harmony val = new Harmony("Green.LethalAccess");
				val.PatchAll(Assembly.GetExecutingAssembly());
				val.PatchAll(typeof(PreInitScenePatch));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"PreInitScene skip patch applied successfully.");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"LethalAccess initialized.");
				RegisterKeybinds();
				((MonoBehaviour)this).StartCoroutine(LoadAudioClip(reachedPositionAudioFilePath));
				SetUISpeech("Canvas/MenuContainer/SettingsPanel/MicSettings/SpeakerButton", new List<Func<string>>
				{
					() => "Microphone Toggle: " + Utilities.GetTextFromGameObject("Canvas/MenuContainer/SettingsPanel/MicSettings/SpeakerButton")
				});
				SetUISpeech("Systems/UI/Canvas/QuickMenu/SettingsPanel/MicSettings/SpeakerButton", new List<Func<string>>
				{
					() => "Microphone Toggle: " + Utilities.GetTextFromGameObject("Systems/UI/Canvas/QuickMenu/SettingsPanel/MicSettings/SpeakerButton")
				});
				SetUISpeech("Canvas/MenuContainer/SettingsPanel/ControlsOptions/LookSensitivity/Slider", new List<Func<string>>
				{
					() => string.Format("{0} Slider: {1}", Utilities.GetTextFromGameObject("Canvas/MenuContainer/SettingsPanel/ControlsOptions/LookSensitivity/Text (1)"), Utilities.GetSliderValue("Canvas/MenuContainer/SettingsPanel/ControlsOptions/LookSensitivity/Slider/Handle Slide Area/Handle"))
				});
				SetUISpeech("Canvas/MenuContainer/SettingsPanel/MasterVolume/Slider", new List<Func<string>>
				{
					() => string.Format("{0} Slider: {1}%", Utilities.GetTextFromGameObject("Canvas/MenuContainer/SettingsPanel/MasterVolume/Text (1)"), Utilities.GetSliderValue("Canvas/MenuContainer/SettingsPanel/MasterVolume/Slider/Handle Slide Area/Handle"))
				});
				SetUISpeech("Systems/UI/Canvas/QuickMenu/SettingsPanel/ControlsOptions/LookSensitivity/Slider", new List<Func<string>>
				{
					() => string.Format("{0} Slider: {1}", Utilities.GetTextFromGameObject("Systems/UI/Canvas/QuickMenu/SettingsPanel/ControlsOptions/LookSensitivity/Text (1)"), Utilities.GetSliderValue("Systems/UI/Canvas/QuickMenu/SettingsPanel/ControlsOptions/LookSensitivity/Slider/Handle Slide Area/Handle"))
				});
				SetUISpeech("Systems/UI/Canvas/QuickMenu/SettingsPanel/MasterVolume/Slider", new List<Func<string>>
				{
					() => string.Format("{0} Slider: {1}%", Utilities.GetTextFromGameObject("Systems/UI/Canvas/QuickMenu/SettingsPanel/MasterVolume/Text (1)"), Utilities.GetSliderValue("Systems/UI/Canvas/QuickMenu/SettingsPanel/MasterVolume/Slider/Handle Slide Area/Handle"))
				});
				SetUISpeech("Canvas/MenuContainer/LobbyList/ListPanel/Scroll View/Viewport/Content/LobbyListItem(Clone)/JoinButton", new List<Func<string>>
				{
					() => Utilities.GetLobbyInfoFromJoinButton(EventSystem.current.currentSelectedGameObject)
				});
				navMenu.RegisterMenuItem("ItemCounter", "Item Counter", "Company Building", "", (Vector3?)new Vector3(-29.141f, -1.154f, -31.461f));
				navMenu.RegisterMenuItem("BellDinger", "Sell Bell", "Company Building", "CompanyBuilding");
				navMenu.RegisterMenuItem("EntranceTeleportA", "Enter Factory", "Factory");
				navMenu.RegisterMenuItem("EntranceTeleportA(Clone)", "Exit Factory", "Factory");
				navMenu.RegisterMenuItem("EntranceTeleportB", "Enter Fire Escape", "Factory");
				navMenu.RegisterMenuItem("EntranceTeleportB(Clone)", "Exit Fire Escape", "Factory");
				navMenu.RegisterMenuItem("TerminalScript", "Terminal", "Ship");
				navMenu.RegisterMenuItem("StartGameLever", "Start Ship Lever", "Ship");
				navMenu.RegisterMenuItem("ShipInside", "Inside of Ship", "Ship");
				navMenu.RegisterMenuItem("StorageCloset", "Storage Closet", "Ship Utilities");
				navMenu.RegisterMenuItem("PlacementBlocker (5)", "Charging Station", "Ship Utilities");
				navMenu.RegisterMenuItem("Bunkbeds", "Bunk Beds", "Ship Utilities");
				navMenu.RegisterMenuItem("LightSwitch", "Light Switch", "Ship Utilities");
				navMenu.RegisterMenuItem("ItemShip", "Item Ship", "Other Utilities");
				navMenu.RegisterMenuItem("RedButton", "Activate Teleporter", "Other Utilities");
				RegisterKeybind("NavigateToLookingObject", (Key)30, PathfindToSelected);
				RegisterKeybind("StopLookingAndPathfinding", (Key)29, StopLookingAndPathfinding);
				RegisterKeybind("FocusPreviousUIElement", (Key)9, FocusPreviousUIElement);
				RegisterKeybind("LeftClickHold", (Key)53, delegate
				{
					SimulateMouseClick(0, isPressed: true);
				});
				RegisterKeybind("RightClickHold", (Key)54, delegate
				{
					SimulateMouseClick(1, isPressed: true);
				});
				RegisterKeybind("ToggleNorthSound", (Key)28, ToggleNorthSound);
				RegisterKeybind("SpeakPlayerDirection", (Key)38, SpeakPlayerDirection);
				SetUINavigation("Canvas/MenuContainer/LobbyHostSettings/FilesPanel/ChallengeMoonButton", "Up", "Canvas/MenuContainer/LobbyHostSettings/FilesPanel/File3");
				SetUINavigation("Canvas/MenuContainer/LobbyHostSettings/FilesPanel/File3", "Down", "Canvas/MenuContainer/LobbyHostSettings/FilesPanel/ChallengeMoonButton");
			}
			else
			{
				Object.Destroy((Object)(object)this);
			}
		}

		private async void Update()
		{
			if (enableCustomKeybinds)
			{
				CheckKeybinds();
			}
			if ((Object)(object)currentLookTarget != (Object)null)
			{
				Utilities.LookAtObject(currentLookTarget);
			}
			bool isShipLanded = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipHasLanded;
			string currentPlanetName = (isShipLanded ? StartOfRound.Instance.currentLevel.PlanetName : string.Empty);
			await Task.Run(delegate
			{
				navMenu.UpdateCategoriesVisibility(isShipLanded, currentPlanetName);
				CheckReachedTrackedObject();
				CheckMainMenuActivation();
				CheckQuickMenuActivation();
			});
			HandleUIElementAnnouncement();
		}

		private void CheckKeybinds()
		{
			//IL_0027: 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)
			foreach (KeyValuePair<string, ConfigEntry<Key>> keybindConfigEntry in keybindConfigEntries)
			{
				if (((ButtonControl)Keyboard.current[keybindConfigEntry.Value.Value]).wasPressedThisFrame)
				{
					if (registeredActions.TryGetValue(keybindConfigEntry.Key, out var value))
					{
						value();
					}
				}
				else if (((ButtonControl)Keyboard.current[keybindConfigEntry.Value.Value]).wasReleasedThisFrame)
				{
					if (keybindConfigEntry.Key == "LeftClickHold")
					{
						SimulateMouseClick(0, isPressed: false);
					}
					else if (keybindConfigEntry.Key == "RightClickHold")
					{
						SimulateMouseClick(1, isPressed: false);
					}
				}
			}
		}

		private void SimulateMouseClick(int buttonIndex, bool isPressed)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			Mouse current = Mouse.current;
			if (current == null)
			{
				return;
			}
			MouseState val;
			switch (buttonIndex)
			{
			case 0:
				if (isPressed)
				{
					val = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)current, ((MouseState)(ref val)).WithButton((MouseButton)0, true), -1.0);
				}
				else
				{
					val = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)current, ((MouseState)(ref val)).WithButton((MouseButton)0, false), -1.0);
				}
				break;
			case 1:
				if (isPressed)
				{
					val = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)current, ((MouseState)(ref val)).WithButton((MouseButton)1, true), -1.0);
				}
				else
				{
					val = default(MouseState);
					InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)current, ((MouseState)(ref val)).WithButton((MouseButton)1, false), -1.0);
				}
				break;
			}
		}

		public static void HandleUIElementAnnouncement()
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)((current != null) ? current.currentSelectedGameObject : null) != (Object)null)
			{
				GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
				if ((Object)(object)currentSelectedGameObject != (Object)(object)lastAnnouncedObject)
				{
					Instance.AnnounceUIElement(currentSelectedGameObject);
					lastAnnouncedObject = currentSelectedGameObject;
				}
			}
		}

		private void AnnounceUIElement(GameObject selectedObject)
		{
			if (!isNavigatingWithPrevKey)
			{
				previouslyFocusedUIElements.Add(lastAnnouncedObject);
				if (previouslyFocusedUIElements.Count > 5)
				{
					previouslyFocusedUIElements.RemoveAt(0);
				}
			}
			string gameObjectPath = Utilities.GetGameObjectPath(selectedObject);
			if (overriddenTexts.TryGetValue(gameObjectPath, out var value))
			{
				string textToAnnounce2 = string.Join(" ", value.Select((Func<string> provider) => provider()));
				textToAnnounce2 = Utilities.RemoveSpecialCharacters(textToAnnounce2);
				if (!string.IsNullOrEmpty(textToAnnounce2))
				{
					UnityMainThreadDispatcher.Instance().Enqueue(delegate
					{
						Utilities.SpeakText(textToAnnounce2);
					});
				}
			}
			else
			{
				string textToAnnounce = Utilities.GetTextFromComponent(selectedObject);
				textToAnnounce = Utilities.RemoveSpecialCharacters(textToAnnounce);
				if (!string.IsNullOrEmpty(textToAnnounce))
				{
					UnityMainThreadDispatcher.Instance().Enqueue(delegate
					{
						Utilities.SpeakText(textToAnnounce);
					});
				}
			}
			UnityMainThreadDispatcher.Instance().Enqueue(delegate
			{
				Utilities.LogUIElementInfo(selectedObject, ((BaseUnityPlugin)this).Logger);
			});
		}

		private void FocusPreviousUIElement()
		{
			if (previouslyFocusedUIElements.Count > 0)
			{
				isNavigatingWithPrevKey = true;
				GameObject val = previouslyFocusedUIElements[previouslyFocusedUIElements.Count - 1];
				previouslyFocusedUIElements.RemoveAt(previouslyFocusedUIElements.Count - 1);
				if ((Object)(object)val != (Object)null && val.activeInHierarchy)
				{
					EventSystem.current.SetSelectedGameObject(val);
				}
				isNavigatingWithPrevKey = false;
			}
		}

		public void SetUINavigation(string uiElementPath, string direction, string connectedUIElementPath)
		{
			if (!customUINavigation.ContainsKey(uiElementPath))
			{
				customUINavigation[uiElementPath] = new Dictionary<string, string>();
			}
			customUINavigation[uiElementPath][direction] = connectedUIElementPath;
		}

		private void SetupCustomUINavigation()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<string, Dictionary<string, string>> item in customUINavigation)
			{
				string key = item.Key;
				Dictionary<string, string> value = item.Value;
				GameObject val = GameObject.Find(key);
				if (!((Object)(object)val != (Object)null))
				{
					continue;
				}
				Selectable component = val.GetComponent<Selectable>();
				if (!((Object)(object)component != (Object)null))
				{
					continue;
				}
				Navigation navigation = component.navigation;
				foreach (KeyValuePair<string, string> item2 in value)
				{
					string key2 = item2.Key;
					string value2 = item2.Value;
					GameObject val2 = GameObject.Find(value2);
					if (!((Object)(object)val2 != (Object)null))
					{
						continue;
					}
					Selectable component2 = val2.GetComponent<Selectable>();
					if ((Object)(object)component2 != (Object)null)
					{
						switch (key2)
						{
						case "Up":
							((Navigation)(ref navigation)).selectOnUp = component2;
							break;
						case "Down":
							((Navigation)(ref navigation)).selectOnDown = component2;
							break;
						case "Left":
							((Navigation)(ref navigation)).selectOnLeft = component2;
							break;
						case "Right":
							((Navigation)(ref navigation)).selectOnRight = component2;
							break;
						}
					}
				}
				component.navigation = navigation;
			}
		}

		private void CheckMainMenuActivation()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name == "MainMenu")
			{
				if (!mainMenuActivated)
				{
					mainMenuActivated = true;
					SetupCustomUINavigation();
				}
			}
			else
			{
				mainMenuActivated = false;
			}
		}

		private void CheckQuickMenuActivation()
		{
			GameObject val = GameObject.Find("QuickMenu");
			if ((Object)(object)val != (Object)null && val.activeSelf)
			{
				if (!quickMenuActivated)
				{
					quickMenuActivated = true;
					SetupCustomUINavigation();
				}
			}
			else
			{
				quickMenuActivated = false;
			}
		}

		private void CheckReachedTrackedObject()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)currentLookTarget == (Object)null || (Object)(object)PlayerTransform == (Object)null)
				{
					return;
				}
				float num = Vector3.Distance(PlayerTransform.position, currentLookTarget.transform.position);
				float valueOrDefault = (Instance?.pathfinder?.stoppingRadius).GetValueOrDefault(1.5f);
				if (num <= valueOrDefault)
				{
					if (!hasPlayedReachedSound)
					{
						string text = navMenu?.GetDisplayNameForObject(currentLookTarget) ?? "Unknown Object";
						Debug.Log((object)("Attempting to play audio clip for " + text));
						((MonoBehaviour)this).StartCoroutine(PlayAudioClipCoroutine(reachedPositionAudioFilePath, currentLookTarget, 0f, 5f));
						Utilities.SpeakText("Reached " + text);
						hasPlayedReachedSound = true;
					}
				}
				else
				{
					hasPlayedReachedSound = false;
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Error in CheckReachedTrackedObject: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		private void RegisterKeybinds()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			foreach (string key in registeredActions.Keys)
			{
				ConfigEntry<Key> value = ((BaseUnityPlugin)this).Config.Bind<Key>("Keybinds", key, keybindConfigEntries[key].Value, (ConfigDescription)null);
				keybindConfigEntries[key] = value;
			}
		}

		public void RegisterKeybind(string keybindName, Key defaultKey, Action action)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!registeredActions.ContainsKey(keybindName))
			{
				registeredActions[keybindName] = action;
				keybindConfigEntries[keybindName] = ((BaseUnityPlugin)this).Config.Bind<Key>("Keybinds", keybindName, defaultKey, (ConfigDescription)null);
			}
		}

		public static void SetUISpeech(string gameObjectPath, List<Func<string>> textProviders)
		{
			overriddenTexts[gameObjectPath] = textProviders;
		}

		public void StopLookingAndPathfinding()
		{
			if ((Object)(object)currentLookTarget != (Object)null)
			{
				string text = navMenu?.GetDisplayNameForObject(currentLookTarget) ?? "Unknown Object";
				Utilities.SpeakText("Stopped looking at " + text);
				currentLookTarget = null;
			}
			if (pathfinder.isPathfinding)
			{
				pathfinder.StopPathfinding();
				Utilities.SpeakText("Stopped pathfinding");
			}
		}

		private void PathfindToSelected()
		{
			Debug.Log((object)"PathfindToSelected() method called.");
			if ((Object)(object)PlayerTransform != (Object)null && (Object)(object)currentLookTarget != (Object)null)
			{
				if ((Object)(object)pathfinder == (Object)null)
				{
					pathfinder = ((Component)PlayerTransform).gameObject.GetComponent<Pathfinder>();
					if ((Object)(object)pathfinder == (Object)null)
					{
						Debug.Log((object)"Adding Pathfinder component to the player.");
						pathfinder = ((Component)PlayerTransform).gameObject.AddComponent<Pathfinder>();
					}
				}
				Debug.Log((object)("Attempting to pathfind to " + ((Object)currentLookTarget).name));
				pathfinder.NavigateTo(currentLookTarget);
			}
			else
			{
				if ((Object)(object)PlayerTransform == (Object)null)
				{
					Debug.Log((object)"Pathfinder initialization failed: PlayerTransform is null.");
				}
				if ((Object)(object)currentLookTarget == (Object)null)
				{
					Debug.Log((object)"Pathfinding not initiated: No object selected or object not found.");
					Utilities.SpeakText("Object not found. Make sure you land the ship before attempting to pathfind.");
				}
			}
		}

		private void ToggleNorthSound()
		{
			northSoundManager.ToggleNorthSound();
			string text = (northSoundManager.isEnabled ? "enabled" : "disabled");
			Utilities.SpeakText("North Sound " + text);
		}

		private void SpeakPlayerDirection()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)PlayerTransform != (Object)null)
			{
				Vector3 forward = PlayerTransform.forward;
				float num = Mathf.Atan2(forward.x, forward.z) * 57.29578f;
				if (num < 0f)
				{
					num += 360f;
				}
				string compassDirection = GetCompassDirection(num);
				int num2 = Mathf.RoundToInt(num);
				string text = $"Facing {compassDirection} at {num2} degrees";
				Utilities.SpeakText(text);
			}
			else
			{
				Utilities.SpeakText("Player position not available");
			}
		}

		private string GetCompassDirection(float angle)
		{
			string[] array = new string[8] { "North", "Northeast", "East", "Southeast", "South", "Southwest", "West", "Northwest" };
			int num = Mathf.RoundToInt(angle / 45f) % 8;
			return array[num];
		}

		private IEnumerator LoadAudioClip(string relativeFilePath)
		{
			string modDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string fullPath = Path.Combine(modDirectory, relativeFilePath);
			string fileURL = "file://" + fullPath;
			UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileURL, (AudioType)20);
			try
			{
				yield return uwr.SendWebRequest();
				if ((int)uwr.result == 2 || (int)uwr.result == 3)
				{
					Debug.LogError((object)("Error While Loading Audio Clip: " + uwr.error));
					yield break;
				}
				AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
				if ((Object)(object)clip != (Object)null)
				{
					Debug.Log((object)("Successfully loaded audio clip: " + relativeFilePath));
				}
				else
				{
					Debug.LogError((object)("Failed to load audio clip: " + relativeFilePath));
				}
			}
			finally
			{
				((IDisposable)uwr)?.Dispose();
			}
		}

		public IEnumerator PlayAudioClipCoroutine(string audioFilePath, GameObject targetGameObject, float minDistance, float maxDistance)
		{
			if ((Object)(object)targetGameObject == (Object)null)
			{
				Debug.LogError((object)"Target GameObject is null. Cannot play audio clip.");
				yield break;
			}
			string modDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string fullPath = Path.Combine(modDirectory, audioFilePath);
			string fileURL = "file://" + fullPath;
			UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileURL, (AudioType)20);
			try
			{
				yield return uwr.SendWebRequest();
				if ((int)uwr.result == 2 || (int)uwr.result == 3)
				{
					Debug.LogError((object)("Error loading audio clip: " + uwr.error));
					yield break;
				}
				AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
				if ((Object)(object)clip != (Object)null)
				{
					AudioSource audioSource = targetGameObject.GetComponent<AudioSource>();
					if ((Object)(object)audioSource == (Object)null)
					{
						audioSource = targetGameObject.AddComponent<AudioSource>();
					}
					audioSource.clip = clip;
					audioSource.spatialBlend = 1f;
					audioSource.rolloffMode = (AudioRolloffMode)1;
					audioSource.minDistance = minDistance;
					audioSource.maxDistance = maxDistance;
					audioSource.Play();
					Debug.Log((object)("Playing audio clip: " + audioFilePath));
				}
				else
				{
					Debug.LogError((object)("Failed to load audio clip: " + audioFilePath));
				}
			}
			finally
			{
				((IDisposable)uwr)?.Dispose();
			}
		}

		private void OnDestroy()
		{
			SpeechSynthesizer.Cleanup();
		}
	}
	public static class SpeechSynthesizer
	{
		static SpeechSynthesizer()
		{
			UnityMainThreadDispatcher.Instance().Enqueue(delegate
			{
				Debug.Log((object)"SpeechSynthesizer initialized.");
			});
		}

		public static void SpeakText(string text)
		{
			try
			{
				LethalSpeechOutput.SpeakText(text);
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					Debug.Log((object)("Spoken text using LethalSpeechOutput: '" + text + "'"));
				});
			}
			catch (Exception ex2)
			{
				Exception ex3 = ex2;
				Exception ex = ex3;
				UnityMainThreadDispatcher.Instance().Enqueue(delegate
				{
					Debug.LogError((object)("Error speaking text: " + ex.Message));
					Debug.LogError((object)("Stack trace: " + ex.StackTrace));
				});
			}
		}

		public static void Cleanup()
		{
			UnityMainThreadDispatcher.Instance().Enqueue(delegate
			{
				Debug.Log((object)"SpeechSynthesizer cleanup completed.");
			});
		}
	}
	internal class Utilities
	{
		public static string GetTextFromGameObject(string gameObjectPath)
		{
			GameObject val = GameObject.Find(gameObjectPath);
			if ((Object)(object)val != (Object)null)
			{
				return GetTextFromComponent(val);
			}
			return string.Empty;
		}

		public static string GetTextFromComponent(GameObject gameObject)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			TextMeshProUGUI componentInChildren = gameObject.GetComponentInChildren<TextMeshProUGUI>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return ((TMP_Text)componentInChildren).text;
			}
			Text component = gameObject.GetComponent<Text>();
			if ((Object)(object)component != (Object)null)
			{
				return component.text;
			}
			foreach (Transform item in gameObject.transform)
			{
				Transform val = item;
				string textFromComponent = GetTextFromComponent(((Component)val).gameObject);
				if (!string.IsNullOrEmpty(textFromComponent))
				{
					return textFromComponent;
				}
			}
			return ((Object)gameObject).name;
		}

		public static string GetLobbyInfoFromJoinButton(GameObject selectedObject)
		{
			if ((Object)(object)selectedObject != (Object)null)
			{
				Transform parent = selectedObject.transform.parent;
				if ((Object)(object)parent != (Object)null)
				{
					LobbySlot component = ((Component)parent).GetComponent<LobbySlot>();
					if ((Object)(object)component != (Object)null)
					{
						string textFromComponent = GetTextFromComponent(((Component)component.LobbyName).gameObject);
						string textFromComponent2 = GetTextFromComponent(((Component)component.playerCount).gameObject);
						return "Lobby: " + textFromComponent + ", Players: " + textFromComponent2;
					}
				}
			}
			return string.Empty;
		}

		public static string RemoveSpecialCharacters(string input)
		{
			string text = "[]{}<>()";
			string text2 = text;
			for (int i = 0; i < text2.Length; i++)
			{
				input = input.Replace(text2[i].ToString(), string.Empty);
			}
			return input;
		}

		public static string GetGameObjectPath(GameObject gameObject)
		{
			string text = ((Object)gameObject).name;
			Transform parent = gameObject.transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		public static float GetSliderValuePercentage(string sliderHandlePath)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find(sliderHandlePath);
			if ((Object)(object)val != (Object)null)
			{
				Vector3 localPosition = val.transform.localPosition;
				float num = (localPosition.x + 70f) / 140f * 100f;
				return Mathf.Clamp(num, 0f, 100f);
			}
			return 0f;
		}

		public static int GetSliderValue(string sliderHandlePath)
		{
			GameObject val = GameObject.Find(sliderHandlePath);
			if ((Object)(object)val != (Object)null)
			{
				Slider componentInParent = val.GetComponentInParent<Slider>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					return Mathf.RoundToInt(componentInParent.value);
				}
			}
			return 0;
		}

		public static void LookAtObject(GameObject targetObject)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)targetObject != (Object)null) || !((Object)(object)LethalAccess.CameraTransform != (Object)null))
			{
				return;
			}
			float num = 15f;
			float num2 = Vector3.Distance(LethalAccess.CameraTransform.position, targetObject.transform.position);
			if (num2 <= num)
			{
				PlayerControllerB component = ((Component)LethalAccess.PlayerTransform).GetComponent<PlayerControllerB>();
				if ((Object)(object)component != (Object)null)
				{
					Vector3 val = targetObject.transform.position - LethalAccess.CameraTransform.position;
					Vector3 val2 = LethalAccess.CameraTransform.InverseTransformDirection(val);
					float num3 = 5f;
					Vector2 val3 = new Vector2(val2.x, val2.y) * num3;
					typeof(PlayerControllerB).GetMethod("CalculateNormalLookingInput", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(component, new object[1] { val3 });
				}
			}
		}

		public static async void SpeakText(string text)
		{
			await Task.Run(delegate
			{
				SpeechSynthesizer.SpeakText(text);
			});
		}

		public static void LogUIElementInfo(GameObject uiElement, ManualLogSource logger)
		{
			string name = ((Object)uiElement).name;
			string gameObjectPath = GetGameObjectPath(uiElement);
			logger.LogInfo((object)("UI Element: " + name + ", GameObject Path: " + gameObjectPath));
		}

		public static async Task<AudioClip> LoadClip(string relativePath)
		{
			AudioClip clip = null;
			string modDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string fullPath = Path.Combine(modDirectory, relativePath);
			string fileURL = "file://" + fullPath;
			try
			{
				UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileURL, (AudioType)20);
				try
				{
					UnityWebRequestAsyncOperation operation = uwr.SendWebRequest();
					while (!((AsyncOperation)operation).isDone)
					{
						await Task.Yield();
					}
					if ((int)uwr.result == 1)
					{
						clip = DownloadHandlerAudioClip.GetContent(uwr);
						Debug.Log((object)("Successfully loaded audio clip: " + relativePath));
					}
					else
					{
						Debug.LogError((object)("Failed to load audio clip: " + uwr.error));
					}
				}
				finally
				{
					((IDisposable)uwr)?.Dispose();
				}
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				Debug.LogError((object)("Error loading audio clip: " + ex.Message));
			}
			return clip;
		}
	}
}
namespace Green.LethalAccess.Patches
{
	[HarmonyPatch(typeof(ClipboardItem))]
	public class ClipboardItemPatches
	{
		[HarmonyPatch("ItemInteractLeftRight")]
		[HarmonyPostfix]
		public static void ItemInteractLeftRightPostfix(ClipboardItem __instance)
		{
			SpeakPage(__instance.currentPage);
		}

		[HarmonyPatch("EquipItem")]
		[HarmonyPostfix]
		public static void EquipItemPostfix(ClipboardItem __instance)
		{
			((MonoBehaviour)LethalAccess.Instance).StartCoroutine(DelayedSpeakPage(__instance.currentPage));
		}

		private static IEnumerator DelayedSpeakPage(int currentPage)
		{
			yield return (object)new WaitForSeconds(0.1f);
			SpeakPage(currentPage);
		}

		private static void SpeakPage(int currentPage)
		{
			string pageContent = GetPageContent(currentPage);
			Utilities.SpeakText($"Page {currentPage}. {pageContent}");
		}

		private static string GetPageContent(int currentPage)
		{
			return currentPage switch
			{
				1 => "An order number, 4186915, is prominently displayed at the upper edge. Below, a list of content categories is presented, indicating the inclusion of general descriptions, procedures for emergencies, diagrams both block and schematic, as well as detailed exploded views and a list of parts. Notably mentioned are the entities Halden Electronics and F. Power Co. A grid with numerous entries, indicative of a specifications chart, spans the central portion, but the text within is blurred, rendering the specifics indiscernible. A triangular warning icon attracts attention to a cautionary note below, which explicitly states that the provided information is tailored for authorized and skilled technicians, explicitly excluding the general public. It highlights an intentional omission of certain cautions or warnings, aimed at enhancing readability, while also clearly disclaiming liability for any harm or fatality that may result from misuse of the information or related tools. The lower segment features the logo of Halden Electronics, reinforcing the brand's presence. Accompanying this is a legal notice, asserting the exclusive trademark rights of Halden Electronics to the content, and strictly prohibiting the distribution of the material therein.", 
				2 => "At the top, a section number and title indicate instructions for operating an Echo Scanner, a patented device for employee use. Instructions suggest using a right mouse button (RMB) to activate the scanner towards objects of interest. Upon detection, the scanner provides data such as monetary value, name, and purpose, with color-coded information: green for places or objects of interest, yellow for objects returnable as valuable scrap to the Company, and red for biological matter such as wildlife.\r\n\r\nA tip box emphasizes using the scanner to locate the autopilot ship or other points of interest when outside, noting the scanner's signal range of up to 50 meters in open areas.\r\n\r\nAn illustration shows radio waves emanating from a human figure wearing a helmet, suggesting the operational range of the scanner.\r\n\r\nBelow, a warning icon prefaces a caution about the scanner's built-in components in helmet compartments emitting radiation, with a potential increase in cancer risk and other illnesses. The Company's obligation to disclose this information complies with the HDHAN Health Act.\r\n\r\nThe page is numbered 146 at the bottom.", 
				3 => "A section title suggests information about the relationship between an autopilot ship, a terminal, and the user, described as a contracted worker provided with one of the company's vehicles as a home base and access to a multi-use Terminal. Instructions for routing to moons using the terminal's GPS feature are given, with a note that travel to distant moons may require Company Credits, the cost of which is determined by a risk and cost-benefit analysis department.\r\n\r\nA tip box advises that safer and closer moons are generally less costly or free, and suggests adherence to these areas as recommended by the risk analysis team for the duration of a contract.\r\n\r\nUnder a subheading about purchasing tools, the Terminal is mentioned as a gateway to the Company Store, where items, specifically under 30 pounds, can be bought in bulk, highlighting a Survival Kit as essential for beginners. The delivery process for purchased items involves their arrival via a transport vehicle on the chosen moon's surface, with a cautionary instruction not to miss the delivery.\r\n\r\nAnother subheading, Bestiary, explains that using the Echo Scanner on wildlife transmits information to a research team, which is then added to the user's terminal bestiary if not already documented.\r\n\r\nThe page concludes with the number 139 at the bottom. An image of a computer terminal with a screen and keyboard is also shown, suggesting the described Terminal.", 
				4 => "A section heading indicates guidelines for returning scrap and conducting transactions with the Company. It underlines the expectation of returning materials in exchange for Company Credits, despite the perceived luxury of the contract period. Directions are given to route to the Company Building on 71-Gordion to sell scrap.\r\n\r\nA warning box lists specific directives for selling scrap: to avoid loitering around the counter, prepare all scrap for bulk placement on the counter, and to signal the Company by ringing a bell until acknowledged, all while maintaining silence.\r\n\r\nA note highlights that the exchange rate from scrap to Credits is variable, advising to verify current rates via the terminal.\r\n\r\nAnother section heading introduces general and miscellaneous job tips. It advises using an electric coil for charging battery-powered items, planning trips considering that the autopilot ship won't stay on a moon surface past midnight, keeping a crewmate at \"home\" for intelligence and remote access capabilities, and using the terminal to broadcast special codes for accessing secure doors and areas, with \"E9\" provided as an example code.\r\n\r\nThe page number 140 is visible at the bottom.", 
				_ => "Unknown page.", 
			};
		}
	}
	public class ControlTipAccessPatch : MonoBehaviour
	{
		private const string SpeakControlTipKeybindName = "SpeakControlTipKey";

		private const Key SpeakControlTipDefaultKey = 5;

		public void Initialize()
		{
			Debug.Log((object)"ControlTipPatch: Initializing input actions.");
			LethalAccess.Instance.RegisterKeybind("SpeakControlTipKey", (Key)5, SpeakControlTip);
			Debug.Log((object)"ControlTipPatch: Input actions are registered.");
		}

		private void SpeakControlTip()
		{
			string text = "";
			for (int i = 1; i <= 3; i++)
			{
				GameObject val = GameObject.Find($"Systems/UI/Canvas/IngamePlayerHUD/TopRightCorner/ControlTip{i}");
				if ((Object)(object)val != (Object)null)
				{
					TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
					if ((Object)(object)component != (Object)null)
					{
						text = text + ((TMP_Text)component).text + ", ";
					}
					else
					{
						Debug.LogError((object)$"[ControlTipPatch] TMP Text component not found on ControlTip{i} GameObject.");
					}
				}
				else
				{
					Debug.LogError((object)$"[ControlTipPatch] ControlTip{i} GameObject not found.");
				}
			}
			if (!string.IsNullOrEmpty(text))
			{
				Debug.Log((object)("[ControlTipPatch] Speaking control tips: " + text));
				Utilities.SpeakText(text);
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
	public static class HUDManagerFillEndGameStatsPatch
	{
		private static void Postfix(HUDManager __instance, EndOfGameStats stats, int scrapCollected)
		{
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Invalid comparison between Unknown and I4
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("End of Round Stats:");
			stringBuilder.AppendLine($"Scrap Collected Value: ${scrapCollected}.");
			int quotaFulfilled = TimeOfDay.Instance.quotaFulfilled;
			int profitQuota = TimeOfDay.Instance.profitQuota;
			stringBuilder.AppendLine($"Quota: ${quotaFulfilled} of ${profitQuota}.");
			for (int i = 0; i < __instance.playersManager.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = __instance.playersManager.allPlayerScripts[i];
				if (!((Object)(object)val != (Object)null) || val.playerUsername.StartsWith("Player #"))
				{
					continue;
				}
				stringBuilder.AppendLine($"Player {i + 1}: {val.playerUsername}.");
				stringBuilder.AppendLine("State: " + (val.isPlayerDead ? "Dead." : "Alive."));
				if (val.isPlayerDead)
				{
					string text = (((int)val.causeOfDeath == 10) ? "Abandoned." : "Deceased.");
					stringBuilder.AppendLine("Cause of Death: " + text + ".");
				}
				if (stats.allPlayerStats.Length <= i)
				{
					continue;
				}
				PlayerStats val2 = stats.allPlayerStats[i];
				if (val2.playerNotes.Count <= 0)
				{
					continue;
				}
				stringBuilder.AppendLine("Notes:");
				foreach (string playerNote in val2.playerNotes)
				{
					stringBuilder.AppendLine("* " + playerNote + ".");
				}
			}
			EndOfGameStatUIElements statsUIElements = __instance.statsUIElements;
			if (!string.IsNullOrEmpty(((TMP_Text)statsUIElements.gradeLetter).text))
			{
				stringBuilder.AppendLine("Grade: " + ((TMP_Text)statsUIElements.gradeLetter).text + ".");
			}
			AnimatorStateInfo currentAnimatorStateInfo = __instance.endgameStatsAnimator.GetCurrentAnimatorStateInfo(0);
			if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("displayPenalty"))
			{
				stringBuilder.AppendLine("Penalties have been applied due to player deaths.");
				if ((Object)(object)statsUIElements.penaltyAddition != (Object)null && (Object)(object)statsUIElements.penaltyTotal != (Object)null)
				{
					stringBuilder.AppendLine("Penalty Addition: " + ((TMP_Text)statsUIElements.penaltyAddition).text + ".");
					stringBuilder.AppendLine("Penalty Total: " + ((TMP_Text)statsUIElements.penaltyTotal).text + ".");
				}
			}
			Utilities.SpeakText(stringBuilder.ToString());
		}
	}
	public class PlayerHealthPatch : MonoBehaviour
	{
		private const string SpeakHealthKeybindName = "SpeakHealthKey";

		private const Key SpeakHealthDefaultKey = 22;

		public void Initialize()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Debug.Log((object)"PlayerHealthPatch: Initializing input actions.");
			LethalAccess.Instance.RegisterKeybind("SpeakHealthKey", (Key)22, SpeakPlayerHealth);
			Debug.Log((object)"PlayerHealthPatch: Input actions are registered.");
			Harmony val = new Harmony("green.lethalaccess.playerhealthaccess");
			val.PatchAll(typeof(HUDManagerUpdateHealthUIPatch));
		}

		private void SpeakPlayerHealth()
		{
			int lastUpdatedHealth = HUDManagerUpdateHealthUIPatch.LastUpdatedHealth;
			Debug.Log((object)("[PlayerHealthPatch] Speaking health: " + lastUpdatedHealth));
			Utilities.SpeakText(lastUpdatedHealth + " HP");
		}
	}
	[HarmonyPatch(typeof(HUDManager), "UpdateHealthUI")]
	public class HUDManagerUpdateHealthUIPatch
	{
		public static int LastUpdatedHealth { get; private set; } = 100;


		private static void Postfix(int health)
		{
			LastUpdatedHealth = health;
			Debug.Log((object)$"[LethalAccess] Player health updated: {health}");
		}
	}
	public static class LethalAccess_InteractionPatches
	{
		[HarmonyPatch(typeof(HUDManager), "Update")]
		public static class HUDManager_UpdatePatch
		{
			[HarmonyPostfix]
			public static void Postfix(HUDManager __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				InitializeTones();
				if ((Object)(object)continuousToneSource == (Object)null)
				{
					return;
				}
				if (__instance.holdFillAmount > 0f)
				{
					float pitch = 1f + __instance.holdFillAmount * 0.7f;
					continuousToneSource.pitch = pitch;
					if (!continuousToneSource.isPlaying)
					{
						continuousToneSource.Play();
					}
					continuousToneSource.volume = Mathf.Lerp(0.1f, 0.5f, __instance.holdFillAmount);
				}
				else if (__instance.holdFillAmount == 0f && continuousToneSource.isPlaying)
				{
					continuousToneSource.Stop();
				}
			}
		}

		[HarmonyPatch(typeof(HUDManager), "HoldInteractionFill")]
		public static class HUDManager_HoldInteractionFillPatch
		{
			[HarmonyPostfix]
			public static void Postfix(HUDManager __instance, float timeToHold, float speedMultiplier, bool __result)
			{
				if (__result)
				{
					PlayCompletionTone();
				}
			}
		}

		private static AudioSource continuousToneSource;

		private static AudioSource completionToneSource;

		private static bool isToneInitialized;

		private static void InitializeTones()
		{
			if ((!isToneInitialized || (Object)(object)continuousToneSource == (Object)null || (Object)(object)completionToneSource == (Object)null) && (Object)(object)LethalAccess.PlayerTransform != (Object)null)
			{
				continuousToneSource = ((Component)LethalAccess.PlayerTransform).gameObject.AddComponent<AudioSource>();
				continuousToneSource.loop = true;
				continuousToneSource.clip = GenerateContinuousToneClip(440f, 1f);
				continuousToneSource.volume = 0.3f;
				completionToneSource = ((Component)LethalAccess.PlayerTransform).gameObject.AddComponent<AudioSource>();
				completionToneSource.loop = false;
				completionToneSource.clip = GenerateCompletionToneClip();
				completionToneSource.volume = 0.7f;
				completionToneSource.priority = 0;
				completionToneSource.bypassEffects = true;
				completionToneSource.bypassListenerEffects = true;
				completionToneSource.bypassReverbZones = true;
				isToneInitialized = true;
			}
		}

		private static AudioClip GenerateContinuousToneClip(float frequency, float duration)
		{
			int num = 44100;
			int num2 = Mathf.RoundToInt((float)num * duration);
			AudioClip val = AudioClip.Create("ContinuousTone", num2, 1, num, false);
			float[] array = new float[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = Mathf.Sin((float)Math.PI * 2f * frequency * (float)i / (float)num);
			}
			val.SetData(array, 0);
			return val;
		}

		private static AudioClip GenerateCompletionToneClip()
		{
			int num = 44100;
			float num2 = 0.15f;
			float num3 = 0.05f;
			int num4 = Mathf.RoundToInt((float)num * (num2 * 2f + num3));
			AudioClip val = AudioClip.Create("CompletionTone", num4, 1, num, false);
			float[] array = new float[num4];
			float num5 = 660f;
			float num6 = 785f;
			int num7 = 0;
			for (int i = 0; i < Mathf.RoundToInt((float)num * num2); i++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num5 * (float)i / (float)num) * 0.5f;
			}
			num7 = Mathf.Min(num7 + Mathf.RoundToInt((float)num * num3), num4);
			for (int j = 0; j < Mathf.RoundToInt((float)num * num2); j++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num6 * (float)j / (float)num) * 0.5f;
			}
			val.SetData(array, 0);
			return val;
		}

		private static void PlayCompletionTone()
		{
			InitializeTones();
			if ((Object)(object)completionToneSource != (Object)null && !completionToneSource.isPlaying)
			{
				completionToneSource.PlayOneShot(completionToneSource.clip, 1f);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	public static class PlayerControllerBUpdatePatch
	{
		private static string lastInteractText = "";

		private static TMP_Text interactTextComponent = null;

		private static void Postfix()
		{
			if ((Object)(object)interactTextComponent == (Object)null || (Object)(object)((Component)interactTextComponent).gameObject == (Object)null)
			{
				GameObject val = GameObject.Find("Systems/UI/Canvas/PlayerCursor/InteractText");
				if ((Object)(object)val != (Object)null)
				{
					interactTextComponent = val.GetComponent<TMP_Text>();
				}
			}
			if ((Object)(object)interactTextComponent != (Object)null && interactTextComponent.text != lastInteractText)
			{
				SpeakInteraction(interactTextComponent.text);
				lastInteractText = interactTextComponent.text;
			}
		}

		private static void SpeakInteraction(string text)
		{
			if (!string.IsNullOrWhiteSpace(text) && !(text == "Climb : [E]") && !(text == "Use door : [E]"))
			{
				Utilities.SpeakText(text);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	public static class IsInsideFactoryPatch
	{
		public static bool IsInFactory;

		private static bool previousIsInFactoryState;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		public static void Postfix()
		{
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if (!((Object)(object)localPlayerController != (Object)null))
			{
				return;
			}
			bool isInsideFactory = localPlayerController.isInsideFactory;
			if (isInsideFactory != previousIsInFactoryState)
			{
				previousIsInFactoryState = isInsideFactory;
				IsInFactory = isInsideFactory;
				if (isInsideFactory)
				{
					Utilities.SpeakText("You have entered the Facility.");
				}
				else
				{
					Utilities.SpeakText("You have left the Facility.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	public static class ItemAction
	{
		private static DateTime lastSpokenTime = DateTime.MinValue;

		private static AudioSource audioSource;

		private static AudioSource twoHandedAudioSource;

		public static event Action OnItemHeld;

		private static void SpeakWithCooldown(string text)
		{
			if ((DateTime.Now - lastSpokenTime).TotalSeconds > 0.05)
			{
				Utilities.SpeakText(text);
				lastSpokenTime = DateTime.Now;
			}
		}

		private static void HandleItemPickedUp(bool isTwoHanded)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (isTwoHanded)
			{
				PlayTwoHandedSound();
			}
			else
			{
				if ((Object)(object)audioSource == (Object)null)
				{
					GameObject val = new GameObject("ItemPickupAudioSource");
					audioSource = val.AddComponent<AudioSource>();
					audioSource.clip = GenerateItemPickupTone();
					audioSource.volume = 0.35f;
				}
				audioSource.Play();
			}
			LethalAccess.currentLookTarget = null;
		}

		private static AudioClip GenerateItemPickupTone()
		{
			int num = 44100;
			float num2 = 0.1f;
			float num3 = 0.028125f;
			int num4 = Mathf.RoundToInt((float)num * (num2 * 2f + num3));
			AudioClip val = AudioClip.Create("ItemPickupTone", num4, 1, num, false);
			float[] array = new float[num4];
			float num5 = 544.5f;
			float num6 = 647.5f;
			int num7 = 0;
			for (int i = 0; i < Mathf.RoundToInt((float)num * num2); i++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num5 * (float)i / (float)num);
			}
			num7 = Mathf.Min(num7 + Mathf.RoundToInt((float)num * num3), num4);
			for (int j = 0; j < Mathf.RoundToInt((float)num * num2); j++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num6 * (float)j / (float)num);
			}
			val.SetData(array, 0);
			return val;
		}

		private static void PlayTwoHandedSound()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)twoHandedAudioSource == (Object)null)
			{
				GameObject val = new GameObject("TwoHandedAudioSource");
				twoHandedAudioSource = val.AddComponent<AudioSource>();
				twoHandedAudioSource.clip = GenerateTwoHandedTone();
				twoHandedAudioSource.volume = 0.35f;
			}
			twoHandedAudioSource.Play();
		}

		private static AudioClip GenerateTwoHandedTone()
		{
			int num = 44100;
			float num2 = 0.1f;
			float num3 = 0.028125f;
			int num4 = Mathf.RoundToInt((float)num * (num2 * 2f + num3));
			AudioClip val = AudioClip.Create("TwoHandedTone", num4, 1, num, false);
			float[] array = new float[num4];
			float num5 = 272.25f;
			float num6 = 323.75f;
			int num7 = 0;
			for (int i = 0; i < Mathf.RoundToInt((float)num * num2); i++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num5 * (float)i / (float)num);
			}
			num7 = Mathf.Min(num7 + Mathf.RoundToInt((float)num * num3), num4);
			for (int j = 0; j < Mathf.RoundToInt((float)num * num2); j++)
			{
				if (num7 >= num4)
				{
					break;
				}
				array[num7++] = Mathf.Sin((float)Math.PI * 2f * num6 * (float)j / (float)num);
			}
			val.SetData(array, 0);
			return val;
		}

		[HarmonyPatch("SwitchToItemSlot")]
		[HarmonyPostfix]
		public static void SwitchToItemSlotPostfix(PlayerControllerB __instance, int slot)
		{
			if (((NetworkBehaviour)__instance).IsOwner && (Object)(object)__instance.ItemSlots[slot] != (Object)null)
			{
				GrabbableObject val = __instance.ItemSlots[slot];
				string itemName = val.itemProperties.itemName;
				int scrapValue = val.scrapValue;
				LethalAccess.Instance.navMenu.RemoveItem(((Object)((Component)val).gameObject).name, "Items");
				string text = "held";
				if (val.isPocketed)
				{
					text = "pocketed";
				}
				else if (val.deactivated)
				{
					text = "deactivated";
				}
				if (val.itemProperties.twoHanded)
				{
					SpeakWithCooldown($"{text} {itemName}, two-handed object, worth ${scrapValue}, cannot switch items until this item is dropped");
				}
				else
				{
					SpeakWithCooldown($"{text} {itemName}, worth ${scrapValue}");
				}
				HandleItemPickedUp(val.itemProperties.twoHanded);
				ItemAction.OnItemHeld?.Invoke();
				if (LethalAccess.Instance.navMenu.currentIndices.categoryIndex == LethalAccess.Instance.navMenu.categories.IndexOf("Items") && LethalAccess.Instance.navMenu.menuItems["Items"].Count > 0 && LethalAccess.Instance.navMenu.