Decompiled source of SchizophreniaMod v1.2.1

BepInEx/plugins/SchizophreniaMod.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SchizophreniaMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("SchizophreniaMod")]
[assembly: AssemblyTitle("SchizophreniaMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SchizophreniaMod
{
	[BepInPlugin("com.tibby.schizophrenia", "Schizophrenia Mod", "1.2.1")]
	public class SchizophreniaBase : BaseUnityPlugin
	{
		public static ManualLogSource mls;

		public static ConfigEntry<float> ConfigBaseChance;

		public static ConfigEntry<float> ConfigInsanityBonus;

		public static ConfigEntry<float> ConfigMinDistance;

		public static ConfigEntry<float> ConfigMaxDistance;

		public static ConfigEntry<float> ConfigCooldown;

		public static ConfigEntry<float> ConfigVolume;

		public static ConfigEntry<float> ConfigActivationDelay;

		private void Awake()
		{
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			mls = Logger.CreateLogSource("SchizoDebug");
			ConfigBaseChance = ((BaseUnityPlugin)this).Config.Bind<float>("Hallucination Settings", "BaseChance", 0.15f, "Base probability per second of hearing a sound (in percent, e.g., 0.15 = 0.15% chance per second).");
			ConfigInsanityBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Hallucination Settings", "InsanityBonus", 0.3f, "Additional chance added when at max insanity (in percent, e.g., 0.30 = 0.30% additional chance).");
			ConfigMinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Audio Settings", "MinDistance", 15f, "Minimum distance from the player in meters where hallucination sounds can spawn.");
			ConfigMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Audio Settings", "MaxDistance", 25f, "Maximum distance from the player in meters where hallucination sounds can spawn.");
			ConfigCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Hallucination Settings", "Cooldown", 18f, "Minimum seconds between hallucinations for each player.");
			ConfigVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio Settings", "Volume", 0.8f, "Master volume of the hallucinations (0.0 = silent, 1.0 = full volume).");
			ConfigActivationDelay = ((BaseUnityPlugin)this).Config.Bind<float>("System Settings", "ActivationDelay", 120f, "Delay in seconds before the mod starts after landing (if no one enters the facility first).");
			new Harmony("com.tibby.schizophrenia").PatchAll();
			mls.LogWarning((object)"=== SCHIZOPHRENIA MOD v1.2.0 LOADED ===");
			mls.LogInfo((object)"Audio hallucination system initialized.");
			mls.LogInfo((object)$"Config loaded: BaseChance={ConfigBaseChance.Value}%, InsanityBonus={ConfigInsanityBonus.Value}%, Cooldown={ConfigCooldown.Value}s");
		}
	}
	public static class AudioClipDatabase
	{
		public static readonly HashSet<string> Blacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"SnareFleaTipChannel", "SlimeIdle", "NutcrackerVentCrawl", "GhostlySynth2", "CrawlerDie", "SpiderDie", "NutcrackerDie", "StingrayDie", "BushWolfDie", "KillCaveDweller",
			"BugDie", "SporeDamage", "SporeDamageB", "SporeDamageC", "SporeDamageD", "PlantSpores", "HangPlayerOnCeiling", "ClingToPlayerLocal", "LradBrainwashingSignal1", "LradBrainwashingSignal4",
			"LradBrainwashingSignal6", "LradBrainwashingSignal7", "LradBrainwashingSignal8", "KillPlayerSpring", "MaskComedyAttach", "JackInTheBoxTheme"
		};

		public static readonly Dictionary<string, string[]> EnemyClipPatterns = new Dictionary<string, string[]>
		{
			{
				"Centipede",
				new string[3] { "centipedewalk", "clingto", "snarebuildup" }
			},
			{
				"Bunker Spider",
				new string[8] { "spiderattack", "spiderhit", "stunspider", "hitweb", "breakweb", "spoolinplayerweb", "clickingmandibles", "stuckweb" }
			},
			{
				"HoarderBug",
				new string[4] { "hoarderbugcry", "chitter", "bugwalk", "takeitems" }
			},
			{
				"Flowerman",
				new string[3] { "flowerman", "bracken", "crackneck" }
			},
			{
				"Crawler",
				new string[6] { "hitcrawler", "stuncrawler", "chargeforward", "startchargeforward", "longroar", "shortroar" }
			},
			{
				"Puffer",
				new string[4] { "puffsfx", "frighten", "rattletail", "hiss" }
			},
			{
				"Jester",
				new string[5] { "jesterstomp", "pop1", "chatteringteeth", "icecreamtruck", "turncrank" }
			},
			{
				"DressGirl",
				new string[6] { "monsternoise", "phonescream", "breathe1", "ghostlysynth", "wallrumblevoice", "voicecry" }
			},
			{
				"Spring",
				new string[4] { "spring1", "spring2", "spring3", "springwobble" }
			},
			{
				"Nutcracker",
				new string[6] { "nutcrackerangry", "nutcrackerhiteye", "nutcrackerturn", "headgoup", "hitmetal", "shotgunreloadnutcracker" }
			},
			{
				"Butler",
				new string[7] { "butlerstab", "butlerblowup", "butlersuitrustle", "butlerbeeswarm", "butlerstep", "butleruntuckknife", "butlermurdertheme" }
			},
			{
				"Masked",
				new string[5] { "maskattackplayer", "maskfacelightup", "maskpuke", "maskcry", "masklaugh" }
			},
			{
				"Hygrodere",
				new string[5] { "walkslime", "hitslime", "slimekillplayer", "slimeangry", "slimedance" }
			},
			{
				"Barber",
				new string[2] { "scissorssnip", "scissors" }
			},
			{
				"Maneater",
				new string[7] { "babycry", "babypuke", "babysquirm", "babyfootstep", "cavedweller", "chewmeat", "biteplay" }
			}
		};

		public static readonly Dictionary<string, string[]> MoonIndoorEnemies = new Dictionary<string, string[]>
		{
			{
				"experimentation",
				new string[9] { "Bunker Spider", "Centipede", "Hygrodere", "HoarderBug", "Puffer", "Crawler", "Flowerman", "DressGirl", "Nutcracker" }
			},
			{
				"assurance",
				new string[11]
				{
					"Centipede", "HoarderBug", "Bunker Spider", "Hygrodere", "Crawler", "Maneater", "Flowerman", "Puffer", "Barber", "DressGirl",
					"Nutcracker"
				}
			},
			{
				"vow",
				new string[10] { "Flowerman", "HoarderBug", "Maneater", "Centipede", "Bunker Spider", "Hygrodere", "Puffer", "Barber", "Crawler", "Spring" }
			},
			{
				"offense",
				new string[10] { "Crawler", "Bunker Spider", "Hygrodere", "Centipede", "Spring", "HoarderBug", "Puffer", "Maneater", "Flowerman", "Nutcracker" }
			},
			{
				"march",
				new string[11]
				{
					"Crawler", "Bunker Spider", "Flowerman", "Centipede", "HoarderBug", "Hygrodere", "Spring", "Puffer", "Maneater", "Nutcracker",
					"Jester"
				}
			},
			{
				"adamance",
				new string[13]
				{
					"Bunker Spider", "Centipede", "HoarderBug", "Hygrodere", "Flowerman", "Puffer", "Crawler", "Spring", "Maneater", "Nutcracker",
					"Masked", "DressGirl", "Jester"
				}
			},
			{
				"rend",
				new string[12]
				{
					"Nutcracker", "Jester", "Flowerman", "Bunker Spider", "Spring", "Centipede", "Masked", "DressGirl", "Butler", "Barber",
					"Puffer", "Hygrodere"
				}
			},
			{
				"dine",
				new string[13]
				{
					"Butler", "Barber", "Flowerman", "Centipede", "Hygrodere", "HoarderBug", "Jester", "Nutcracker", "Spring", "DressGirl",
					"Crawler", "Puffer", "Maneater"
				}
			},
			{
				"titan",
				new string[12]
				{
					"Jester", "Nutcracker", "Flowerman", "Bunker Spider", "Spring", "Crawler", "Centipede", "HoarderBug", "Masked", "Hygrodere",
					"DressGirl", "Puffer"
				}
			},
			{
				"artifice",
				new string[15]
				{
					"Bunker Spider", "Flowerman", "Nutcracker", "HoarderBug", "Crawler", "Jester", "Butler", "Puffer", "Masked", "Spring",
					"Centipede", "Hygrodere", "Barber", "DressGirl", "Maneater"
				}
			},
			{
				"embrion",
				new string[10] { "HoarderBug", "Hygrodere", "Barber", "Puffer", "Crawler", "Spring", "Bunker Spider", "Nutcracker", "Centipede", "Flowerman" }
			}
		};

		public static string[] GetIndoorEnemiesForMoon(string planetName)
		{
			string text = planetName.ToLower();
			foreach (KeyValuePair<string, string[]> moonIndoorEnemy in MoonIndoorEnemies)
			{
				if (text.Contains(moonIndoorEnemy.Key))
				{
					return moonIndoorEnemy.Value;
				}
			}
			return EnemyClipPatterns.Keys.ToArray();
		}
	}
	public class GhostAudioMover : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <MoveRoutine>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioSource src;

			public Vector3 dir;

			public float speed;

			public float dur;

			public GhostAudioMover <>4__this;

			private float <elapsed>5__1;

			private float <startVol>5__2;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0066: 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_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<elapsed>5__1 = 0f;
					<startVol>5__2 = (((Object)(object)src != (Object)null) ? src.volume : 0f);
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<elapsed>5__1 < dur && (Object)(object)src != (Object)null)
				{
					Transform transform = ((Component)<>4__this).transform;
					transform.position += dir * speed * Time.deltaTime;
					if (<elapsed>5__1 > dur * 0.8f)
					{
						src.volume = Mathf.Lerp(<startVol>5__2, 0f, (<elapsed>5__1 - dur * 0.8f) / (dur * 0.2f));
					}
					<elapsed>5__1 += Time.deltaTime;
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				Object.Destroy((Object)(object)((Component)<>4__this).gameObject);
				return false;
			}

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

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

		public void Initialize(AudioSource src, Vector3 dir, float speed, float dur)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			((MonoBehaviour)this).StartCoroutine(MoveRoutine(src, dir, speed, dur));
		}

		[IteratorStateMachine(typeof(<MoveRoutine>d__1))]
		private IEnumerator MoveRoutine(AudioSource src, Vector3 dir, float speed, float dur)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MoveRoutine>d__1(0)
			{
				<>4__this = this,
				src = src,
				dir = dir,
				speed = speed,
				dur = dur
			};
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	public class PlayerSchizoPatch
	{
		private static float timer = 0f;

		private static bool isSystemActive = false;

		private static float activationCountdown = 120f;

		private static bool countdownExpired = false;

		private static float countdownLogTimer = 0f;

		private static readonly Dictionary<ulong, float> PlayerCooldowns = new Dictionary<ulong, float>();

		private static List<(AudioClip clip, string enemyName)> _cachedClips = null;

		private static string _lastPlanetName = "";

		private static Dictionary<string, Dictionary<string, int>> PlayerHallucinationStats = new Dictionary<string, Dictionary<string, int>>();

		private static bool _debugMode = false;

		[HarmonyPostfix]
		private static void Postfix(PlayerControllerB __instance)
		{
			if (!((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled)
			{
				return;
			}
			ulong playerClientId = __instance.playerClientId;
			if (UnityInput.Current.GetKey((KeyCode)290) && UnityInput.Current.GetKeyDown((KeyCode)291))
			{
				_debugMode = !_debugMode;
				if (_debugMode)
				{
					SchizophreniaBase.mls.LogWarning((object)"╔══════════════════════════════════════════╗");
					SchizophreniaBase.mls.LogWarning((object)"║         DEBUG MODE ENABLED               ║");
					SchizophreniaBase.mls.LogWarning((object)"║  K = force hallucination                 ║");
					SchizophreniaBase.mls.LogWarning((object)"║  L = dump all AudioClips to log          ║");
					SchizophreniaBase.mls.LogWarning((object)"║  Hold F9 + tap F10 to disable             ║");
					SchizophreniaBase.mls.LogWarning((object)"╚══════════════════════════════════════════╝");
				}
				else
				{
					SchizophreniaBase.mls.LogWarning((object)"╔══════════════════════════════════════════╗");
					SchizophreniaBase.mls.LogWarning((object)"║         DEBUG MODE DISABLED              ║");
					SchizophreniaBase.mls.LogWarning((object)"║  Running in normal release mode          ║");
					SchizophreniaBase.mls.LogWarning((object)"╚══════════════════════════════════════════╝");
				}
				return;
			}
			if (_debugMode)
			{
				if (UnityInput.Current.GetKeyDown((KeyCode)107))
				{
					SchizophreniaBase.mls.LogWarning((object)"=== [DEBUG K] Forced audio playback ===");
					PlaySchizoAudio(__instance, debugLog: true);
					return;
				}
				if (UnityInput.Current.GetKeyDown((KeyCode)108))
				{
					DumpAllAudioClips();
					return;
				}
			}
			if (PlayerCooldowns.TryGetValue(playerClientId, out var value) && value > 0f)
			{
				PlayerCooldowns[playerClientId] = Mathf.Max(0f, value - Time.deltaTime);
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || !StartOfRound.Instance.shipHasLanded)
			{
				if (isSystemActive)
				{
					ResetSystem();
				}
				return;
			}
			SelectableLevel currentLevel = StartOfRound.Instance.currentLevel;
			if (currentLevel.levelID == 3 || currentLevel.PlanetName.ToLower().Contains("gordion"))
			{
				if (isSystemActive)
				{
					ResetSystem();
				}
				return;
			}
			if (!isSystemActive)
			{
				if (StartOfRound.Instance.allPlayerScripts.Any((PlayerControllerB p) => p.isPlayerControlled && p.isInsideFactory))
				{
					isSystemActive = true;
					SchizophreniaBase.mls.LogWarning((object)"!!! [SYSTEM ACTIVE] A player entered the facility !!!");
					return;
				}
				if (!countdownExpired)
				{
					activationCountdown -= Time.deltaTime;
					countdownLogTimer -= Time.deltaTime;
					if (countdownLogTimer <= 0f)
					{
						countdownLogTimer = 10f;
						if (_debugMode && activationCountdown > 0f)
						{
							SchizophreniaBase.mls.LogInfo((object)$"[Countdown] System activates in: {activationCountdown:F0}s");
						}
					}
					if (activationCountdown <= 0f)
					{
						activationCountdown = 0f;
						countdownExpired = true;
						isSystemActive = true;
						SchizophreniaBase.mls.LogWarning((object)"!!! [SYSTEM ACTIVE] Activation delay expired !!!");
					}
				}
				if (!isSystemActive)
				{
					return;
				}
			}
			if (__instance.isInsideFactory && !__instance.isInHangarShipRoom)
			{
				timer += Time.deltaTime;
				if (timer >= 1f)
				{
					timer = 0f;
					ProcessLogic(__instance);
				}
			}
		}

		private static void DumpAllAudioClips()
		{
			AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
			SchizophreniaBase.mls.LogWarning((object)$"=== [DUMP L] AudioClips in RAM: {array.Length} ===");
			List<AudioClip> list = (from c in array
				where (Object)(object)c != (Object)null && c.length > 0.05f
				orderby ((Object)c).name
				select c).ToList();
			foreach (AudioClip item in list)
			{
				SchizophreniaBase.mls.LogInfo((object)$"  [CLIP] {((Object)item).name} | {item.length:F2}s");
			}
			SchizophreniaBase.mls.LogWarning((object)$"=== [DUMP L] End of list ({list.Count} clips) ===");
		}

		private static void ResetSystem()
		{
			PrintRoundSummary();
			isSystemActive = false;
			activationCountdown = SchizophreniaBase.ConfigActivationDelay.Value;
			countdownExpired = false;
			countdownLogTimer = 0f;
			PlayerCooldowns.Clear();
			PlayerHallucinationStats.Clear();
			_cachedClips = null;
			_lastPlanetName = "";
		}

		private static void ProcessLogic(PlayerControllerB player)
		{
			ulong playerClientId = player.playerClientId;
			float value = SchizophreniaBase.ConfigCooldown.Value;
			if (PlayerCooldowns.TryGetValue(playerClientId, out var value2) && value2 > 0f)
			{
				if (_debugMode)
				{
					SchizophreniaBase.mls.LogInfo((object)$"[RNG] Cooldown {player.playerUsername}: {value2:F1}s");
				}
				return;
			}
			float num = Mathf.Clamp(player.insanityLevel / 50f, 0f, 1f);
			float num2 = SchizophreniaBase.ConfigBaseChance.Value / 100f;
			float num3 = SchizophreniaBase.ConfigInsanityBonus.Value / 100f;
			float num4 = num2 + num * num3;
			float num5 = CalculateWeight(player);
			float num6 = num4 * num5;
			float value3 = Random.value;
			if (_debugMode)
			{
				SchizophreniaBase.mls.LogInfo((object)($"[RNG] {player.playerUsername} | Roll: {value3:F5} | Chance: {num6:F5} | " + $"Fear: {player.insanityLevel:F1}/50 ({num * 100f:F0}%) | Weight: {num5}"));
			}
			if (value3 < num6)
			{
				if (_debugMode)
				{
					SchizophreniaBase.mls.LogWarning((object)("[HIT] " + player.playerUsername + " | Triggering audio!"));
				}
				PlaySchizoAudio(player, _debugMode);
			}
			else if (_debugMode)
			{
				SchizophreniaBase.mls.LogInfo((object)$"[MISS] {player.playerUsername} | Roll {value3:F5} >= {num6:F5}");
			}
		}

		private static float CalculateWeight(PlayerControllerB player)
		{
			return StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB p) => (Object)(object)p != (Object)(object)player && !p.isPlayerDead && p.isPlayerControlled && p.isInsideFactory && Vector3.Distance(((Component)player).transform.position, ((Component)p).transform.position) < 15f) switch
			{
				0 => 2f, 
				1 => 1f, 
				_ => 0.5f, 
			};
		}

		private static void PlaySchizoAudio(PlayerControllerB player, bool debugLog = false)
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			SelectableLevel val = StartOfRound.Instance?.currentLevel;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string planetName = val.PlanetName;
			if (_cachedClips == null || _lastPlanetName != planetName)
			{
				_lastPlanetName = planetName;
				_cachedClips = BuildClipCache(planetName, val, debugLog);
			}
			if (_cachedClips.Count != 0)
			{
				var (val2, text) = _cachedClips[Random.Range(0, _cachedClips.Count)];
				if (debugLog)
				{
					SchizophreniaBase.mls.LogWarning((object)("[Audio] Selected: [" + text + "] | Clip: [" + ((Object)val2).name + "] | " + $"Length: {val2.length:F2}s | Pool: {_cachedClips.Count} clips"));
				}
				float value = SchizophreniaBase.ConfigMinDistance.Value;
				float value2 = SchizophreniaBase.ConfigMaxDistance.Value;
				float num = Random.Range(value, value2);
				Vector3 position = ((Component)player).transform.position;
				Vector3 val3 = Random.insideUnitSphere;
				Vector3 val4 = position + ((Vector3)(ref val3)).normalized * num;
				NavMeshHit val5 = default(NavMeshHit);
				Vector3 val6 = (NavMesh.SamplePosition(val4, ref val5, 10f, -1) ? ((NavMeshHit)(ref val5)).position : val4);
				GameObject val7 = new GameObject("SchizoGhost");
				val7.transform.position = val6;
				AudioSource val8 = val7.AddComponent<AudioSource>();
				val8.spatialize = false;
				val8.spatialBlend = 1f;
				val8.rolloffMode = (AudioRolloffMode)1;
				val8.minDistance = 10f;
				val8.maxDistance = 40f;
				val8.volume = SchizophreniaBase.ConfigVolume.Value;
				val8.clip = val2;
				AudioMixerGroup val9 = ((IEnumerable<AudioMixerGroup>)Resources.FindObjectsOfTypeAll<AudioMixerGroup>()).FirstOrDefault((Func<AudioMixerGroup, bool>)((AudioMixerGroup g) => ((Object)g).name == "Master"));
				if ((Object)(object)val9 != (Object)null)
				{
					val8.outputAudioMixerGroup = val9;
				}
				val3 = val6 - ((Component)player).transform.position;
				Vector3 normalized = ((Vector3)(ref val3)).normalized;
				val7.AddComponent<GhostAudioMover>().Initialize(val8, normalized, 3f, val2.length);
				if (!PlayerHallucinationStats.ContainsKey(player.playerUsername))
				{
					PlayerHallucinationStats[player.playerUsername] = new Dictionary<string, int>();
				}
				if (!PlayerHallucinationStats[player.playerUsername].ContainsKey(text))
				{
					PlayerHallucinationStats[player.playerUsername][text] = 0;
				}
				PlayerHallucinationStats[player.playerUsername][text]++;
				val8.Play();
				PlayerCooldowns[player.playerClientId] = SchizophreniaBase.ConfigCooldown.Value;
				if (debugLog)
				{
					SchizophreniaBase.mls.LogWarning((object)("[Audio] PLAYED | " + player.playerUsername + " | " + $"[{text}] [{((Object)val2).name}] | Distance: {num:F1}m | Cooldown: {SchizophreniaBase.ConfigCooldown.Value}s"));
				}
			}
		}

		private static List<(AudioClip, string)> BuildClipCache(string planetName, SelectableLevel level, bool debugLog = false)
		{
			List<(AudioClip, string)> list = new List<(AudioClip, string)>();
			string[] indoorEnemiesForMoon = AudioClipDatabase.GetIndoorEnemiesForMoon(planetName);
			if (debugLog)
			{
				SchizophreniaBase.mls.LogInfo((object)("[Cache] Building cache for: " + planetName + " | " + string.Format("Allowed enemies ({0}): {1}", indoorEnemiesForMoon.Length, string.Join(", ", indoorEnemiesForMoon))));
			}
			AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
			HashSet<string> hashSet = new HashSet<string>();
			if (debugLog)
			{
				SchizophreniaBase.mls.LogInfo((object)$"[Cache] AudioClips in RAM: {array.Length}");
			}
			AudioClip[] array2 = array;
			foreach (AudioClip val in array2)
			{
				if ((Object)(object)val == (Object)null || val.length < 0.1f || AudioClipDatabase.Blacklist.Contains(((Object)val).name))
				{
					continue;
				}
				string clipLower = ((Object)val).name.ToLower();
				foreach (KeyValuePair<string, string[]> enemyClipPattern in AudioClipDatabase.EnemyClipPatterns)
				{
					string key = enemyClipPattern.Key;
					if (!indoorEnemiesForMoon.Contains(key) || !enemyClipPattern.Value.Any((string pattern) => clipLower.Contains(pattern)))
					{
						continue;
					}
					string item = key + "_" + ((Object)val).name;
					if (hashSet.Add(item))
					{
						list.Add((val, key));
					}
					break;
				}
			}
			if ((Object)(object)level != (Object)null)
			{
				HashSet<string> hashSet2 = new HashSet<string>(list.Select(((AudioClip, string) r) => r.Item2));
				string[] array3 = indoorEnemiesForMoon;
				foreach (string enemyKey in array3)
				{
					if (hashSet2.Contains(enemyKey))
					{
						continue;
					}
					EnemyType val2 = level.Enemies.Select((SpawnableEnemyWithRarity e) => e.enemyType).FirstOrDefault((Func<EnemyType, bool>)((EnemyType e) => (Object)(object)e != (Object)null && e.enemyName != null && AudioClipDatabase.EnemyClipPatterns.ContainsKey(enemyKey) && (e.enemyName.Contains(enemyKey) || enemyKey.Contains(e.enemyName) || NameMatchesKey(e.enemyName, enemyKey))));
					if (val2?.audioClips == null || val2.audioClips.Length == 0)
					{
						continue;
					}
					int num = 0;
					AudioClip[] audioClips = val2.audioClips;
					foreach (AudioClip val3 in audioClips)
					{
						if (!((Object)(object)val3 == (Object)null) && !(val3.length < 0.1f) && !AudioClipDatabase.Blacklist.Contains(((Object)val3).name))
						{
							string item2 = enemyKey + "_" + ((Object)val3).name;
							if (hashSet.Add(item2))
							{
								list.Add((val3, enemyKey));
								num++;
							}
						}
					}
					if (debugLog && num > 0)
					{
						SchizophreniaBase.mls.LogInfo((object)$"[Cache] EnemyType fallback: {enemyKey} ({val2.enemyName}) -> {num} clips");
					}
				}
			}
			if (debugLog)
			{
				List<string> values = (from x in list
					group x by x.Item2 into g
					orderby g.Key
					select $"{g.Key}({g.Count()})").ToList();
				if (list.Count > 0)
				{
					SchizophreniaBase.mls.LogWarning((object)string.Format("[Cache] Built {0} clips for [{1}]: {2}", list.Count, planetName, string.Join(", ", values)));
				}
				else
				{
					SchizophreniaBase.mls.LogError((object)("[Cache] Zero clips for [" + planetName + "]! Press L in-game to inspect the RAM clip list."));
				}
			}
			return list;
		}

		private static bool NameMatchesKey(string enemyName, string enemyKey)
		{
			if (enemyName == null || enemyKey == null)
			{
				return false;
			}
			string text = enemyName.ToLower().Replace(" ", "").Replace("-", "");
			string text2 = enemyKey.ToLower().Replace(" ", "").Replace("-", "");
			if (text == text2)
			{
				return true;
			}
			return text2 switch
			{
				"hoarderbug" => text.Contains("hoarding") || text.Contains("hoarder"), 
				"centipede" => text.Contains("centipede") || text.Contains("snare"), 
				"flowerman" => text.Contains("flowerman") || text.Contains("bracken"), 
				"crawler" => text.Contains("crawler") || text.Contains("thumper"), 
				"puffer" => text.Contains("puffer") || text.Contains("spore"), 
				"dressgirl" => text.Contains("dressgirl") || text.Contains("girl"), 
				"spring" => text.Contains("spring") || text.Contains("coil"), 
				"hygrodere" => text.Contains("hygrodere") || text.Contains("blob") || text.Contains("slime"), 
				"maneater" => text.Contains("maneater") || text.Contains("cavedweller") || text.Contains("cave"), 
				"bunker spider" => text.Contains("spider") || text.Contains("bunker"), 
				_ => text.Contains(text2) || text2.Contains(text), 
			};
		}

		private static void PrintRoundSummary()
		{
			if (PlayerHallucinationStats.Count == 0)
			{
				return;
			}
			SchizophreniaBase.mls.LogWarning((object)"========================================");
			SchizophreniaBase.mls.LogWarning((object)"      HALLUCINATION SUMMARY");
			SchizophreniaBase.mls.LogWarning((object)"========================================");
			foreach (KeyValuePair<string, Dictionary<string, int>> item in PlayerHallucinationStats.OrderBy((KeyValuePair<string, Dictionary<string, int>> x) => x.Key))
			{
				IOrderedEnumerable<KeyValuePair<string, int>> source = item.Value.OrderByDescending((KeyValuePair<string, int> x) => x.Value);
				int num = source.Sum((KeyValuePair<string, int> x) => x.Value);
				string text = string.Join(", ", source.Select((KeyValuePair<string, int> x) => $"{x.Value}x {x.Key}"));
				SchizophreniaBase.mls.LogWarning((object)("  " + item.Key + ": " + text));
				SchizophreniaBase.mls.LogWarning((object)$"    Total: {num} hallucination(s)");
			}
			SchizophreniaBase.mls.LogWarning((object)"========================================");
		}
	}
}