Decompiled source of Potatoes TNH BGM Loader v4.1.3

PTNHBGML.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FMOD.Studio;
using FMODUnity;
using FistVR;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Sodalite;
using Sodalite.Api;
using Sodalite.UiWidgets;
using Sodalite.Utilities;
using Stratum;
using Stratum.Extensions;
using TNHBGLoader;
using TNHBGLoader.Sosig;
using TNHBGLoader.Soundtrack;
using TNH_BGLoader;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TNH_BGLoader")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TNH_BGLoader")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("C923A9F9-4F2D-4F11-B5F3-8AB581565FB4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
public class WavUtility
{
	private const int BlockSize_16Bit = 2;

	public static AudioClip ToAudioClip(string filePath)
	{
		return ToAudioClip(File.ReadAllBytes(filePath));
	}

	public static AudioClip ToAudioClip(byte[] fileBytes, int offsetSamples = 0, string name = "wav")
	{
		int num = BitConverter.ToInt32(fileBytes, 16);
		FormatCode(BitConverter.ToUInt16(fileBytes, 20));
		ushort num2 = BitConverter.ToUInt16(fileBytes, 22);
		int num3 = BitConverter.ToInt32(fileBytes, 24);
		ushort num4 = BitConverter.ToUInt16(fileBytes, 34);
		int num5 = 20 + num + 4;
		int dataSize = BitConverter.ToInt32(fileBytes, num5);
		float[] array = num4 switch
		{
			8 => Convert8BitByteArrayToAudioClipData(fileBytes, num5, dataSize), 
			16 => Convert16BitByteArrayToAudioClipData(fileBytes, num5, dataSize), 
			24 => Convert24BitByteArrayToAudioClipData(fileBytes, num5, dataSize), 
			32 => Convert32BitByteArrayToAudioClipData(fileBytes, num5, dataSize), 
			_ => throw new Exception(num4 + " bit depth is not supported."), 
		};
		AudioClip obj = AudioClip.Create(name, array.Length, (int)num2, num3, false);
		obj.SetData(array, 0);
		return obj;
	}

	private static float[] Convert8BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
	{
		int num = BitConverter.ToInt32(source, headerOffset);
		headerOffset += 4;
		float[] array = new float[num];
		sbyte b = sbyte.MaxValue;
		for (int i = 0; i < num; i++)
		{
			array[i] = (float)(int)source[i] / (float)b;
		}
		return array;
	}

	private static float[] Convert16BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
	{
		int num = BitConverter.ToInt32(source, headerOffset);
		headerOffset += 4;
		int num2 = 2;
		int num3 = num / num2;
		float[] array = new float[num3];
		short num4 = short.MaxValue;
		int num5 = 0;
		for (int i = 0; i < num3; i++)
		{
			num5 = i * num2 + headerOffset;
			array[i] = (float)BitConverter.ToInt16(source, num5) / (float)num4;
		}
		return array;
	}

	private static float[] Convert24BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
	{
		int num = BitConverter.ToInt32(source, headerOffset);
		headerOffset += 4;
		int num2 = 3;
		int num3 = num / num2;
		int num4 = int.MaxValue;
		float[] array = new float[num3];
		byte[] array2 = new byte[4];
		int num5 = 0;
		for (int i = 0; i < num3; i++)
		{
			num5 = i * num2 + headerOffset;
			Buffer.BlockCopy(source, num5, array2, 1, num2);
			array[i] = (float)BitConverter.ToInt32(array2, 0) / (float)num4;
		}
		return array;
	}

	private static float[] Convert32BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
	{
		int num = BitConverter.ToInt32(source, headerOffset);
		headerOffset += 4;
		int num2 = 4;
		int num3 = num / num2;
		int num4 = int.MaxValue;
		float[] array = new float[num3];
		int num5 = 0;
		for (int i = 0; i < num3; i++)
		{
			num5 = i * num2 + headerOffset;
			array[i] = (float)BitConverter.ToInt32(source, num5) / (float)num4;
		}
		return array;
	}

	public static byte[] FromAudioClip(AudioClip audioClip)
	{
		string filepath;
		return FromAudioClip(audioClip, out filepath, saveAsFile: false);
	}

	public static byte[] FromAudioClip(AudioClip audioClip, out string filepath, bool saveAsFile = true, string dirname = "recordings")
	{
		MemoryStream stream = new MemoryStream();
		ushort bitDepth = 16;
		int fileSize = audioClip.samples * 2 + 44;
		WriteFileHeader(ref stream, fileSize);
		WriteFileFormat(ref stream, audioClip.channels, audioClip.frequency, bitDepth);
		WriteFileData(ref stream, audioClip, bitDepth);
		byte[] array = stream.ToArray();
		if (saveAsFile)
		{
			filepath = string.Format("{0}/{1}/{2}.{3}", Application.persistentDataPath, dirname, DateTime.UtcNow.ToString("yyMMdd-HHmmss-fff"), "wav");
			Directory.CreateDirectory(Path.GetDirectoryName(filepath));
			File.WriteAllBytes(filepath, array);
		}
		else
		{
			filepath = null;
		}
		stream.Dispose();
		return array;
	}

	private static int WriteFileHeader(ref MemoryStream stream, int fileSize)
	{
		byte[] bytes = Encoding.ASCII.GetBytes("RIFF");
		int num = 0 + WriteBytesToMemoryStream(ref stream, bytes, "ID");
		int value = fileSize - 8;
		int num2 = num + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value), "CHUNK_SIZE");
		byte[] bytes2 = Encoding.ASCII.GetBytes("WAVE");
		return num2 + WriteBytesToMemoryStream(ref stream, bytes2, "FORMAT");
	}

	private static int WriteFileFormat(ref MemoryStream stream, int channels, int sampleRate, ushort bitDepth)
	{
		byte[] bytes = Encoding.ASCII.GetBytes("fmt ");
		int num = 0 + WriteBytesToMemoryStream(ref stream, bytes, "FMT_ID");
		int value = 16;
		int num2 = num + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value), "SUBCHUNK_SIZE");
		ushort value2 = 1;
		int num3 = num2 + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value2), "AUDIO_FORMAT");
		ushort value3 = Convert.ToUInt16(channels);
		int num4 = num3 + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value3), "CHANNELS") + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(sampleRate), "SAMPLE_RATE");
		int value4 = sampleRate * channels * BytesPerSample(bitDepth);
		int num5 = num4 + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value4), "BYTE_RATE");
		ushort value5 = Convert.ToUInt16(channels * BytesPerSample(bitDepth));
		return num5 + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value5), "BLOCK_ALIGN") + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(bitDepth), "BITS_PER_SAMPLE");
	}

	private static int WriteFileData(ref MemoryStream stream, AudioClip audioClip, ushort bitDepth)
	{
		float[] array = new float[audioClip.samples * audioClip.channels];
		audioClip.GetData(array, 0);
		byte[] bytes = ConvertAudioClipDataToInt16ByteArray(array);
		byte[] bytes2 = Encoding.ASCII.GetBytes("data");
		int num = 0 + WriteBytesToMemoryStream(ref stream, bytes2, "DATA_ID");
		int value = Convert.ToInt32(audioClip.samples * 2);
		return num + WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(value), "SAMPLES") + WriteBytesToMemoryStream(ref stream, bytes, "DATA");
	}

	private static byte[] ConvertAudioClipDataToInt16ByteArray(float[] data)
	{
		MemoryStream memoryStream = new MemoryStream();
		int count = 2;
		short num = short.MaxValue;
		for (int i = 0; i < data.Length; i++)
		{
			memoryStream.Write(BitConverter.GetBytes(Convert.ToInt16(data[i] * (float)num)), 0, count);
		}
		byte[] result = memoryStream.ToArray();
		memoryStream.Dispose();
		return result;
	}

	private static int WriteBytesToMemoryStream(ref MemoryStream stream, byte[] bytes, string tag = "")
	{
		int num = bytes.Length;
		stream.Write(bytes, 0, num);
		return num;
	}

	public static ushort BitDepth(AudioClip audioClip)
	{
		return Convert.ToUInt16((float)(audioClip.samples * audioClip.channels) * audioClip.length / (float)audioClip.frequency);
	}

	private static int BytesPerSample(ushort bitDepth)
	{
		return bitDepth / 8;
	}

	private static int BlockSize(ushort bitDepth)
	{
		return bitDepth switch
		{
			32 => 4, 
			16 => 2, 
			8 => 1, 
			_ => throw new Exception(bitDepth + " bit depth is not supported."), 
		};
	}

	private static string FormatCode(ushort code)
	{
		switch (code)
		{
		case 1:
			return "PCM";
		case 2:
			return "ADPCM";
		case 3:
			return "IEEE";
		case 7:
			return "μ-law";
		case 65534:
			return "WaveFormatExtensable";
		default:
			Debug.LogWarning((object)("Unknown wav code format:" + code));
			return "";
		}
	}
}
namespace TNHBGLoader
{
	public class AnnouncerYamlfest
	{
		public string Name { get; set; }

		[YamlMember(Alias = "Guid")]
		public string GUID { get; set; }

		public string VoiceLines { get; set; }

		[CanBeNull]
		public string Location { get; set; }

		[DefaultValue(0.2f)]
		public float FrontPadding { get; set; }

		[DefaultValue(1.2f)]
		public float BackPadding { get; set; }
	}
	public static class Common
	{
		public static int Wrap(this int self, int min, int max)
		{
			if (self < min)
			{
				return max - (self + min + 1);
			}
			if (self > max)
			{
				return min + (self - max - 1);
			}
			return self;
		}

		public static int Wrap(this int self, int[] range)
		{
			return self.Wrap(range[0], range[1]);
		}
	}
	public class GeneralAPI : MonoBehaviour
	{
		public static Texture2D GetIcon(string guid, string[] paths)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			PluginMain.LogSpam("Loading image for " + guid);
			foreach (string text in paths)
			{
				if (File.Exists(text))
				{
					byte[] array = File.ReadAllBytes(text);
					Texture2D val = new Texture2D(1, 1);
					val.LoadImage(array);
					if ((Object)(object)val != (Object)null)
					{
						PluginMain.LogSpam("Loading icon from " + text);
						return val;
					}
				}
			}
			PluginMain.DebugLog.LogError((object)("Cannot find icon for " + guid + "!\nPossible locations:\n" + string.Join("\n", paths)));
			return null;
		}

