Decompiled source of AIExtended v1.0.0

AIExtended.dll

Decompiled a day 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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Mirror;
using MoveClasses;
using UnityEngine;
using UnityEngine.SceneManagement;
using Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Disemberment")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Disemberment")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("61440d51-602e-416a-b15f-dcc42c72d09e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
public enum SpawnMode
{
	Normal,
	Waves,
	Random
}
public enum WaveStyle
{
	Random,
	Progressive,
	Regressive
}
[BepInPlugin("com.morsecodeguy.aiextended", "AIExtended", "1.0.0")]
public class AIExtended : BaseUnityPlugin
{
	private Rect win = new Rect((float)(Screen.width / 2 - 220), (float)(Screen.height / 2 - 210), 440f, 460f);

	private Vector2 scroll;

	private bool show;

	private bool dropSet;

	private bool dropMode;

	private bool listeningForKey;

	private int setIdx;

	private int modeIdx;

	private int waveStyleIdx;

	private KeyCode menuKey = (KeyCode)279;

	private ConfigEntry<string> keyConfig;

	private readonly List<MoveSet> allSets = new List<MoveSet>();

	private string normalAmtIn = "1";

	private string waveMinIn = "3";

	private string waveMaxIn = "6";

	private string waveCntIn = "5";

	private int normalAmt = 1;

	private int waveMin = 3;

	private int waveMax = 6;

	private int waveTotal = 5;

	private int waveIndex;

	private bool zombieMode;

	private bool allowCustom = true;

	private bool allowBasic = true;

	private bool allowCommunity = true;

	public static AIExtended Instance { get; private set; }

	public static SpawnMode CurrentMode => ((Object)(object)Instance != (Object)null) ? ((SpawnMode)Instance.modeIdx) : SpawnMode.Normal;

	public static bool WavesFinished => (Object)(object)Instance == (Object)null || Instance.waveIndex >= Instance.waveTotal;

	private bool Host => NetworkServer.active || (!NetworkServer.active && !NetworkClient.active);

	private void Awake()
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		keyConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MenuKey", "End", "Key to open the AIExtended menu");
		Enum.TryParse<KeyCode>(keyConfig.Value, out menuKey);
		new Harmony("com.morsecodeguy.aiextended").PatchAll();
		SceneManager.activeSceneChanged += delegate
		{
			waveIndex = 0;
		};
	}

	private void Update()
	{
		//IL_000a: 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_00ee: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
		if (!listeningForKey && Input.GetKeyDown(menuKey) && (!NetworkClient.active || NetworkServer.active))
		{
			show = !show;
			dropSet = (dropMode = false);
			if (show)
			{
				((Rect)(ref win)).x = ((float)Screen.width - ((Rect)(ref win)).width) * 0.5f;
				((Rect)(ref win)).y = ((float)Screen.height - ((Rect)(ref win)).height) * 0.5f;
				LoadMoveSets();
			}
		}
		if (listeningForKey)
		{
			foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
			{
				KeyCode val = value;
				if (Input.GetKeyDown(val))
				{
					menuKey = val;
					keyConfig.Value = ((object)(KeyCode)(ref val)).ToString();
					listeningForKey = false;
					break;
				}
			}
		}
		if (!Host || CurrentMode == SpawnMode.Normal)
		{
			return;
		}
		bool flag = Object.FindObjectsOfType<PlayerHealth>().Any((PlayerHealth p) => p.ai);
		bool flag2 = Object.FindObjectsOfType<PlayerHealth>().Any((PlayerHealth p) => !p.ai && p.alive);
		if (!flag && waveIndex < waveTotal && flag2)
		{
			if (CurrentMode == SpawnMode.Waves)
			{
				SpawnWaves(allSets[setIdx]);
			}
			else
			{
				SpawnRandom();
			}
		}
	}

	private void OnGUI()
	{
		//IL_000f: 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_002a: Expected O, but got Unknown
		//IL_0025: 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)
		if (show)
		{
			win = GUI.Window(99, win, new WindowFunction(DrawWindow), "AIExtended");
		}
	}

	private void DrawWindow(int id)
	{
		//IL_0034: 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_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0498: Unknown result type (might be due to invalid IL or missing references)
		//IL_0607: Unknown result type (might be due to invalid IL or missing references)
		//IL_0645: Unknown result type (might be due to invalid IL or missing references)
		LoadMoveSets();
		GUILayout.BeginArea(new Rect(12f, 30f, ((Rect)(ref win)).width - 24f, ((Rect)(ref win)).height - 42f));
		scroll = GUILayout.BeginScrollView(scroll, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (CurrentMode == SpawnMode.Random)
		{
			GUILayout.Box("Random sets", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) });
		}
		else
		{
			string text = ((allSets.Count > 0 && setIdx < allSets.Count) ? allSets[setIdx].name : "Select moveset");
			if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				dropSet = !dropSet;
				dropMode = false;
			}
		}
		GUILayout.Space(8f);
		string[] array = new string[3] { "Normal", "Waves", "Random" };
		if (GUILayout.Button(array[modeIdx], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
		{
			dropMode = !dropMode;
			dropSet = false;
		}
		GUILayout.EndHorizontal();
		if (dropSet && CurrentMode != SpawnMode.Random)
		{
			for (int i = 0; i < allSets.Count; i++)
			{
				if (GUILayout.Button(allSets[i].name, Array.Empty<GUILayoutOption>()))
				{
					setIdx = i;
					dropSet = false;
				}
			}
		}
		if (dropMode)
		{
			for (int j = 0; j < array.Length; j++)
			{
				if (GUILayout.Button(array[j], Array.Empty<GUILayoutOption>()))
				{
					modeIdx = j;
					dropMode = false;
				}
			}
		}
		zombieMode = GUILayout.Toggle(zombieMode, "Zombie Mode (head-shots only)", Array.Empty<GUILayoutOption>());
		if (CurrentMode == SpawnMode.Normal)
		{
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("AI Amount", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			normalAmtIn = GUILayout.TextField(normalAmtIn, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			GUILayout.EndHorizontal();
		}
		else
		{
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Min", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			waveMinIn = GUILayout.TextField(waveMinIn, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.Space(8f);
			GUILayout.Label("Max", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			waveMaxIn = GUILayout.TextField(waveMaxIn, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Waves", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			waveCntIn = GUILayout.TextField(waveCntIn, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			string[] array2 = new string[3] { "Random", "Progressive", "Regressive" };
			if (GUILayout.Button(array2[waveStyleIdx], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
			{
				waveStyleIdx = (waveStyleIdx + 1) % array2.Length;
			}
			GUILayout.Space(6f);
			allowCustom = GUILayout.Toggle(allowCustom, "Include Custom movesets", Array.Empty<GUILayoutOption>());
			allowBasic = GUILayout.Toggle(allowBasic, "Include Basic movesets", Array.Empty<GUILayoutOption>());
			allowCommunity = GUILayout.Toggle(allowCommunity, "Include Community movesets", Array.Empty<GUILayoutOption>());
		}
		GUILayout.Space(10f);
		GUILayout.Label("General Settings:", Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label($"Menu Key: {menuKey}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) });
		if (GUILayout.Button("Change Key", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
		{
			listeningForKey = true;
			show = true;
		}
		GUILayout.EndHorizontal();
		if (listeningForKey)
		{
			GUILayout.Label("Press any key to bind...", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
		}
		GUILayout.Space(10f);
		if (GUILayout.Button("Spawn", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
		{
			if (allSets.Count == 0)
			{
				LoadMoveSets();
			}
			if (allSets.Count == 0)
			{
				return;
			}
			ParseInputs();
			waveIndex = 0;
			MoveSet ms = allSets[Mathf.Clamp(setIdx, 0, allSets.Count - 1)];
			if (CurrentMode == SpawnMode.Normal)
			{
				SpawnNormal(ms, normalAmt);
			}
			else if (CurrentMode == SpawnMode.Waves)
			{
				SpawnWaves(ms);
			}
			else
			{
				SpawnRandom();
			}
		}
		GUILayout.EndScrollView();
		GUILayout.Label($"Press {menuKey} to toggle", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(false) });
		GUILayout.EndArea();
		GUI.DragWindow(new Rect(0f, 0f, 9999f, 24f));
	}

	private void ParseInputs()
	{
		int.TryParse(normalAmtIn, out normalAmt);
		if (normalAmt < 1)
		{
			normalAmt = 1;
		}
		int.TryParse(waveMinIn, out waveMin);
		if (waveMin < 1)
		{
			waveMin = 1;
		}
		int.TryParse(waveMaxIn, out waveMax);
		if (waveMax < waveMin)
		{
			waveMax = waveMin;
		}
		int.TryParse(waveCntIn, out waveTotal);
		if (waveTotal < 1)
		{
			waveTotal = 1;
		}
	}

	private void LoadMoveSets()
	{
		try
		{
			MoveSetHelpers.LoadMoveSetsJson(false);
			FieldInfo fieldInfo = typeof(MoveSetHelpers).GetField("loadedMoveSetList", BindingFlags.Static | BindingFlags.NonPublic) ?? typeof(MoveSetHelpers).GetField("loadedMoveSets", BindingFlags.Static | BindingFlags.NonPublic) ?? typeof(MoveSetHelpers).GetField("moveSetList", BindingFlags.Static | BindingFlags.NonPublic);
			allSets.Clear();
			if (fieldInfo == null || !(fieldInfo.GetValue(null) is List<MoveSet> list))
			{
				return;
			}
			foreach (MoveSet item in list)
			{
				if (item == null)
				{
					continue;
				}
				MoveSet val = (item.loaded ? item : null);
				if (val == null)
				{
					try
					{
						val = MoveSetHelpers.GetFullMoveSet(item, false);
					}
					catch
					{
						continue;
					}
				}
				if (val != null && !string.IsNullOrEmpty(val.name))
				{
					bool flag = val.name.ToLower().Contains("basic");
					bool communityMoveset = val.communityMoveset;
					bool flag2 = !flag && !communityMoveset;
					if (!(!allowBasic && flag) && !(!allowCommunity && communityMoveset) && !(!allowCustom && flag2))
					{
						allSets.Add(val);
					}
				}
			}
			if (setIdx >= allSets.Count)
			{
				setIdx = 0;
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AIExtended] move-set load failed: " + ex));
			allSets.Clear();
		}
	}

	private void SpawnNormal(MoveSet ms, int amt)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		switch (((Scene)(ref activeScene)).name)
		{
		case "map_ArenaOfBlades":
			SpawnScatter(ms, amt, 5f, 5f);
			break;
		case "map_CrackedBladeAzula":
			SpawnScatter(ms, amt, 2.5f, 5f);
			break;
		case "map_TheSpecialistsDojo":
			SpawnScatter(ms, amt, 2.5f, 1f, new Vector3(-5f, 0f, 0f));
			break;
		default:
			SpawnFromPoints(ms, amt);
			break;
		}
	}

	private void SpawnWaves(MoveSet ms)
	{
		InternalWaveSpawn(ms, NextWaveCount());
	}

	private void SpawnRandom()
	{
		InternalWaveSpawn(null, NextWaveCount());
	}

	private int NextWaveCount()
	{
		int result = (WaveStyle)waveStyleIdx switch
		{
			WaveStyle.Random => Random.Range(waveMin, waveMax + 1), 
			WaveStyle.Progressive => Mathf.Clamp(waveMin + waveIndex, waveMin, waveMax), 
			_ => Mathf.Clamp(waveMax - waveIndex, waveMin, waveMax), 
		};
		waveIndex++;
		return result;
	}

	private void InternalWaveSpawn(MoveSet fixedSet, int count)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: 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_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: 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_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		bool flag = ((Scene)(ref activeScene)).name == "map_TheSpecialistsDojo";
		Vector3 val = (flag ? Vector3.zero : ((from p in Object.FindObjectsOfType<PlayerHealth>()
			where !p.ai
			select ((Component)p).transform.position).Aggregate(Vector3.zero, (Vector3 sum, Vector3 pos) => sum + pos) / (float)Math.Max(1, Object.FindObjectsOfType<PlayerHealth>().Count((PlayerHealth p) => !p.ai))));
		float num = (flag ? 5f : 10f);
		float num2 = (flag ? 1f : 2f);
		for (int i = 0; i < count; i++)
		{
			float num3 = (float)i * (float)Math.PI * 2f / (float)count;
			Vector3 val2 = val + new Vector3(Mathf.Cos(num3), 0f, Mathf.Sin(num3)) * num;
			Vector3 pos2 = val2 + Vector3.up * num2;
			if (flag || Physics.OverlapBox(val2, Vector3.one).Length == 0)
			{
				MoveSet ms = fixedSet ?? allSets[Random.Range(0, allSets.Count)];
				SpawnAI(pos2, ms);
			}
		}
	}

	private void SpawnScatter(MoveSet ms, int amt, float radius, float yOff, Vector3 extra = default(Vector3))
	{
		//IL_0006: 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_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < amt; i++)
		{
			Vector2 val = Random.insideUnitCircle * radius;
			SpawnAI(new Vector3(val.x, yOff, val.y) + extra, ms);
		}
	}

	private void SpawnFromPoints(MoveSet ms, int amt)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: 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)
		GameObject val = GameObject.Find("SpawnPoints");
		if (!Object.op_Implicit((Object)(object)val))
		{
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name == "MoveEditorTestMoveset")
			{
				for (int i = 0; i < amt; i++)
				{
					SpawnAI(Random.insideUnitSphere * 5f, ms);
				}
				return;
			}
		}
		if (!Object.op_Implicit((Object)(object)val))
		{
			return;
		}
		foreach (Transform item in (from Transform t in (IEnumerable)val.transform
			where Physics.OverlapBox(t.position, Vector3.one * 0.5f).Length == 0
			select t).Take(amt))
		{
			SpawnAI(item.position, ms);
		}
	}

	private void SpawnAI(Vector3 pos, MoveSet ms)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		if (NetworkClient.active && !NetworkServer.active)
		{
			return;
		}
		GameObject val = ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => ((Object)p).name == "PlayerCharacterMultiplayer"));
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		GameObject val2 = Object.Instantiate<GameObject>(val, pos, Quaternion.identity);
		PlayerHealth component = val2.GetComponent<PlayerHealth>();
		component.playerAnimator.SetMoveSet(ms, false, true);
		if (ms.defaultEquipment != null)
		{
			List<EquippedEquipment> list = ms.defaultEquipment.Where((EquippedEquipment e) => e != null).Select((Func<EquippedEquipment, EquippedEquipment>)((EquippedEquipment e) => new EquippedEquipment
			{
				position = e.position,
				equipment = e.equipment,
				equipmentStartHoldType = e.equipmentStartHoldType,
				equipmentStartHoldPosition = e.equipmentStartHoldPosition
			})).ToList();
			if (list.Count > 0)
			{
				component.SetEquipment(list, true);
			}
		}
		val2.AddComponent<PlayerInputAIManager>().ConnectToPlayerCharacter(val2);
		component.ai = true;
		component.playerName = "AI";
		if (zombieMode)
		{
			WeaponDamageablePart[] componentsInChildren = val2.GetComponentsInChildren<WeaponDamageablePart>(true);
			foreach (WeaponDamageablePart val3 in componentsInChildren)
			{
				if (val3.lethal && ((Object)((Component)val3).gameObject).name != "Lethal_Brain")
				{
					val3.lethal = false;
				}
			}
			val2.AddComponent<ZombieImmortality>();
		}
		val2.AddComponent<AIDeathCleanup>();
		if (NetworkServer.active)
		{
			NetworkServer.Spawn(val2, (NetworkConnection)null);
		}
	}

	public static void CleanAllAI()
	{
		foreach (GameObject item in from p in Object.FindObjectsOfType<PlayerHealth>()
			where p.ai
			select ((Component)p).gameObject)
		{
			Object.Destroy((Object)(object)item);
		}
	}
}
[HarmonyPatch]
internal class GameOverGuard
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		yield return AccessTools.Method(typeof(GameMaster), "GameOver", (Type[])null, (Type[])null);
		Type mp = AccessTools.TypeByName("MultiplayerGameMaster");
		if (mp != null)
		{
			MethodInfo mi = AccessTools.Method(mp, "GameOver", (Type[])null, (Type[])null);
			if (mi != null)
			{
				yield return mi;
			}
		}
	}

	private static bool Prefix()
	{
		if (AIExtended.CurrentMode == SpawnMode.Normal)
		{
			return true;
		}
		if (AIExtended.WavesFinished)
		{
			return true;
		}
		bool flag = Object.FindObjectsOfType<PlayerHealth>().Any((PlayerHealth p) => !p.ai && p.alive);
		return !flag;
	}
}
[HarmonyPatch]
internal class GameOverCleanup
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		yield return AccessTools.Method(typeof(GameMaster), "GameOver", (Type[])null, (Type[])null);
		Type mp = AccessTools.TypeByName("MultiplayerGameMaster");
		if (mp != null)
		{
			MethodInfo mi = AccessTools.Method(mp, "GameOver", (Type[])null, (Type[])null);
			if (mi != null)
			{
				yield return mi;
			}
		}
	}

	private static void Postfix()
	{
		((MonoBehaviour)AIExtended.Instance).StartCoroutine(DelayedClean());
	}

	private static IEnumerator DelayedClean()
	{
		yield return null;
		AIExtended.CleanAllAI();
	}
}
[HarmonyPatch(typeof(PlayerHealth), "Die")]
internal class DiePatch
{
	private static bool Prefix(PlayerHealth __instance)
	{
		if ((Object)(object)__instance != (Object)null && __instance.ai && (Object)(object)((Component)__instance).GetComponent<ZombieImmortality>() != (Object)null)
		{
			WeaponDamageablePart val = ((IEnumerable<WeaponDamageablePart>)((Component)__instance).GetComponentsInChildren<WeaponDamageablePart>(true)).FirstOrDefault((Func<WeaponDamageablePart, bool>)((WeaponDamageablePart p) => ((Object)((Component)p).gameObject).name == "Lethal_Brain"));
			if ((Object)(object)val != (Object)null && !val.destroyed)
			{
				return false;
			}
		}
		return true;
	}
}
public class ZombieImmortality : MonoBehaviour
{
	private PlayerHealth ph;

