Decompiled source of PEAK Zombies v2.0.0
Zombies Anywhere.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 ExitGames.Client.Photon; using HarmonyLib; using Peak; using Peak.Afflictions; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [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("2.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace Zombies_Anywhere { [BepInPlugin("tony4twenty.PEAK_Zombies", "PEAK Zombies", "2.0.0")] public class ZombiesAnywhereMod : BaseUnityPlugin { [HarmonyPatch(typeof(Ascents), "get_shouldSpawnZombie")] private static class ShouldSpawnZombiePatch { private static void Postfix(ref bool __result) { try { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null)) { if (instance.ZombiesDisabled) { __result = false; } else if (instance.ShouldForceZombies()) { __result = true; } } } catch (Exception ex) { LogOnce(ref loggedShouldSpawnError, "shouldSpawnZombie postfix failed.", ex); } } } [HarmonyPatch(typeof(CharacterAfflictions), "StatusAffectsZombie")] private static class StatusAffectsZombiePatch { private static void Postfix(ref bool __result) { if (!__result && AllowZombieVanillaAfflictions()) { __result = true; } } } [HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")] private static class AddStatusAirportPatch { private static void Prefix(CharacterAfflictions __instance, ref bool __state) { __state = false; if (!((Object)(object)__instance == (Object)null) && AllowZombieVanillaAfflictions()) { Character character = __instance.character; if (!((Object)(object)character == (Object)null) && character.isZombie && __instance.m_inAirport) { __instance.m_inAirport = false; __state = true; } } } private static void Postfix(CharacterAfflictions __instance, bool __state) { if (__state && (Object)(object)__instance != (Object)null) { __instance.m_inAirport = true; } } } [HarmonyPatch(typeof(CharacterAfflictions), "get_willZombify")] private static class WillZombifyPatch { private static void Postfix(CharacterAfflictions __instance, ref bool __result) { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance == (Object)null)) { Character character = __instance.character; if ((Object)(object)character != (Object)null && character.isZombie) { __result = false; return; } if (instance.ZombiesDisabled || instance.PreventPlayerZombification) { __result = false; return; } float currentStatus = __instance.GetCurrentStatus((STATUSTYPE)10); __result = currentStatus >= instance.GetZombificationSporeThreshold() && Ascents.shouldSpawnZombie; } } } [HarmonyPatch(typeof(Character), "RPCA_Zombify")] private static class RpcaZombifyPatch { private static bool Prefix() { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null)) { if (!instance.ZombiesDisabled) { return !instance.PreventPlayerZombification; } return false; } return true; } } [HarmonyPatch(typeof(ZombieManager), "Update")] private static class ZombieManagerUpdatePatch { private static void Prefix(ZombieManager __instance) { try { Instance?.ApplyManagerCap(__instance); } catch (Exception ex) { LogOnce(ref loggedManagerUpdateError, "ZombieManager.Update prefix failed.", ex); } } } [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.ZombiesDisabled) { if ((Object)(object)__instance != (Object)null) { Object.Destroy((Object)(object)((Component)__instance).gameObject); } return false; } bool flag = (Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<ModPlacedSpawner>() != (Object)null; if (instance.DisableVanillaSpawners && !flag) { if ((Object)(object)__instance != (Object)null) { Object.Destroy((Object)(object)((Component)__instance).gameObject); } return false; } if (!Ascents.shouldSpawnZombie) { Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } if (!flag && __instance.cullRandomly && !instance.DisableRandomSpawnerCull && Random.Range(0f, 1f) > instance.SpawnerKeepChance) { LogVerbose("Vanilla zombie spawner culled by random chance."); Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } if ((Object)(object)ZombieManager.Instance != (Object)null && !ZombieManager.Instance.spawners.Contains(__instance)) { ZombieManager.Instance.spawners.Add(__instance); } return false; } } [HarmonyPatch(typeof(MushroomZombie), "Start")] private static class MushroomZombieStartPatch { private static void Postfix(MushroomZombie __instance) { try { if ((Object)(object)__instance != (Object)null) { ((MonoBehaviour)__instance).StartCoroutine(ZombieLooks.ApplyAfterReady(__instance)); } if (ShouldForceAggro(__instance)) { ForceStandAndChase(__instance); } } catch (Exception ex) { LogOnce(ref loggedStartError, "MushroomZombie.Start postfix failed.", ex); } } } [HarmonyPatch(typeof(MushroomZombieSpawner), "ReadyToSpawn")] private static class ReadyToSpawnPatch { private static bool Prefix(MushroomZombieSpawner __instance, ref bool __result) { //IL_00c7: 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) try { if ((Object)(object)__instance == (Object)null || !((Behaviour)__instance).isActiveAndEnabled || (Object)(object)__instance.mushroomZombiePrefab == (Object)null) { __result = false; return false; } ZombiesAnywhereMod instance = Instance; if ((Object)(object)instance != (Object)null && instance.DirectorActive) { __result = false; return false; } ModPlacedSpawner component = ((Component)__instance).GetComponent<ModPlacedSpawner>(); if ((Object)(object)component == (Object)null) { return true; } if (!component.HasRemaining) { __result = false; return false; } float distanceToEnable = __instance.mushroomZombiePrefab.distanceToEnable; List<Character> allCharacters = Character.AllCharacters; if (allCharacters != null) { for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (!((Object)(object)val == (Object)null) && !val.isZombie && !val.isBot && !val.data.dead && Vector3.Distance(val.Center, ((Component)__instance).transform.position) <= distanceToEnable) { __result = true; return false; } } } __result = false; return false; } catch (Exception ex) { LogOnce(ref loggedReadyToSpawnError, "MushroomZombieSpawner.ReadyToSpawn prefix failed.", ex); __result = false; return false; } } } [HarmonyPatch(typeof(MushroomZombieSpawner), "Spawn")] private static class SpawnerSpawnPatch { private static bool Prefix(MushroomZombieSpawner __instance) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0059: 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) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) try { ModPlacedSpawner component = ((Component)__instance).GetComponent<ModPlacedSpawner>(); if ((Object)(object)component == (Object)null) { BeginArmedSpawn(); return true; } if (!PhotonNetwork.IsMasterClient) { return false; } if (!component.HasRemaining) { __instance.spawned = true; return false; } Vector3 val = ((Component)__instance).transform.position; if (component.total > 1) { val = VanillaStyleScatter.OffsetSpawnPosition(val); } BeginArmedSpawn(); GameObject val2; try { val2 = PhotonNetwork.Instantiate(((Object)((Component)__instance.mushroomZombiePrefab).gameObject).name, val, ((Component)__instance).transform.rotation, (byte)0, (object[])null); } finally { EndArmedSpawn(); } if ((Object)(object)val2 == (Object)null) { return false; } MushroomZombie component2 = val2.GetComponent<MushroomZombie>(); if ((Object)(object)component2 == (Object)null) { PhotonNetwork.Destroy(val2); return false; } component.ConsumeOne(); __instance.spawned = !component.HasRemaining; __instance.spawnedZombie = null; ArmAroundPlayerZombie(component2); return false; } catch (Exception ex) { LogOnce(ref loggedSpawnerSpawnError, "MushroomZombieSpawner.Spawn prefix failed.", ex); return true; } } private static void Postfix(MushroomZombieSpawner __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.spawnedZombie != (Object)null) { ArmAroundPlayerZombie(__instance.spawnedZombie); } } catch (Exception ex) { LogOnce(ref loggedSpawnerSpawnError, "MushroomZombieSpawner.Spawn postfix failed.", ex); } finally { EndArmedSpawn(); } } } [HarmonyPatch(typeof(MapHandler), "GoToSegment")] private static class MapHandlerGoToSegmentPatch { private static void Postfix() { VanillaStyleScatter.RequestCurrentSegment(); } } [HarmonyPatch(typeof(MapHandler), "ActivateCurrentSegment")] private static class MapHandlerActivateSegmentPatch { private static void Postfix() { VanillaStyleScatter.RequestCurrentSegment(); } } [HarmonyPatch(typeof(MapHandler), "JumpToSegmentLogic")] private static class MapHandlerJumpToSegmentPatch { private static void Postfix() { VanillaStyleScatter.RequestCurrentSegment(); } } [HarmonyPatch(typeof(MushroomZombie), "Awake")] private static class MushroomZombieAwakePatch { private static void Postfix(MushroomZombie __instance) { try { Instance?.ApplyZombieTuning(__instance); if (ArmedSpawnPending) { TagAggroOnSpawn(__instance); } } catch (Exception ex) { LogOnce(ref loggedAwakeError, "MushroomZombie.Awake postfix failed.", ex); } } } [HarmonyPatch(typeof(CharacterMovement), "GetMovementForce")] private static class CharacterMovementForcePatch { private static void Postfix(CharacterMovement __instance, ref float __result) { try { Character val = (((Object)(object)__instance != (Object)null) ? __instance.character : null); if ((Object)(object)val == (Object)null || !val.isZombie) { return; } if (ShouldHaltNpcAi(val)) { __result = 0f; return; } ApplyJumpImpulse(__instance, val); ZombiesAnywhereMod instance = _instance; if (!((Object)(object)instance == (Object)null)) { float num = MovementScaleFor(val, __instance, instance); if (!Mathf.Approximately(num, 1f)) { __result *= num; } } } catch (Exception ex) { LogOnce(ref loggedMoveError, "Zombie move-speed patch failed.", ex); } } } [HarmonyPatch(typeof(MushroomZombie), "ClimbTowards")] private static class ZombieClimbSpeedPatch { private static bool Prefix(MushroomZombie __instance, ref float mult) { try { if (!ContinueAi(__instance)) { return false; } ZombiesAnywhereMod instance = _instance; if ((Object)(object)instance == (Object)null) { return true; } float climbSpeedMultiplier = instance.ClimbSpeedMultiplier; if (!Mathf.Approximately(climbSpeedMultiplier, 1f)) { mult *= climbSpeedMultiplier; } } catch (Exception ex) { LogOnce(ref loggedMoveError, "Zombie climb-speed patch failed.", ex); } return true; } } [HarmonyPatch(typeof(CharacterMovement), "TryToJump")] private static class ZombieJumpImpulsePatch { private static bool Prefix(CharacterMovement __instance) { try { Character character = (((Object)(object)__instance != (Object)null) ? __instance.character : null); if (ShouldHaltNpcAi(character)) { return false; } ApplyJumpImpulse(__instance, character); } catch (Exception ex) { LogOnce(ref loggedMoveError, "Zombie jump patch failed.", ex); } return true; } } [HarmonyPatch(typeof(MushroomZombie), "ReadyToDisable")] private static class ReadyToDisablePatch { private static bool Prefix(MushroomZombie __instance, ref bool __result) { try { ZombiesAnywhereMod instance = Instance; if ((Object)(object)instance == (Object)null) { return true; } __result = instance.EvaluateReadyToDisable(__instance, out var handled); return !handled; } catch (Exception ex) { LogOnce(ref loggedReadyToDisableError, "ReadyToDisable prefix failed.", ex); return true; } } } [HarmonyPatch(typeof(MushroomZombie), "GetClosestCharacter")] private static class GetClosestCharacterPatch { private static bool Prefix(MushroomZombie __instance, Character ignoredCharacter, ref Character __result) { __result = FindClosestPlayer(__instance, ignoredCharacter); return false; } } [HarmonyPatch(typeof(MushroomZombie), "TargetIsValid")] private static class TargetIsValidPatch { private static void Postfix(MushroomZombie __instance, Character target, ref bool __result) { if ((Object)(object)target == (Object)null || (Object)(object)target == (Object)(object)__instance.character || target.isZombie) { __result = false; } else if (!__result) { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.AttackUnconsciousPlayers && !target.isBot && !target.data.dead) { __result = target.data.fullyPassedOut; } } } } [HarmonyPatch(typeof(Character), "HandleLife")] private static class ZombieHandleLifePatch { private static bool Prefix(Character __instance) { try { return ZombieDeath.TryHandleLife(__instance); } catch (Exception ex) { LogOnce(ref loggedPassOutError, "Zombie HandleLife pass-out prefix failed.", ex); return true; } } } [HarmonyPatch(typeof(MushroomZombie), "Update")] private static class ZombieUpdatePassOutPatch { private static void Postfix(MushroomZombie __instance) { try { if (ShouldHaltNpcAi(__instance)) { HaltZombieAi(__instance); } } catch (Exception ex) { LogOnce(ref loggedPassOutError, "Zombie Update pass-out postfix failed.", ex); } } } [HarmonyPatch(typeof(MushroomZombie), "StartChasing")] private static class StartChasingPassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "DoChasing")] private static class DoChasingPassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "StartLunging")] private static class StartLungingPassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "TryLunge")] private static class TryLungePassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "DoLungeRecovery")] private static class DoLungeRecoveryPassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "DoIdle")] private static class DoIdlePassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "Chase")] private static class ChasePassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "WalkTowards")] private static class WalkTowardsPassOutPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } } [HarmonyPatch(typeof(MushroomZombie), "DoLunging")] private static class DoLungingPatch { private static bool Prefix(MushroomZombie __instance) { return ContinueAi(__instance); } private static void Postfix(MushroomZombie __instance) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if (ShouldHaltNpcAi(__instance)) { return; } ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null) && (int)__instance.currentState == 5 && !((Object)(object)__instance.character == (Object)null)) { __instance.character.data.fallSeconds = instance.LungeStumbleSeconds; if ((Object)(object)__instance.view != (Object)null && __instance.view.IsMine) { __instance.PushState(); } } } } [HarmonyPatch(typeof(MushroomZombie), "OnBitCharacter")] private static class OnBitCharacterPatch { private static void Postfix(MushroomZombie __instance) { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance.character == (Object)null)) { __instance.character.data.fallSeconds = instance.BiteSelfStumbleSeconds; if ((Object)(object)__instance.view != (Object)null && __instance.view.IsMine) { __instance.PushState(); } } } } [HarmonyPatch(typeof(MushroomZombieBiteCollider), "OnTriggerEnter")] private static class BiteColliderPatch { private static bool Prefix(MushroomZombieBiteCollider __instance, Collider other) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown try { ZombiesAnywhereMod instance = Instance; if ((Object)(object)instance == (Object)null) { return true; } if (Time.time - __instance.lastBitLocalCharacter < instance.BiteTriggerCooldown) { return false; } MushroomZombie parentZombie = __instance.parentZombie; if (ShouldHaltNpcAi(parentZombie)) { return false; } Character val = default(Character); if (!CharacterRagdoll.TryGetCharacterFromCollider(other, ref val) || !val.IsLocal) { return false; } __instance.lastBitLocalCharacter = Time.time; if (val.data.isSkeleton) { val.refs.afflictions.AddStatus((STATUSTYPE)0, parentZombie.biteInitialInjury / 8f * 2f, false, true, true, false); } else { val.refs.afflictions.AddStatus((STATUSTYPE)0, parentZombie.biteInitialInjury, false, true, true, false); } val.refs.afflictions.AddStatus((STATUSTYPE)10, parentZombie.biteInitialSpores, false, true, true, false); val.refs.afflictions.AddAffliction((Affliction)new Affliction_ZombieBite(parentZombie.totalBiteSporesTime, parentZombie.biteDelayBeforeSpores, parentZombie.biteSporesPerSecond), false); val.Fall(parentZombie.biteStunTime, 0f); parentZombie.OnBitCharacter(val); return false; } catch (Exception ex) { LogOnce(ref loggedBiteError, "Bite collider prefix failed.", ex); return true; } } } public const string PluginGuid = "tony4twenty.PEAK_Zombies"; public const string PluginName = "PEAK Zombies"; public const string PluginVersion = "2.0.0"; internal const string NpcPrefabNameDefault = "MushroomZombie"; private const float InfiniteLifetimeSeconds = 3.1536E+09f; private const float VanillaSpawnChance = 0.333f; private const float VanillaCullDistance = 100f; private const float VanillaSporeThreshold = 0.5f; private const float VanillaBiteCooldown = 5f; private const float VanillaLungeStumbleSeconds = 3f; private const float VanillaBiteSelfStumbleSeconds = 8f; private const float VanillaSleepCullPadding = 5f; private static ManualLogSource logger; private static ZombiesAnywhereMod _instance; private static string cachedPrefabName; private static bool loggedAwakeError; private static bool loggedStartError; private static bool loggedReadyToDisableError; private static bool loggedReadyToSpawnError; private static bool loggedManagerUpdateError; private static bool loggedBiteError; private static bool loggedPassOutError; private static bool loggedShouldSpawnError; private static bool loggedSpawnerSpawnError; private static bool loggedDebugError; private static bool loggedMoveError; private static readonly Dictionary<int, float> VanillaJumpImpulse = new Dictionary<int, float>(); private static int armSpawnDepth; private int directorLock; private Harmony harmony; private Coroutine autoSpawnCoroutine; private Coroutine initCoroutine; private int vanillaMaxActiveZombies = -1; private ConfigEntry<bool> disableZombies; private ConfigEntry<bool> forceZombies; private ConfigEntry<bool> allowTenderfootZombies; private ConfigEntry<bool> preventPlayerZombification; private ConfigEntry<float> zombificationSporeThreshold; 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> vanillaStyleEnabled; private ConfigEntry<bool> vanillaStyleIncludeRoots; private ConfigEntry<string> vanillaStyleBiomes; private ConfigEntry<int> vanillaStyleSpawnersPerSegment; private ConfigEntry<int> vanillaStyleZombiesPerSpawnerMin; private ConfigEntry<int> vanillaStyleZombiesPerSpawnerMax; private ConfigEntry<float> vanillaStyleMinSpacing; private ConfigEntry<float> vanillaStyleMaxSlope; private ConfigEntry<bool> disableVanillaSpawners; private ConfigEntry<bool> disableRandomSpawnerCull; private ConfigEntry<float> spawnerKeepChance; private ConfigEntry<bool> bypassMaxZombieLimit; private ConfigEntry<int> customMaxZombies; private ConfigEntry<bool> disableDistanceCulling; private ConfigEntry<float> cullDistance; private ConfigEntry<bool> removeZombieLifetime; private ConfigEntry<float> zombieLifetimeOverride; private ConfigEntry<bool> hideMushroomVisuals; private ConfigEntry<bool> enableMushroomGrowth; private ConfigEntry<bool> attackUnconsciousPlayers; private ConfigEntry<float> biteTriggerCooldown; private ConfigEntry<float> lungeStumbleSeconds; private ConfigEntry<float> biteSelfStumbleSeconds; private ConfigEntry<bool> allowVanillaAfflictions; private ConfigEntry<bool> instantPassOutRagdoll; private ConfigEntry<float> passOutSeconds; private ConfigEntry<float> downedSeconds; private ConfigEntry<bool> skipPassOut; private ConfigEntry<string> boneMode; private ConfigEntry<bool> canRecoverFromPassOut; private ConfigEntry<float> corpseLifetime; private ConfigEntry<float> skeletonLifetime; private ConfigEntry<bool> beesAffectZombies; private ConfigEntry<bool> statusFieldsAffectZombies; private ConfigEntry<bool> beetlesAffectZombies; private ConfigEntry<bool> flytrapsAffectZombies; private ConfigEntry<bool> scorpionsAffectZombies; private ConfigEntry<bool> cannonsAffectZombies; private ConfigEntry<bool> scoutmasterHuntsZombies; 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> walkSpeedMultiplier; private ConfigEntry<float> sprintSpeedMultiplier; private ConfigEntry<float> climbSpeedMultiplier; private ConfigEntry<float> jumpImpulseMultiplier; private ConfigEntry<float> lungeSpeedMultiplier; 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 ConfigEntry<bool> randomizeLooks; private ConfigEntry<KeyboardShortcut> captureLookKey; private ConfigEntry<string> cachedLook; private ConfigEntry<bool> overrideEyes; private ConfigEntry<bool> noHat; private ConfigEntry<bool> noSash; private ConfigEntry<bool> showPauseMenuButton; private ConfigEntry<KeyCode> menuKey; private ConfigEntry<KeyCode> menuModifier; private ConfigEntry<bool> verboseLogging; internal static ZombiesAnywhereMod Instance => _instance; internal ConfigFile PluginConfig => ((BaseUnityPlugin)this).Config; internal bool DirectorActive => directorLock > 0; internal bool ZombiesDisabled { get { if (disableZombies != null) { return disableZombies.Value; } return false; } } internal bool ForceZombies { get { if (forceZombies != null) { return forceZombies.Value; } return false; } } internal bool AllowTenderfootZombies { get { if (allowTenderfootZombies != null) { return allowTenderfootZombies.Value; } return false; } } internal bool PreventPlayerZombification { get { if (preventPlayerZombification != null) { return preventPlayerZombification.Value; } return false; } } internal bool DisableVanillaSpawners { get { if (disableVanillaSpawners != null) { return disableVanillaSpawners.Value; } return false; } } internal bool DisableRandomSpawnerCull { get { if (disableRandomSpawnerCull != null) { return disableRandomSpawnerCull.Value; } return false; } } internal bool DisableDistanceCulling { get { if (disableDistanceCulling != null) { return disableDistanceCulling.Value; } return false; } } internal bool AttackUnconsciousPlayers { get { if (attackUnconsciousPlayers != null) { return attackUnconsciousPlayers.Value; } return false; } } internal bool VerboseLogging { get { if (verboseLogging != null) { return verboseLogging.Value; } return false; } } internal bool AroundPlayerSpawnEnabled { get { if (autoSpawnEnabled != null) { return autoSpawnEnabled.Value; } return false; } } internal bool VanillaStyleEnabled { get { if (vanillaStyleEnabled != null) { return vanillaStyleEnabled.Value; } return false; } } internal bool VanillaStyleIncludeRoots { get { if (vanillaStyleIncludeRoots != null) { return vanillaStyleIncludeRoots.Value; } return false; } } internal int VanillaStyleSpawnersPerSegment { get { if (vanillaStyleSpawnersPerSegment == null) { return 12; } return vanillaStyleSpawnersPerSegment.Value; } } internal int VanillaStyleZombiesPerSpawnerMin { get { if (vanillaStyleZombiesPerSpawnerMin == null) { return 1; } return vanillaStyleZombiesPerSpawnerMin.Value; } } internal int VanillaStyleZombiesPerSpawnerMax { get { if (vanillaStyleZombiesPerSpawnerMax == null) { return 1; } return vanillaStyleZombiesPerSpawnerMax.Value; } } internal float VanillaStyleMinSpacing { get { if (vanillaStyleMinSpacing == null) { return 25f; } return vanillaStyleMinSpacing.Value; } } internal float VanillaStyleMaxSlope { get { if (vanillaStyleMaxSlope == null) { return 50f; } return vanillaStyleMaxSlope.Value; } } internal float SpawnerKeepChance { get { if (spawnerKeepChance == null) { return 0.333f; } return spawnerKeepChance.Value; } } internal float CullDistance { get { if (cullDistance == null) { return 100f; } return cullDistance.Value; } } internal float BiteTriggerCooldown { get { if (biteTriggerCooldown == null) { return 5f; } return biteTriggerCooldown.Value; } } internal float LungeStumbleSeconds { get { if (lungeStumbleSeconds == null) { return 3f; } return lungeStumbleSeconds.Value; } } internal float BiteSelfStumbleSeconds { get { if (biteSelfStumbleSeconds == null) { return 8f; } return biteSelfStumbleSeconds.Value; } } internal float WalkSpeedMultiplier => ScaleOrDefault(walkSpeedMultiplier); internal float SprintSpeedMultiplier => ScaleOrDefault(sprintSpeedMultiplier); internal float ClimbSpeedMultiplier => ScaleOrDefault(climbSpeedMultiplier); internal float JumpImpulseMultiplier => ScaleOrDefault(jumpImpulseMultiplier); internal float LungeSpeedMultiplier => ScaleOrDefault(lungeSpeedMultiplier); internal bool RandomizeLooks { get { if (randomizeLooks != null) { return randomizeLooks.Value; } return false; } } internal bool OverrideEyes { get { if (overrideEyes != null) { return overrideEyes.Value; } return false; } } internal bool NoHat { get { if (noHat != null) { return noHat.Value; } return false; } } internal bool NoSash { get { if (noSash != null) { return noSash.Value; } return false; } } internal bool UnlimitedZombies { get { if (bypassMaxZombieLimit != null) { return bypassMaxZombieLimit.Value; } return false; } } internal bool LocalHideMushroomVisuals { get { if (hideMushroomVisuals != null) { return hideMushroomVisuals.Value; } return false; } } internal bool LocalEnableMushroomGrowth { get { if (enableMushroomGrowth != null) { return enableMushroomGrowth.Value; } return true; } } internal bool LocalAllowVanillaAfflictions { get { if (allowVanillaAfflictions != null) { return allowVanillaAfflictions.Value; } return true; } } internal bool InstantPassOutRagdoll { get { if (instantPassOutRagdoll != null) { return instantPassOutRagdoll.Value; } return false; } } internal float PassOutSeconds { get { if (passOutSeconds == null) { return 5f; } return passOutSeconds.Value; } } internal float DownedSeconds { get { if (downedSeconds == null) { return 60f; } return downedSeconds.Value; } } internal bool SkipPassOut { get { if (skipPassOut != null) { return skipPassOut.Value; } return false; } } internal bool CanRecoverFromPassOut { get { if (canRecoverFromPassOut != null) { return canRecoverFromPassOut.Value; } return true; } } internal ZombieBoneMode BoneMode => ZombieDeath.ParseBoneMode((boneMode != null) ? boneMode.Value : "Skeleton"); internal float CorpseLifetime { get { if (corpseLifetime == null) { return 45f; } return corpseLifetime.Value; } } internal float SkeletonLifetime { get { if (skeletonLifetime == null) { return 0f; } return skeletonLifetime.Value; } } internal bool BeesAffectZombies { get { if (beesAffectZombies != null) { return beesAffectZombies.Value; } return true; } } internal bool StatusFieldsAffectZombies { get { if (statusFieldsAffectZombies != null) { return statusFieldsAffectZombies.Value; } return true; } } internal bool BeetlesAffectZombies { get { if (beetlesAffectZombies != null) { return beetlesAffectZombies.Value; } return true; } } internal bool FlytrapsAffectZombies { get { if (flytrapsAffectZombies != null) { return flytrapsAffectZombies.Value; } return true; } } internal bool ScorpionsAffectZombies { get { if (scorpionsAffectZombies != null) { return scorpionsAffectZombies.Value; } return true; } } internal bool CannonsAffectZombies { get { if (cannonsAffectZombies != null) { return cannonsAffectZombies.Value; } return true; } } internal bool ScoutmasterHuntsZombies { get { if (scoutmasterHuntsZombies != null) { return scoutmasterHuntsZombies.Value; } return true; } } internal bool EffectiveHideMushroomVisuals { get { if (HostHandshake.ShouldUseHostVisuals) { return HostHandshake.SyncedHideMushrooms; } return LocalHideMushroomVisuals; } } internal bool EffectiveEnableMushroomGrowth { get { if (HostHandshake.ShouldUseHostVisuals) { return HostHandshake.SyncedEnableGrowth; } return LocalEnableMushroomGrowth; } } internal bool EffectiveAllowVanillaAfflictions { get { if (HostHandshake.ShouldUseHostVisuals) { return HostHandshake.SyncedAllowVanillaAfflictions; } return LocalAllowVanillaAfflictions; } } internal bool CaptureLookKeyDown { get { //IL_000e: 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) if (captureLookKey != null) { KeyboardShortcut value = captureLookKey.Value; return ((KeyboardShortcut)(ref value)).IsDown(); } return false; } } internal bool HasCachedLook { get { CharacterCustomizationData look; if (cachedLook != null) { return ZombieLooks.TryParse(cachedLook.Value, out look); } return false; } } internal string CachedLook { get { if (cachedLook == null) { return string.Empty; } return cachedLook.Value; } set { if (cachedLook != null) { cachedLook.Value = value ?? string.Empty; } } } internal static bool ArmedSpawnPending => armSpawnDepth > 0; internal static bool InstantPassOutRagdollEnabled { get { ZombiesAnywhereMod instance = Instance; if (!((Object)(object)instance == (Object)null)) { return instance.InstantPassOutRagdoll; } return true; } } private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown _instance = this; logger = ((BaseUnityPlugin)this).Logger; LoadConfiguration(); ((BaseUnityPlugin)this).Config.SettingChanged += OnConfigChanged; HostHandshake.Initialize(this); ZombiesMenu.EnsureCreated(); harmony = new Harmony("tony4twenty.ZombiesAnywhere.Patches"); harmony.PatchAll(typeof(ZombiesAnywhereMod).Assembly); SceneManager.sceneLoaded += OnSceneLoaded; logger.LogInfo((object)"PEAK Zombies 2.0.0 loaded."); LogStartupSummary(); } private void Update() { try { ZombieLooks.TickCapture(); } catch (Exception ex) { LogOnce(ref loggedDebugError, "Debug tick failed.", ex); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; ((BaseUnityPlugin)this).Config.SettingChanged -= OnConfigChanged; StopAutoSpawning(); if (initCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(initCoroutine); initCoroutine = null; } Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void LoadConfiguration() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Expected O, but got Unknown //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Expected O, but got Unknown //IL_0a22: Unknown result type (might be due to invalid IL or missing references) disableZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableZombies", false, "Master off switch. Blocks NPC spawns, vanilla spawners, and player zombification."); forceZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceZombies", true, "When true, ignore Tenderfoot and custom-run Hazard Zombies so zombies can exist anywhere. DisableZombies still wins."); allowTenderfootZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowTenderfootZombies", false, "If ForceZombies is false, still keep zombies on Tenderfoot (ascent -1) when the run's Hazard Zombies setting is on."); preventPlayerZombification = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PreventPlayerZombification", false, "When true, spore death stays a normal death instead of spawning a player Mushroom Zombie."); zombificationSporeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ZombificationSporeThreshold", 0.5f, new ConfigDescription("Spores required before a downed player becomes a zombie. Vanilla is 0.5. Set below 0 to keep vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), Array.Empty<object>())); autoSpawnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Around Players", "Enabled", false, "Spawn extra NPC zombies around the living party. Independent of vanilla-style map spawners."); autoSpawnInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Around Players", "IntervalSeconds", 10f, "Seconds between around-player waves. 0 disables repeating waves."); autoSpawnRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Around Players", "Radius", 50f, "Radius around the party centroid used for around-player spawns."); initialSpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("Around Players", "InitialSpawnCount", 3, "NPC zombies to spawn once the climb map is ready (not the Airport)."); zombiesPerSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Around Players", "ZombiesPerWave", 2, "NPC zombies to spawn each around-player wave."); initialSpawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Around Players", "InitialSpawnDelay", 15f, "Seconds to wait after a scene load before the first around-player spawn."); vanillaStyleEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Vanilla Style", "Enabled", true, "Plant Roots-style spawners on other segments: fixed points, spawn when a player gets close. They spawn standing and chase immediately. Independent of around-player spawn."); vanillaStyleIncludeRoots = ((BaseUnityPlugin)this).Config.Bind<bool>("Vanilla Style", "IncludeRoots", false, "Also scatter extra spawners in Roots. Leave off to keep Landfall's own Roots spawners."); vanillaStyleBiomes = ((BaseUnityPlugin)this).Config.Bind<string>("Vanilla Style", "Biomes", "Shore,Tropics,Alpine,Mesa,Volcano,Swamp,Temple", "Comma-separated biomes. Gloom is Swamp. Citadel and Kiln are their own segments after the Gloom/Caldera campfire (TheKiln slot); include Swamp/Volcano or Citadel/Kiln to plant there. Roots is controlled by IncludeRoots."); vanillaStyleSpawnersPerSegment = ((BaseUnityPlugin)this).Config.Bind<int>("Vanilla Style", "SpawnersPerSegment", 12, new ConfigDescription("Exact number of spawners to plant per segment. All of them are kept.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); vanillaStyleZombiesPerSpawnerMin = ((BaseUnityPlugin)this).Config.Bind<int>("Vanilla Style", "ZombiesPerSpawnerMin", 1, new ConfigDescription("Minimum zombies each vanilla-style spawner can produce when a player gets close.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); vanillaStyleZombiesPerSpawnerMax = ((BaseUnityPlugin)this).Config.Bind<int>("Vanilla Style", "ZombiesPerSpawnerMax", 1, new ConfigDescription("Maximum zombies each vanilla-style spawner can produce when a player gets close. Rolled per spawner between min and max.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); vanillaStyleMinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Vanilla Style", "MinSpacing", 25f, "Minimum meters between spawners."); vanillaStyleMaxSlope = ((BaseUnityPlugin)this).Config.Bind<float>("Vanilla Style", "MaxSlopeDegrees", 50f, "Reject terrain steeper than this. Vanilla prop scatter uses about 50."); disableVanillaSpawners = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "DisableVanillaSpawners", false, "Destroy map zombie spawners and rely only on auto-spawn / player zombification."); disableRandomSpawnerCull = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "DisableRandomSpawnerCull", false, "Keep every Landfall Roots spawner instead of randomly deleting ~2/3 of them. Does not affect mod-placed spawners."); spawnerKeepChance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "SpawnerKeepChance", 0.333f, new ConfigDescription("Chance a Landfall Roots spawner survives random cull. Vanilla is 0.333. Does not apply to mod-placed spawners. Ignored when DisableRandomSpawnerCull is true.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); bypassMaxZombieLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Limits", "UnlimitedZombies", false, "Ignore maxActiveZombies. Leave off unless you want unlimited zombies; that tanks FPS."); customMaxZombies = ((BaseUnityPlugin)this).Config.Bind<int>("Zombie Limits", "CustomMaxZombies", -1, "Max live NPC zombies when UnlimitedZombies is false. -1 keeps the game prefab value."); disableDistanceCulling = ((BaseUnityPlugin)this).Config.Bind<bool>("Culling", "NeverDespawnFarZombies", false, "Do not destroy far-away zombies. Leave off so they despawn when the party moves on; otherwise they pile up and kill FPS."); cullDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Culling", "CullDistance", 100f, "Player distance used when NeverDespawnFarZombies is false. Vanilla is 100."); removeZombieLifetime = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "RemoveZombieLifetime", false, "NPC zombies do not die of old age after falling/passing out. Off keeps vanilla lifetime (~120s)."); zombieLifetimeOverride = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Behavior", "ZombieLifetimeOverride", -1f, "Lifetime in seconds when RemoveZombieLifetime is false. -1 keeps vanilla 120."); hideMushroomVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "HideMushroomVisuals", false, "Hide mushroom props on zombies. Host setting syncs to everyone with this mod. Vanilla clients still see mushrooms."); enableMushroomGrowth = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "EnableMushroomGrowth", true, "If false, mushrooms start at full size with no grow animation. Host setting syncs to everyone with this mod."); attackUnconsciousPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Zombie Behavior", "AttackUnconsciousPlayers", false, "Allow zombies to keep targeting fully passed-out players. Vanilla ignores them."); biteTriggerCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Combat", "BiteTriggerCooldown", 5f, "Seconds before the same local player can be bitten again. Vanilla is 5."); lungeStumbleSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Combat", "LungeStumbleSeconds", 3f, "Replaces vanilla 3s stumble after a lunge. Does not stack."); biteSelfStumbleSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Combat", "BiteSelfStumbleSeconds", 8f, "Replaces vanilla 8s stumble after the zombie lands a bite. Does not stack."); allowVanillaAfflictions = ((BaseUnityPlugin)this).Config.Bind<bool>("Combat", "AllowVanillaAfflictions", true, "Let vanilla statuses (injury, poison, spores, cold, heat, curse, etc.) apply to zombies. Vanilla only allows drowsy and web. Other mods can then call AddStatus / SubtractStatus. Also skips the Airport status lock on zombies so API spawns can be injured there. Host setting syncs to clients with this mod."); instantPassOutRagdoll = ((BaseUnityPlugin)this).Config.Bind<bool>("Combat", "InstantPassOutRagdoll", false, "NPC zombies ragdoll immediately when they would pass out (status sum over 0.99) and cannot chase, lunge, or bite during that collapse. Off uses Death.PassOutSeconds (vanilla is 5). SkipPassOut ignores this and kills instead."); passOutSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Death", "PassOutSeconds", 5f, "Seconds from shouldPassOut to ragdoll when InstantPassOutRagdoll is off. Vanilla ramps passOutValue over 5 seconds. 0 is instant."); downedSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Death", "DownedSeconds", 60f, "Seconds fully passed out before the zombie is killed. Vanilla deathTimer is about 60s. Negative means they stay down until Kill() or they recover."); skipPassOut = ((BaseUnityPlugin)this).Config.Bind<bool>("Death", "SkipPassOut", false, "Kill as soon as status sum exceeds 0.99. No pass-out ragdoll."); boneMode = ((BaseUnityPlugin)this).Config.Bind<string>("Death", "Bones", "Skeleton", "After death: Despawn (Photon destroy, no pile), Skeleton (vanilla bone pile), LeaveRagdoll (body stays). Case-insensitive; 'skeleton' is the same as Skeleton."); canRecoverFromPassOut = ((BaseUnityPlugin)this).Config.Bind<bool>("Death", "CanRecover", true, "If status drops below 1 while passed out, the zombie gets up (vanilla UnPassOut after 3s)."); corpseLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Death", "CorpseLifetime", 45f, "Seconds a LeaveRagdoll body stays in the world before Photon-destroy. 0 or less = never despawn."); skeletonLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Death", "SkeletonLifetime", 0f, "Seconds a Bones-mode skeleton pile stays before it is destroyed. 0 or less = never despawn (vanilla)."); beesAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "BeesAffectZombies", true, "Bee swarms can sting zombies. Vanilla chases any conscious character but only poisons the local player."); statusFieldsAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "StatusFieldsAffectZombies", true, "Poison fog, gloom, lava volumes, and other status fields apply to zombies. Bees have their own toggle."); beetlesAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "BeetlesAffectZombies", true, "Beetles can bonk zombies. Vanilla only applies the knockback to the local player."); flytrapsAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "FlytrapsAffectZombies", true, "Venus flytraps can grab zombies. Vanilla only bites the local player (IsLocal). Drag already works once bitten; this also applies Fall, FlyTrap status, poison ticks, and release."); scorpionsAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "ScorpionsAffectZombies", true, "Scorpions can poison zombies. Vanilla only applies the sting to the local player."); cannonsAffectZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "CannonsAffectZombies", true, "Scout cannons ragdoll and launch zombies. Vanilla already pulls every Character, but only bots get the extra Fall that sucks them in."); scoutmasterHuntsZombies = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "ScoutmasterHuntsZombies", true, "Scoutmaster treats zombies as prey. Vanilla already does (it only skips isBot). Turn off so he only hunts players. Throw injury still needs AllowVanillaAfflictions."); reachForce = BindStat("ReachForce", -1f, "Lunge/reach force. -1 keeps the prefab value."); distanceBeforeWakeup = BindStat("DistanceBeforeWakeup", 30f, "Vanilla sleep only: how close a player must be to wake a sleeping zombie. Does not affect this mod's NPC spawns (they snap to chase). Still used by player-corpse zombies if they sleep."); lookAngleBeforeWakeup = BindStat("LookAngleBeforeWakeup", 30f, "Vanilla sleep only: look-angle to wake a sleeping zombie. Does not affect this mod's NPC spawns. Still used by player-corpse zombies if they sleep."); initialWakeUpTime = BindStat("InitialWakeUpTime", 5f, "Vanilla wake ragdoll duration. Does not affect this mod's NPC spawns (they skip that stand-up). Still used by player-corpse zombies standing up."); distanceBeforeChase = BindStat("DistanceBeforeChase", 30f, "Vanilla idle-to-chase distance. Does not affect this mod's NPC spawns (they snap to chase). Still used if a zombie is in vanilla Idle, including player corpses after waking."); zombieSprintDistance = BindStat("ZombieSprintDistance", 20f, "Distance within which a chasing zombie sprints."); chaseTimeBeforeSprint = BindStat("ChaseTimeBeforeSprint", 3f, "Chase time required before sprinting."); walkSpeedMultiplier = BindMoveScale("WalkSpeedMultiplier", "Walk speed. 1 is vanilla. Independent of sprint, climb, jump, and lunge."); sprintSpeedMultiplier = BindMoveScale("SprintSpeedMultiplier", "Run/sprint speed. 1 is vanilla sprint. Independent of walk speed."); climbSpeedMultiplier = BindMoveScale("ClimbSpeedMultiplier", "Climb speed when a zombie is on a wall. 1 is vanilla."); jumpImpulseMultiplier = BindMoveScale("JumpImpulseMultiplier", "Jump HEIGHT/strength, not how often they jump. 1 is vanilla hop. 2 is a higher hop. 0 stops hopping. They only jump when the AI sees a gap."); lungeSpeedMultiplier = BindMoveScale("LungeSpeedMultiplier", "Movement speed during a lunge. 1 is vanilla. Independent of walk and sprint."); zombieLungeDistance = BindStat("ZombieLungeDistance", 10f, "Distance within which a zombie lunges."); lungeTime = BindStat("LungeTime", 1.5f, "Lunge duration."); lungeRecoveryTime = BindStat("LungeRecoveryTime", 5f, "Recovery after a lunge."); biteStunTime = BindStat("BiteStunTime", 3f, "Seconds the bitten player is stunned."); biteInitialInjury = BindStat("BiteInitialInjury", -1f, "Injury applied on bite. -1 keeps the prefab value."); biteInitialSpores = BindStat("BiteInitialSpores", -1f, "Spores applied on bite. -1 keeps the prefab value."); biteDelayBeforeSpores = BindStat("BiteDelayBeforeSpores", -1f, "Delay before post-bite spores. -1 keeps the prefab value."); biteSporesPerSecond = BindStat("BiteSporesPerSecond", -1f, "Spores per second after a bite. -1 keeps the prefab value."); totalBiteSporesTime = BindStat("TotalBiteSporesTime", -1f, "Duration of post-bite spores. -1 keeps the prefab value."); distanceToEnable = BindStat("DistanceToEnable", -1f, "Vanilla spawner wake/cull radius. -1 keeps the prefab value."); zombieGruntWaitMin = BindStat("ZombieGruntWaitMin", 10f, "Minimum seconds between grunts."); zombieGruntWaitMax = BindStat("ZombieGruntWaitMax", 20f, "Maximum seconds between grunts."); mushroomGrowTimeMin = BindStat("MushroomGrowTimeMin", -1f, "Minimum mushroom grow time. -1 keeps the prefab value."); mushroomGrowTimeMax = BindStat("MushroomGrowTimeMax", -1f, "Maximum mushroom grow time. -1 keeps the prefab value."); attackHeightDelta = BindStat("AttackHeightDelta", 100f, "Vertical offset used when aiming attacks."); randomizeLooks = ((BaseUnityPlugin)this).Config.Bind<bool>("Looks", "RandomizeLooks", false, "Each NPC zombie rolls a random passport look from the local catalog (including custom packs this machine has). Hat and sash rolls include a none option. Host rolls; other modded clients copy those indices. Player-corpse zombies still use the dead scout. When off, NPCs use CachedLook if you have captured one, otherwise vanilla skirt/shorts."); captureLookKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Looks", "CaptureLookKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Host: wear the zombie outfit on your scout (passport or Closet), then press this to snapshot those eight cosmetic indices into CachedLook. New NPC spawns use it when RandomizeLooks is off. Recapture overwrites. Custom packs only appear for clients who have the same packs."); cachedLook = ((BaseUnityPlugin)this).Config.Bind<string>("Looks", "CachedLook", "", "Passport snapshot: skin,accessory,eyes,mouth,outfit,hat,sash,medal. Filled by CaptureLookKey. Edit by hand if you want. Empty means vanilla NPC clothes unless RandomizeLooks is on."); overrideEyes = ((BaseUnityPlugin)this).Config.Bind<bool>("Looks", "OverrideEyes", false, "If true, captured or random looks replace vanilla zombie eyes with the passport eye texture. If false, NPCs keep zombie eyes and the rest of the outfit still applies. Host setting is sent with each spawn."); noHat = ((BaseUnityPlugin)this).Config.Bind<bool>("Looks", "NoHat", false, "NPC zombies never wear a hat (including outfit-forced and custom hats). Captured looks drop the hat. RandomizeLooks still rolls other slots."); noSash = ((BaseUnityPlugin)this).Config.Bind<bool>("Looks", "NoSash", false, "NPC zombies never wear a sash. Captured looks drop the sash. RandomizeLooks still rolls other slots."); showPauseMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "ShowPauseMenuButton", false, "Add a PEAK Zombies button to the pause menu."); menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Menu", "MenuKey", (KeyCode)122, "Open the in-game PEAK Zombies menu (used with MenuModifier). Also available from the pause menu."); menuModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Menu", "MenuModifier", (KeyCode)306, "Optional modifier. Default LeftControl (Ctrl+Z). Set to None to use MenuKey alone."); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Log each spawn, cull skip, and Tenderfoot registration. Leave off during normal play."); } private ConfigEntry<float> BindStat(string key, float defaultValue, string description) { return ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", key, defaultValue, description); } private ConfigEntry<float> BindMoveScale(string key, string description) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>("Zombie Stats", key, 1f, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); } private static float ScaleOrDefault(ConfigEntry<float> entry) { if (entry == null) { return 1f; } return Mathf.Max(0f, entry.Value); } private void LogStartupSummary() { //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) logger.LogInfo((object)("Global zombies: " + (ZombiesDisabled ? "DISABLED" : "ENABLED"))); logger.LogInfo((object)("Force zombies: " + (ForceZombies ? "ON" : "OFF"))); logger.LogInfo((object)("Tenderfoot override: " + (AllowTenderfootZombies ? "ON" : "OFF"))); logger.LogInfo((object)("Player zombification: " + (PreventPlayerZombification ? "BLOCKED" : "ALLOWED"))); logger.LogInfo((object)("Distance culling: " + (DisableDistanceCulling ? "DISABLED" : ("ON (" + CullDistance + "m)")))); logger.LogInfo((object)("Around-player spawn: " + (AroundPlayerSpawnEnabled ? (zombiesPerSpawn.Value + " every " + autoSpawnInterval.Value + "s") : "OFF"))); logger.LogInfo((object)("Vanilla-style spawners: " + (VanillaStyleEnabled ? "ON" : "OFF"))); if (RandomizeLooks) { logger.LogInfo((object)("Zombie looks: random catalog (capture key " + ((object)captureLookKey.Value/*cast due to .constrained prefix*/).ToString() + ")")); } else if (HasCachedLook) { logger.LogInfo((object)("Zombie looks: cached passport " + CachedLook)); } else { logger.LogInfo((object)("Zombie looks: vanilla skirt/shorts. Press " + ((object)captureLookKey.Value/*cast due to .constrained prefix*/).ToString() + " to snapshot your passport.")); } if (bypassMaxZombieLimit.Value && disableDistanceCulling.Value) { logger.LogWarning((object)"UnlimitedZombies and NeverDespawnFarZombies are both on. Expect a large FPS drop."); } } internal static void LogInfo(string message) { if (logger != null) { logger.LogInfo((object)message); } } internal static void LogWarning(string message) { if (logger != null) { logger.LogWarning((object)message); } } internal static void LogVerbose(string message) { if ((Object)(object)_instance != (Object)null && _instance.VerboseLogging && logger != null) { logger.LogInfo((object)message); } } internal static void LogOnce(ref bool flag, string message) { if (!flag && logger != null) { flag = true; logger.LogWarning((object)message); } } internal static void LogOnce(ref bool flag, string message, Exception ex) { if (!flag && logger != null) { flag = true; logger.LogError((object)(message + " " + ex)); } } internal static void RefreshAllZombieVisuals() { ZombiesAnywhereMod instance = Instance; if ((Object)(object)instance == (Object)null) { return; } MushroomZombie[] array = Object.FindObjectsOfType<MushroomZombie>(); if (array == null) { return; } for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { instance.ApplyMushroomVisuals(array[i]); } } } internal static bool CanEditGameplaySettings() { if (PhotonNetwork.InRoom) { return PhotonNetwork.IsMasterClient; } return true; } internal bool IsMenuHotkeyDown() { //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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Invalid comparison between Unknown and I4 //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 if (ZombiesMenu.IsListeningForHotkey) { return false; } KeyCode val = (KeyCode)((menuKey == null) ? 122 : ((int)menuKey.Value)); if ((int)val == 0) { return false; } KeyCode val2 = (KeyCode)((menuModifier == null) ? 306 : ((int)menuModifier.Value)); if ((int)val2 == 0) { return Input.GetKeyDown(val); } bool flag = Input.GetKey(val2); if ((int)val2 == 306 || (int)val2 == 305) { flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } else if ((int)val2 == 308 || (int)val2 == 307) { flag = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } else if ((int)val2 == 304 || (int)val2 == 303) { flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } if (flag) { return Input.GetKeyDown(val); } return false; } internal static bool GetShowPauseMenuButton() { if ((Object)(object)Instance != (Object)null && Instance.showPauseMenuButton != null) { return Instance.showPauseMenuButton.Value; } return false; } internal unsafe static string PrettyKey(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0038: Expected I4, but got Unknown //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 if ((int)key <= 13) { if ((int)key == 0) { return "None"; } if ((int)key == 13) { return "Enter"; } } else { if ((int)key == 27) { return "Esc"; } switch (key - 303) { case 3: return "Left Ctrl"; case 2: return "Right Ctrl"; case 5: return "Left Alt"; case 4: return "Right Alt"; case 1: return "Left Shift"; case 0: return "Right Shift"; } } string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Alpha", StringComparison.Ordinal) && text.Length == 6) { return text.Substring(5); } return text; } internal void SetDisableZombies(bool value) { if (disableZombies != null) { disableZombies.Value = value; } } internal void SetForceZombies(bool value) { if (forceZombies != null) { forceZombies.Value = value; } } internal void SetPreventPlayerZombification(bool value) { if (preventPlayerZombification != null) { preventPlayerZombification.Value = value; } } internal void SetAroundPlayerSpawn(bool value) { if (autoSpawnEnabled != null) { autoSpawnEnabled.Value = value; } } internal void SetVanillaStyleEnabled(bool value) { if (vanillaStyleEnabled != null) { vanillaStyleEnabled.Value = value; } } internal void SetUnlimitedZombies(bool value) { if (bypassMaxZombieLimit != null) { bypassMaxZombieLimit.Value = value; } } internal void SetNeverDespawnFar(bool value) { if (disableDistanceCulling != null) { disableDistanceCulling.Value = value; } } internal void SetHideMushroomVisuals(bool value) { if (hideMushroomVisuals != null) { hideMushroomVisuals.Value = value; } } internal void SetAllowVanillaAfflictions(bool value) { if (allowVanillaAfflictions != null) { allowVanillaAfflictions.Value = value; } } internal void SetInstantPassOutRagdoll(bool value) { if (instantPassOutRagdoll != null) { instantPassOutRagdoll.Value = value; } } internal void SetPassOutSeconds(float seconds) { if (passOutSeconds != null) { passOutSeconds.Value = Mathf.Max(0f, seconds); } if (instantPassOutRagdoll != null) { instantPassOutRagdoll.Value = seconds <= 0.001f; } } internal void SetDownedSeconds(float seconds) { if (downedSeconds != null) { downedSeconds.Value = seconds; } } internal void SetSkipPassOut(bool skip) { if (skipPassOut != null) { skipPassOut.Value = skip; } } internal void SetBoneMode(ZombieBoneMode mode) { if (boneMode != null) { boneMode.Value = mode.ToString(); } } internal void SetCanRecoverFromPassOut(bool recover) { if (canRecoverFromPassOut != null) { canRecoverFromPassOut.Value = recover; } } internal void SetCorpseLifetime(float seconds) { if (corpseLifetime != null) { corpseLifetime.Value = seconds; } } internal void SetSkeletonLifetime(float seconds) { if (skeletonLifetime != null) { skeletonLifetime.Value = seconds; } } internal void SetBeesAffectZombies(bool value) { if (beesAffectZombies != null) { beesAffectZombies.Value = value; } } internal void SetStatusFieldsAffectZombies(bool value) { if (statusFieldsAffectZombies != null) { statusFieldsAffectZombies.Value = value; } } internal void SetBeetlesAffectZombies(bool value) { if (beetlesAffectZombies != null) { beetlesAffectZombies.Value = value; } } internal void SetFlytrapsAffectZombies(bool value) { if (flytrapsAffectZombies != null) { flytrapsAffectZombies.Value = value; } } internal void SetScorpionsAffectZombies(bool value) { if (scorpionsAffectZombies != null) { scorpionsAffectZombies.Value = value; } } internal void SetCannonsAffectZombies(bool value) { if (cannonsAffectZombies != null) { cannonsAffectZombies.Value = value; } } internal void SetScoutmasterHuntsZombies(bool value) { if (scoutmasterHuntsZombies != null) { scoutmasterHuntsZombies.Value = value; } } internal void AddDirector() { directorLock++; if (directorLock == 1) { StopAutoSpawning(); logger.LogInfo((object)"Spawn director active — PEAK Zombies built-in spawners paused."); } } internal void RemoveDirector() { if (directorLock > 0) { directorLock--; if (directorLock == 0) { logger.LogInfo((object)"Spawn director released."); TryResumeBuiltInSpawning(); } } } internal void TryResumeBuiltInSpawning() { if (!DirectorActive && !ZombiesDisabled && !IsAirport() && PhotonNetwork.IsMasterClient && (AroundPlayerSpawnEnabled || VanillaStyleEnabled)) { if (initCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(initCoroutine); initCoroutine = null; } initCoroutine = ((MonoBehaviour)this).StartCoroutine(DelayedInitialization()); } } private void OnConfigChanged(object sender, SettingChangedEventArgs e) { if (!HostHandshake.IsSyncingFromNet && e != null) { if ((object)e.ChangedSetting == hideMushroomVisuals || (object)e.ChangedSetting == enableMushroomGrowth) { HostHandshake.NotifyHostSettingsChanged(); RefreshAllZombieVisuals(); } if ((object)e.ChangedSetting == allowVanillaAfflictions) { HostHandshake.NotifyHostSettingsChanged(); } ZombiesMenu.RefreshIfOpen(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { cachedPrefabName = null; vanillaMaxActiveZombies = -1; VanillaStyleScatter.Reset(); ZombiesMenu.OnAfterSceneLoad(); if (initCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(initCoroutine); initCoroutine = null; } StopAutoSpawning(); if (DirectorActive) { logger.LogInfo((object)"Spawn director active — skipping built-in spawn setup."); } else if (ZombiesDisabled) { logger.LogInfo((object)"Global zombies disabled — skipping spawn setup."); } else if (IsAirport()) { logger.LogInfo((object)"Airport scene — zombies will not spawn here."); } else if (AroundPlayerSpawnEnabled || VanillaStyleEnabled) { initCoroutine = ((MonoBehaviour)this).StartCoroutine(DelayedInitialization()); } } private IEnumerator DelayedInitialization() { yield return (object)new WaitForSeconds(Mathf.Max(0f, initialSpawnDelay.Value)); if (ZombiesDisabled) { yield break; } while (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { yield return (object)new WaitForSeconds(1f); if (ZombiesDisabled) { yield break; } } while (IsAirport()) { yield return (object)new WaitForSeconds(2f); if (ZombiesDisabled) { yield break; } } ApplyManagerCap(ZombieManager.Instance); logger.LogInfo((object)"Climb map ready."); VanillaStyleScatter.RequestCurrentSegment(); if (AroundPlayerSpawnEnabled && PhotonNetwork.IsMasterClient) { SpawnInitialZombies(); } if (AroundPlayerSpawnEnabled && autoSpawnInterval.Value > 0f) { StartAutoSpawning(autoSpawnInterval.Value, autoSpawnRadius.Value); } initCoroutine = null; } internal void ApplyManagerCap(ZombieManager manager) { if (!((Object)(object)manager == (Object)null)) { if (vanillaMaxActiveZombies < 0) { vanillaMaxActiveZombies = manager.maxActiveZombies; } int effectiveMaxZombies = GetEffectiveMaxZombies(manager); if (manager.maxActiveZombies != effectiveMaxZombies) { manager.maxActiveZombies = effectiveMaxZombies; } } } internal int GetEffectiveMaxZombies(ZombieManager manager) { if (bypassMaxZombieLimit.Value) { return int.MaxValue; } if (customMaxZombies.Value > 0) { return customMaxZombies.Value; } if (vanillaMaxActiveZombies >= 0) { return vanillaMaxActiveZombies; } if (!((Object)(object)manager != (Object)null)) { return 0; } return manager.maxActiveZombies; } internal bool IsAtCap(ZombieManager manager) { if ((Object)(object)manager == (Object)null || bypassMaxZombieLimit.Value) { return false; } return manager.zombies.Count >= GetEffectiveMaxZombies(manager); } internal bool ShouldForceZombies() { if (ZombiesDisabled) { return false; } if (ForceZombies) { return true; } if (!AllowTenderfootZombies || Ascents.currentAscent >= 0) { return false; } return RunSettings.GetValue((SETTINGTYPE)1400, false) != 0; } internal float GetZombificationSporeThreshold() { if (zombificationSporeThreshold == null || zombificationSporeThreshold.Value < 0f) { return 0.5f; } return zombificationSporeThreshold.Value; } internal static bool IsAirport() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (!string.IsNullOrEmpty(name) && name.IndexOf("Airport", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null) { return localCharacter.inAirport; } return false; } internal bool AllowsVanillaStyleSegment(int index, BiomeType biome) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (AllowsVanillaStyleBiome(biome)) { return true; } if (!VanillaStyleScatter.IsKilnOrCitadelSlot(index)) { return false; } if (!BiomeListContains("Citadel") && !BiomeListContains("Kiln")) { return BiomeListContains("TheKiln"); } return true; } internal bool AllowsVanillaStyleBiome(BiomeType biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) if ((int)biome == 7) { return VanillaStyleIncludeRoots; } string[] array = SplitBiomeList(); for (int i = 0; i < array.Length; i++) { if (BiomeNameMatches(array[i], biome)) { return true; } } return false; } private bool BiomeListContains(string name) { if (string.IsNullOrEmpty(name)) { return false; } string[] array = SplitBiomeList(); for (int i = 0; i < array.Length; i++) { if (string.Equals(array[i], name, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private string[] SplitBiomeList() { string text = ((vanillaStyleBiomes != null) ? vanillaStyleBiomes.Value : string.Empty); if (string.IsNullOrEmpty(text)) { return new string[0]; } string[] array = text.Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { array[i] = array[i].Trim(); } return array; } private unsafe static bool BiomeNameMatches(string configured, BiomeType biome) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 if (string.IsNullOrEmpty(configured)) { return false; } if (string.Equals(configured, ((object)(*(BiomeType*)(&biome))/*cast due to .constrained prefix*/).ToString(), StringComparison.OrdinalIgnoreCase)) { return true; } if ((int)biome == 8) { return string.Equals(configured, "Gloom", StringComparison.OrdinalIgnoreCase); } if ((int)biome == 9) { return string.Equals(configured, "Citadel", StringComparison.OrdinalIgnoreCase); } if ((int)biome == 0) { return string.Equals(configured, "Beach", StringComparison.OrdinalIgnoreCase); } if ((int)biome == 3) { return string.Equals(configured, "Caldera", StringComparison.OrdinalIgnoreCase); } return false; } internal static void BeginArmedSpawn() { armSpawnDepth++; } internal static void EndArmedSpawn() { if (armSpawnDepth > 0) { armSpawnDepth--; } } internal static void TagAggroOnSpawn(MushroomZombie zombie) { if (!((Object)(object)zombie == (Object)null)) { ModSpawnedZombie modSpawnedZombie = ((Component)zombie).GetComponent<ModSpawnedZombie>(); if ((Object)(object)modSpawnedZombie == (Object)null) { modSpawnedZombie = ((Component)zombie).gameObject.AddComponent<ModSpawnedZombie>(); } modSpawnedZombie.aggroOnSpawn = true; } } internal static void ArmAroundPlayerZombie(MushroomZombie zombie) { TagAggroOnSpawn(zombie); } internal static bool ShouldForceAggro(MushroomZombie zombie) { if ((Object)(object)zombie != (Object)null) { return zombie.isNPCZombie; } return false; } internal static Character FindClosestPlayer(MushroomZombie zombie, Character ignoredCharacter) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)zombie == (Object)null || (Object)(object)zombie.character == (Object)null) { return Character.localCharacter; } Character val = null; float num = float.MaxValue; Character character = zombie.character; List<Character> allCharacters = Character.AllCharacters; if (allCharacters != null) { for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)ignoredCharacter || (Object)(object)val2 == (Object)(object)character || val2.isZombie || val2.isBot || val2.data.dead) { continue; } ZombiesAnywhereMod instance = Instance; if (!val2.data.fullyPassedOut || (!((Object)(object)instance == (Object)null) && instance.AttackUnconsciousPlayers)) { float num2 = Vector3.Distance(val2.Center, character.Center); if ((Object)(object)val == (Object)null || num2 < num) { val = val2; num = num2; } } } } if ((Object)(object)val != (Object)null) { return val; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter != (Object)(object)character && !localCharacter.isZombie && !localCharacter.data.dead) { return localCharacter; } return null; } internal static void AssignTarget(MushroomZombie zombie, Character target, float forceSeconds) { if ((Object)(object)zombie == (Object)null || (Object)(object)target == (Object)null) { return; } bool num = (Object)(object)zombie._currentTarget == (Object)(object)target; zombie._currentTarget = target; if (forceSeconds > 0f) { zombie.targetForcedUntil = Time.time + forceSeconds; } zombie.discovered = target; if (num || (Object)(object)zombie.view == (Object)null || !zombie.view.IsMine || (Object)(object)((MonoBehaviourPun)target).photonView == (Object)null) { return; } try { zombie.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)1, new object[2] { ((MonoBehaviourPun)target).photonView.ViewID, forceSeconds }); } catch (Exception ex) { LogOnce(ref loggedStartError, "RPCA_SetCurrentTarget failed.", ex); } } internal static bool IsPassingOut(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return false; } if (character.data.dead || character.data.passedOut || character.data.fullyPassedOut) { return true; } if (character.refs != null && (Object)(object)character.refs.afflictions != (Object)null) { return character.refs.afflictions.shouldPassOut; } return false; } internal static bool ShouldHaltNpcAi(MushroomZombie zombie) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if ((Object)(object)zombie == (Object)null || !zombie.isNPCZombie) { return false; } if ((int)zombie.currentState == 6 || ZombieDeath.IsLeaveRagdollCorpse(zombie)) { return true; } return IsPassingOut(zombie.character); } internal static bool ShouldHaltNpcAi(Character character) { if ((Object)(object)character == (Object)null || !character.isZombie) { return false; } return ShouldHaltNpcAi(((Component)character).GetComponent<MushroomZombie>()); } internal static void HaltZombieAi(MushroomZombie zombie) { //IL_002c: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 if ((Object)(object)zombie == (Object)null) { return; } try { zombie.ResetInput(); if ((Object)(object)zombie.biteColliderObject != (Object)null) { zombie.biteColliderObject.SetActive(false); } State currentState = zombie.currentState; if ((int)currentState == 3 || (int)currentState == 4 || (int)currentState == 5) { zombie.currentState = (State)2; if ((Object)(object)zombie.view != (Object)null && zombie.view.IsMine) { zombie.PushState(); } } } catch (Exception ex) { LogOnce(ref loggedPassOutError, "HaltZombieAi failed.", ex); } } internal static bool ContinueAi(MushroomZombie zombie) { if (!ShouldHaltNpcAi(zombie)) { return true; } HaltZombieAi(zombie); return false; } internal static void ForceStandAndChase(MushroomZombie zombie) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if ((Object)(object)zombie == (Object)null) { return; } if (ShouldHaltNpcAi(zombie)) { HaltZombieAi(zombie); return; } State currentState = zombie.currentState; Character currentTarget = zombie._currentTarget; bool flag = (int)currentState == 3 || (int)currentState == 4 || (int)currentState == 5; if (flag && (Object)(object)currentTarget != (Object)null && !currentTarget.isZombie && !currentTarget.data.dead) { return; } TagAggroOnSpawn(zombie); try { Character character = zombie.character; ModSpawnedZombie component = ((Component)zombie).GetComponent<ModSpawnedZombie>(); if ((Object)(object)character != (Object)null && ((Object)(object)component == (Object)null || !component.stoodUp)) { character.data.fallSeconds = 0f; character.data.passedOut = false; character.data.fullyPassedOut = false; if (character.refs != null) { if ((Object)(object)character.refs.animations != (Object)null) { character.refs.animations.ResetForceSpeed(); } if ((Object)(object)character.refs.ragdoll != (Object)null) { character.refs.ragdoll.ToggleKinematic(false); } } if ((Object)(object)component != (Object)null) { component.stoodUp = true; } } Character val = FindClosestPlayer(zombie, null); if ((Object)(object)val != (Object)null) { AssignTarget(zombie, val, 1f); } zombie.timeSpentWakingUp = 0f; zombie.idledFor = 99f; zombie.sinceLookForTarget = 99f; if (!flag) { zombie.StartChasing(); } } catch (Exception ex) { LogOnce(ref loggedStartError, "ForceStandAndChase failed.", ex); } } private void SpawnInitialZombies() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0045: Unknown result type (might be due to invalid IL or missing references) if (!ZombiesDisabled) { Vector3 spawnCenter = GetSpawnCenter(); if (!(spawnCenter == Vector3.zero)) { LogVerbose("Spawning " + initialSpawnCount.Value + " initial zombies."); SpawnZombiesAround(spawnCenter, autoSpawnRadius.Value, initialSpawnCount.Value); } } } private Vector3 GetSpawnCenter() { //IL_0013: 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_001e: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0051: 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 (Character.AllCharacters == null || Character.AllCharacters.Count == 0) { return Vector3.zero; } Vector3 val = Vector3.zero; int num = 0; for (int i = 0; i < Character.AllCharacters.Count; i++) { Character val2 = Character.AllCharacters[i]; if ((Object)(object)val2 != (Object)null && !val2.isZombie && !val2.isBot) { val += val2.Center; num++; } } if (num == 0) { return Vector3.zero; } return val / (float)num; } public static MushroomZombie SpawnZombieAt(Vector3 position, Quaternion rotation = default(Quaternion), MushroomZombie zombiePrefab = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return SpawnZombieAt(position, rotation, zombiePrefab, ignoreCap: false, ignoreDisabled: false); } internal unsafe static MushroomZombie SpawnZombieAt(Vector3 position, Quaternion rotation, MushroomZombie zombiePrefab, bool ignoreCap, bool ignoreDisabled) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00b0: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (!ignoreDisabled && (Object)(object)_instance != (Object)null && _instance.ZombiesDisabled) { return null; } if (!PhotonNetwork.IsMasterClient) { return null; } ZombieManager instance = ZombieManager.Instance; if (!ignoreCap && (Object)(object)_instance != (Object)null && _instance.IsAtCap(instance)) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)"Max active zombies reached. Cannot spawn more."); } return null; } string text = (((Object)(object)zombiePrefab != (Object)null) ? ((Object)((Component)zombiePrefab).gameObject).name : GetZombiePrefabName()); if (string.IsNullOrEmpty(text)) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)"Could not resolve the NPC zombie prefab name."); } return null; } Quaternion rotation2 = (((Quaternion)(ref rotation)).Equals(default(Quaternion)) ? Quaternion.identity : rotation); GameObject val = TryInstantiateZombie(text, position, rotation2); if ((Object)(object)val == (Object)null) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)("Failed to instantiate zombie prefab '" + text + "'.")); } return null; } MushroomZombie component = val.GetComponent<MushroomZombie>(); if ((Object)(object)component == (Object)null) { ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogError((object)"Spawned object is not a MushroomZombie."); } PhotonNetwork.Destroy(val); return null; } LogVerbose("Spawned zombie at " + ((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString()); ArmAroundPlayerZombie(component); ZombiesApi.RaiseSpawned(component); return component; } internal static MushroomZombie SpawnDebugZombieAt(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return SpawnZombieAt(position, Quaternion.identity, null, ignoreCap: true, ignoreDisabled: true); } internal static bool DestroyZombie(MushroomZombie zombie) { if ((Object)(object)zombie == (Object)null || (Object)(object)((Component)zombie).gameObject == (Object)null) { return false; } if (!PhotonNetwork.IsMasterClient) { return false; } PhotonView val = (((Object)(object)zombie.view != (Object)null) ? zombie.view : ((Component)zombie).GetComponent<PhotonView>()); if ((Object)(object)val == (Object)null || !val.IsMine) { return false; } ZombiesApi.RaiseDespawning(zombie); PhotonNetwork.Destroy(((Component)zombie).gameObject); return true; } public static List<MushroomZombie> SpawnZombiesAround(Vector3 center, float radius, int count) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //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_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_0042: 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) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_005f: 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.IsAtCap(instance)) { break; } Vector2 val = Random.insideUnitCircle * radius; MushroomZombie val2 = SpawnZombieAt(FindGroundPosition(center + new Vector3(val.x, 0f, val.y))); if ((Object)(object)val2 != (Object)null) { list.Add(val2); } } return list; } private static GameObject TryInstantiateZombie(string preferredName, Vector3 position, Quaternion rotation) { //IL_0041: 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) string[] array = new string[3] { preferredName, "MushroomZombie", "0_Items/MushroomZombie" }; for (int i = 0; i < array.Length; i++) { string text = array[i]; if (string.IsNullOrEmpty(text) || (i > 0 && text == array[0])) { continue; } try { BeginArmedSpawn(); GameObject val = PhotonNetwork.Instantiate(text, position, rotation, (byte)0, (object[])null); if ((Object)(object)val != (Object)null) { cachedPrefabName = text; return val; } } catch (Exception ex) { ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("PhotonNetwork.Instantiate('" + text + "') failed: " + ex.Message)); } } finally { EndArmedSpawn(); } } return null; } private static string GetZombiePrefabName() { if (!string.IsNullOrEmpty(cachedPrefabName)) { return cachedPrefabName; } ZombieManager instance = ZombieManager.Instance; if ((Object)(object)instance != (Object)null && instance.spawners != null) { for (int i = 0; i < instance.spawners.Count; i++) { MushroomZombieSpawner val = instance.spawners[i]; if ((Object)(object)val != (Object)null && (Object)(object)val.mushroomZombiePrefab != (Object)null) { cachedPrefabName = ((Object)((Component)val.mushroomZombiePrefab).gameObject).name; return cachedPrefabName; } } } cachedPrefabName = "MushroomZombie"; return cachedPrefabName; } internal static Vector3 FindGroundPosition(Vector3 position) { //IL_0000: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0051: 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_006c: 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) int num = LayerMask.op_Implicit(HelperFunctions.terrainMapMask); RaycastHit val = default(RaycastHit); if (Physics.Raycast(position + Vector3.up * 10f, Vector3.down, ref val, 100f, num)) { return ((RaycastHit)(ref val)).point; } 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.ZombiesDisabled && !_instance.DirectorActive && _instance.AroundPlayerSpawnEnabled && _instance.autoSpawnCoroutine == null) { _instance.autoSpawnCoroutine = ((MonoBehaviour)_instance).StartCoroutine(_instance.AutoSpawnCoroutine(intervalSeconds, spawnRadius)); ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Auto-spawning started: " + intervalSeconds + "s interval, " + spawnRadius + " unit radius.")); } } } public void StopAutoSpawning() { if (autoSpawnCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(autoSpawnCoroutine); autoSpawnCoroutine = null; } } private IEnumerator AutoSpawnCoroutine(float intervalSeconds, float spawnRadius) { WaitForSeconds wait = new WaitForSeconds(intervalSeconds); while (true) { yield return wait; if (ZombiesDisabled || DirectorActive || !AroundPlayerSpawnEnabled) { break; } if (!PhotonNetwork.IsMasterClient || IsAirport()) { continue; } Vector3 spawnCenter = GetSpawnCenter(); if (!(spawnCenter == Vector3.zero)) { int count = SpawnZombiesAround(spawnCenter, spawnRadius, zombiesPerSpawn.Value).Count; if (count > 0) { int num = (((Object)(object)ZombieManager.Instance != (Object)null) ? ZombieManager.Instance.zombies.Count : count); LogVerbose("Auto-spawned " + count + " zombie(s). Active: " + num); } } } autoSpawnCoroutine = null; } internal void ApplyZombieTuning(MushroomZombie zombie) { //IL_01cc: 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_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: 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; } float num = zombieGruntWaitMin.Value; float num2 = zombieGruntWaitMax.Value; if (num > num2) { float num3 = num; num = num2; num2 = num3; } zombie.zombieGruntWaitTimeMinMax = new Vector2(num, num2); zombie.attackHeightDelta = attackHeightDelta.Value; float num4 = ((mushroomGrowTimeMin.Value >= 0f) ? mushroomGrowTimeMin.Value : zombie.minMaxMushroomGrowTime.x); float num5 = ((mushroomGrowTimeMax.Value >= 0f) ? mushroomGrowTimeMax.Value : zombie.minMaxMushroomGrowTime.y); if (mushroomGrowTimeMin.Value >= 0f || mushroomGrowTimeMax.Value >= 0f) { zombie.minMaxMushroomGrowTime = new Vector2(num4, num5); } if (removeZombieLifetime.Value) { zombie.lifetime = 3.1536E+09f; } else if (zombieLifetimeOverride.Value > 0f) { zombie.lifetime = zombieLifetimeOverride.Value; } ApplyMushroomVisuals(zombie); } } private void ApplyMushroomVisuals(MushroomZombie zombie) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (EffectiveHideMushroomVisu