		public static bool IfIsInRange(float input, float min, float max)
		{
			return Mathf.Clamp(input, min, max) == input;
		}
	}
	public class Patcher_FistVR
	{
		[HarmonyPatch(typeof(Sosig), "Start")]
		[HarmonyPrefix]
		public static bool Sosig_Start_SetVLS(Sosig __instance)
		{
			string name = ((Object)__instance.Speech).name;
			if (SosigVLSAPI.VLSGuidOrder.Contains(name))
			{
				if (SosigVLSAPI.CurrentSosigVlsOfVlsSet(name).guid == "h3vr.default")
				{
					return true;
				}
				if (SosigVLSAPI.CurrentSosigVlsOfVlsSet(name).guid == "h3vr.zosig")
				{
					return true;
				}
				__instance.Speech = SosigVLSAPI.CurrentSosigVlsOfVlsSet(name).SpeechSet;
			}
			return true;
		}

		[HarmonyPatch(typeof(FVRFMODController), "SetMasterVolume")]
		[HarmonyPrefix]
		public static bool FVRFMODController_SetMasterVolume_IncludeBGMVol(ref float i)
		{
			i *= PluginMain.BackgroundMusicVolume.Value;
			return true;
		}

		[HarmonyPatch(typeof(SM), "PlayCoreSoundDelayed")]
		[HarmonyPrefix]
		public static bool SM_PlayCoreSoundDelayed_IncludeAnnouncerVol(ref AudioEvent ClipSet)
		{
			ClipSet.VolumeRange.x *= PluginMain.AnnouncerMusicVolume.Value;
			ClipSet.VolumeRange.y *= PluginMain.AnnouncerMusicVolume.Value;
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "VoiceUpdate")]
		[HarmonyPrefix]
		public static bool TNH_Manager_VoiceUpdate_AccountForVoiceLinePadding(TNH_Manager __instance)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0097: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.timeTilLineClear >= 0f)
			{
				__instance.timeTilLineClear -= Time.deltaTime;
				return true;
			}
			if (__instance.QueuedLines.Count > 0)
			{
				TNH_VoiceLineID key = __instance.QueuedLines.Dequeue();
				if (__instance.voiceDic_Standard.ContainsKey(key))
				{
					int index = Random.Range(0, __instance.voiceDic_Standard[key].Count);
					AudioClip val = __instance.voiceDic_Standard[key][index];
					AudioEvent val2 = new AudioEvent();
					val2.Clips.Add(val);
					val2.PitchRange = new Vector2(1f, 1f);
					val2.VolumeRange = new Vector2(0.6f, 0.6f);
					__instance.timeTilLineClear = val.length + AnnouncerAPI.CurrentAnnouncer.BackPadding;
					SM.PlayCoreSoundDelayed((FVRPooledAudioType)20, val2, ((Component)__instance).transform.position, AnnouncerAPI.CurrentAnnouncer.FrontPadding);
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(TNH_UIManager), "Start")]
		[HarmonyPostfix]
		public static void TNH_UIManager_SpawnPanel()
		{
			//IL_0035: 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)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			TNHPanel tNHPanel = new TNHPanel();
			tNHPanel.Initialize("tnh", hasBgms: true, hasVls: true, hasAnnouncers: true);
			GameObject orCreatePanel = tNHPanel.Panel.GetOrCreatePanel();
			orCreatePanel.transform.position = new Vector3(0.0561f, 1f, 7.1821f);
			orCreatePanel.transform.localEulerAngles = new Vector3(315f, 0f, 0f);
			orCreatePanel.GetComponent<FVRPhysicalObject>().SetIsKinematicLocked(true);
			IconDisplayWaitForInit iconDisplayWaitForInit = new GameObject().AddComponent<IconDisplayWaitForInit>();
			iconDisplayWaitForInit.panel = orCreatePanel;
			iconDisplayWaitForInit.bgmpanel = tNHPanel;
			if (!PluginMain.IsSoundtrack.Value)
			{
				for (int i = 0; i < BankAPI.LoadedBankLocations.Count; i++)
				{
					if (Path.GetFileNameWithoutExtension(BankAPI.LoadedBankLocations[i]) == PluginMain.LastLoadedBank.Value)
					{
						BankAPI.SwapBank(i);
						break;
					}
				}
			}
			AnnouncerAPI.CurrentAnnouncerIndex = AnnouncerAPI.GetAnnouncerIndexFromGUID(PluginMain.LastLoadedAnnouncer.Value);
		}

		[HarmonyPatch(typeof(TNH_Manager), "Start")]
		[HarmonyPrefix]
		public static bool TNH_Manager_Start_NukeSongSnippets()
		{
			BankAPI.NukeSongSnippets();
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "InitLibraries")]
		[HarmonyPrefix]
		public static bool TNH_Manager_InitLibraries_LoadAnnouncers(TNH_Manager __instance)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			AnnouncerManifest currentAnnouncer = AnnouncerAPI.CurrentAnnouncer;
			if (currentAnnouncer.GUID == "h3vr.corrupted")
			{
				TNH_VoiceDatabase voiceDB = __instance.VoiceDB;
				foreach (TNH_VoiceLine line in voiceDB.Lines)
				{
					line.Clip_Standard = line.Clip_Corrupted;
				}
				__instance.VoiceDB = voiceDB;
				return true;
			}
			if (currentAnnouncer.GUID == "h3vr.default")
			{
				return true;
			}
			TNH_VoiceDatabase val = ScriptableObject.CreateInstance<TNH_VoiceDatabase>();
			val.Lines = new List<TNH_VoiceLine>();
			foreach (VoiceLine voiceLine in currentAnnouncer.VoiceLines)
			{
				AudioClip val2 = null;
				val2 = AnnouncerAPI.GetAudioFromFile(voiceLine.ClipPath);
				if ((Object)(object)val2 == (Object)null)
				{
					PluginMain.DebugLog.LogWarning((object)("Failed to load from " + voiceLine.ClipPath + "!"));
				}
				TNH_VoiceLine val3 = new TNH_VoiceLine();
				val3.ID = voiceLine.ID;
				val3.Clip_Standard = val2;
				val.Lines.Add(val3);
			}
			foreach (int vlid in Enum.GetValues(typeof(TNH_VoiceLineID)))
			{
				if (val.Lines.FindAll((TNH_VoiceLine line) => (int)line.ID == vlid).Count == 0)
				{
					string[] unusedVoicelines = AnnouncerAPI.UnusedVoicelines;
					TNH_VoiceLineID val4 = (TNH_VoiceLineID)vlid;
					if (unusedVoicelines.Any(((object)(TNH_VoiceLineID)(ref val4)).ToString().Contains))
					{
						ManualLogSource debugLog = PluginMain.DebugLog;
						string[] obj = new string[5] { "ID ", null, null, null, null };
						val4 = (TNH_VoiceLineID)vlid;
						obj[1] = ((object)(TNH_VoiceLineID)(ref val4)).ToString();
						obj[2] = " is empty for ";
						obj[3] = currentAnnouncer.GUID;
						obj[4] = "! Was this intentional?";
						debugLog.LogWarning((object)string.Concat(obj));
					}
					List<TNH_VoiceLine> second = __instance.VoiceDB.Lines.FindAll((TNH_VoiceLine line) => (int)line.ID == vlid);
					val.Lines = val.Lines.Concat(second).ToList();
				}
			}
			stopwatch.Stop();
			__instance.VoiceDB = val;
			PluginMain.LogSpam(stopwatch.ElapsedMilliseconds + "ms to load all voicelines!");
			PluginMain.DebugLog.LogInfo((object)("TNH run started! PTNHBGML Info:\nLoaded announcer: " + AnnouncerAPI.CurrentAnnouncer.GUID + "\nLoaded song: " + BankAPI.GetNameFromIndex(BankAPI.CurrentBankIndex)));
			return true;
		}
	}
	public class Patcher_FMOD
	{
		[HarmonyPatch(typeof(RuntimeUtils), "GetBankPath")]
		[HarmonyPrefix]
		public static bool FMODRuntimeUtilsPatch_GetBankPath(ref string bankName, ref string __result)
		{
			string streamingAssetsPath = Application.streamingAssetsPath;
			if (Path.GetExtension(bankName) != ".bank")
			{
				if (Path.IsPathRooted(bankName))
				{
					__result = bankName + ".bank";
					return false;
				}
				__result = $"{streamingAssetsPath}/{bankName}.bank";
				return false;
			}
			if (Path.IsPathRooted(bankName))
			{
				__result = bankName;
				return false;
			}
			__result = $"{streamingAssetsPath}/{bankName}";
			return false;
		}

		[HarmonyPatch(typeof(RuntimeManager))]
		[HarmonyPatch("LoadBank", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		[HarmonyPrefix]
		public static bool FMODRuntimeManagerPatch_LoadBank(ref string bankName)
		{
			if (bankName == "MX_TAH" && !BankAPI.BanksEmptyOrNull)
			{
				if (BankAPI.CurrentBankLocation == "Select Random" && !PluginMain.IsSoundtrack.Value)
				{
					PluginMain.DebugLog.LogInfo((object)("Activated Random. Current Bank: " + BankAPI.CurrentBankLocation));
					int num = Random.Range(1, BankAPI.LoadedBankLocations.Count + SoundtrackAPI.Soundtracks.Count);
					PluginMain.DebugLog.LogInfo((object)$"Selected: {num}");
					if (num < BankAPI.LoadedBankLocations.Count)
					{
						PluginMain.IsSoundtrack.Value = false;
						BankAPI.CurrentBankIndex = num;
					}
					else
					{
						PluginMain.IsSoundtrack.Value = true;
						SoundtrackAPI.SelectedSoundtrackIndex = num - BankAPI.LoadedBankLocations.Count;
					}
				}
				PluginMain.DebugLog.LogInfo((object)("IsSoundtrack loading bank/soundtrack time: " + PluginMain.IsSoundtrack.Value));
				if (!PluginMain.IsSoundtrack.Value)
				{
					PluginMain.DebugLog.LogInfo((object)("Injecting bank " + Path.GetFileName(BankAPI.CurrentBankLocation) + " into TNH!"));
					bankName = BankAPI.CurrentBankLocation;
				}
				else
				{
					if (SoundtrackAPI.SelectedSoundtrackIndex >= SoundtrackAPI.Soundtracks.Count || SoundtrackAPI.SelectedSoundtrackIndex < 0)
					{
						PluginMain.DebugLog.LogInfo((object)"Enabled soundtrack not in soundtrack database! Resetting to default.");
						PluginMain.IsSoundtrack.Value = false;
						bankName = BankAPI.LoadedBankLocations[0];
					}
					PluginMain.DebugLog.LogInfo((object)("Loading soundtrack " + SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex].Guid + " into TNH!"));
				}
			}
			return true;
		}
	}
	public static class Extensions
	{
		public static string ToOneLine<T>(this T[] list)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < list.Length; i++)
			{
				stringBuilder.Append(list[i].ToString());
				if (i != list.Length - 1)
				{
					stringBuilder.Append(", ");
				}
			}
			return stringBuilder.ToString();
		}
	}
	[BepInPlugin("dll.potatoes.ptnhbgml", "Potatoes' Take And Hold Background Music Loader", "4.1.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("stratum", "1.1.0")]
	public class PluginMain : StratumPlugin
	{
		public static ConfigEntry<float> BackgroundMusicVolume;

		public static ConfigEntry<float> AnnouncerMusicVolume;

		public static ConfigEntry<string> LastLoadedBank;

		public static ConfigEntry<string> LastLoadedAnnouncer;

		public static ConfigEntry<string> LastLoadedSosigVLS;

		public static ConfigEntry<bool> EnableDebugLogging;

		public static ConfigEntry<bool> IsSoundtrack;

		public static ConfigEntry<bool> LoadSoundtracksOnStartup;

		internal static ManualLogSource DebugLog;

		private IDeserializer _deserializer;

		public static string AssemblyDirectory => Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));

		public static void LogSpam(object data)
		{
			if (EnableDebugLogging.Value)
			{
				DebugLog.LogInfo(data);
			}
		}

		public void Awake()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			DebugLog = ((BaseUnityPlugin)this).Logger;
			InitConfig();
			BankAPI.LoadedBankLocations = (from x in BankAPI.GetLegacyBanks()
				orderby x
				select x).ToList();
			BankAPI.LoadedBankLocations = BankAPI.LoadedBankLocations.Distinct().ToList();
			BankAPI.LoadedBankLocations.Insert(0, "Select Random");
			_deserializer = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).Build();
			AnnouncerAPI.LoadedAnnouncers.Add(AnnouncerManifest.RandomAnnouncer);
			AnnouncerAPI.LoadedAnnouncers.Add(AnnouncerManifest.DefaultAnnouncer);
			AnnouncerAPI.LoadedAnnouncers.Add(AnnouncerManifest.CorruptedAnnouncer);
			SosigVLSDefinitionSetLaod(new VLSGuidToNameDefinitionsYamlfest
			{
				GuidsToNames = new string[2] { "SosigSpeech_Anton:Default", "SosigSpeech_Zosig:Zosig" }
			});
			SosigVLSAPI.LoadedSosigVLSs.Add(SosigManifest.RandomSosigVLS());
			SosigVLSAPI.LoadedSosigVLSs.Add(SosigManifest.DefaultSosigVLS());
			SosigVLSAPI.LoadedSosigVLSs.Add(SosigManifest.DefaultZosigVLS());
			Harmony.CreateAndPatchAll(typeof(Patcher_FMOD), (string)null);
			Harmony.CreateAndPatchAll(typeof(Patcher_FistVR), (string)null);
			Harmony.CreateAndPatchAll(typeof(TnHSoundtrackInterface), (string)null);
		}

		public void InitConfig()
		{
			EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Debug Logs", false, "Spams your log with debug info.");
			BackgroundMusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BGM Volume", 1f, "Changes the magnitude of the BGM volume. Must be between 0 and 4.");
			BackgroundMusicVolume.Value = Mathf.Clamp(BackgroundMusicVolume.Value, 0f, 4f);
			AnnouncerMusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Announcer Volume", 1f, "Changes the magnitude of the Announcer volume. Must be between 0 and 20. (Please don't set the volume to 2000%.)");
			AnnouncerMusicVolume.Value = Mathf.Clamp(BackgroundMusicVolume.Value, 0f, 20f);
			LastLoadedBank = ((BaseUnityPlugin)this).Config.Bind<string>("no touchy", "Saved Bank", "MX_TAH", "Not meant to be changed manually. This autosaves your last bank used, so you don't have to reset it every time you launch H3.");
			LastLoadedAnnouncer = ((BaseUnityPlugin)this).Config.Bind<string>("no touchy", "Saved Announcer", "h3vr.default", "Not meant to be changed manually. This autosaves your last announcer used, so you don't have to reset it every time you launch H3.");
			LastLoadedSosigVLS = ((BaseUnityPlugin)this).Config.Bind<string>("no touchy", "Saved Sosig VLS", "h3vr.default", "Not meant to be changed manually. This autosaves your last sosig set used, so you don't have to reset it every time you launch H3.");
			IsSoundtrack = ((BaseUnityPlugin)this).Config.Bind<bool>("no touchy", "Saved Is Soundtrack", false, "Not meant to be changed manually. This autosaves your last sosig set used, so you don't have to reset it every time you launch H3.");
			LoadSoundtracksOnStartup = ((BaseUnityPlugin)this).Config.Bind<bool>("no touchy", "Load Soundtracks On Startup", false, "Debug. Loads ALL soundtracks on H3 start, not the current soundtrack when loading TnH. Enable only to catch soundtrack loading bugs on start.");
		}

		public override void OnSetup(IStageContext<Empty> ctx)
		{
			ctx.Loaders.Add("tnhbankfile", LoadTNHBankFile);
			ctx.Loaders.Add("tnhannouncer", LoadAnnouncer);
			ctx.Loaders.Add("tnhbgmlsosigvls", LoadSosigVoiceLineSet);
			ctx.Loaders.Add("tnhbgmlvlsdictionary", LoadSosigVoiceLineDefinitionSet);
			ctx.Loaders.Add("tnhbgml_soundtrack", LoadSoundtrack);
		}

		public Empty LoadTNHBankFile(FileSystemInfo handle)
		{
			//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)
			FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle);
			if (!BankAPI.LoadedBankLocations.Contains(fileInfo.FullName))
			{
				BankAPI.LoadedBankLocations.Add(fileInfo.FullName);
			}
			return default(Empty);
		}

		public Empty LoadAnnouncer(FileSystemInfo handle)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle);
			AnnouncerYamlfest announcerYamlfest = new AnnouncerYamlfest();
			announcerYamlfest = _deserializer.Deserialize<AnnouncerYamlfest>(File.ReadAllText(fileInfo.FullName));
			DebugLog.LogInfo((object)("Loaded announcer file " + announcerYamlfest.GUID));
			announcerYamlfest.Location = fileInfo.FullName;
			AnnouncerAPI.LoadedAnnouncers.Add(AnnouncerAPI.GetManifestFromYamlfest(announcerYamlfest));
			return default(Empty);
		}

		public Empty LoadSosigVoiceLineSet(FileSystemInfo handle)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle);
			SosigYamlfest sosigYamlfest = new SosigYamlfest();
			sosigYamlfest = _deserializer.Deserialize<SosigYamlfest>(File.ReadAllText(fileInfo.FullName));
			DebugLog.LogInfo((object)("Loaded Sosig Voiceline set " + sosigYamlfest.GUID));
			sosigYamlfest.Location = fileInfo.FullName;
			SosigVLSAPI.LoadedSosigVLSs.Add(SosigVLSAPI.GetManifestFromYamlfest(sosigYamlfest));
			return default(Empty);
		}

		public Empty LoadSosigVoiceLineDefinitionSet(FileSystemInfo handle)
		{
			//IL_0027: 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)
			FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle);
			VLSGuidToNameDefinitionsYamlfest yamlfest = _deserializer.Deserialize<VLSGuidToNameDefinitionsYamlfest>(File.ReadAllText(fileInfo.FullName));
			SosigVLSDefinitionSetLaod(yamlfest);
			return default(Empty);
		}

		public Empty LoadSoundtrack(FileSystemInfo handle)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle);
			SoundtrackYamlfest soundtrackYamlfest = _deserializer.Deserialize<SoundtrackYamlfest>(File.ReadAllText(fileInfo.FullName));
			DebugLog.LogInfo((object)("Soundtrack detected: " + soundtrackYamlfest.Name));
			SoundtrackManifest soundtrackManifest = soundtrackYamlfest.ToManifest(fileInfo.FullName);
			if (LoadSoundtracksOnStartup.Value)
			{
				soundtrackManifest.AssembleMusicData();
			}
			SoundtrackAPI.Soundtracks.Add(soundtrackManifest);
			return default(Empty);
		}

		private void SosigVLSDefinitionSetLaod(VLSGuidToNameDefinitionsYamlfest yamlfest)
		{
			for (int i = 0; i < yamlfest.GuidsToNames.Length; i++)
			{
				string[] array = yamlfest.GuidsToNames[i].Split(new char[1] { ':' });
				DebugLog.LogInfo((object)("Loading Sosig Voiceline Dictionary Set defining: " + array[0]));
				SosigVLSAPI.VLSGuidToName[array[0]] = array[1];
				SosigVLSAPI.CurrentSosigVLSIndex[array[0]] = 1;
				if (array[0] == "SosigSpeech_Zosig")
				{
					SosigVLSAPI.CurrentSosigVLSIndex[array[0]] = 2;
				}
				if (!SosigVLSAPI.VLSGuidOrder.Contains(array[0]))
				{
					SosigVLSAPI.VLSGuidOrder.Add(array[0]);
				}
			}
		}

		public override IEnumerator OnRuntime(IStageContext<IEnumerator> ctx)
		{
			yield break;
		}
	}
	internal static class PluginDetails
	{
		public const string GUID = "dll.potatoes.ptnhbgml";

		public const string NAME = "Potatoes' Take And Hold Background Music Loader";

		public const string VERS = "4.1.3";
	}
	public class Save
	{
		public string LastLoadedBank { get; set; }

		public string LastLoadedAnnouncer { get; set; }

		public string[] LastLoadedVls { get; set; }

		public string[] LastLoadedVlsSets { get; set; }

		public void Write()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			string contents = Path.Combine(Directory.GetCurrentDirectory(), "lastloaded.yaml");
			File.WriteAllText(((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).Build().Serialize((object)this), contents);
		}

		public static Save Read()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			string path = Path.Combine(Directory.GetCurrentDirectory(), "lastloaded.yaml");
			return ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).Build().Deserialize<Save>(File.ReadAllText(path));
		}
	}
	public class SosigYamlfest
	{
		public string Name { get; set; }

		[YamlMember(Alias = "Guid")]
		public string GUID { get; set; }

		public string VoiceLines { get; set; }

		public string? Location { get; set; }

		public float BasePitch { get; set; }

		public float BaseVolume { get; set; }

		public bool ForceDeathSpeech { get; set; }

		public bool UseAltDeathOnHeadExplode { get; set; }

		public bool LessTalkativeSkirmish { get; set; }
	}
	public class VLSGuidToNameDefinitionsYamlfest
	{
		public string[] GuidsToNames { get; set; }
	}
	public class TNHPanel : MonoBehaviour
	{
		public enum TNHPstates
		{
			BGM,
			Announcer,
			Sosig_Voicelines
		}

		public struct BankOrSoundtrack
		{
			public bool IsBank;

			public string BankGuid;

			public string SoundtrackGuid;

			public string Name;
		}

		public LockablePanel Panel;

		public TNHPstates TNHPstate;

		public string GameMode;

		public List<BankOrSoundtrack> BGMs;

		public bool HasBgms = true;

		public bool HasVls = true;

		public bool HasAnnouncers = true;

		private TextWidget _bankText;

		private TextWidget _volumeText;

		private ButtonWidget[] _musicButtons = (ButtonWidget[])(object)new ButtonWidget[8];

		private ButtonWidget[] _volControls = (ButtonWidget[])(object)new ButtonWidget[2];

		private ButtonWidget[] _cycleControls = (ButtonWidget[])(object)new ButtonWidget[2];

		private ButtonWidget _switchstate;

		private int _firstMusicIndex;

		public RawImage icondisplay;

		private int _selectedVLSSet;

		public void Initialize(string gameMode, bool hasBgms = true, bool hasVls = false, bool hasAnnouncers = false)
		{
			PluginMain.DebugLog.LogInfo((object)$"Initializing. Gamemode: {gameMode}, {hasBgms} {hasVls} {hasAnnouncers}");
			GameMode = gameMode;
			HasBgms = hasBgms;
			HasVls = hasVls;
			HasAnnouncers = hasAnnouncers;
			PluginMain.DebugLog.LogInfo((object)$"Initialized. Gamemode: {GameMode}, {HasBgms} {HasVls} {HasAnnouncers}");
			if (!hasBgms)
			{
				if (!hasAnnouncers)
				{
					TNHPstate = TNHPstates.Sosig_Voicelines;
				}
				if (!hasVls)
				{
					TNHPstate = TNHPstates.Announcer;
				}
			}
			BGMs = new List<BankOrSoundtrack>();
			if (GameMode == "tnh")
			{
				foreach (string loadedBankLocation in BankAPI.LoadedBankLocations)
				{
					BankOrSoundtrack item = default(BankOrSoundtrack);
					item.IsBank = true;
					item.BankGuid = loadedBankLocation;
					item.Name = BankAPI.GetNameFromLocation(loadedBankLocation);
					BGMs.Add(item);
				}
			}
			foreach (SoundtrackManifest soundtrack in SoundtrackAPI.Soundtracks)
			{
				PluginMain.DebugLog.LogInfo((object)("Gamemode: " + GameMode + ", Soundtrack GM: " + soundtrack.GameMode + " of " + soundtrack.Guid));
				if (!(soundtrack.GameMode != GameMode))
				{
					BankOrSoundtrack item2 = default(BankOrSoundtrack);
					item2.IsBank = false;
					item2.SoundtrackGuid = soundtrack.Guid;
					item2.Name = soundtrack.Name;
					BGMs.Add(item2);
				}
			}
			for (int i = 0; i < BGMs.Count(); i++)
			{
				PluginMain.DebugLog.LogInfo((object)$"BGM Loaded: {BGMs[i].Name}, index {i}, IsBank {BGMs[i].IsBank}");
			}
		}

		public TNHPanel()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			Panel = new LockablePanel();
			Panel.Configure += ConfigurePanel;
			Panel.TextureOverride = SodaliteUtils.LoadTextureFromBytes(SodaliteUtils.GetResource(Assembly.GetExecutingAssembly(), "panel.png"));
		}

		private void ConfigurePanel(GameObject panel)
		{
			UiWidget.CreateAndConfigureWidget<GridLayoutWidget>(((Component)panel.transform.Find("OptionsCanvas_0_Main/Canvas")).gameObject, (Action<GridLayoutWidget>)delegate(GridLayoutWidget widget)
			{
				//IL_0015: 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_0035: 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_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: 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)
				((Transform)((UiWidget)widget).RectTransform).localScale = new Vector3(0.07f, 0.07f, 0.07f);
				((Transform)((UiWidget)widget).RectTransform).localPosition = Vector3.zero;
				((UiWidget)widget).RectTransform.anchoredPosition = Vector2.zero;
				((UiWidget)widget).RectTransform.sizeDelta = new Vector2(528.5714f, 342.85715f);
				((UiWidget)widget).RectTransform.pivot = new Vector2(0.5f, 1f);
				((Transform)((UiWidget)widget).RectTransform).localRotation = Quaternion.identity;
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.cellSize = new Vector2(171f, 50f);
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.spacing = Vector2.one * 4f;
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.startCorner = (Corner)0;
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.startAxis = (Axis)0;
				((LayoutGroup)((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup).childAlignment = (TextAnchor)1;
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.constraint = (Constraint)1;
				((LayoutWidget<GridLayoutGroup>)(object)widget).LayoutGroup.constraintCount = 3;
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Expected O, but got Unknown
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					button.ButtonText.text = "Cycle List Up";
					button.AddButtonListener(new ButtonClickEvent(UpdateMusicList));
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
					_cycleControls[0] = button;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num8 = 0;
					button.ButtonText.text = GetNameWithOffset(num8);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num8] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num7 = 1;
					button.ButtonText.text = GetNameWithOffset(num7);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num7] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text)
				{
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					text.Text.text = "Selected:\n" + GetCurrentSelectedItemName();
					_bankText = text;
					text.Text.alignment = (TextAnchor)4;
					Text text6 = text.Text;
					text6.fontSize = text6.fontSize;
					((Transform)((UiWidget)text).RectTransform).localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num6 = 2;
					button.ButtonText.text = GetNameWithOffset(num6);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num6] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num5 = 3;
					button.ButtonText.text = GetNameWithOffset(num5);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num5] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Expected O, but got Unknown
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					button.ButtonText.text = "Cycle List Down";
					button.AddButtonListener(new ButtonClickEvent(UpdateMusicList));
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
					_cycleControls[1] = button;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num4 = 4;
					button.ButtonText.text = GetNameWithOffset(num4);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num4] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num3 = 5;
					button.ButtonText.text = GetNameWithOffset(num3);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num3] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text)
				{
					text.Text.text = "";
					text.Text.alignment = (TextAnchor)4;
					Text text5 = text.Text;
					text5.fontSize += 5;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num2 = 6;
					button.ButtonText.text = GetNameWithOffset(num2);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num2] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					int num = 7;
					button.ButtonText.text = GetNameWithOffset(num);
					button.AddButtonListener(new ButtonClickEvent(SetCurrentItem));
					_musicButtons[num] = button;
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text)
				{
					text.Text.text = "";
					text.Text.alignment = (TextAnchor)4;
					Text text4 = text.Text;
					text4.fontSize += 5;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Expected O, but got Unknown
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					button.ButtonText.text = "BGM";
					button.AddButtonListener(new ButtonClickEvent(SwitchState));
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
					_switchstate = button;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text)
				{
					text.Text.text = "";
					text.Text.alignment = (TextAnchor)4;
					Text text3 = text.Text;
					text3.fontSize += 5;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Expected O, but got Unknown
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					button.ButtonText.text = "Decrease volume";
					button.AddButtonListener(new ButtonClickEvent(UpdateVolume));
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
					_volControls[0] = button;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<TextWidget>((Action<TextWidget>)delegate(TextWidget text)
				{
					text.Text.text = GetVolumePercent();
					_volumeText = text;
					text.Text.alignment = (TextAnchor)4;
					Text text2 = text.Text;
					text2.fontSize += 5;
				});
				((LayoutWidget<GridLayoutGroup>)(object)widget).AddChild<ButtonWidget>((Action<ButtonWidget>)delegate(ButtonWidget button)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Expected O, but got Unknown
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					button.ButtonText.text = "Increase volume";
					button.AddButtonListener(new ButtonClickEvent(UpdateVolume));
					((Component)button.ButtonText).transform.localRotation = Quaternion.identity;
					_volControls[1] = button;
				});
			});
		}

		public void SwitchState(object sender, ButtonClickEventArgs args)
		{
			if (TNHPstate == TNHPstates.BGM)
			{
				TNHPstate = TNHPstates.Announcer;
			}
			else if (TNHPstate == TNHPstates.Announcer)
			{
				TNHPstate = TNHPstates.Sosig_Voicelines;
			}
			else if (TNHPstate == TNHPstates.Sosig_Voicelines)
			{
				TNHPstate = TNHPstates.BGM;
			}
			_switchstate.ButtonText.text = TNHPstate.ToString().Replace('_', ' ');
			_bankText.Text.text = "Selected:\n" + GetCurrentSelectedItemName();
			_firstMusicIndex = 0;
			UpdateMusicList(null, null);
			UpdateVolume(null, null);
			SetIcon();
		}

		private void UpdateMusicList(object sender, ButtonClickEventArgs args)
		{
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (BGMs.Count <= 4)
				{
					return;
				}
				break;
			case TNHPstates.Announcer:
				if (AnnouncerAPI.LoadedAnnouncers.Count <= 4)
				{
					return;
				}
				break;
			case TNHPstates.Sosig_Voicelines:
				if (SosigVLSAPI.LoadedSosigVLSs.Count <= 4)
				{
					return;
				}
				break;
			}
			int num = 0;
			if (sender != null)
			{
				if ((Object)((sender is ButtonWidget) ? sender : null) == (Object)(object)_cycleControls[0])
				{
					num = -1;
				}
				else if ((Object)((sender is ButtonWidget) ? sender : null) == (Object)(object)_cycleControls[1])
				{
					num = 1;
				}
			}
			num = 4 * num;
			int num2 = _firstMusicIndex + num;
			bool flag = num2 < 0;
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (num2 >= BGMs.Count)
				{
					flag = true;
				}
				break;
			case TNHPstates.Announcer:
				if (num2 >= AnnouncerAPI.LoadedAnnouncers.Count)
				{
					flag = true;
				}
				break;
			case TNHPstates.Sosig_Voicelines:
				if (num2 >= SosigVLSAPI.LoadedSosigVLSs.Count)
				{
					flag = true;
				}
				break;
			}
			if (flag)
			{
				WristMenuAPI.Instance.Aud.PlayOneShot(WristMenuAPI.Instance.AudClip_Err);
				return;
			}
			_firstMusicIndex = num2;
			for (int i = 0; i < _musicButtons.Length; i++)
			{
				_musicButtons[i].ButtonText.text = GetNameWithOffset(i);
			}
		}

		private void CycleVLS(object? sender)
		{
			int[] range = new int[2]
			{
				0,
				SosigVLSAPI.VLSGuidOrder.Count - 1
			};
			if (sender != null)
			{
				_selectedVLSSet = (_selectedVLSSet + (((Object)((sender is ButtonWidget) ? sender : null) == (Object)(object)_volControls[1]) ? 1 : (-1))).Wrap(range);
			}
			_volumeText.Text.text = SosigVLSAPI.VLSGuidToName[SosigVLSAPI.VLSGuidOrder[_selectedVLSSet]];
			_volControls[0].ButtonText.text = SosigVLSAPI.VLSGuidToName[SosigVLSAPI.VLSGuidOrder[(_selectedVLSSet - 1).Wrap(range)]];
			_volControls[1].ButtonText.text = SosigVLSAPI.VLSGuidToName[SosigVLSAPI.VLSGuidOrder[(_selectedVLSSet + 1).Wrap(range)]];
			PlaySnippet(SosigVLSAPI.GetRandomPreview(SosigVLSAPI.CurrentSosigVlsOfVlsSet(_selectedVLSSet).guid));
		}

		private void UpdateVolume(object sender, ButtonClickEventArgs args)
		{
			if (TNHPstate == TNHPstates.Sosig_Voicelines)
			{
				CycleVLS(sender);
				return;
			}
			_volControls[0].ButtonText.text = "Decrease volume";
			_volControls[1].ButtonText.text = "Increase volume";
			float num = 0f;
			if (sender != null)
			{
				if ((Object)((sender is ButtonWidget) ? sender : null) == (Object)(object)_volControls[0])
				{
					num = -0.05f;
				}
				else if ((Object)((sender is ButtonWidget) ? sender : null) == (Object)(object)_volControls[1])
				{
					num = 0.05f;
				}
			}
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
			{
				ConfigEntry<float> backgroundMusicVolume = PluginMain.BackgroundMusicVolume;
				backgroundMusicVolume.Value += num;
				if (!GeneralAPI.IfIsInRange(PluginMain.BackgroundMusicVolume.Value, 0f, 4f))
				{
					WristMenuAPI.Instance.Aud.PlayOneShot(WristMenuAPI.Instance.AudClip_Err);
				}
				PluginMain.BackgroundMusicVolume.Value = Mathf.Clamp(PluginMain.BackgroundMusicVolume.Value, 0f, 4f);
				break;
			}
			case TNHPstates.Announcer:
			{
				ConfigEntry<float> announcerMusicVolume = PluginMain.AnnouncerMusicVolume;
				announcerMusicVolume.Value += num;
				if (!GeneralAPI.IfIsInRange(PluginMain.AnnouncerMusicVolume.Value, 0f, 20f))
				{
					WristMenuAPI.Instance.Aud.PlayOneShot(WristMenuAPI.Instance.AudClip_Err);
				}
				PluginMain.AnnouncerMusicVolume.Value = Mathf.Clamp(PluginMain.AnnouncerMusicVolume.Value, 0f, 20f);
				break;
			}
			}
			_volumeText.Text.text = GetVolumePercent();
		}

		private string GetNameWithOffset(int offset)
		{
			int num = _firstMusicIndex + offset;
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (num < BGMs.Count)
				{
					return $"{num + 1}: {BGMs[num].Name}";
				}
				break;
			case TNHPstates.Announcer:
				if (num < AnnouncerAPI.LoadedAnnouncers.Count)
				{
					return num + 1 + ": " + AnnouncerAPI.LoadedAnnouncers[num].Name;
				}
				break;
			case TNHPstates.Sosig_Voicelines:
				if (num < SosigVLSAPI.LoadedSosigVLSs.Count)
				{
					return num + 1 + ": " + SosigVLSAPI.LoadedSosigVLSs[num].name;
				}
				break;
			}
			return "";
		}

		private string GetCurrentSelectedItemName()
		{
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (!PluginMain.IsSoundtrack.Value)
				{
					return BankAPI.GetNameFromIndex(BankAPI.CurrentBankIndex, returnWithIndex: true);
				}
				return $"{BankAPI.LoadedBankLocations.Count + SoundtrackAPI.SelectedSoundtrackIndex + 1}: {SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex].Name}";
			case TNHPstates.Announcer:
				return AnnouncerAPI.CurrentAnnouncerIndex + 1 + ": " + AnnouncerAPI.CurrentAnnouncer.Name;
			case TNHPstates.Sosig_Voicelines:
				return SosigVLSAPI.CurrentSosigVlsIndexOfVlsSet(_selectedVLSSet) + 1 + ": " + SosigVLSAPI.CurrentSosigVlsOfVlsSet(_selectedVLSSet).name;
			default:
				return "";
			}
		}

		private string GetVolumePercent()
		{
			float num = 0f;
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				num = PluginMain.BackgroundMusicVolume.Value;
				break;
			case TNHPstates.Announcer:
				num = PluginMain.AnnouncerMusicVolume.Value;
				break;
			case TNHPstates.Sosig_Voicelines:
				num = 1f;
				break;
			}
			return Mathf.Round(num * 100f).ToString(CultureInfo.InvariantCulture) + "%";
		}

		private void SetCurrentItem(object sender, ButtonClickEventArgs args)
		{
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			int num = _firstMusicIndex + Array.IndexOf(_musicButtons, (ButtonWidget)((sender is ButtonWidget) ? sender : null));
			if ((Object)(object)GM.TNH_Manager != (Object)null)
			{
				WristMenuAPI.Instance.Aud.PlayOneShot(WristMenuAPI.Instance.AudClip_Err);
				return;
			}
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (BGMs[num].IsBank && BGMs[num].BankGuid == "Select Random")
				{
					num = Random.Range(0, BGMs.Count);
				}
				PluginMain.DebugLog.LogInfo((object)$"Setting song to index {num}, {BGMs[num].Name}");
				if (BGMs[num].IsBank)
				{
					BankAPI.SwapBank(num);
					GameObject val = new GameObject();
					if (BankAPI.LoadedBankLocations[num] != "Your Mix" && BankAPI.LoadedBankLocations[num] != "Select Random")
					{
						val.AddComponent(typeof(PlayFModSnippet));
					}
					PluginMain.DebugLog.LogInfo((object)$"index: {num}, index bank: {BankAPI.LoadedBankLocations[num]}");
					if (BankAPI.LoadedBankLocations[num] == "Your Mix")
					{
						SoundtrackAPI.IsMix = true;
					}
					else
					{
						SoundtrackAPI.IsMix = false;
					}
				}
				else
				{
					PluginMain.IsSoundtrack.Value = true;
					SoundtrackAPI.EnableSoundtrackFromGUID(BGMs[num].SoundtrackGuid);
					new GameObject().AddComponent(typeof(PlaySoundtrackSnippet));
					SoundtrackAPI.IsMix = false;
				}
				break;
			case TNHPstates.Announcer:
			{
				int index = Mathf.Clamp(num, 0, AnnouncerAPI.LoadedAnnouncers.Count);
				AnnouncerAPI.SwapAnnouncer(AnnouncerAPI.LoadedAnnouncers[index].GUID);
				PlaySnippet(AnnouncerAPI.GetRandomPreview(AnnouncerAPI.CurrentAnnouncer.GUID));
				break;
			}
			case TNHPstates.Sosig_Voicelines:
			{
				int index = Mathf.Clamp(num, 0, SosigVLSAPI.LoadedSosigVLSs.Count);
				SosigVLSAPI.SwapSosigVLS(SosigVLSAPI.LoadedSosigVLSs[index].guid, SosigVLSAPI.VLSGuidOrder[_selectedVLSSet]);
				PlaySnippet(SosigVLSAPI.GetRandomPreview(SosigVLSAPI.CurrentSosigVlsOfVlsSet(_selectedVLSSet).guid));
				break;
			}
			}
			SetIcon();
			if (!PluginMain.IsSoundtrack.Value)
			{
				_bankText.Text.text = "Selected:\n" + GetCurrentSelectedItemName() + "\n(BANK MOD: NO INSTITUTION SUPPORT)";
			}
			else
			{
				_bankText.Text.text = "Selected:\n" + GetCurrentSelectedItemName();
			}
		}

		public void PlaySnippet(AudioClip snip)
		{
			//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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			float num = 1f;
			float num2 = 0.6f;
			switch (TNHPstate)
			{
			case TNHPstates.Announcer:
				num2 = 0.6f * PluginMain.AnnouncerMusicVolume.Value;
				break;
			case TNHPstates.Sosig_Voicelines:
				num = SosigVLSAPI.CurrentSosigVlsOfVlsSet(_selectedVLSSet).SpeechSet.BasePitch;
				break;
			}
			SM.PlayGenericSound(new AudioEvent
			{
				Clips = { snip },
				PitchRange = new Vector2(num, num),
				VolumeRange = new Vector2(num2, num2)
			}, ((Component)GM.CurrentPlayerBody).transform.position);
		}

		private void SetIcon()
		{
			if ((Object)(object)icondisplay == (Object)null)
			{
				return;
			}
			Debug.Log((object)("IsMix: " + SoundtrackAPI.IsMix + ", CurBank: " + GetCurrentSelectedItemName() + ", CurSoundtrack: " + SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex].Guid));
			switch (TNHPstate)
			{
			case TNHPstates.BGM:
				if (SoundtrackAPI.IsMix)
				{
					icondisplay.texture = (Texture)(object)BankAPI.GetBankIcon("Your Mix");
				}
				else if (!PluginMain.IsSoundtrack.Value)
				{
					icondisplay.texture = (Texture)(object)BankAPI.GetBankIcon(BankAPI.CurrentBankLocation);
				}
				else
				{
					icondisplay.texture = (Texture)(object)SoundtrackAPI.GetIcon(SoundtrackAPI.SelectedSoundtrackIndex);
				}
				break;
			case TNHPstates.Announcer:
				icondisplay.texture = (Texture)(object)AnnouncerAPI.GetAnnouncerIcon(AnnouncerAPI.CurrentAnnouncer);
				break;
			case TNHPstates.Sosig_Voicelines:
				icondisplay.texture = (Texture)(object)SosigVLSAPI.GetSosigVLSIcon(SosigVLSAPI.CurrentSosigVlsOfVlsSet(_selectedVLSSet));
				break;
			}
		}
	}
}
namespace TNHBGLoader.Soundtrack
{
	public static class SoundtrackAPI
	{
		public static List<SoundtrackManifest> Soundtracks = new List<SoundtrackManifest>();

