Decompiled source of BigTypingoftheHive v1.0.1

zombie zombo.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("zombie zombo")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Go Go Gadget zombies")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("zombie zombo")]
[assembly: AssemblyTitle("zombie zombo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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;
		}
	}
}
public static class Sfx
{
	private static readonly Dictionary<string, List<AudioSource>> _libraries = new Dictionary<string, List<AudioSource>>();

	private static GameObject _host;

	private static bool _classRegistered = false;

	private static string _defaultLibrary = null;

	public static void Init(string folderName = "sfx")
	{
		//IL_004a: 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_005d: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Expected O, but got Unknown
		if (!_libraries.ContainsKey(folderName))
		{
			if (!_classRegistered)
			{
				ClassInjector.RegisterTypeInIl2Cpp<SfxLoader>();
				_classRegistered = true;
			}
			if ((Object)(object)_host == (Object)null)
			{
				_host = new GameObject("SfxHost")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)(object)_host);
			}
			if (_defaultLibrary == null)
			{
				_defaultLibrary = folderName;
			}
			_libraries[folderName] = new List<AudioSource>();
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string path = Path.Combine(directoryName, folderName);
			GameObject val = new GameObject("SfxLoader_" + folderName);
			val.transform.SetParent(_host.transform, false);
			SfxLoader sfxLoader = val.AddComponent<SfxLoader>();
			sfxLoader.BeginLoad(folderName, path);
		}
	}

	public static void PlayRandom(string folderName = null)
	{
		string text = folderName ?? _defaultLibrary;
		if (text == null || !_libraries.TryGetValue(text, out var value) || value.Count == 0)
		{
			Debug.LogWarning(Object.op_Implicit("[Sfx] PlayRandom('" + folderName + "') — no sounds loaded yet for that library. Did you call Sfx.Init()?"));
			return;
		}
		AudioSource val = value[Random.Range(0, value.Count)];
		if ((Object)(object)val == (Object)null || (Object)(object)val.clip == (Object)null)
		{
			Debug.LogWarning(Object.op_Implicit("[Sfx] Picked a null/destroyed clip holder — skipping this play."));
		}
		else
		{
			val.Play();
		}
	}

	public static AudioClip GetRandomClip(string folderName = null)
	{
		string text = folderName ?? _defaultLibrary;
		if (text == null || !_libraries.TryGetValue(text, out var value) || value.Count == 0)
		{
			return null;
		}
		AudioSource val = value[Random.Range(0, value.Count)];
		return ((Object)(object)val != (Object)null) ? val.clip : null;
	}

	public static int GetLoadedCount(string folderName = null)
	{
		string text = folderName ?? _defaultLibrary;
		List<AudioSource> value;
		return (text != null && _libraries.TryGetValue(text, out value)) ? value.Count : 0;
	}

	internal static void RegisterHolder(string folderName, AudioSource holder)
	{
		if (!_libraries.TryGetValue(folderName, out var value))
		{
			value = new List<AudioSource>();
			_libraries[folderName] = value;
		}
		value.Add(holder);
	}
}
internal class SfxLoader : MonoBehaviour
{
	private string libraryKey;

	private string folderPath;

	private readonly Queue<string> pendingFiles = new Queue<string>();

	private UnityWebRequest currentRequest;

	private string currentFile;

	public SfxLoader(IntPtr ptr)
		: base(ptr)
	{
	}

	public void BeginLoad(string key, string path)
	{
		libraryKey = key;
		folderPath = path;
		if (!Directory.Exists(folderPath))
		{
			Debug.LogWarning(Object.op_Implicit($"[Sfx] '{libraryKey}': no folder found at {folderPath} — this library will have no sounds."));
			return;
		}
		string[] files = Directory.GetFiles(folderPath);
		foreach (string text in files)
		{
			string text2 = Path.GetExtension(text).ToLowerInvariant();
			if (text2 == ".wav" || text2 == ".ogg" || text2 == ".mp3")
			{
				pendingFiles.Enqueue(text);
			}
		}
		Debug.Log(Object.op_Implicit($"[Sfx] '{libraryKey}': found {pendingFiles.Count} sound file(s) in {folderPath}, loading..."));
		StartNextLoad();
	}

	private void StartNextLoad()
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		if (pendingFiles.Count == 0)
		{
			Debug.Log(Object.op_Implicit($"[Sfx] '{libraryKey}': finished loading — {Sfx.GetLoadedCount(libraryKey)} sound(s) ready."));
		}
		else
		{
			currentFile = pendingFiles.Dequeue();
			AudioType audioType = GetAudioType(currentFile);
			string absoluteUri = new Uri(currentFile).AbsoluteUri;
			currentRequest = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, audioType);
			currentRequest.SendWebRequest();
		}
	}

	private void Update()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Invalid comparison between Unknown and I4
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Expected O, but got Unknown
		if (currentRequest == null || !currentRequest.isDone)
		{
			return;
		}
		try
		{
			if ((int)currentRequest.result == 1)
			{
				AudioClip content = DownloadHandlerAudioClip.GetContent(currentRequest);
				if ((Object)(object)content != (Object)null)
				{
					((Object)content).name = Path.GetFileNameWithoutExtension(currentFile);
					GameObject val = new GameObject("SfxClipHolder_" + libraryKey + "_" + ((Object)content).name);
					val.transform.SetParent(((Component)this).transform, false);
					AudioSource val2 = ((Il2CppObjectBase)val.AddComponent(Il2CppType.Of<AudioSource>())).Cast<AudioSource>();
					val2.clip = content;
					val2.playOnAwake = false;
					val2.spatialBlend = 0f;
					Sfx.RegisterHolder(libraryKey, val2);
					Debug.Log(Object.op_Implicit($"[Sfx] '{libraryKey}': loaded '{((Object)content).name}'."));
				}
				else
				{
					Debug.LogWarning(Object.op_Implicit($"[Sfx] '{libraryKey}': {currentFile} downloaded fine but produced a null AudioClip."));
				}
			}
			else
			{
				Debug.LogWarning(Object.op_Implicit($"[Sfx] '{libraryKey}': failed to load {currentFile}: {currentRequest.error}"));
			}
		}
		catch (Exception value)
		{
			Debug.LogError(Object.op_Implicit($"[Sfx] '{libraryKey}': exception loading {currentFile}: {value}"));
		}
		finally
		{
			currentRequest.Dispose();
			currentRequest = null;
		}
		StartNextLoad();
	}

	private static AudioType GetAudioType(string filePath)
	{
		//IL_003a: 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_003f: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		return (AudioType)(Path.GetExtension(filePath).ToLowerInvariant() switch
		{
			".mp3" => 13, 
			".ogg" => 14, 
			".wav" => 20, 
			_ => 0, 
		});
	}
}
namespace ZombieMod
{
	public static class NightDirector
	{
		private enum State
		{
			Idle,
			FastForwardingToNight,
			HoldingNight,
			RestoringDaylight
		}

