Decompiled source of PEAK Zombies v1.0.0

tony4twentys-PEAK Zombies.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
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: AssemblyTitle("Zombies Anywhere")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Zombies Anywhere")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("887df093-284b-4d21-b615-1096ecf89525")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Zombies_Anywhere;

[BepInPlugin("tony4twenty.PEAK_Zombies", "PEAK Zombies", "1.0.0")]
public class ZombiesAnywhereMod : BaseUnityPlugin
{
	[HarmonyPatch(typeof(MushroomZombieSpawner), "Start")]
	private static class MushroomZombieSpawnerStartPatch
	{
		private static bool Prefix(MushroomZombieSpawner __instance)
		{
			ZombiesAnywhereMod instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			if (instance.disableZombies.Value)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).gameObject != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)__instance).gameObject);
				}
				ManualLogSource logger = ZombiesAnywhereMod.logger;
				if (logger != null)
				{
					logger.LogInfo((object)"Destroyed zombie spawner because zombies are globally disabled.");
				}
				return false;
			}
			if (Ascents.currentAscent == -1 && instance.allowTenderfootZombies.Value)
			{
				if (__instance.cullRandomly && Random.Range(0f, 1f) > 0.333f)
				{
					ManualLogSource logger2 = ZombiesAnywhereMod.logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)"Tenderfoot zombie spawner culled by random chance.");
					}
					Object.Destroy((Object)(object)((Component)__instance).gameObject);
					return false;
				}
				if (!ZombieManager.Instance.spawners.Contains(__instance))
				{
					ZombieManager.Instance.spawners.Add(__instance);
				}
				ManualLogSource logger3 = ZombiesAnywhereMod.logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)"Registered Tenderfoot zombie spawner (AllowTenderfootZombies=true).");
				}
				return false;
			}
			if (Ascents.currentAscent == -1 && !instance.allowTenderfootZombies.Value)
			{
				ManualLogSource logger4 = ZombiesAnywhereMod.logger;
				if (logger4 != null)
				{
					logger4.LogInfo((object)"Tenderfoot zombie spawner destroyed (AllowTenderfootZombies=false).");
				}
			}
			return true;
		}
	}

	[CompilerGenerated]
	private sealed class <AutoSpawnCoroutine>d__59 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float intervalSeconds;

		public float spawnRadius;

		public ZombiesAnywhereMod <>4__this;

		private Vector3 <spawnCenter>5__1;

		private int <spawnCount>5__2;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				break;
			case 1:
				<>1__state = -1;
				if (<>4__this.disableZombies.Value)
				{
					break;
				}
				if (!PhotonNetwork.IsMasterClient)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				<spawnCenter>5__1 = (((Object)(object)_instance != (Object)null) ? _instance.GetSpawnCenter() : Vector3.zero);
				if (<spawnCenter>5__1 != Vector3.zero)
				{
					<spawnCount>5__2 = ((!((Object)(object)_instance != (Object)null)) ? 1 : _instance.zombiesPerSpawn.Value);
					SpawnZombiesAround(<spawnCenter>5__1, spawnRadius, <spawnCount>5__2);
					if (logger != null)
					{
						logger.LogInfo((object)$"Auto-spawned {<spawnCount>5__2} zombie(s). Total active zombies: {(((Object)(object)ZombieManager.Instance != (Object)null) ? ZombieManager.Instance.zombies.Count : 0)}");
					}
				}
				else
				{
					logger.LogWarning((object)"No valid spawn center found, skipping auto-spawn");
				}
				break;
			case 2:
				<>1__state = -1;
				break;
			}
			<>2__current = (object)new WaitForSeconds(intervalSeconds);
			<>1__state = 1;
			return true;
		}

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

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

	[CompilerGenerated]
	private sealed class <DelayedInitialization>d__48 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public ZombiesAnywhereMod <>4__this;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(<>4__this.initialSpawnDelay.Value);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if (<>4__this.disableZombies.Value)
				{
					return false;
				}
				goto IL_009a;
			case 2:
				<>1__state = -1;
				goto IL_009a;
			case 3:
				{
					<>1__state = -1;
					break;
				}
				IL_009a:
				if (!PhotonNetwork.IsConnected)
				{
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 2;
					return true;
				}
				break;
			}
			if (!PhotonNetwork.InRoom)
			{
				<>2__current = (object)new WaitForSeconds(1f);
				<>1__state = 3;
				return true;
			}
			if (<>4__this.disableZombies.Value)
			{
				return false;
			}
			logger.LogInfo((object)"Game ready! Starting zombie spawning...");
			if (PhotonNetwork.IsMasterClient)
			{
				<>4__this.SpawnInitialZombies();
			}
			if (<>4__this.autoSpawnInterval.Value > 0f)
			{
				StartAutoSpawning(<>4__this.autoSpawnInterval.Value, <>4__this.autoSpawnRadius.Value);
			}
			return false;
		}

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

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

	private static ManualLogSource logger;

	private static ZombiesAnywhereMod _instance;

	private ConfigEntry<bool> autoSpawnEnabled;

	private ConfigEntry<float> autoSpawnInterval;

	private ConfigEntry<float> autoSpawnRadius;

	private ConfigEntry<int> initialSpawnCount;

	private ConfigEntry<int> zombiesPerSpawn;

	private ConfigEntry<float> initialSpawnDelay;

	private ConfigEntry<bool> bypassMaxZombieLimit;

	private ConfigEntry<int> customMaxZombies;

	private ConfigEntry<bool> removeZombieLifetime;

	private ConfigEntry<float> zombieLifetimeOverride;

	private ConfigEntry<bool> hideMushroomVisuals;

	private ConfigEntry<bool> enableMushroomGrowth;

	private ConfigEntry<bool> disableZombies;

	private ConfigEntry<bool> allowTenderfootZombies;

	private ConfigEntry<float> reachForce;

	private ConfigEntry<float> distanceBeforeWakeup;

	private ConfigEntry<float> lookAngleBeforeWakeup;

	private ConfigEntry<float> initialWakeUpTime;

	private ConfigEntry<float> distanceBeforeChase;

	private ConfigEntry<float> zombieSprintDistance;

	private ConfigEntry<float> chaseTimeBeforeSprint;

	private ConfigEntry<float> zombieLungeDistance;

	private ConfigEntry<float> lungeTime;

	private ConfigEntry<float> lungeRecoveryTime;

	private ConfigEntry<float> biteStunTime;

	private ConfigEntry<float> biteInitialInjury;

	private ConfigEntry<float> biteInitialSpores;

	private ConfigEntry<float> biteDelayBeforeSpores;

	private ConfigEntry<float> biteSporesPerSecond;

	private ConfigEntry<float> totalBiteSporesTime;

	private ConfigEntry<float> distanceToEnable;

	private ConfigEntry<float> zombieGruntWaitMin;

	private ConfigEntry<float> zombieGruntWaitMax;

	private ConfigEntry<float> mushroomGrowTimeMin;

	private ConfigEntry<float> mushroomGrowTimeMax;

	private ConfigEntry<float> attackHeightDelta;

	private static readonly FieldInfo MushroomsGrowingField = typeof(MushroomZombie).GetField("mushroomsGrowing", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly FieldInfo MushroomGrowTimesField = typeof(MushroomZombie).GetField("mushroomGrowTimes", BindingFlags.Instance | BindingFlags.NonPublic);

	private Harmony harmony;

	private Coroutine autoSpawnCoroutine;

	internal static ZombiesAnywhereMod Instance => _instance;

	private void Awake()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		_instance = this;
		logger = ((BaseUnityPlugin)this).Logger;
		LoadConfiguration();
		harmony = new Harmony("tony4twenty.ZombiesAnywhere.Patches");
		harmony.PatchAll(typeof(ZombiesAnywhereMod).Assembly);
		SceneManager.sceneLoaded += OnSceneLoaded;
		logger.LogInfo((object)"PEAK Zombies mod loaded!");
		logger.LogInfo((object)("Global zombies: " + (disableZombies.Value ? "DISABLED" : "ENABLED")));
		logger.LogInfo((object)("Tenderfoot zombies: " + (allowTenderfootZombies.Value ? "ALLOWED" : "BLOCKED")));
		ZombieManager instance = ZombieManager.Instance;
		if ((Object)(object)instance != (Object)null)
		{
			logger.LogInfo((object)$"Game's max active zombies: {instance.maxActiveZombies}");
			if (bypassMaxZombieLimit.Value)
			{
				logger.LogInfo((object)"Max zombie limit bypass: ENABLED (unlimited zombies)");
			}
			else if (customMaxZombies.Value > 0)
			{
				logger.LogInfo((object)$"Custom max zombies: {customMaxZombies.Value}");
			}
		}
		if (removeZombieLifetime.Value)
		{
			logger.LogInfo((object)"Zombie lifetime: REMOVED (zombies live forever)");
		}
		else if (zombieLifetimeOverride.Value > 0f)
		{
			logger.LogInfo((object)$"Zombie lifetime: {zombieLifetimeOverride.Value} seconds");
		}
		else
		{
			logger.LogInfo((object)"Zombie lifetime: Using game default (120 seconds)");
		}
		logger.LogInfo((object)$"Auto-spawn settings: {zombiesPerSpawn.Value} zombie(s) every {autoSpawnInterval.Value} seconds");
		logger.LogInfo((object)("Mushroom visuals: " + (hideMushroomVisuals.Value ? "HIDDEN" : "VISIBLE")));
		logger.LogInfo((object)("Mushroom growth: " + (enableMushroomGrowth.Value ? "ENABLED" : "DISABLED (instant full size)")));
	}

	private void LoadConfiguration()
	{
		disableZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableZombies", false, "Master toggle. Set true to prevent any zombies from spawning or registering");
		allowTenderfootZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowTenderfootZombies", true, "If true, prevents Tenderfoot ascent from destroying zombie spawners");
		autoSpawnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoSpawnEnabled", true, "Enable automatic zombie spawning");
		autoSpawnInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "AutoSpawnInterval", 10f, "How often to spawn zombies (in seconds)");
		autoSpawnRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "AutoSpawnRadius", 50f, "Radius around players to spawn zombies within");
		initialSpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "InitialSpawnCount", 3, "Number of zombies to spawn when game starts");
		zombiesPerSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ZombiesPerSpawn", 2, "Number of zombies to spawn each auto-spawn cycle");
		initialSpawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InitialSpawnDelay", 15f, "Delay in seconds before first spawn after scene load");
		bypassMaxZombieLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Limits", "BypassMaxZombieLimit", true, "If true, ignore the game's maxActiveZombies limit (unlimited zombies)");
		customMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Limits", "CustomMaxZombies", -1, "Custom max zombie limit. Set to -1 to use game default, or > 0 to set your own limit");
		removeZombieLifetime = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "RemoveZombieLifetime", true, "If true, zombies won't die from old age (they'll live forever)");
		zombieLifetimeOverride = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Behavior", "ZombieLifetimeOverride", -1f, "Override zombie lifetime in seconds. Set to -1 to use game default, or > 0 to set custom lifetime");
		hideMushroomVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "HideMushroomVisuals", false, "If true, hides the mushroom visuals on zombies");
		enableMushroomGrowth = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "EnableMushroomGrowth", true, "If false, mushrooms start fully grown and do not animate");
		reachForce = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ReachForce", -1f, "Override reach force when lunging/reaching (set to -1 to keep prefab value)");
		distanceBeforeWakeup = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "DistanceBeforeWakeup", 30f, "Distance at which a sleeping zombie wakes up");
		lookAngleBeforeWakeup = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "LookAngleBeforeWakeup", 30f, "Look angle threshold required to wake a sleeping zombie");
		initialWakeUpTime = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "InitialWakeUpTime", 5f, "Time a zombie spends waking up before becoming active");
		distanceBeforeChase = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "DistanceBeforeChase", 30f, "Distance at which a zombie starts chasing its target");
		zombieSprintDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ZombieSprintDistance", 20f, "Distance within which zombies start sprinting");
		chaseTimeBeforeSprint = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ChaseTimeBeforeSprint", 3f, "Time spent chasing before zombies start sprinting");
		zombieLungeDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ZombieLungeDistance", 10f, "Distance within which zombies lunge");
		lungeTime = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "LungeTime", 1.5f, "Duration of the lunge attack");
		lungeRecoveryTime = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "LungeRecoveryTime", 5f, "Recovery time after a lunge");
		biteStunTime = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "BiteStunTime", 3f, "Time a target is stunned after being bitten");
		biteInitialInjury = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "BiteInitialInjury", -1f, "Override initial injury applied when bitten (set to -1 to keep prefab value)");
		biteInitialSpores = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "BiteInitialSpores", -1f, "Override initial spores applied when bitten (set to -1 to keep prefab value)");
		biteDelayBeforeSpores = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "BiteDelayBeforeSpores", -1f, "Override delay before spores begin applying after a bite (set to -1 to keep prefab value)");
		biteSporesPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "BiteSporesPerSecond", -1f, "Override spores applied per second after a bite (set to -1 to keep prefab value)");
		totalBiteSporesTime = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "TotalBiteSporesTime", -1f, "Override total duration spores are applied after a bite (set to -1 to keep prefab value)");
		distanceToEnable = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "DistanceToEnable", -1f, "Override enable distance for NPC zombies (set to -1 to keep prefab value)");
		zombieGruntWaitMin = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ZombieGruntWaitMin", 10f, "Minimum seconds between zombie grunts");
		zombieGruntWaitMax = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "ZombieGruntWaitMax", 20f, "Maximum seconds between zombie grunts");
		mushroomGrowTimeMin = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "MushroomGrowTimeMin", -1f, "Override minimum mushroom grow time (set to -1 to keep prefab value)");
		mushroomGrowTimeMax = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "MushroomGrowTimeMax", -1f, "Override maximum mushroom grow time (set to -1 to keep prefab value)");
		attackHeightDelta = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", "AttackHeightDelta", 100f, "Vertical offset used when aiming attacks");
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		StopAutoSpawning();
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name));
		if (disableZombies.Value)
		{
			logger.LogInfo((object)"Global zombies disabled – skipping auto spawn setup.");
		}
		else if (autoSpawnEnabled.Value)
		{
			((MonoBehaviour)this).StartCoroutine(DelayedInitialization());
		}
	}

	[IteratorStateMachine(typeof(<DelayedInitialization>d__48))]
	private IEnumerator DelayedInitialization()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DelayedInitialization>d__48(0)
		{
			<>4__this = this
		};
	}

	private void SpawnInitialZombies()
	{
		//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_001a: 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_004f: Unknown result type (might be due to invalid IL or missing references)
		if (!disableZombies.Value)
		{
			Vector3 spawnCenter = GetSpawnCenter();
			if (spawnCenter != Vector3.zero)
			{
				logger.LogInfo((object)$"Spawning {initialSpawnCount.Value} initial zombies...");
				SpawnZombiesAround(spawnCenter, autoSpawnRadius.Value, initialSpawnCount.Value);
			}
		}
	}

	private Vector3 GetSpawnCenter()
	{
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		if (Character.AllCharacters != null && Character.AllCharacters.Count > 0)
		{
			Vector3 val = Vector3.zero;
			int num = 0;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if ((Object)(object)allCharacter != (Object)null)
				{
					val += allCharacter.Center;
					num++;
				}
			}
			if (num > 0)
			{
				return val / (float)num;
			}
		}
		return Vector3.zero;
	}

	public static MushroomZombie SpawnZombieAt(Vector3 position, Quaternion rotation = default(Quaternion), MushroomZombie zombiePrefab = null)
	{
		//IL_01c7: 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)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0499: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_instance != (Object)null && _instance.disableZombies.Value)
		{
			if (logger != null)
			{
				logger.LogWarning((object)"Attempted to spawn zombie while global zombies are disabled.");
			}
			return null;
		}
		if (!PhotonNetwork.IsMasterClient)
		{
			if (logger != null)
			{
				logger.LogWarning((object)"Only master client can spawn zombies!");
			}
			return null;
		}
		if ((Object)(object)zombiePrefab == (Object)null)
		{
			zombiePrefab = GetZombiePrefab();
			if ((Object)(object)zombiePrefab == (Object)null)
			{
				if (logger != null)
				{
					logger.LogError((object)"Could not find MushroomZombie prefab! Make sure spawners exist in the scene.");
				}
				return null;
			}
		}
		ZombieManager instance = ZombieManager.Instance;
		if ((Object)(object)_instance != (Object)null && !_instance.bypassMaxZombieLimit.Value && (Object)(object)instance != (Object)null)
		{
			int num = ((_instance.customMaxZombies.Value > 0) ? _instance.customMaxZombies.Value : instance.maxActiveZombies);
			if (instance.zombies.Count >= num)
			{
				if (logger != null)
				{
					logger.LogWarning((object)$"Max active zombies reached ({num}). Cannot spawn more. (Current: {instance.zombies.Count})");
				}
				return null;
			}
		}
		if (logger != null)
		{
			logger.LogInfo((object)$"Spawning zombie at position: {position}");
		}
		GameObject val = PhotonNetwork.Instantiate(((Object)((Component)zombiePrefab).gameObject).name, position, (rotation == default(Quaternion)) ? Quaternion.identity : rotation, (byte)0, (object[])null);
		if ((Object)(object)val == (Object)null)
		{
			if (logger != null)
			{
				logger.LogError((object)"Failed to instantiate zombie!");
			}
			return null;
		}
		MushroomZombie component = val.GetComponent<MushroomZombie>();
		if ((Object)(object)component == (Object)null)
		{
			if (logger != null)
			{
				logger.LogError((object)"Spawned object doesn't have MushroomZombie component!");
			}
			PhotonNetwork.Destroy(val);
			return null;
		}
		if (component.isNPCZombie && (Object)(object)instance != (Object)null)
		{
			instance.RegisterZombie(component);
		}
		if ((Object)(object)_instance != (Object)null && _instance.removeZombieLifetime.Value)
		{
			component.lifetime = 3.1536E+09f;
			if (logger != null)
			{
				logger.LogInfo((object)"Removed lifetime for zombie (set to infinite)");
			}
		}
		else if ((Object)(object)_instance != (Object)null && _instance.zombieLifetimeOverride.Value > 0f)
		{
			component.lifetime = _instance.zombieLifetimeOverride.Value;
			if (logger != null)
			{
				logger.LogInfo((object)$"Set zombie lifetime to {_instance.zombieLifetimeOverride.Value} seconds");
			}
		}
		if ((Object)(object)_instance != (Object)null && _instance.hideMushroomVisuals.Value)
		{
			if (component.mushroomVisuals != null && component.mushroomVisuals.Count > 0)
			{
				foreach (GameObject mushroomVisual in component.mushroomVisuals)
				{
					if ((Object)(object)mushroomVisual != (Object)null)
					{
						mushroomVisual.SetActive(false);
					}
				}
				if (logger != null)
				{
					logger.LogInfo((object)$"Hid {component.mushroomVisuals.Count} mushroom visual(s) on zombie");
				}
			}
		}
		else if ((Object)(object)_instance != (Object)null && !_instance.enableMushroomGrowth.Value && component.mushroomVisuals != null)
		{
			foreach (GameObject mushroomVisual2 in component.mushroomVisuals)
			{
				if ((Object)(object)mushroomVisual2 != (Object)null)
				{
					mushroomVisual2.SetActive(true);
					mushroomVisual2.transform.localScale = Vector3.one;
				}
			}
			if (MushroomsGrowingField != null)
			{
				MushroomsGrowingField.SetValue(component, false);
			}
			if (MushroomGrowTimesField != null && MushroomGrowTimesField.GetValue(component) is List<float> list)
			{
				for (int i = 0; i < list.Count; i++)
				{
					list[i] = 0f;
				}
			}
			if (logger != null)
			{
				logger.LogInfo((object)"Disabled mushroom growth (instant full size)");
			}
		}
		if ((Object)(object)_instance != (Object)null)
		{
			_instance.ApplyZombieTuning(component);
		}
		return component;
	}

	private void ApplyZombieTuning(MushroomZombie zombie)
	{
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)zombie == (Object)null))
		{
			if (reachForce.Value >= 0f)
			{
				zombie.reachForce = reachForce.Value;
			}
			zombie.distanceBeforeWakeup = distanceBeforeWakeup.Value;
			zombie.lookAngleBeforeWakeup = lookAngleBeforeWakeup.Value;
			zombie.initialWakeUpTime = initialWakeUpTime.Value;
			zombie.distanceBeforeChase = distanceBeforeChase.Value;
			zombie.zombieSprintDistance = zombieSprintDistance.Value;
			zombie.chaseTimeBeforeSprint = chaseTimeBeforeSprint.Value;
			zombie.zombieLungeDistance = zombieLungeDistance.Value;
			zombie.lungeTime = lungeTime.Value;
			zombie.lungeRecoveryTime = lungeRecoveryTime.Value;
			zombie.biteStunTime = biteStunTime.Value;
			if (biteInitialInjury.Value >= 0f)
			{
				zombie.biteInitialInjury = biteInitialInjury.Value;
			}
			if (biteInitialSpores.Value >= 0f)
			{
				zombie.biteInitialSpores = biteInitialSpores.Value;
			}
			if (biteDelayBeforeSpores.Value >= 0f)
			{
				zombie.biteDelayBeforeSpores = biteDelayBeforeSpores.Value;
			}
			if (biteSporesPerSecond.Value >= 0f)
			{
				zombie.biteSporesPerSecond = biteSporesPerSecond.Value;
			}
			if (totalBiteSporesTime.Value >= 0f)
			{
				zombie.totalBiteSporesTime = totalBiteSporesTime.Value;
			}
			if (distanceToEnable.Value >= 0f)
			{
				zombie.distanceToEnable = distanceToEnable.Value;
			}
			zombie.zombieGruntWaitTimeMinMax = new Vector2(zombieGruntWaitMin.Value, zombieGruntWaitMax.Value);
			float num = ((mushroomGrowTimeMin.Value >= 0f) ? mushroomGrowTimeMin.Value : zombie.minMaxMushroomGrowTime.x);
			float num2 = ((mushroomGrowTimeMax.Value >= 0f) ? mushroomGrowTimeMax.Value : zombie.minMaxMushroomGrowTime.y);
			if (mushroomGrowTimeMin.Value >= 0f || mushroomGrowTimeMax.Value >= 0f)
			{
				zombie.minMaxMushroomGrowTime = new Vector2(num, num2);
			}
			zombie.attackHeightDelta = attackHeightDelta.Value;
			if (zombie.zombieGruntWaitTimeMinMax.x > zombie.zombieGruntWaitTimeMinMax.y)
			{
				zombie.zombieGruntWaitTimeMinMax = new Vector2(zombie.zombieGruntWaitTimeMinMax.y, zombie.zombieGruntWaitTimeMinMax.x);
			}
		}
	}

	public static MushroomZombie SpawnZombieNearCharacter(Character character, Vector3 offset = default(Vector3))
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null)
		{
			if (logger != null)
			{
				logger.LogError((object)"Character is null!");
			}
			return null;
		}
		if (offset == default(Vector3))
		{
			offset = ((Component)character.refs.head).transform.forward * 5f;
		}
		Vector3 position = character.Center + offset;
		return SpawnZombieAt(position);
	}

	public static List<MushroomZombie> SpawnZombiesAround(Vector3 center, float radius, int count)
	{
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		List<MushroomZombie> list = new List<MushroomZombie>();
		ZombieManager instance = ZombieManager.Instance;
		for (int i = 0; i < count; i++)
		{
			if ((Object)(object)_instance != (Object)null && !_instance.bypassMaxZombieLimit.Value && (Object)(object)instance != (Object)null)
			{
				int num = ((_instance.customMaxZombies.Value > 0) ? _instance.customMaxZombies.Value : instance.maxActiveZombies);
				if (instance.zombies.Count >= num)
				{
					if (logger != null)
					{
						logger.LogWarning((object)$"Max active zombies reached ({num}). Only spawned {list.Count} out of {count} requested.");
					}
					break;
				}
			}
			Vector2 val = Random.insideUnitCircle * radius;
			Vector3 position = center + new Vector3(val.x, 0f, val.y);
			position = FindGroundPosition(position);
			MushroomZombie val2 = SpawnZombieAt(position);
			if ((Object)(object)val2 != (Object)null)
			{
				list.Add(val2);
			}
		}
		return list;
	}

	private static MushroomZombie GetZombiePrefab()
	{
		ZombieManager instance = ZombieManager.Instance;
		if ((Object)(object)instance != (Object)null && instance.spawners.Count > 0)
		{
			foreach (MushroomZombieSpawner spawner in instance.spawners)
			{
				if ((Object)(object)spawner != (Object)null && (Object)(object)spawner.mushroomZombiePrefab != (Object)null)
				{
					return spawner.mushroomZombiePrefab;
				}
			}
		}
		MushroomZombieSpawner[] array = Object.FindObjectsByType<MushroomZombieSpawner>((FindObjectsSortMode)0);
		MushroomZombieSpawner[] array2 = array;
		foreach (MushroomZombieSpawner val in array2)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)val.mushroomZombiePrefab != (Object)null)
			{
				return val.mushroomZombiePrefab;
			}
		}
		return null;
	}

	private static Vector3 FindGroundPosition(Vector3 position)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_0016: 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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		RaycastHit val = default(RaycastHit);
		if (Physics.Raycast(position + Vector3.up * 10f, Vector3.down, ref val, 100f))
		{
			return ((RaycastHit)(ref val)).point;
		}
		return position;
	}

	public static void StartAutoSpawning(float intervalSeconds, float spawnRadius = 50f)
	{
		if ((Object)(object)_instance != (Object)null && !_instance.disableZombies.Value && _instance.autoSpawnCoroutine == null)
		{
			_instance.autoSpawnCoroutine = ((MonoBehaviour)_instance).StartCoroutine(_instance.AutoSpawnCoroutine(intervalSeconds, spawnRadius));
			logger.LogInfo((object)$"Auto-spawning started: {intervalSeconds}s interval, {spawnRadius} unit radius");
		}
	}

	public void StopAutoSpawning()
	{
		if (autoSpawnCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(autoSpawnCoroutine);
			autoSpawnCoroutine = null;
			logger.LogInfo((object)"Auto-spawning stopped");
		}
	}

	[IteratorStateMachine(typeof(<AutoSpawnCoroutine>d__59))]
	private IEnumerator AutoSpawnCoroutine(float intervalSeconds, float spawnRadius)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <AutoSpawnCoroutine>d__59(0)
		{
			<>4__this = this,
			intervalSeconds = intervalSeconds,
			spawnRadius = spawnRadius
		};
	}
}