		public static int SelectedSoundtrackIndex;

		public static bool IsMix;

		public static SoundtrackManifest GetCurrentSoundtrack => Soundtracks[SelectedSoundtrackIndex];

		public static void AssembleMusicData(this SoundtrackManifest manifest)
		{
			string[] directories = Directory.GetDirectories(Path.Combine(Path.GetDirectoryName(manifest.Path), manifest.Location));
			List<TrackSet> list = new List<TrackSet>();
			string[] array = directories;
			foreach (string text in array)
			{
				string[] array2 = Path.GetFileName(text).Split(new char[1] { '_' });
				if (File.Exists(text) && !text.Contains(".ogg"))
				{
					continue;
				}
				TrackSet item = default(TrackSet);
				item.Tracks = new List<Track>();
				item.Type = array2[0];
				item.Situation = array2[1];
				if (array2.Length == 3)
				{
					item.Metadata = new string[1] { "" };
					item.Name = array2[2];
				}
				else
				{
					item.Metadata = array2[2].Split(new char[1] { '-' });
					item.Name = array2[3];
				}
				string[] files = Directory.GetFiles(text, "*.ogg", SearchOption.TopDirectoryOnly);
				foreach (string path in files)
				{
					string fileName = Path.GetFileName(path);
					Track item2 = default(Track);
					if (Path.GetExtension(fileName) != ".ogg")
					{
						PluginMain.DebugLog.LogError((object)(fileName + " has an invalid extension! (Valid extensions: .ogg, file extension: " + Path.GetExtension(fileName) + ")"));
					}
					else
					{
						item2.Clip = LoadOgg(path);
					}
					string[] array3 = Path.GetFileNameWithoutExtension(path).Split(new char[1] { '_' });
					item2.Type = array3[0];
					item2.Situation = item.Situation;
					if (array3.Length == 2)
					{
						item2.Metadata = new string[1] { "" };
						item2.Name = array3[1];
					}
					else
					{
						item2.Metadata = array3[1].Split(new char[1] { '-' });
						item2.Name = array3[2];
					}
					item.Tracks.Add(item2);
				}
				list.Add(item);
			}
			foreach (TrackSet item3 in list)
			{
				PluginMain.DebugLog.LogInfo((object)$"Loading set {item3.Name}, {item3.Type}, {item3.Tracks.Count}, {item3.Situation}");
			}
			manifest.Sets = list;
			manifest.Loaded = true;
		}