		private static State _state;

		private static float _originalHour;

		private static float _fromHour;

		private static float _targetHour;

		private static float _forwardDistance;

		private static float _transitionStartTime;

		private static float _transitionDuration;

		public static bool IsNightLocked => _state == State.FastForwardingToNight || _state == State.HoldingNight;

		public static void RequestNight()
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			if (!Plugin.NightUntilScriptComplete.Value || _state == State.FastForwardingToNight || _state == State.HoldingNight || !SkyManagerReady())
			{
				return;
			}
			float currentTime = SkyManager.GetCurrentTime();
			if (_state == State.Idle)
			{
				_originalHour = currentTime;
			}
			_fromHour = currentTime;
			_targetHour = Mathf.Repeat(Plugin.NightTargetHour.Value, 24f);
			float num;
			for (num = _targetHour - _fromHour; num < 0f; num += 24f)
			{
			}
			_forwardDistance = num;
			_transitionDuration = Mathf.Max(0.5f, Plugin.NightTransitionSeconds.Value);
			_transitionStartTime = Time.time;
			_state = State.FastForwardingToNight;
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("NightDirector: forcing night, ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_fromHour, "0.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("h -> ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_targetHour, "0.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("h over ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_transitionDuration, "0.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s.");
				}
				modLog.LogInfo(val);
			}
		}

		public static void ReleaseNight()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			if (_state == State.Idle || _state == State.RestoringDaylight)
			{
				return;
			}
			if (!SkyManagerReady())
			{
				_state = State.Idle;
				return;
			}
			float currentTime = SkyManager.GetCurrentTime();
			_fromHour = currentTime;
			_targetHour = _originalHour;
			float num;
			for (num = _targetHour - _fromHour; num < 0f; num += 24f)
			{
			}
			_forwardDistance = num;
			_transitionDuration = Mathf.Max(0.5f, Plugin.NightTransitionSeconds.Value * 0.8f);
			_transitionStartTime = Time.time;
			_state = State.RestoringDaylight;
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(55, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("NightDirector: script complete, restoring daylight (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_originalHour, "0.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("h).");
				}
				modLog.LogInfo(val);
			}
		}