	private WeaponDamageablePart brain;

	private void Start()
	{
		ph = ((Component)this).GetComponent<PlayerHealth>();
		brain = ((IEnumerable<WeaponDamageablePart>)((Component)this).GetComponentsInChildren<WeaponDamageablePart>(true)).FirstOrDefault((Func<WeaponDamageablePart, bool>)((WeaponDamageablePart x) => ((Object)((Component)x).gameObject).name == "Lethal_Brain"));
	}

	private void Update()
	{
		if (!((Object)(object)ph == (Object)null))
		{
			ph.bloodAmount = 2.0;
			if ((Object)(object)brain != (Object)null && !brain.destroyed)
			{
				ph.alive = true;
			}
		}
	}
}
public class AIDeathCleanup : MonoBehaviour
{
	private PlayerHealth ph;

	private bool flagged;

	private void Start()
	{
		ph = ((Component)this).GetComponent<PlayerHealth>();
	}

	private void Update()
	{
		if (!flagged && (Object)(object)ph != (Object)null && !ph.alive)
		{
			flagged = true;
			((MonoBehaviour)this).StartCoroutine(DelayDestroy());
		}
	}

	private IEnumerator DelayDestroy()
	{
		yield return (object)new WaitForSeconds(5f);
		Object.Destroy((Object)(object)((Component)this).gameObject);
	}
}