		public static SoundtrackManifest ToManifest(this SoundtrackYamlfest yamlfest, string path)
		{
			return new SoundtrackManifest
			{
				Name = yamlfest.Name,
				Guid = yamlfest.Guid,
				Path = path,
				Location = yamlfest.Location,
				Loaded = false,
				GameMode = yamlfest.GameMode
			};
		}

		public static void LoadSoundtrack(int index)
		{
			PluginMain.IsSoundtrack.Value = true;
			SelectedSoundtrackIndex = index;
		}

		public static TrackSet[] GetAllSets(string type, int situation)
		{
			string type2 = type;
			PluginMain.DebugLog.LogInfo((object)$"Getting set of type {type2}, {situation}. Cur soundtrack: {Soundtracks[SelectedSoundtrackIndex].Guid}");
			SoundtrackManifest soundtrackManifest = Soundtracks[SelectedSoundtrackIndex];
			TrackSet[] array = (from x in soundtrackManifest.Sets
				where x.Type == type2
				where x.Situation.TimingsMatch(situation)
				select x).ToArray();
			if (!array.Any())
			{
				array = (from x in soundtrackManifest.Sets
					where x.Type == type2
					where x.Situation == "fallback"
					select x).ToArray();
			}
			if (!array.Any())
			{
				PluginMain.DebugLog.LogError((object)$"No set! Are you sure you have a set for the situation {situation}, or a fallback?");
			}
			return array;
		}