		public static void Tick()
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			if (_state == State.Idle)
			{
				return;
			}
			if (!SkyManagerReady())
			{
				_state = State.Idle;
			}
			else if (_state == State.FastForwardingToNight)
			{
				float num = Mathf.Clamp01((Time.time - _transitionStartTime) / _transitionDuration);
				float num2 = Mathf.SmoothStep(0f, 1f, num);
				SkyManager.SetFixedTime(Mathf.Repeat(_fromHour + _forwardDistance * num2, 24f));
				if (num >= 1f)
				{
					_state = State.HoldingNight;
					SkyManager.SetFixedTime(_targetHour);
				}
			}
			else if (_state == State.HoldingNight)
			{
				SkyManager.SetFixedTime(_targetHour);
			}
			else
			{
				if (_state != State.RestoringDaylight)
				{
					return;
				}
				float num3 = Mathf.Clamp01((Time.time - _transitionStartTime) / _transitionDuration);
				float num4 = Mathf.SmoothStep(0f, 1f, num3);
				SkyManager.SetFixedTime(Mathf.Repeat(_fromHour + _forwardDistance * num4, 24f));
				if (!(num3 >= 1f))
				{
					return;
				}
				RestoreImmediate();
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(37, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("NightDirector: daylight restored (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_originalHour, "0.0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("h).");
					}
					modLog.LogInfo(val);
				}
			}
		}

		public static void RestoreImmediate()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			bool flag = _state != State.Idle;
			_state = State.Idle;
			if (!flag || !SkyManagerReady())
			{
				return;
			}
			bool flag2 = default(bool);
			try
			{
				SkyManager.SetFixedTime(_originalHour);
				SkyManager.ClearFixedTime();
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("NightDirector: hard-restored daylight instantly (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(_originalHour, "0.0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("h).");
					}
					modLog.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource modLog2 = Plugin.ModLog;
				if (modLog2 != null)
				{
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(71, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("NightDirector: RestoreImmediate hit an error, sky may still be frozen: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					modLog2.LogWarning(val2);
				}
			}
		}

		private static bool SkyManagerReady()
		{
			try
			{
				return SkyManager.initalized;
			}
			catch
			{
				return false;
			}
		}
	}
	[BepInPlugin("gogogadgetjustice.bigtypingofthehive", "Typing of the Hive", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public static ManualLogSource ModLog;

		public static ConfigEntry<KeyCode> ActivationKey { get; private set; }

		public static ConfigEntry<KeyCode> SpawnKey { get; private set; }

		public static ConfigEntry<float> SpawnDistanceMin { get; private set; }

		public static ConfigEntry<float> SpawnDistanceMax { get; private set; }

		public static ConfigEntry<float> ZombieSpeed { get; private set; }

		public static ConfigEntry<int> MaxZombies { get; private set; }

		public static ConfigEntry<float> SurroundRadiusMin { get; private set; }

		public static ConfigEntry<float> SurroundRadiusMax { get; private set; }

		public static ConfigEntry<bool> EnableTypingMode { get; private set; }

		public static ConfigEntry<string> PhraseBankFileName { get; private set; }

		public static ConfigEntry<bool> RandomMode { get; private set; }

		public static ConfigEntry<float> LabelHeightOffset { get; private set; }

		public static ConfigEntry<int> LabelFontSize { get; private set; }

		public static ConfigEntry<bool> AutoRespawnOnKill { get; private set; }

		public static ConfigEntry<bool> EnableSfx { get; private set; }

		public static ConfigEntry<string> KeySoundFolder { get; private set; }

		public static ConfigEntry<string> SpaceSoundFolder { get; private set; }

		public static ConfigEntry<string> BuzzSoundFolder { get; private set; }

		public static ConfigEntry<float> BuzzIntervalMin { get; private set; }

		public static ConfigEntry<float> BuzzIntervalMax { get; private set; }

		public static ConfigEntry<float> BuzzMinDistance { get; private set; }

		public static ConfigEntry<float> BuzzMaxDistance { get; private set; }

		public static ConfigEntry<float> BuzzVolume { get; private set; }

		public static ConfigEntry<bool> NightUntilScriptComplete { get; private set; }

		public static ConfigEntry<float> NightTargetHour { get; private set; }

		public static ConfigEntry<float> NightTransitionSeconds { get; private set; }

		public static ConfigEntry<int> CyclesBeforeDawn { get; private set; }

		public static ConfigEntry<KeyCode> HardResetKey { get; private set; }

		public static ConfigEntry<bool> AutoResetOnSceneLoad { get; private set; }

		public static PhraseSelectionMode CurrentSelectionMode => RandomMode.Value ? PhraseSelectionMode.Random : PhraseSelectionMode.Sequential;

		public override void Load()
		{
			ModLog = ((BasePlugin)this).Log;
			ActivationKey = ((BasePlugin)this).Config.Bind<KeyCode>("Controls", "ActivationKey", (KeyCode)45, "Press '-' to enable zombie spawning.");
			SpawnKey = ((BasePlugin)this).Config.Bind<KeyCode>("Controls", "SpawnKey", (KeyCode)270, "Press '+' to spawn a zombie.");
			SpawnDistanceMin = ((BasePlugin)this).Config.Bind<float>("Settings", "SpawnDistanceMin", 8f, "Nearest distance (meters) a new zombie can spawn from the player. Spawns at a random compass direction, not just straight ahead.");
			SpawnDistanceMax = ((BasePlugin)this).Config.Bind<float>("Settings", "SpawnDistanceMax", 14f, "Farthest distance (meters) a new zombie can spawn from the player.");
			ZombieSpeed = ((BasePlugin)this).Config.Bind<float>("Settings", "ZombieSpeed", 2.5f, "Zombie movement speed.");
			MaxZombies = ((BasePlugin)this).Config.Bind<int>("Settings", "MaxZombies", 30, "Max active zombies allowed.");
			SurroundRadiusMin = ((BasePlugin)this).Config.Bind<float>("Settings", "SurroundRadiusMin", 3.5f, "Nearest distance (meters) zombies circle at while waiting. Bigger = easier to read their phrase.");
			SurroundRadiusMax = ((BasePlugin)this).Config.Bind<float>("Settings", "SurroundRadiusMax", 6f, "Farthest distance (meters) zombies circle at while waiting.");
			EnableTypingMode = ((BasePlugin)this).Config.Bind<bool>("Typing", "EnableTypingMode", true, "If true, each zombie carries a phrase you must type to kill it (Typing of the Dead style).");
			PhraseBankFileName = ((BasePlugin)this).Config.Bind<string>("Typing", "PhraseBankFile", "phrases.json", "Name of the JSON phrase bank file, expected to sit next to this plugin's DLL. Generate one from any text file with the included phrase_converter.py script.");
			RandomMode = ((BasePlugin)this).Config.Bind<bool>("Typing", "RandomMode", false, "false (default) = walk straight down the phrase file in order, wrapping at the end. true = shuffled, guaranteed no repeats until every phrase has been used once.");
			LabelHeightOffset = ((BasePlugin)this).Config.Bind<float>("Typing", "LabelHeightOffset", 0.55f, "How far above the zombie's head (in meters) the floating phrase label sits.");
			LabelFontSize = ((BasePlugin)this).Config.Bind<int>("Typing", "LabelFontSize", 42, "Font size for the floating typing label.");
			AutoRespawnOnKill = ((BasePlugin)this).Config.Bind<bool>("Typing", "AutoRespawnOnKill", true, "If true, typing out a zombie immediately spawns a fresh one so the horde never runs dry.");
			EnableSfx = ((BasePlugin)this).Config.Bind<bool>("Audio", "EnableSfx", true, "Master on/off switch for keystroke and ambient buzzing sound effects.");
			KeySoundFolder = ((BasePlugin)this).Config.Bind<string>("Audio", "KeySoundFolder", "key", "Subfolder (next to this DLL) holding the sound played for a correctly typed letter — e.g. key.ogg.");
			SpaceSoundFolder = ((BasePlugin)this).Config.Bind<string>("Audio", "SpaceSoundFolder", "space", "Subfolder holding the sound played for a correctly typed space — e.g. space.ogg.");
			BuzzSoundFolder = ((BasePlugin)this).Config.Bind<string>("Audio", "BuzzSoundFolder", "buzz", "Subfolder holding bee-buzz sounds — e.g. bzz.ogg and buzz.ogg. Each zombie has its own positional AudioSource and picks a random clip from this folder on its own timer below.");
			BuzzIntervalMin = ((BasePlugin)this).Config.Bind<float>("Audio", "BuzzIntervalMin", 1.5f, "Shortest gap (seconds) between one zombie's own buzz sounds.");
			BuzzIntervalMax = ((BasePlugin)this).Config.Bind<float>("Audio", "BuzzIntervalMax", 4f, "Longest gap (seconds) between one zombie's own buzz sounds.");
			BuzzMinDistance = ((BasePlugin)this).Config.Bind<float>("Audio", "BuzzMinDistance", 2f, "Distance (meters) within which a zombie's buzz plays at full volume.");
			BuzzMaxDistance = ((BasePlugin)this).Config.Bind<float>("Audio", "BuzzMaxDistance", 20f, "Distance (meters) beyond which a zombie's buzz is inaudible. Should comfortably cover SurroundRadiusMax so a circling bee doesn't go silent.");
			BuzzVolume = ((BasePlugin)this).Config.Bind<float>("Audio", "BuzzVolume", 0.8f, "Per-zombie buzz volume (0-1). Lower this if a full horde gets too loud.");
			NightUntilScriptComplete = ((BasePlugin)this).Config.Bind<bool>("Night", "NightUntilScriptComplete", true, "If true, activating the mod forces night (via the game's own SkyManager,) until the whole phrase script has been typed through.");
			NightTargetHour = ((BasePlugin)this).Config.Bind<float>("Night", "NightTargetHour", 0f, "The hour (0-24) to fast-forward to and hold. 0 = midnight.");
			NightTransitionSeconds = ((BasePlugin)this).Config.Bind<float>("Night", "NightTransitionSeconds", 2.5f, "Seconds to smoothly fast-forward into (and, later, back out of) night.");
			CyclesBeforeDawn = ((BasePlugin)this).Config.Bind<int>("Night", "CyclesBeforeDawn", 1, "How many full passes through the phrase script are required before daylight is restored.");
			HardResetKey = ((BasePlugin)this).Config.Bind<KeyCode>("Reset", "HardResetKey", (KeyCode)290, "Press to instantly clear every zombie, stop ambient sound, restore the sky, and restart the phrase script from the top.");
			AutoResetOnSceneLoad = ((BasePlugin)this).Config.Bind<bool>("Reset", "AutoResetOnSceneLoad", true, "If true, a hard reset runs automatically whenever a new scene loads (e.g. joining a new session), so nothing - zombies, sound, forced night, script position - carries over from a previous session.");
			ClassInjector.RegisterTypeInIl2Cpp<ZombieManager>();
			string directoryName = Path.GetDirectoryName(typeof(Plugin).Assembly.Location);
			string jsonPath = Path.Combine(directoryName ?? ".", PhraseBankFileName.Value);
			PhraseBank.Load(jsonPath);
			if (EnableSfx.Value)
			{
				Sfx.Init(KeySoundFolder.Value);
				Sfx.Init(SpaceSoundFolder.Value);
				Sfx.Init(BuzzSoundFolder.Value);
			}
			ZombieManager.EnsureExists();
			ModLog.LogInfo((object)"Zombie Horde Mod initialized. Press '-' to activate.");
		}
	}
	public enum PhraseSelectionMode
	{
		Sequential,
		Random
	}
	public static class TypingColors
	{
		public static readonly Color Typed = new Color(1f, 0.85f, 0.15f);

		public static readonly Color ActiveRemaining = Color.white;

		public static readonly Color IdleRemaining = new Color(0.75f, 0.75f, 0.75f);
	}
	public static class PhraseBank
	{
		private static List<string> _phrases = new List<string>();

		private static int _sequentialIndex = 0;

		private static Queue<string> _shuffleBag = new Queue<string>();

		private static string _lastHandedOut = null;

		private static int _completedCount = 0;

		public static bool IsLoaded => _phrases.Count > 0;

		public static int Count => _phrases.Count;

		public static int CompletedCycles => (_phrases.Count > 0) ? (_completedCount / _phrases.Count) : 0;

		public static void MarkCompleted()
		{
			_completedCount++;
		}

		public static void ResetProgress()
		{
			_sequentialIndex = 0;
			_shuffleBag.Clear();
			_lastHandedOut = null;
			_completedCount = 0;
		}

		public static bool Load(string jsonPath)
		{
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			_phrases.Clear();
			_sequentialIndex = 0;
			_shuffleBag.Clear();
			_lastHandedOut = null;
			_completedCount = 0;
			bool flag = default(bool);
			try
			{
				if (string.IsNullOrEmpty(jsonPath) || !File.Exists(jsonPath))
				{
					ManualLogSource modLog = Plugin.ModLog;
					if (modLog != null)
					{
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(67, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PhraseBank: file not found at '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(jsonPath);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'. Falling back to built-in phrases.");
						}
						modLog.LogWarning(val);
					}
					LoadFallback();
					return false;
				}
				string json = File.ReadAllText(jsonPath);
				List<string> list = ParsePhrasesFromJson(json);
				if (list.Count == 0)
				{
					ManualLogSource modLog2 = Plugin.ModLog;
					if (modLog2 != null)
					{
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(70, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PhraseBank: '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(jsonPath);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' contained no phrases. Falling back to built-in phrases.");
						}
						modLog2.LogWarning(val);
					}
					LoadFallback();
					return false;
				}
				foreach (string item in list)
				{
					if (!string.IsNullOrWhiteSpace(item))
					{
						_phrases.Add(item.Trim());
					}
				}
				if (_phrases.Count == 0)
				{
					ManualLogSource modLog3 = Plugin.ModLog;
					if (modLog3 != null)
					{
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(80, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PhraseBank: '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(jsonPath);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' had entries but all were empty. Falling back to built-in phrases.");
						}
						modLog3.LogWarning(val);
					}
					LoadFallback();
					return false;
				}
				ManualLogSource modLog4 = Plugin.ModLog;
				if (modLog4 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(36, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PhraseBank: loaded ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_phrases.Count);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" phrases from '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(jsonPath);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
					}
					modLog4.LogInfo(val2);
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource modLog5 = Plugin.ModLog;
				if (modLog5 != null)
				{
					BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(31, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("PhraseBank: failed to load '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(jsonPath);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
					}
					modLog5.LogError(val3);
				}
				LoadFallback();
				return false;
			}
		}

		private static List<string> ParsePhrasesFromJson(string json)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrEmpty(json))
			{
				return list;
			}
			int num = json.IndexOf("\"phrases\"", StringComparison.OrdinalIgnoreCase);
			if (num < 0)
			{
				return list;
			}
			int num2 = json.IndexOf('[', num);
			if (num2 < 0)
			{
				return list;
			}
			int num3 = FindMatchingBracket(json, num2);
			if (num3 < 0)
			{
				num3 = json.Length - 1;
			}
			int i = num2 + 1;
			while (i < num3)
			{
				for (; i < num3 && (char.IsWhiteSpace(json[i]) || json[i] == ','); i++)
				{
				}
				if (i >= num3 || json[i] != '"')
				{
					break;
				}
				i++;
				StringBuilder stringBuilder = new StringBuilder();
				while (i < num3 && json[i] != '"')
				{
					char c = json[i];
					if (c == '\\' && i + 1 < num3)
					{
						switch (json[i + 1])
						{
						case '"':
							stringBuilder.Append('"');
							i += 2;
							continue;
						case '\\':
							stringBuilder.Append('\\');
							i += 2;
							continue;
						case '/':
							stringBuilder.Append('/');
							i += 2;
							continue;
						case 'n':
							stringBuilder.Append('\n');
							i += 2;
							continue;
						case 't':
							stringBuilder.Append('\t');
							i += 2;
							continue;
						case 'r':
							stringBuilder.Append('\r');
							i += 2;
							continue;
						case 'b':
							stringBuilder.Append('\b');
							i += 2;
							continue;
						case 'f':
							stringBuilder.Append('\f');
							i += 2;
							continue;
						case 'u':
							if (i + 6 <= json.Length)
							{
								string s = json.Substring(i + 2, 4);
								if (int.TryParse(s, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
								{
									stringBuilder.Append((char)result);
								}
								i += 6;
								continue;
							}
							break;
						}
					}
					stringBuilder.Append(c);
					i++;
				}
				i++;
				list.Add(stringBuilder.ToString());
			}
			return list;
		}

		private static int FindMatchingBracket(string json, int openIndex)
		{
			int num = 0;
			for (int i = openIndex; i < json.Length; i++)
			{
				if (json[i] == '[')
				{
					num++;
				}
				else if (json[i] == ']')
				{
					num--;
					if (num == 0)
					{
						return i;
					}
				}
			}
			return -1;
		}

		private static void LoadFallback()
		{
			_phrases = new List<string> { "brains", "run for your life", "the horde is coming", "type to survive", "keep your fingers moving", "do not stop typing" };
		}

		public static string GetNext(PhraseSelectionMode mode)
		{
			if (_phrases.Count == 0)
			{
				LoadFallback();
			}
			return (mode == PhraseSelectionMode.Sequential) ? GetSequential() : GetRandomNoRepeat();
		}

		private static string GetSequential()
		{
			string result = _phrases[_sequentialIndex % _phrases.Count];
			_sequentialIndex++;
			return result;
		}

		private static string GetRandomNoRepeat()
		{
			if (_shuffleBag.Count == 0)
			{
				RefillShuffleBag();
			}
			return _lastHandedOut = _shuffleBag.Dequeue();
		}

		private static void RefillShuffleBag()
		{
			List<string> list = new List<string>(_phrases);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = Random.Range(0, num + 1);
				List<string> list2 = list;
				int index = num;
				int index2 = num2;
				string value = list[num2];
				string value2 = list[num];
				list2[index] = value;
				list[index2] = value2;
			}
			if (list.Count > 1 && list[0] == _lastHandedOut)
			{
				List<string> list2 = list;
				string value2 = list[1];
				string value = list[0];
				list[0] = value2;
				list2[1] = value;
			}
			_shuffleBag = new Queue<string>(list);
		}
	}
	public static class ZombieLabel
	{
		public static TextMesh Create(Transform parent, float heightOffset, int fontSize)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_002b: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			GameObject val = new GameObject("TypingLabel");
			val.transform.SetParent(parent, false);
			val.transform.localPosition = new Vector3(0f, heightOffset, 0f);
			TextMesh val2 = val.AddComponent<TextMesh>();
			val2.characterSize = 0.12f;
			val2.fontSize = fontSize;
			val2.anchor = (TextAnchor)4;
			val2.alignment = (TextAlignment)1;
			val2.richText = true;
			val2.color = Color.white;
			MeshRenderer component = val.GetComponent<MeshRenderer>();
			if ((Object)component != (Object)null)
			{
				((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)component).receiveShadows = false;
			}
			return val2;
		}

		public static void SetText(TextMesh tm, string fullPhrase, int typedCount, bool isActiveTarget)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)tm == (Object)null) && !string.IsNullOrEmpty(fullPhrase))
			{
				typedCount = Mathf.Clamp(typedCount, 0, fullPhrase.Length);
				string value = fullPhrase.Substring(0, typedCount);
				string value2 = fullPhrase.Substring(typedCount);
				string value3 = ColorUtility.ToHtmlStringRGB(TypingColors.Typed);
				Color val = (isActiveTarget ? TypingColors.ActiveRemaining : TypingColors.IdleRemaining);
				string value4 = ColorUtility.ToHtmlStringRGB(val);
				tm.text = ((typedCount > 0) ? $"<color=#{value3}>{value}</color><color=#{value4}>{value2}</color>" : $"<color=#{value4}>{value2}</color>");
			}
		}

		public static void Billboard(TextMesh tm, Camera cam)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			if (!((Object)tm == (Object)null) && !((Object)cam == (Object)null))
			{
				Transform transform = ((Component)tm).transform;
				Vector3 val = transform.position - ((Component)cam).transform.position;
				val.y = 0f;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
				{
					transform.rotation = Quaternion.LookRotation(val);
				}
			}
		}
	}
	public class ZombieManager : MonoBehaviour
	{
		private class ZombieInstance
		{
			public GameObject Root;

			public Transform Transform;

			public Transform HeadTransform;

			public float BobOffset;

			public float VerticalVelocity;

			public Vector3 TargetOffset;

			public float SwayFrequency;

			public float SwayAmplitude;

			public float SwayPhase;

			public string Phrase;

			public int TypedCount;

			public TextMesh Label;

			public bool IsActiveTarget;

			public AudioSource BuzzSource;

			public float NextBuzzTime;
		}

		private static Shader _cachedShader;

		private bool _isActivated = false;

		private readonly List<ZombieInstance> _zombies = new List<ZombieInstance>();

		private ZombieInstance _currentTarget;

		private int _lastSceneHandle;

		public static ZombieManager Instance { get; private set; }

		public ZombieManager(IntPtr ptr)
			: base(ptr)
		{
		}

		public static void EnsureExists()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null || (Object)Instance == (Object)null)
			{
				GameObject val = new GameObject("ZombieManager");
				Object.DontDestroyOnLoad((Object)(object)val);
				Instance = val.AddComponent<ZombieManager>();
			}
		}

		private void Awake()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Scene activeScene = SceneManager.GetActiveScene();
			_lastSceneHandle = SceneHandle.op_Implicit(((Scene)(ref activeScene)).handle);
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				modLog.LogInfo((object)"ZombieManager awake and persistent.");
			}
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(Plugin.HardResetKey.Value))
			{
				PerformHardReset("manual key press");
			}
			if (Plugin.AutoResetOnSceneLoad.Value)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).handle != SceneHandle.op_Implicit(_lastSceneHandle))
				{
					_lastSceneHandle = SceneHandle.op_Implicit(((Scene)(ref activeScene)).handle);
					PerformHardReset("scene changed to '" + ((Scene)(ref activeScene)).name + "'");
				}
			}
			PurgeDeadZombies();
			NightDirector.Tick();
			if (!_isActivated)
			{
				if (Input.GetKeyDown(Plugin.ActivationKey.Value) || ((Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) && Input.GetKeyDown((KeyCode)45)))
				{
					_isActivated = true;
					ManualLogSource modLog = Plugin.ModLog;
					if (modLog != null)
					{
						modLog.LogInfo((object)"Zombie Mod Activated! Press '+' to spawn zombies.");
					}
					NightDirector.RequestNight();
				}
			}
			else
			{
				if (Input.GetKeyDown(Plugin.SpawnKey.Value) || ((Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) && Input.GetKeyDown((KeyCode)61)))
				{
					SpawnZombie();
				}
				UpdateZombieAI();
				ProcessTypingInput();
			}
		}

		private void PurgeDeadZombies()
		{
			_zombies.RemoveAll((ZombieInstance z) => z == null || (Object)z.Root == (Object)null);
		}

		public static void HardReset(string reason)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null || (Object)Instance == (Object)null)
			{
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(66, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ZombieManager: hard reset requested (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") but no instance exists yet.");
					}
					modLog.LogInfo(val);
				}
			}
			else
			{
				Instance.PerformHardReset(reason);
			}
		}

		private void PerformHardReset(string reason)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			int count = _zombies.Count;
			foreach (ZombieInstance zombie in _zombies)
			{
				if (zombie != null && (Object)zombie.Root != (Object)null)
				{
					Object.Destroy((Object)(object)zombie.Root);
				}
			}
			_zombies.Clear();
			_currentTarget = null;
			_isActivated = false;
			NightDirector.RestoreImmediate();
			PhraseBank.ResetProgress();
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				modLog.LogInfo((object)($"ZombieManager: hard reset ({reason}) - cleared {count} zombie(s) (and their buzz sources), " + "restored the sky, and restarted the script from the top."));
			}
		}

		private static Shader GetWorkingShader()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			if ((Object)_cachedShader != (Object)null)
			{
				return _cachedShader;
			}
			string[] array = new string[7] { "Universal Render Pipeline/Lit", "Universal Render Pipeline/Simple Lit", "Universal Render Pipeline/Unlit", "HDRP/Lit", "Standard", "Legacy Shaders/Diffuse", "Sprites/Default" };
			string[] array2 = array;
			bool flag = default(bool);
			foreach (string text in array2)
			{
				Shader val = Shader.Find(text);
				if (!((Object)val != (Object)null))
				{
					continue;
				}
				_cachedShader = val;
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(29, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ZombieManager using shader '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'");
					}
					modLog.LogInfo(val2);
				}
				return val;
			}
			ManualLogSource modLog2 = Plugin.ModLog;
			if (modLog2 != null)
			{
				modLog2.LogWarning((object)"ZombieManager: No URP shader found.");
			}
			return null;
		}

		private static void ApplyColor(Renderer rend, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)rend == (Object)null)
			{
				return;
			}
			Shader workingShader = GetWorkingShader();
			if ((Object)workingShader != (Object)null)
			{
				Material val = new Material(workingShader);
				if (val.HasProperty("_BaseColor"))
				{
					val.SetColor("_BaseColor", color);
				}
				if (val.HasProperty("_Color"))
				{
					val.SetColor("_Color", color);
				}
				rend.material = val;
			}
			else
			{
				rend.material.color = color;
			}
		}

		private void SpawnZombie()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Expected O, but got Unknown
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Expected O, but got Unknown
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Expected O, but got Unknown
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Expected O, but got Unknown
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_0631: Unknown result type (might be due to invalid IL or missing references)
			//IL_0638: Unknown result type (might be due to invalid IL or missing references)
			//IL_063d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Expected O, but got Unknown
			//IL_06dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e4: Expected O, but got Unknown
			//IL_06f7: Unknown result type (might be due to invalid IL or missing references)
			_zombies.RemoveAll((ZombieInstance z) => z == null || (Object)z.Root == (Object)null);
			bool flag = default(bool);
			if (_zombies.Count >= Plugin.MaxZombies.Value)
			{
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(22, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Zombie cap reached (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Plugin.MaxZombies.Value);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
					}
					modLog.LogWarning(val);
				}
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null || (Object)main == (Object)null)
			{
				ManualLogSource modLog2 = Plugin.ModLog;
				if (modLog2 != null)
				{
					modLog2.LogError((object)"Cannot spawn zombie: Camera.main not found.");
				}
				return;
			}
			float num = Random.Range(0f, 360f);
			float num2 = Random.Range(Plugin.SpawnDistanceMin.Value, Plugin.SpawnDistanceMax.Value);
			Vector3 val2 = Quaternion.Euler(0f, num, 0f) * Vector3.forward;
			Vector3 val3 = ((Component)main).transform.position + val2 * num2;
			if (TryGetGroundY(val3, null, out var groundY))
			{
				val3.y = groundY;
			}
			GameObject val4 = new GameObject("Zombie_NPC");
			val4.transform.position = val3;
			Vector3 val5 = default(Vector3);
			((Vector3)(ref val5))..ctor(0f - val2.x, 0f, 0f - val2.z);
			val4.transform.rotation = ((((Vector3)(ref val5)).sqrMagnitude > 0.0001f) ? Quaternion.LookRotation(val5) : Quaternion.identity);
			Color color = default(Color);
			((Color)(ref color))..ctor(1f, 0.82f, 0.05f, 1f);
			Color color2 = default(Color);
			((Color)(ref color2))..ctor(0.05f, 0.05f, 0.05f, 1f);
			Color black = Color.black;
			GameObject val6 = GameObject.CreatePrimitive((PrimitiveType)0);
			val6.transform.SetParent(val4.transform, false);
			val6.transform.localPosition = new Vector3(0f, 0.4f, 0f);
			val6.transform.localScale = new Vector3(0.85f, 0.75f, 0.85f);
			Object.Destroy((Object)val6.GetComponent<Collider>());
			ApplyColor(val6.GetComponent<Renderer>(), color);
			GameObject val7 = GameObject.CreatePrimitive((PrimitiveType)0);
			val7.transform.SetParent(val4.transform, false);
			val7.transform.localPosition = new Vector3(0f, 1f, 0f);
			val7.transform.localScale = new Vector3(0.65f, 0.65f, 0.65f);
			Object.Destroy((Object)val7.GetComponent<Collider>());
			ApplyColor(val7.GetComponent<Renderer>(), color2);
			GameObject val8 = GameObject.CreatePrimitive((PrimitiveType)0);
			val8.transform.SetParent(val4.transform, false);
			val8.transform.localPosition = new Vector3(0f, 1.55f, 0f);
			val8.transform.localScale = new Vector3(0.55f, 0.55f, 0.55f);
			Object.Destroy((Object)val8.GetComponent<Collider>());
			ApplyColor(val8.GetComponent<Renderer>(), color);
			GameObject val9 = GameObject.CreatePrimitive((PrimitiveType)3);
			val9.transform.SetParent(val8.transform, false);
			val9.transform.localPosition = new Vector3(-0.15f, 0.05f, 0.22f);
			val9.transform.localRotation = Quaternion.Euler(0f, 0f, 45f);
			val9.transform.localScale = new Vector3(0.12f, 0.03f, 0.03f);
			Object.Destroy((Object)val9.GetComponent<Collider>());
			ApplyColor(val9.GetComponent<Renderer>(), black);
			GameObject val10 = GameObject.CreatePrimitive((PrimitiveType)3);
			val10.transform.SetParent(val8.transform, false);
			val10.transform.localPosition = new Vector3(0.15f, 0.05f, 0.22f);
			val10.transform.localRotation = Quaternion.Euler(0f, 0f, -45f);
			val10.transform.localScale = new Vector3(0.12f, 0.03f, 0.03f);
			Object.Destroy((Object)val10.GetComponent<Collider>());
			ApplyColor(val10.GetComponent<Renderer>(), black);
			Vector2 val11 = Random.insideUnitCircle * Random.Range(Plugin.SurroundRadiusMin.Value, Plugin.SurroundRadiusMax.Value);
			string next = PhraseBank.GetNext(Plugin.CurrentSelectionMode);
			TextMesh val12 = null;
			if (Plugin.EnableTypingMode.Value)
			{
				val12 = ZombieLabel.Create(val8.transform, Plugin.LabelHeightOffset.Value, Plugin.LabelFontSize.Value);
				ZombieLabel.SetText(val12, next, 0, isActiveTarget: false);
			}
			AudioSource val13 = null;
			if (Plugin.EnableSfx.Value)
			{
				GameObject val14 = new GameObject("ZombieBuzzSource");
				val14.transform.SetParent(val7.transform, false);
				val13 = ((Il2CppObjectBase)val14.AddComponent(Il2CppType.Of<AudioSource>())).Cast<AudioSource>();
				val13.playOnAwake = false;
				val13.loop = false;
				val13.spatialBlend = 1f;
				val13.minDistance = Plugin.BuzzMinDistance.Value;
				val13.maxDistance = Plugin.BuzzMaxDistance.Value;
				val13.rolloffMode = (AudioRolloffMode)1;
				val13.volume = Plugin.BuzzVolume.Value;
			}
			_zombies.Add(new ZombieInstance
			{
				Root = val4,
				Transform = val4.transform,
				HeadTransform = val8.transform,
				BobOffset = Random.Range(0f, 100f),
				VerticalVelocity = 0f,
				TargetOffset = new Vector3(val11.x, 0f, val11.y),
				SwayFrequency = Random.Range(2f, 4.5f),
				SwayAmplitude = Random.Range(0.5f, 1.3f),
				SwayPhase = Random.Range(0f, 6.28f),
				Phrase = next,
				TypedCount = 0,
				Label = val12,
				IsActiveTarget = false,
				BuzzSource = val13,
				NextBuzzTime = Time.time + Random.Range(0f, Plugin.BuzzIntervalMax.Value)
			});
			ManualLogSource modLog3 = Plugin.ModLog;
			if (modLog3 != null)
			{
				BepInExInfoLogInterpolatedStringHandler val15 = new BepInExInfoLogInterpolatedStringHandler(49, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val15).AppendLiteral("Zombie spawned at ");
					((BepInExLogInterpolatedStringHandler)val15).AppendFormatted<Vector3>(val3);
					((BepInExLogInterpolatedStringHandler)val15).AppendLiteral(" with phrase \"");
					((BepInExLogInterpolatedStringHandler)val15).AppendFormatted<string>(next);
					((BepInExLogInterpolatedStringHandler)val15).AppendLiteral("\". Active count: ");
					((BepInExLogInterpolatedStringHandler)val15).AppendFormatted<int>(_zombies.Count);
				}
				modLog3.LogInfo(val15);
			}
		}

		private void UpdateZombieAI()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0030: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: 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_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null || (Object)main == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)main).transform.position;
			float value = Plugin.ZombieSpeed.Value;
			float deltaTime = Time.deltaTime;
			Vector3 val = default(Vector3);
			for (int i = 0; i < _zombies.Count; i++)
			{
				ZombieInstance zombieInstance = _zombies[i];
				if (zombieInstance == null || (Object)zombieInstance.Root == (Object)null)
				{
					continue;
				}
				Vector3 position2 = zombieInstance.Transform.position;
				float num = Time.time * zombieInstance.SwayFrequency + zombieInstance.SwayPhase;
				((Vector3)(ref val))..ctor(Mathf.Sin(num) * zombieInstance.SwayAmplitude, 0f, Mathf.Cos(num * 0.63f) * zombieInstance.SwayAmplitude * 0.75f);
				Vector3 val2 = position + zombieInstance.TargetOffset + val;
				Vector3 val3 = val2 - position2;
				val3.y = 0f;
				Vector3 val4 = Vector3.zero;
				for (int j = 0; j < _zombies.Count; j++)
				{
					if (i == j)
					{
						continue;
					}
					ZombieInstance zombieInstance2 = _zombies[j];
					if (zombieInstance2 != null && !((Object)zombieInstance2.Root == (Object)null))
					{
						Vector3 val5 = position2 - zombieInstance2.Transform.position;
						val5.y = 0f;
						float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
						if (sqrMagnitude < 0.64f && sqrMagnitude > 0.0001f)
						{
							val4 += ((Vector3)(ref val5)).normalized * ((0.8f - Mathf.Sqrt(sqrMagnitude)) * 2f);
						}
					}
				}
				float magnitude = ((Vector3)(ref val3)).magnitude;
				Vector3 val6 = Vector3.zero;
				if (magnitude > 0.001f)
				{
					float num2 = Mathf.Max(Mathf.Clamp01(magnitude / 1.5f), 0.35f);
					val6 = val3 / magnitude * (value * num2);
				}
				Vector3 val7 = val6 + val4;
				if (((Vector3)(ref val7)).sqrMagnitude > 0.0025f)
				{
					Quaternion val8 = Quaternion.LookRotation(((Vector3)(ref val7)).normalized);
					zombieInstance.Transform.rotation = Quaternion.Slerp(zombieInstance.Transform.rotation, val8, deltaTime * 6f);
				}
				Vector3 val9 = position2 + val7 * deltaTime;
				if (TryGetGroundY(val9, zombieInstance.Transform, out var groundY))
				{
					val9.y = groundY;
					zombieInstance.VerticalVelocity = 0f;
				}
				else
				{
					zombieInstance.VerticalVelocity -= 9.81f * deltaTime;
					val9.y += zombieInstance.VerticalVelocity * deltaTime;
				}
				zombieInstance.Transform.position = val9;
				float num3 = Mathf.Sin(Time.time * 8f + zombieInstance.BobOffset) * 0.05f;
				zombieInstance.HeadTransform.localPosition = new Vector3(0f, 1.55f + num3, 0f);
				if ((Object)zombieInstance.Label != (Object)null)
				{
					ZombieLabel.Billboard(zombieInstance.Label, main);
				}
				UpdateZombieBuzz(zombieInstance);
			}
		}

		private void UpdateZombieBuzz(ZombieInstance zombie)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (Plugin.EnableSfx.Value && !((Object)zombie.BuzzSource == (Object)null) && !(Time.time < zombie.NextBuzzTime))
			{
				AudioClip randomClip = Sfx.GetRandomClip(Plugin.BuzzSoundFolder.Value);
				if ((Object)(object)randomClip != (Object)null)
				{
					zombie.BuzzSource.clip = randomClip;
					zombie.BuzzSource.Play();
				}
				zombie.NextBuzzTime = Time.time + Random.Range(Plugin.BuzzIntervalMin.Value, Plugin.BuzzIntervalMax.Value);
			}
		}

		private void ProcessTypingInput()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (!Plugin.EnableTypingMode.Value)
			{
				return;
			}
			string inputString = Input.inputString;
			if (string.IsNullOrEmpty(inputString))
			{
				return;
			}
			for (int i = 0; i < inputString.Length; i++)
			{
				char c = char.ToLowerInvariant(inputString[i]);
				if (char.IsControl(c) && c != ' ')
				{
					continue;
				}
				if (_currentTarget == null || (Object)_currentTarget.Root == (Object)null)
				{
					ZombieInstance zombieInstance = FindTargetStartingWith(c);
					if (zombieInstance != null)
					{
						if (zombieInstance.TypedCount >= zombieInstance.Phrase.Length)
						{
							KillZombie(zombieInstance);
							_currentTarget = null;
						}
						else
						{
							_currentTarget = zombieInstance;
						}
					}
				}
				else
				{
					TryAdvanceTarget(c);
				}
			}
		}

		private ZombieInstance FindTargetStartingWith(char c)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			Vector3 val = (((Object)(object)main != (Object)null && (Object)main != (Object)null) ? ((Component)main).transform.position : Vector3.zero);
			ZombieInstance zombieInstance = null;
			float num = float.MaxValue;
			foreach (ZombieInstance zombie in _zombies)
			{
				if (zombie != null && !((Object)zombie.Root == (Object)null) && !string.IsNullOrEmpty(zombie.Phrase) && char.ToLowerInvariant(zombie.Phrase[0]) == c)
				{
					Vector3 val2 = zombie.Transform.position - val;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						zombieInstance = zombie;
					}
				}
			}
			if (zombieInstance != null)
			{
				zombieInstance.IsActiveTarget = true;
				zombieInstance.TypedCount = 1;
				RefreshLabel(zombieInstance);
				PlayKeystrokeSound(c);
			}
			return zombieInstance;
		}

		private void TryAdvanceTarget(char c)
		{
			ZombieInstance currentTarget = _currentTarget;
			if (currentTarget.TypedCount >= currentTarget.Phrase.Length)
			{
				KillZombie(currentTarget);
				_currentTarget = null;
				return;
			}
			char c2 = char.ToLowerInvariant(currentTarget.Phrase[currentTarget.TypedCount]);
			if (c == c2)
			{
				PlayKeystrokeSound(c);
				currentTarget.TypedCount++;
				if (currentTarget.TypedCount >= currentTarget.Phrase.Length)
				{
					KillZombie(currentTarget);
					_currentTarget = null;
				}
				else
				{
					RefreshLabel(currentTarget);
				}
			}
		}

		private void RefreshLabel(ZombieInstance z)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			if ((Object)z.Label != (Object)null)
			{
				ZombieLabel.SetText(z.Label, z.Phrase, z.TypedCount, z.IsActiveTarget);
			}
		}

		private void PlayKeystrokeSound(char c)
		{
			if (Plugin.EnableSfx.Value)
			{
				Sfx.PlayRandom((c == ' ') ? Plugin.SpaceSoundFolder.Value : Plugin.KeySoundFolder.Value);
			}
		}

		private void KillZombie(ZombieInstance z)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			_zombies.Remove(z);
			if ((Object)z.Root != (Object)null)
			{
				Object.Destroy((Object)(object)z.Root);
			}
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(20, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Zombie typed out: \"");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(z.Phrase);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\"");
				}
				modLog.LogInfo(val);
			}
			PhraseBank.MarkCompleted();
			if (PhraseBank.CompletedCycles >= Mathf.Max(1, Plugin.CyclesBeforeDawn.Value))
			{
				TriggerVictory();
			}
			else if (_isActivated && Plugin.AutoRespawnOnKill.Value)
			{
				SpawnZombie();
			}
		}

		private void TriggerVictory()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			int count = _zombies.Count;
			foreach (ZombieInstance zombie in _zombies)
			{
				if (zombie != null && (Object)zombie.Root != (Object)null)
				{
					Object.Destroy((Object)(object)zombie.Root);
				}
			}
			_zombies.Clear();
			_currentTarget = null;
			_isActivated = false;
			NightDirector.ReleaseNight();
			PhraseBank.ResetProgress();
			ManualLogSource modLog = Plugin.ModLog;
			if (modLog != null)
			{
				modLog.LogInfo((object)("Horde defeated - full script typed out" + ((count > 0) ? $" (cleared {count} remaining zombie(s))" : "") + $". Press '{Plugin.ActivationKey.Value}' to start a new round."));
			}
		}

		private static bool TryGetGroundY(Vector3 pos, Transform selfTransform, out float groundY)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			groundY = pos.y;
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(pos + Vector3.up * 2.5f, Vector3.down);
			RaycastHit[] array = Il2CppArrayBase<RaycastHit>.op_Implicit((Il2CppArrayBase<RaycastHit>)(object)Physics.RaycastAll(val, 15f));
			if (array != null && array.Length != 0)
			{
				float num = -9999f;
				bool flag = false;
				for (int i = 0; i < array.Length; i++)
				{
					RaycastHit val2 = array[i];
					if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !((RaycastHit)(ref val2)).collider.isTrigger && (!((Object)(object)selfTransform != (Object)null) || !((RaycastHit)(ref val2)).transform.IsChildOf(selfTransform)) && ((RaycastHit)(ref val2)).point.y > num)
					{
						num = ((RaycastHit)(ref val2)).point.y;
						flag = true;
					}
				}
				if (flag)
				{
					groundY = num;
					return true;
				}
			}
			return false;
		}
	}
}