		public static TrackSet[] GetAllSetsWithMetadata(string type, int situation, string[] metadatas)
		{
			TrackSet[] allSets = GetAllSets(type, situation);
			List<TrackSet> list = new List<TrackSet>();
			foreach (string metadata in metadatas)
			{
				list.AddRange(allSets.Where((TrackSet x) => x.Metadata.Contains(metadata)));
			}
			if (!list.Any())
			{
				PluginMain.DebugLog.LogError((object)"No set! Getting fallback,");
				return allSets;
			}
			return list.ToArray();
		}

		public static TrackSet GetSetWithMetadata(string type, int situation, string[] metadatas)
		{
			TrackSet random = SodaliteUtils.GetRandom<TrackSet>((IList<TrackSet>)GetAllSetsWithMetadata(type, situation, metadatas));
			PluginMain.DebugLog.LogInfo((object)("Selecting trackset " + random.Name));
			return random;
		}

		public static TrackSet GetSet(string type, int situation)
		{
			TrackSet random = SodaliteUtils.GetRandom<TrackSet>((IList<TrackSet>)GetAllSets(type, situation));
			PluginMain.DebugLog.LogInfo((object)("Selecting trackset " + random.Name));
			return random;
		}

		public static bool TimingsMatch(this string seqTiming, int situation)
		{
			switch (seqTiming)
			{
			case "all":
				return true;
			case "fallback":
				return false;
			case "death":
				if (situation == -1)
				{
					return true;
				}
				return false;
			case "win":
				if (situation == -2)
				{
					return true;
				}
				return false;
			default:
				if (Enumerable.Contains(seqTiming, ','))
				{
					if (seqTiming.Split(new char[1] { ',' }).Contains(situation.ToString()))
					{
						return true;
					}
					return false;
				}
				if (Enumerable.Contains(seqTiming, '-'))
				{
					string[] array = seqTiming.Split(new char[1] { '-' });
					if (situation >= int.Parse(array[0]) && situation <= int.Parse(array[1]))
					{
						return true;
					}
					return false;
				}
				if (seqTiming.Contains("ge"))
				{
					int num = int.Parse(seqTiming.Replace("ge", string.Empty));
					if (situation >= num)
					{
						return true;
					}
					return false;
				}
				if (seqTiming.Contains("le"))
				{
					int num2 = int.Parse(seqTiming.Replace("le", string.Empty));
					if (situation <= num2)
					{
						return true;
					}
					return false;
				}
				if (situation == int.Parse(seqTiming))
				{
					return true;
				}
				return false;
			}
		}

		public static void EnableSoundtrackFromGUID(string guid)
		{
			for (int i = 0; i < Soundtracks.Count; i++)
			{
				if (Soundtracks[i].Guid == guid)
				{
					SelectedSoundtrackIndex = i;
				}
			}
		}

		public static Texture2D GetIcon(int soundtrack)
		{
			return GeneralAPI.GetIcon(Soundtracks[soundtrack].Guid, new string[1] { Path.Combine(Path.GetDirectoryName(Soundtracks[soundtrack].Path), "icon.png") });
		}

		public static AudioClip LoadOgg(string path)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			WWW val = new WWW("file://" + path);
			for (int i = 0; i < 500; i++)
			{
				if (val.isDone)
				{
					break;
				}
				Thread.Sleep(10);
			}
			AudioClip audioClip = WWWAudioExtensions.GetAudioClip(val, false);
			((Object)audioClip).name = Path.GetFileName(path);
			return audioClip;
		}

		public static (AudioClip?, bool) GetSnippet(SoundtrackManifest manifest)
		{
			bool item = true;
			string path = Path.Combine(Path.Combine(Path.GetDirectoryName(manifest.Path), manifest.Location), "preview_loop.ogg");
			if (!File.Exists(path))
			{
				path = Path.Combine(Path.Combine(Path.GetDirectoryName(manifest.Path), manifest.Location), "preview.ogg");
				item = false;
			}
			AudioClip item2 = null;
			if (File.Exists(path))
			{
				item2 = LoadOgg(path);
			}
			return (item2, item);
		}
	}
	public struct Track
	{
		public AudioClip Clip;

		public string Situation;

		public string[] Metadata;

		public string Name;

		public string Type;
	}
	public struct TrackSet
	{
		public List<Track> Tracks;

		public string Situation;

		public string[] Metadata;

		public string Name;

		public string Type;
	}
	public class SoundtrackManifest
	{
		public bool Loaded;

		public string Name;

		public string Path;

		public string Guid;

		public string Location;

		public List<TrackSet> Sets;

		public string GameMode;
	}
	public class SoundtrackPlayer : MonoBehaviour
	{
		public static SoundtrackPlayer? Instance;

		public static SoundtrackManifest? CurrentSoundtrack;

		public static AudioSource[] AudioSources;

		public static int CurrentAudioSource;

		public static List<Track> SongQueue = new List<Track>();

		public static Track CurrentTrack;

		public static string GameMode;

		private static bool isSwitching;

		private static float switchStartTime;

		public static float TrackFadeTime = 1.5f;

		public static float Volume = 1f;

		public static double SongLength;

		public static float SongStartTime;

		public AudioSource GetNotCurrentAudioSource => AudioSources[(CurrentAudioSource == 0) ? 1 : 0];

		public AudioSource GetCurrentAudioSource => AudioSources[CurrentAudioSource];

		public virtual bool QueueRandomOfType(TrackSet set, string type, bool mandatory = true)
		{
			string type2 = type;
			Track[] array = set.Tracks.Where((Track x) => x.Type == type2).ToArray();
			if (array.Any())
			{
				QueueRandom(array);
				return true;
			}
			if (mandatory)
			{
				PluginMain.DebugLog.LogError((object)("Track set " + set.Name + " did not contain mandatory track type " + type2 + "!"));
			}
			return false;
		}

		public virtual void QueueRandom(Track[] track)
		{
			Queue(track[Random.Range(0, track.Length)]);
		}

		public virtual void QueueMany(Track[] tracks)
		{
			foreach (Track track in tracks)
			{
				Queue(track);
			}
		}

		public virtual void Queue(Track track)
		{
			PluginMain.DebugLog.LogInfo((object)("Queueing " + track.Type + ", " + track.Name + " of situation " + track.Situation));
			SongQueue.Add(track);
			if (SongQueue.Count == 1)
			{
				GetNotCurrentAudioSource.clip = track.Clip;
			}
		}

		public virtual void ClearQueue()
		{
			SongQueue = new List<Track>();
		}

		private static void CreateAudioSources()
		{
			AudioSources = (AudioSource[])(object)new AudioSource[2]
			{
				((Component)ManagerSingleton<GM>.Instance.m_currentPlayerBody.Head).gameObject.AddComponent<AudioSource>(),
				((Component)ManagerSingleton<GM>.Instance.m_currentPlayerBody.Head).gameObject.AddComponent<AudioSource>()
			};
			AudioSource[] audioSources = AudioSources;
			foreach (AudioSource obj in audioSources)
			{
				obj.playOnAwake = false;
				obj.priority = 0;
				obj.volume = Volume;
				obj.spatialBlend = 0f;
				obj.loop = true;
			}
		}

		public virtual void SwitchSong(Track newTrack, float timeOverride = 0f)
		{
			CurrentTrack = newTrack;
			bool flag = newTrack.Metadata.Any((string x) => x == "loop");
			bool flag2 = newTrack.Metadata.All((string x) => x != "dnf");
			if (!newTrack.Metadata.Any((string x) => x == "st"))
			{
				SongStartTime = Time.time;
			}
			else
			{
				timeOverride = GetCurrentAudioSource.time;
			}
			SongLength = newTrack.Clip.length;
			PluginMain.DebugLog.LogInfo((object)$"{Time.time:F}: Playing track {newTrack.Name} ({newTrack.Type}, metadata {newTrack.Metadata.ToOneLine()}) of calculated length {SongLength:F} with override time {timeOverride}.");
			int currentAudioSource = ((CurrentAudioSource == 0) ? 1 : 0);
			if (flag2)
			{
				switchStartTime = Time.time;
				CurrentAudioSource = currentAudioSource;
				isSwitching = true;
				GetCurrentAudioSource.clip = newTrack.Clip;
				GetCurrentAudioSource.volume = 0f;
				if (flag)
				{
					GetCurrentAudioSource.loop = true;
				}
				else
				{
					GetCurrentAudioSource.loop = false;
				}
				GetCurrentAudioSource.Play();
			}
			else
			{
				GetCurrentAudioSource.Stop();
				if (SongQueue.Count > 0)
				{
					GetCurrentAudioSource.clip = SongQueue[0].Clip;
				}
				CurrentAudioSource = currentAudioSource;
				if ((Object)(object)GetCurrentAudioSource.clip != (Object)(object)newTrack.Clip)
				{
					GetCurrentAudioSource.clip = newTrack.Clip;
				}
				GetCurrentAudioSource.volume = Volume;
				if (flag)
				{
					GetCurrentAudioSource.loop = true;
				}
				else
				{
					GetCurrentAudioSource.loop = false;
				}
				GetCurrentAudioSource.Play();
			}
			GetCurrentAudioSource.time = timeOverride;
		}

		public void Initialize(string gameMode, SoundtrackManifest soundtrack, float trackFadeTime, float volume)
		{
			GameMode = gameMode;
			Instance = this;
			TrackFadeTime = trackFadeTime;
			CurrentSoundtrack = soundtrack;
			Volume = volume;
			CreateAudioSources();
			if (!CurrentSoundtrack.Loaded)
			{
				CurrentSoundtrack.AssembleMusicData();
			}
		}

		public void Update()
		{
			if (isSwitching)
			{
				float num = (Time.time - switchStartTime) / TrackFadeTime;
				float num2 = num * Volume;
				GetCurrentAudioSource.volume = num2;
				GetNotCurrentAudioSource.volume = Volume - num2;
				if (num >= 1f)
				{
					isSwitching = false;
					GetNotCurrentAudioSource.Stop();
				}
			}
			float num3 = (float)SongLength - (Time.time - SongStartTime);
			float num4 = TrackFadeTime;
			if (SongQueue.Count > 0 && SongQueue[0].Metadata.Contains("dnf"))
			{
				num4 = 0.05f;
			}
			if (num3 <= num4 && !GetCurrentAudioSource.loop && SongQueue.Count > 0)
			{
				Debug.Log((object)"End of song incoming. Playing next song.");
				PlayNextSongInQueue();
			}
		}

		public virtual void PlayNextSongInQueue()
		{
			if (SongQueue.Count == 0)
			{
				PluginMain.DebugLog.LogError((object)"Ran out of songs in the queue!");
				return;
			}
			Track newTrack = SongQueue[0];
			SongQueue.RemoveAt(0);
			SwitchSong(newTrack);
		}

		public virtual void PlayNextTrackInQueueOfType(string type)
		{
			PlayNextTrackInQueueOfType(new string[1] { type });
		}

		public virtual void PlayNextTrackInQueueOfType(string[] types)
		{
			while (!types.Contains(SongQueue[0].Type))
			{
				Debug.Log((object)("Skipping song " + SongQueue[0].Name + " of type " + SongQueue[0].Type));
				SongQueue.RemoveAt(0);
			}
			PlayNextSongInQueue();
		}
	}
	public class SoundtrackYamlfest
	{
		public string Name { get; set; }

		public string Guid { get; set; }

		public string Location { get; set; }

		public string GameMode { get; set; }
	}
	public class TnHSoundtrackInterface : SoundtrackPlayer
	{
		public static TNH_Manager Manager;

		public static TrackSet HoldMusic;

		public static TrackSet? TakeMusic;

		public static bool failureSyncInfoReady;

		public static float timeIdentified;

		public static float timeFail;

		public static bool isInstitutionMode = false;

		public static int currentInstitutionArea = 0;

		public static bool currentlyInAlert = false;

		public static int alertCooldown = 0;

		public static Track? storedTakeTrack;

		public static float storedTakeTrackPlayhead;

		public static bool changedAreaMidFight;

		public static int Level;

		public static readonly string[] AreaFromInt = new string[5] { "center", "north", "south", "west", "east" };

		public static int Intensity = 1;

		public void Awake()
		{
			Initialize("tnh", SoundtrackAPI.GetCurrentSoundtrack, 1.5f, PluginMain.AnnouncerMusicVolume.Value / 4f);
			ClearQueue();
			Level = 0;
		}

		public override void SwitchSong(Track newTrack, float timeOverride = -1f)
		{
			bool num = newTrack.Metadata.Any((string x) => x == "fs");
			float timeOverride2 = timeOverride % newTrack.Clip.length;
			if (num)
			{
				if (failureSyncInfoReady)
				{
					float num2 = timeFail - timeIdentified - (Time.time - timeIdentified);
					if (num2 > newTrack.Clip.length)
					{
						PluginMain.DebugLog.LogError((object)$"Soundtrack {SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex]}:{newTrack.Name} is TOO SHORT! Song length: {newTrack.Clip.length}, Time to Fail: {num2}! Lengthen your song!");
						return;
					}
					timeOverride2 = newTrack.Clip.length - num2;
					failureSyncInfoReady = false;
				}
				else
				{
					PluginMain.DebugLog.LogError((object)$"Soundtrack {SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex]}:{newTrack.Name} DID NOT have enough time to get info about how long the hold is! (FailureSync). Please lengthen your transition or intro to give more buffer time for the info to load! It should be AT LEAST 5 seconds.");
				}
			}
			base.SwitchSong(newTrack, timeOverride2);
		}

		[HarmonyPatch(typeof(FVRFMODController), "SetIntParameterByIndex")]
		[HarmonyPrefix]
		public static bool InstitutionChangeRegion(ref string s, ref float f)
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			if (isInstitutionMode && s == "TAH2 Area")
			{
				TrackSet trackSet = (TakeMusic.HasValue ? TakeMusic.Value : HoldMusic);
				if (trackSet.Metadata.Contains("nsbr") || (!trackSet.Metadata.Contains(AreaFromInt[0]) && !trackSet.Metadata.Contains(AreaFromInt[1]) && !trackSet.Metadata.Contains(AreaFromInt[2]) && !trackSet.Metadata.Contains(AreaFromInt[3]) && !trackSet.Metadata.Contains(AreaFromInt[4]) && !trackSet.Metadata.Contains("anyreg")))
				{
					return true;
				}
				int num = (int)f;
				if (currentInstitutionArea != num)
				{
					if (!currentlyInAlert)
					{
						ChangeArea(num);
					}
					if (currentlyInAlert)
					{
						changedAreaMidFight = true;
					}
					PluginMain.DebugLog.LogInfo((object)$"Changing to area {num}");
					currentInstitutionArea = num;
				}
			}
			return true;
		}

		public void FixedUpdate()
		{
			if (alertCooldown > 0)
			{
				alertCooldown--;
			}
			if (!PluginMain.IsSoundtrack.Value)
			{
				return;
			}
			bool flag = ((!isInstitutionMode) ? ((int)Manager.m_takeMusicIntensity == 2) : ((int)Manager.m_takeMusicIntensity >= 1));
			if (alertCooldown != 0)
			{
				flag = false;
			}
			if (currentlyInAlert == flag)
			{
				return;
			}
			if (flag)
			{
				Track[] array = new Track[0];
				if (HoldMusic.Tracks != null)
				{
					array = HoldMusic.Tracks.Where((Track x) => x.Type == "alert").ToArray();
				}
				if (!array.Any() && TakeMusic.HasValue)
				{
					array = TakeMusic.Value.Tracks.Where((Track x) => x.Type == "alert").ToArray();
				}
				if (array.Any())
				{
					storedTakeTrack = SoundtrackPlayer.CurrentTrack;
					storedTakeTrackPlayhead = SoundtrackPlayer.Instance.GetCurrentAudioSource.time;
					if (SoundtrackPlayer.CurrentTrack.Type != "take")
					{
						return;
					}
					SoundtrackPlayer.Instance.SwitchSong(SodaliteUtils.GetRandom<Track>((IList<Track>)array));
				}
			}
			else
			{
				if (SoundtrackPlayer.CurrentTrack.Type == "take")
				{
					return;
				}
				if (changedAreaMidFight)
				{
					changedAreaMidFight = false;
					ChangeArea(currentInstitutionArea);
				}
				else
				{
					float num = 0f;
					if (storedTakeTrack.HasValue && !SoundtrackPlayer.CurrentTrack.Metadata.Contains("restart"))
					{
						float time = SoundtrackPlayer.Instance.GetCurrentAudioSource.time;
						num = storedTakeTrackPlayhead + time;
						if (SoundtrackPlayer.CurrentTrack.Metadata.Contains("return"))
						{
							num = storedTakeTrackPlayhead;
						}
						SoundtrackPlayer.Instance.SwitchSong(storedTakeTrack.Value, num);
					}
					else
					{
						TrackSet trackSet = ((!TakeMusic.HasValue) ? HoldMusic : TakeMusic.Value);
						IEnumerable<Track> source = trackSet.Tracks.Where((Track x) => x.Type == "takeintro");
						if (source.Count() != 0)
						{
							SoundtrackPlayer.Instance.SwitchSong(SodaliteUtils.GetRandom<Track>((IList<Track>)source.ToArray()));
						}
						else
						{
							SoundtrackPlayer.Instance.SwitchSong(SodaliteUtils.GetRandom<Track>((IList<Track>)trackSet.Tracks.Where((Track x) => x.Type == "take").ToArray()));
						}
					}
				}
			}
			currentlyInAlert = flag;
		}

		public static void ChangeArea(int newArea)
		{
			SoundtrackPlayer.Instance.ClearQueue();
			HoldMusic = SoundtrackAPI.GetSetWithMetadata("hold", Level, new string[2]
			{
				AreaFromInt[newArea],
				"anyreg"
			});
			SetOrbTouchTracks();
			if (HoldMusic.Tracks.Any((Track x) => x.Type == "take"))
			{
				QueueTake(HoldMusic);
			}
			else
			{
				QueueTake(SoundtrackAPI.GetSetWithMetadata("take", Level, new string[2]
				{
					AreaFromInt[newArea],
					"anyreg"
				}));
			}
			SoundtrackPlayer.Instance.PlayNextSongInQueue();
		}

		[HarmonyPatch(typeof(FVRFMODController), "SwitchTo")]
		[HarmonyPrefix]
		public static bool QueueHoldAndTakeTracks(ref int musicIndex, ref float timeDelayStart, ref bool shouldStop, ref bool shouldDeadStop)
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			if (musicIndex != 1)
			{
				return false;
			}
			SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "intro", mandatory: false);
			if (!HoldMusic.Tracks.Any((Track x) => x.Type.Contains("phase")))
			{
				SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "lo");
				SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "transition", mandatory: false);
				SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "medhi", mandatory: false);
			}
			else
			{
				int phaseNo = 0;
				while (HoldMusic.Tracks.Any((Track x) => x.Type == "phase" + phaseNo) && phaseNo < 20)
				{
					SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "phase" + phaseNo);
					SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "phasetr" + phaseNo, mandatory: false);
					phaseNo++;
				}
			}
			SoundtrackPlayer.Instance.QueueRandomOfType(HoldMusic, "end", mandatory: false);
			Level++;
			PluginMain.DebugLog.LogInfo((object)$"Level: {Level}");
			if (!isInstitutionMode)
			{
				HoldMusic = SoundtrackAPI.GetSet("hold", Level);
			}
			else
			{
				HoldMusic = SoundtrackAPI.GetSetWithMetadata("hold", Level, new string[2]
				{
					AreaFromInt[currentInstitutionArea],
					"anyreg"
				});
			}
			if (HoldMusic.Tracks.Any((Track x) => x.Type == "take"))
			{
				QueueTake(HoldMusic);
			}
			else
			{
				TakeMusic = SoundtrackAPI.GetSet("take", Level);
				QueueTake(TakeMusic.Value);
			}
			currentlyInAlert = false;
			storedTakeTrack = null;
			SoundtrackPlayer.Instance.PlayNextTrackInQueueOfType(new string[3] { "intro", "lo", "phase0" });
			return false;
		}

		[HarmonyPatch(typeof(TNH_HoldPoint), "BeginPhase")]
		[HarmonyPrefix]
		public static bool PlayPhaseTracks()
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue.Count == 0 || SoundtrackPlayer.CurrentTrack.Type == "intro")
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue[0].Type.Contains("phasetr") || SoundtrackPlayer.SongQueue[0].Type.Contains("phase"))
			{
				SoundtrackPlayer.Instance.PlayNextSongInQueue();
			}
			return true;
		}

		[HarmonyPatch(typeof(TNH_HoldPoint), "BeginAnalyzing")]
		[HarmonyPrefix]
		public static bool PlayMedHiTrack(TNH_HoldPoint __instance)
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue.Any((Track x) => x.Type == "transition") || Intensity != 2)
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue.Any((Track x) => x.Type == "medhi"))
			{
				SoundtrackPlayer.Instance.PlayNextTrackInQueueOfType(new string[1] { "medhi" });
			}
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "SetHoldWaveIntensity")]
		[HarmonyPrefix]
		public static bool PlayTransitionTrack(ref int intensity)
		{
			Intensity = intensity;
			if (!PluginMain.IsSoundtrack.Value || intensity != 2)
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue.All((Track x) => x.Type != "medhi"))
			{
				return true;
			}
			if (SoundtrackPlayer.SongQueue.Any((Track x) => x.Type == "transition"))
			{
				SoundtrackPlayer.Instance.PlayNextTrackInQueueOfType(new string[1] { "transition" });
			}
			return true;
		}

		[HarmonyPatch(typeof(TNH_HoldPoint), "FailOut")]
		[HarmonyPrefix]
		public static bool QueueFailTrack()
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			Track[] array = HoldMusic.Tracks.Where((Track x) => x.Type == "endfail").ToArray();
			if (array.Length == 0)
			{
				return true;
			}
			for (int i = 0; i < SoundtrackPlayer.SongQueue.Count; i++)
			{
				if (SoundtrackPlayer.SongQueue[i].Type == "end")
				{
					SoundtrackPlayer.SongQueue[i] = array[Random.Range(0, array.Length)];
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "SetPhase_Take")]
		[HarmonyPrefix]
		public static bool SkipToEndTrack()
		{
			if (!PluginMain.IsSoundtrack.Value || SoundtrackPlayer.SongQueue.Count == 0)
			{
				return true;
			}
			SoundtrackPlayer.Instance.PlayNextTrackInQueueOfType(new string[4] { "end", "take", "takeintro", "endfail" });
			alertCooldown = 300;
			return true;
		}

		public static void QueueTake(int situation)
		{
			QueueTake(SoundtrackAPI.GetSet("take", situation));
		}

		public static void QueueTake(TrackSet set)
		{
			SoundtrackPlayer.Instance.QueueRandomOfType(set, "takeintro", mandatory: false);
			SoundtrackPlayer.Instance.QueueRandomOfType(set, "take");
		}

		[HarmonyPatch(typeof(TNH_Manager), "SetPhase_Dead")]
		[HarmonyPrefix]
		public static bool PlayDeadTrack()
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			SoundtrackPlayer.Instance.ClearQueue();
			QueueTake(-1);
			SoundtrackPlayer.Instance.PlayNextSongInQueue();
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "SetPhase_Completed")]
		[HarmonyPrefix]
		public static bool PlayWinTrack()
		{
			if (!PluginMain.IsSoundtrack.Value)
			{
				return true;
			}
			SoundtrackPlayer.Instance.ClearQueue();
			QueueTake(-2);
			SoundtrackPlayer.Instance.PlayNextSongInQueue();
			return true;
		}

		[HarmonyPatch(typeof(TNH_Manager), "Start")]
		[HarmonyPostfix]
		public static void InitializeTnHSoundtrackInterface(ref TNH_Manager __instance)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!PluginMain.IsSoundtrack.Value)
			{
				return;
			}
			Manager = __instance;
			isInstitutionMode = __instance.UsesInstitutionMusic;
			if (SoundtrackAPI.SelectedSoundtrackIndex >= SoundtrackAPI.Soundtracks.Count)
			{
				PluginMain.DebugLog.LogInfo((object)"Selected soundtrack out of bounds!");
				PluginMain.IsSoundtrack.Value = false;
				return;
			}
			((Component)__instance).gameObject.AddComponent<TnHSoundtrackInterface>();
			((Bus)(ref GM.TNH_Manager.FMODController.MasterBus)).setMute(true);
			PluginMain.DebugLog.LogInfo((object)$"IsMix: {SoundtrackAPI.IsMix.ToString()}, CurSoundtrack: {SoundtrackAPI.Soundtracks[SoundtrackAPI.SelectedSoundtrackIndex].Guid}, IsSOundtrack: {PluginMain.IsSoundtrack.Value}");
			PluginMain.DebugLog.LogInfo((object)$"Level: {Level}");
			if (!isInstitutionMode)
			{
				HoldMusic = SoundtrackAPI.GetSet("hold", Level);
				if (HoldMusic.Tracks.Any((Track x) => x.Type == "take"))
				{
					QueueTake(HoldMusic);
					return;
				}
				TakeMusic = SoundtrackAPI.GetSet("take", Level);
				QueueTake(TakeMusic.Value);
			}
			else
			{
				ChangeArea(currentInstitutionArea);
			}
		}

		[HarmonyPatch(typeof(TNH_HoldPoint), "BeginAnalyzing")]
		[HarmonyPostfix]
		public static void GatherFailureSyncInfo(ref TNH_HoldPoint __instance)
		{
			failureSyncInfoReady = true;
			timeIdentified = Time.time;
			timeFail = Time.time + 120f + __instance.m_tickDownToIdentification + 3f;
		}

		[HarmonyPatch(typeof(TNH_HoldPointSystemNode), "Start")]
		[HarmonyPrefix]
		public static bool SetOrbTouchTracksNonInstitution(ref TNH_HoldPointSystemNode __instance)
		{
			if (!PluginMain.IsSoundtrack.Value || isInstitutionMode)
			{
				return true;
			}
			SetOrbTouchTracks();
			return true;
		}

		public static void SetOrbTouchTracks()
		{
			List<AudioClip> list = new List<AudioClip>();
			Track[] array = HoldMusic.Tracks.Where((Track x) => x.Type == "orbactivate").ToArray();
			Track[] array2;
			if (array.Length != 0)
			{
				array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					Track track = array2[i];
					list.Add(track.Clip);
				}
				foreach (TNH_HoldPoint holdPoint in Manager.HoldPoints)
				{
					if ((Object)(object)holdPoint != (Object)null && (Object)(object)holdPoint.m_systemNode != (Object)null)
					{
						holdPoint.m_systemNode.AUDEvent_HoldActivate.Clips = list;
					}
				}
			}
			list = new List<AudioClip>();
			array = HoldMusic.Tracks.Where((Track x) => x.Type == "orbwave").ToArray();
			if (array.Length != 0)
			{
				array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					Track track2 = array2[i];
					list.Add(track2.Clip);
				}
				foreach (TNH_HoldPoint holdPoint2 in Manager.HoldPoints)
				{
					if ((Object)(object)holdPoint2 != (Object)null && (Object)(object)holdPoint2.m_systemNode != (Object)null && (Object)(object)holdPoint2.m_systemNode.HoldPoint != (Object)null)
					{
						holdPoint2.m_systemNode.HoldPoint.AUDEvent_HoldWave.Clips = list;
					}
				}
			}
			list = new List<AudioClip>();
			array = HoldMusic.Tracks.Where((Track x) => x.Type == "orbsuccess").ToArray();
			if (array.Length != 0)
			{
				array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					Track track3 = array2[i];
					list.Add(track3.Clip);
				}
				foreach (TNH_HoldPoint holdPoint3 in Manager.HoldPoints)
				{
					if ((Object)(object)holdPoint3 != (Object)null && (Object)(object)holdPoint3.m_systemNode != (Object)null && (Object)(object)holdPoint3.m_systemNode.HoldPoint != (Object)null)
					{
						holdPoint3.m_systemNode.HoldPoint.AUDEvent_Success.Clips = list;
					}
				}
			}
			list = new List<AudioClip>();
			array = HoldMusic.Tracks.Where((Track x) => x.Type == "orbfailure").ToArray();
			if (array.Length == 0)
			{
				return;
			}
			array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				Track track4 = array2[i];
				list.Add(track4.Clip);
			}
			foreach (TNH_HoldPoint holdPoint4 in Manager.HoldPoints)
			{
				if ((Object)(object)holdPoint4 != (Object)null && (Object)(object)holdPoint4.m_systemNode != (Object)null && (Object)(object)holdPoint4.m_systemNode.HoldPoint != (Object)null)
				{
					holdPoint4.m_systemNode.HoldPoint.AUDEvent_Failure.Clips = list;
				}
			}
		}
	}
}
namespace TNHBGLoader.Sosig
{
	public class SosigManifest
	{
		public SosigSpeechSet SpeechSet;

		public string guid;

		public string name;

		public string location;

		public List<AudioClip> previews = new List<AudioClip>();

		public static SosigSpeechSet[] sets;

		public static SosigManifest DefaultSosigVLS()
		{
			SosigSpeechSet val = ScriptableObject.CreateInstance<SosigSpeechSet>();
			val.BasePitch = 1.15f;
			return new SosigManifest
			{
				name = "Default",
				guid = "h3vr.default",
				SpeechSet = val
			};
		}

		public static SosigManifest DefaultZosigVLS()
		{
			SosigSpeechSet val = ScriptableObject.CreateInstance<SosigSpeechSet>();
			val.BasePitch = 1.15f;
			return new SosigManifest
			{
				name = "Zosig",
				guid = "h3vr.zosig",
				SpeechSet = val
			};
		}

		public static SosigManifest RandomSosigVLS()
		{
			SosigSpeechSet val = ScriptableObject.CreateInstance<SosigSpeechSet>();
			val.BasePitch = 1.15f;
			return new SosigManifest
			{
				name = "Select Random Voiceline",
				guid = "ptnhbgml.random",
				SpeechSet = val
			};
		}
	}
	public class SosigVLSAPI : MonoBehaviour
	{
		public static List<SosigManifest> LoadedSosigVLSs = new List<SosigManifest>();

		public static Dictionary<string, string> VLSGuidToName = new Dictionary<string, string>();

		public static List<string> VLSGuidOrder = new List<string>();

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

		public static SosigSpeechSet[] DefaultVLSs;

		public static int GetSosigVLSIndexFromGUID(string GUID)
		{
			return LoadedSosigVLSs.IndexOf(GetManifestFromGUID(GUID));
		}

		public static int GetSosigVLSIndexFromManifest(SosigManifest manifest)
		{
			return LoadedSosigVLSs.IndexOf(manifest);
		}

		public static SosigManifest GetManifestFromGUID(string GUID)
		{
			string GUID2 = GUID;
			return LoadedSosigVLSs.FindAll((SosigManifest a) => a.guid == GUID2).First();
		}

		public static int CurrentSosigVlsIndexOfVlsSet(int index)
		{
			if (!CurrentSosigVLSIndex.ContainsKey(VLSGuidOrder[index]))
			{
				PluginMain.DebugLog.LogFatal((object)(VLSGuidOrder[index] + " was not in the VLS index database!"));
			}
			return CurrentSosigVLSIndex[VLSGuidOrder[index]];
		}

		public static int CurrentSosigVlsIndexOfVlsSet(string guid)
		{
			return CurrentSosigVLSIndex[guid];
		}

		public static SosigManifest CurrentSosigVlsOfVlsSet(int index)
		{
			return LoadedSosigVLSs[CurrentSosigVLSIndex[VLSGuidOrder[index]]];
		}

		public static SosigManifest CurrentSosigVlsOfVlsSet(string guid)
		{
			return LoadedSosigVLSs[CurrentSosigVLSIndex[guid]];
		}

		public static Texture2D GetSosigVLSIcon(SosigManifest sosigVLS)
		{
			string directoryName = Path.GetDirectoryName(sosigVLS.location);
			string[] array = new string[0];
			return GeneralAPI.GetIcon(paths: (sosigVLS.guid == "h3vr.default") ? new string[1] { Path.Combine(PluginMain.AssemblyDirectory, "default/sosigvls_default.png") } : ((!(sosigVLS.guid == "h3vr.zosig")) ? new string[2]
			{
				directoryName + "/icon.png",
				Directory.GetParent(directoryName)?.ToString() + "/icon.png"
			} : new string[1] { Path.Combine(PluginMain.AssemblyDirectory, "default/sosigvls_zosig.png") }), guid: sosigVLS.guid);
		}

		public static void SwapSosigVLS(string guid, string vlsSet)
		{
			if (guid == "ptnhbgml.random")
			{
				guid = LoadedSosigVLSs[Random.Range(1, LoadedSosigVLSs.Count)].guid;
			}
			CurrentSosigVLSIndex[vlsSet] = GetSosigVLSIndexFromGUID(guid);
		}

		public static SosigManifest GetManifestFromYamlfest(SosigYamlfest yamlfest)
		{
			yamlfest.VoiceLines = Path.Combine(Path.GetDirectoryName(yamlfest.Location), yamlfest.VoiceLines);
			SosigManifest manifest = new SosigManifest();
			manifest.SpeechSet = ScriptableObject.CreateInstance<SosigSpeechSet>();
			manifest.SpeechSet.BasePitch = yamlfest.BasePitch;
			manifest.SpeechSet.BaseVolume = yamlfest.BaseVolume;
			manifest.SpeechSet.ForceDeathSpeech = yamlfest.ForceDeathSpeech;
			manifest.SpeechSet.UseAltDeathOnHeadExplode = yamlfest.UseAltDeathOnHeadExplode;
			manifest.SpeechSet.LessTalkativeSkirmish = yamlfest.LessTalkativeSkirmish;
			manifest.name = yamlfest.Name;
			manifest.guid = yamlfest.GUID;
			manifest.location = yamlfest.Location;
			List<string> list = Directory.GetFiles(yamlfest.VoiceLines, "*.wav", SearchOption.AllDirectories).ToList();
			InitializeLists(ref manifest.SpeechSet);
			foreach (string item in list)
			{
				AddNameToSpeechSet(ref manifest, GetAudioFromFile(item), Path.GetFileName(item) + ", " + new FileInfo(item).Directory.Name);
			}
			return manifest;
		}

		public static AudioClip GetRandomPreview(string guid)
		{
			if (guid == "h3vr.default")
			{
				return GetAudioFromFile(Path.Combine(PluginMain.AssemblyDirectory, "default/sosigvls_default.wav"));
			}
			SosigManifest manifestFromGUID = GetManifestFromGUID(guid);
			if (manifestFromGUID.previews.Count == 0)
			{
				return null;
			}
			int index = Random.Range(0, manifestFromGUID.previews.Count);
			return manifestFromGUID.previews[index];
		}

		public static void InitializeLists(ref SosigSpeechSet speechset)
		{
			speechset.OnJointBreak = new List<AudioClip>();
			speechset.OnJointSlice = new List<AudioClip>();
			speechset.OnJointSever = new List<AudioClip>();
			speechset.OnDeath = new List<AudioClip>();
			speechset.OnBackBreak = new List<AudioClip>();
			speechset.OnNeckBreak = new List<AudioClip>();
			speechset.OnPain = new List<AudioClip>();
			speechset.OnConfusion = new List<AudioClip>();
			speechset.OnDeathAlt = new List<AudioClip>();
			speechset.OnWander = new List<AudioClip>();
			speechset.OnSkirmish = new List<AudioClip>();
			speechset.OnInvestigate = new List<AudioClip>();
			speechset.OnSearchingForGuns = new List<AudioClip>();
			speechset.OnTakingCover = new List<AudioClip>();
			speechset.OnBeingAimedAt = new List<AudioClip>();
			speechset.OnAssault = new List<AudioClip>();
			speechset.OnReloading = new List<AudioClip>();
			speechset.OnMedic = new List<AudioClip>();
			speechset.OnCall_Skirmish = new List<AudioClip>();
			speechset.OnRespond_Skirmish = new List<AudioClip>();
			speechset.OnCall_Assistance = new List<AudioClip>();
			speechset.OnRespond_Assistance = new List<AudioClip>();
		}

		public static void AddNameToSpeechSet(ref SosigManifest manifest, AudioClip clip, string name)
		{
			if ((Object)(object)clip == (Object)null)
			{
				PluginMain.DebugLog.LogFatal((object)("Cannot find clip for " + name + "!"));
			}
			if (name.Contains("pain_joint_break"))
			{
				manifest.SpeechSet.OnJointBreak.Add(clip);
			}
			else if (name.Contains("pain_joint_slice"))
			{
				manifest.SpeechSet.OnJointSlice.Add(clip);
			}
			else if (name.Contains("pain_joint_sever"))
			{
				manifest.SpeechSet.OnJointSever.Add(clip);
			}
			else if (name.Contains("pain_death"))
			{
				manifest.SpeechSet.OnDeath.Add(clip);
			}
			else if (name.Contains("pain_break_back"))
			{
				manifest.SpeechSet.OnBackBreak.Add(clip);
			}
			else if (name.Contains("pain_break_neck"))
			{
				manifest.SpeechSet.OnNeckBreak.Add(clip);
			}
			else if (name.Contains("pain_default"))
			{
				manifest.SpeechSet.OnPain.Add(clip);
			}
			else if (name.Contains("pain_confusion"))
			{
				manifest.SpeechSet.OnConfusion.Add(clip);
			}
			else if (name.Contains("pain_alt_death"))
			{
				manifest.SpeechSet.OnDeathAlt.Add(clip);
			}
			else if (name.Contains("state_wander"))
			{
				manifest.SpeechSet.OnWander.Add(clip);
			}
			else if (name.Contains("state_skirmish"))
			{
				manifest.SpeechSet.OnSkirmish.Add(clip);
			}
			else if (name.Contains("state_investigate"))
			{
				manifest.SpeechSet.OnInvestigate.Add(clip);
			}
			else if (name.Contains("state_gunsearch"))
			{
				manifest.SpeechSet.OnSearchingForGuns.Add(clip);
			}
			else if (name.Contains("state_takecover"))
			{
				manifest.SpeechSet.OnTakingCover.Add(clip);
			}
			else if (name.Contains("state_aimedat"))
			{
				manifest.SpeechSet.OnBeingAimedAt.Add(clip);
			}
			else if (name.Contains("state_assault"))
			{
				manifest.SpeechSet.OnAssault.Add(clip);
			}
			else if (name.Contains("state_reload"))
			{
				manifest.SpeechSet.OnReloading.Add(clip);
			}
			else if (name.Contains("state_medic"))
			{
				manifest.SpeechSet.OnMedic.Add(clip);
			}
			else if (name.Contains("call_skirmish"))
			{
				manifest.SpeechSet.OnCall_Skirmish.Add(clip);
			}
			else if (name.Contains("respond_skirmish"))
			{
				manifest.SpeechSet.OnRespond_Skirmish.Add(clip);
			}
			else if (name.Contains("call_assistance"))
			{
				manifest.SpeechSet.OnCall_Assistance.Add(clip);
			}
			else if (name.Contains("respond_assistance"))
			{
				manifest.SpeechSet.OnRespond_Assistance.Add(clip);
			}
			else if (name.Contains("example"))
			{
				manifest.previews.Add(clip);
			}
			else if (!name.Contains("unused"))
			{
				PluginMain.DebugLog.LogError((object)("voiceline " + name + " has no voiceline match!"));
			}
		}

		public static AudioClip GetAudioFromFile(string path)
		{
			try
			{
				return WavUtility.ToAudioClip(path);
			}
			catch (Exception arg)
			{
				PluginMain.DebugLog.LogError((object)$"Failed loading audio file {Path.GetFileName(path)} with reason {arg}");
				return null;
			}
		}
	}
}
namespace TNH_BGLoader
{
	public class AnnouncerAPI
	{
		public static List<AnnouncerManifest> LoadedAnnouncers = new List<AnnouncerManifest>();

		public static int CurrentAnnouncerIndex = 0;

		private static bool validid = true;

		public static readonly string[] UnusedVoicelines = new string[11]
		{
			"base_", "encryption_cascading", "encryption_cascading", "encryption_orthagonal", "encryption_polymorphic", "encryption_refractive", "game_lose_connection", "game_lose_operator", "loot_regen", "loot_resource",
			"loot_tool"
		};

		public static AnnouncerManifest CurrentAnnouncer => LoadedAnnouncers[CurrentAnnouncerIndex];

		public static void SwapAnnouncer(string GUID)
		{
			if (GUID == "ptnhbgml.random")
			{
				GUID = LoadedAnnouncers[Random.Range(1, LoadedAnnouncers.Count)].GUID;
			}
			CurrentAnnouncerIndex = GetAnnouncerIndexFromGUID(GUID);
			PluginMain.LastLoadedAnnouncer.Value = CurrentAnnouncer.GUID;
		}

		public static int GetAnnouncerIndexFromGUID(string GUID)
		{
			return LoadedAnnouncers.IndexOf(GetManifestFromGUID(GUID));
		}

		public static int GetAnnouncerIndexFromManifest(AnnouncerManifest manifest)
		{
			return LoadedAnnouncers.IndexOf(manifest);
		}

		public static AnnouncerManifest GetManifestFromGUID(string GUID)
		{
			string GUID2 = GUID;
			return LoadedAnnouncers.FindAll((AnnouncerManifest a) => a.GUID == GUID2).First();
		}

		public static Texture2D GetAnnouncerIcon(AnnouncerManifest announcer)
		{
			string directoryName = Path.GetDirectoryName(announcer.Location);
			string[] array = new string[0];
			return GeneralAPI.GetIcon(paths: (!(announcer.GUID == "h3vr.default") && !(announcer.GUID == "h3vr.corrupted")) ? new string[2]
			{
				directoryName + "/icon.png",
				Directory.GetParent(directoryName)?.ToString() + "/icon.png"
			} : new string[1] { Path.Combine(PluginMain.AssemblyDirectory, "default/announcer_default.png") }, guid: announcer.GUID);
		}

		public static AudioClip GetRandomPreview(string guid)
		{
			if (guid == "h3vr.default")
			{
				return GetAudioFromFile(Path.Combine(PluginMain.AssemblyDirectory, "default/announcer_default.wav"));
			}
			if (guid == "h3vr.corrupted")
			{
				return GetAudioFromFile(Path.Combine(PluginMain.AssemblyDirectory, "default/announcer_corrupted.wav"));
			}
			AnnouncerManifest manifestFromGUID = GetManifestFromGUID(guid);
			int index = Random.Range(0, manifestFromGUID.Previews.Count);
			return GetAudioFromFile(manifestFromGUID.Previews[index]);
		}

		public static AnnouncerManifest GetManifestFromYamlfest(AnnouncerYamlfest yamlfest)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			yamlfest.VoiceLines = Path.Combine(Path.GetDirectoryName(yamlfest.Location), yamlfest.VoiceLines);
			AnnouncerManifest announcerManifest = new AnnouncerManifest();
			announcerManifest.VoiceLines = new List<VoiceLine>();
			announcerManifest.Name = yamlfest.Name;
			announcerManifest.GUID = yamlfest.GUID;
			announcerManifest.FrontPadding = yamlfest.FrontPadding;
			announcerManifest.BackPadding = yamlfest.BackPadding;
			announcerManifest.Location = yamlfest.Location;
			announcerManifest.Previews = Directory.GetFiles(yamlfest.VoiceLines, "example*.wav", SearchOption.AllDirectories).ToList();
			foreach (string item in Directory.GetFiles(yamlfest.VoiceLines, "*.wav", SearchOption.AllDirectories).ToList())
			{
				VoiceLine voiceLine = new VoiceLine();
				string song = item;
				voiceLine.ID = GetNameFromID(song);
				if (validid)
				{
					voiceLine.ClipPath = item;
					announcerManifest.VoiceLines.Add(voiceLine);
				}
			}
			return announcerManifest;
		}

		public static TNH_VoiceLineID GetNameFromID(string song)
		{
			string fileName = Path.GetFileName(song);
			validid = true;
			if (!fileName.Contains("game_intro"))
			{
				if (!fileName.Contains("hold_intro"))
				{
					if (!fileName.Contains("hold_analyze"))
					{
						if (!fileName.Contains("encryption_static"))
						{
							if (!fileName.Contains("encryption_hardened"))
							{
								if (!fileName.Contains("encryption_swarm"))
								{
									if (!fileName.Contains("encryption_recursive"))
									{
										if (!fileName.Contains("encryption_stealth"))
										{
											if (!fileName.Contains("encryption_agile"))
											{
												if (!fileName.Contains("encryption_regen"))
												{
													if (!fileName.Contains("encryption_polymo