Decompiled source of ButteryFixes v1.4.1

ButteryFixes.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ButteryFixes.Utility;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ButteryFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bundle of miscellaneous vanilla-compatible fixes")]
[assembly: AssemblyFileVersion("1.4.1.0")]
[assembly: AssemblyInformationalVersion("1.4.1")]
[assembly: AssemblyProduct("ButteryFixes")]
[assembly: AssemblyTitle("ButteryFixes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ButteryFixes
{
	internal enum MusicDopplerLevel
	{
		Vanilla = -1,
		None,
		Reduced
	}
	internal enum GameResolution
	{
		DontChange = -1,
		Low,
		High
	}
	[BepInPlugin("butterystancakes.lethalcompany.butteryfixes", "Buttery Fixes", "1.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private const string PLUGIN_GUID = "butterystancakes.lethalcompany.butteryfixes";

		private const string PLUGIN_NAME = "Buttery Fixes";

		private const string PLUGIN_VERSION = "1.4.1";

		internal static ManualLogSource Logger;

		internal static bool DISABLE_LADDER_PATCH;

		internal static bool ENABLE_SCAN_PATCH;

		internal static bool GENERAL_IMPROVEMENTS;

		internal static ConfigEntry<MusicDopplerLevel> configMusicDopplerLevel;

		internal static ConfigEntry<GameResolution> configGameResolution;

		internal static ConfigEntry<bool> configMakeConductive;

		internal static ConfigEntry<bool> configMaskHornetsPower;

		internal static ConfigEntry<bool> configFixJumpCheese;

		internal static ConfigEntry<bool> configKeysAreScrap;

		private void Awake()
		{
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			if (Chainloader.PluginInfos.ContainsKey("inoyu.FastClimbing") || Chainloader.PluginInfos.ContainsKey("e3s1.BetterLadders"))
			{
				Logger.LogInfo((object)"CROSS-COMPATIBILITY - Ladder patch will be disabled");
				DISABLE_LADDER_PATCH = true;
			}
			GENERAL_IMPROVEMENTS = Chainloader.PluginInfos.ContainsKey("ShaosilGaming.GeneralImprovements");
			configGameResolution = ((BaseUnityPlugin)this).Config.Bind<GameResolution>("Visual", "GameResolution", GameResolution.DontChange, "The internal resolution rendered by the game. There are unused resolution presets in the game data that you can enable using this option.\n\"DontChange\" makes no changes - vanilla is 860x520, but this setting is also compatible with other resolution mods.\n\"Low\" is 620x350. \"High\" is 970x580.");
			configMusicDopplerLevel = ((BaseUnityPlugin)this).Config.Bind<MusicDopplerLevel>("Audio", "MusicDopplerLevel", MusicDopplerLevel.Vanilla, "Controls how much Unity's simulated \"doppler effect\" applies to music sources like the dropship, boombox, etc. (This is what causes pitch distortion when moving towards/away from the source of the music)\n\"Vanilla\" makes no changes. \"Reduced\" will make the effect more subtle. \"None\" will disable it completely (so music always plays at the correct pitch)");
			configMakeConductive = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "MakeConductive", true, "(Host only) Makes some metallic items that are non-conductive in vanilla actually conductive. This fix applies sensibly to the existing items, but you can disable it if you are used to vanilla's properties.");
			configMaskHornetsPower = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "MaskHornetsPower", false, "(Host only) Mask hornets internally have the same power level as butlers, but because they spawn in a non-standard way, they don't contribute to the indoor power. Enabling this will prevent additional monsters spawning to replace dead butlers.");
			configFixJumpCheese = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "FixJumpCheese", true, "(Host only) Enabling this makes enemies hear players jumping and landing on the floor. This fixes the exploit where you can silently move past dogs with sprinting speed by spamming the jump button.");
			configKeysAreScrap = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "KeysAreScrap", false, "(Host only) Enabling this will allow you to sell keys for $3 as listed, but will also cause them to be lost if all players die. If this is disabled, they will no longer show \"Value: $3\" on the scanner, instead.");
			new Harmony("butterystancakes.lethalcompany.butteryfixes").PatchAll();
			Logger.LogInfo((object)"Buttery Fixes v1.4.1 loaded");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "ButteryFixes";

		public const string PLUGIN_NAME = "ButteryFixes";

		public const string PLUGIN_VERSION = "1.4.1";
	}
}
namespace ButteryFixes.Utility
{
	internal class GlobalReferences
	{
		internal static Dictionary<string, EnemyType> allEnemiesList = new Dictionary<string, EnemyType>();

		internal static float dopplerLevelMult = 1f;

		internal static float nutcrackerSyncDistance = 1f;

		internal static Mesh tragedyMask;

		internal static Mesh tragedyMaskLOD;

		internal static Mesh tragedyMaskEyesFilled;

		internal static Material tragedyMaskMat;

		internal static AudioClip[] tragedyMaskRandomClips;
	}
	internal static class NonPatchFunctions
	{
		internal static bool[] playerWasLastSprinting = new bool[50];

		public static void ShotgunPreProcess(Vector3 shotgunPosition, ref int num, ref RaycastHit[] results)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			int num2 = 0;
			HashSet<EnemyAI> hashSet = new HashSet<EnemyAI>();
			List<RaycastHit> list = new List<RaycastHit>();
			RaycastHit[] array = (from hit in results.Take(num)
				orderby Vector3.Distance(shotgunPosition, ((RaycastHit)(ref hit)).point)
				select hit).ToArray();
			EnemyAICollisionDetect val = default(EnemyAICollisionDetect);
			for (int i = 0; i < num; i++)
			{
				if (!((Component)((RaycastHit)(ref array[i])).transform).TryGetComponent<EnemyAICollisionDetect>(ref val) || val.onlyCollideWhenGrounded)
				{
					continue;
				}
				EnemyAI mainScript = val.mainScript;
				if (!hashSet.Add(mainScript))
				{
					continue;
				}
				EnemyType enemyType = mainScript.enemyType;
				if (!enemyType.canDie || ((Object)enemyType).name == "RadMech" || ((Object)enemyType).name == "DocileLocustBees")
				{
					list.Add(array[i]);
				}
				else if (!mainScript.isEnemyDead)
				{
					results[num2] = array[i];
					num2++;
					if (num2 == 10)
					{
						num = 10;
						return;
					}
				}
			}
			if (list.Count > 0)
			{
				foreach (RaycastHit item in list.OrderByDescending((RaycastHit invincible) => ((Component)((RaycastHit)(ref invincible)).transform).GetComponent<EnemyAICollisionDetect>().mainScript is BlobAI))
				{
					results[num2] = item;
					num2++;
					if (num2 == 10)
					{
						num = 10;
						return;
					}
				}
			}
			num = num2;
		}

		internal static IEnumerator ShellsAppearAfterDelay(ShotgunItem shotgun)
		{
			yield return (object)new WaitForSeconds(((GrabbableObject)shotgun).isHeldByEnemy ? 0.85f : 1.9f);
			if (((GrabbableObject)shotgun).isHeldByEnemy)
			{
				((Renderer)shotgun.shotgunShellLeft).forceRenderingOff = false;
				((Renderer)shotgun.shotgunShellLeft).enabled = true;
				((Renderer)shotgun.shotgunShellRight).forceRenderingOff = false;
				((Renderer)shotgun.shotgunShellRight).enabled = true;
			}
			else if (((Renderer)shotgun.shotgunShellLeft).enabled)
			{
				((Renderer)shotgun.shotgunShellRight).enabled = true;
			}
			else
			{
				((Renderer)shotgun.shotgunShellLeft).enabled = true;
			}
			yield return (object)new WaitForSeconds(((GrabbableObject)shotgun).isHeldByEnemy ? 0.66f : 0.75f);
			if (!((GrabbableObject)shotgun).isHeldByEnemy)
			{
				yield return (object)new WaitUntil((Func<bool>)(() => !shotgun.isReloading));
			}
			((Renderer)shotgun.shotgunShellLeft).forceRenderingOff = true;
			((Renderer)shotgun.shotgunShellRight).forceRenderingOff = true;
			Plugin.Logger.LogInfo((object)$"Finished animating shotgun shells (held by enemy: {((GrabbableObject)shotgun).isHeldByEnemy})");
		}

		internal static void FakeFootstepAlert(PlayerControllerB player)
		{
			//IL_0067: 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)
			bool flag = player.isInHangarShipRoom && StartOfRound.Instance.hangarDoorsClosed;
			if (((NetworkBehaviour)player).IsOwner ? player.isSprinting : playerWasLastSprinting[player.actualClientId])
			{
				RoundManager.Instance.PlayAudibleNoise(((Component)player).transform.position, 22f, 0.6f, 0, flag, 3322);
			}
			else
			{
				RoundManager.Instance.PlayAudibleNoise(((Component)player).transform.position, 17f, 0.4f, 0, flag, 3322);
			}
		}

		internal static void ConvertMaskToTragedy(Transform mask)
		{
			Transform val = mask.Find("Mesh");
			if ((Object)(object)val != (Object)null && (Object)(object)GlobalReferences.tragedyMask != (Object)null && (Object)(object)GlobalReferences.tragedyMaskMat != (Object)null)
			{
				((Component)val).GetComponent<MeshFilter>().mesh = GlobalReferences.tragedyMask;
				((Renderer)((Component)val).GetComponent<MeshRenderer>()).material = GlobalReferences.tragedyMaskMat;
				Transform obj = val.Find("EyesFilled");
				MeshFilter val2 = ((obj != null) ? ((Component)obj).GetComponent<MeshFilter>() : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)GlobalReferences.tragedyMaskEyesFilled != (Object)null)
				{
					val2.mesh = GlobalReferences.tragedyMaskEyesFilled;
					Transform obj2 = mask.Find("ComedyMaskLOD1");
					MeshFilter val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshFilter>() : null);
					if ((Object)(object)val3 != (Object)null && (Object)(object)GlobalReferences.tragedyMaskLOD != (Object)null)
					{
						val3.mesh = GlobalReferences.tragedyMaskLOD;
						((Renderer)((Component)val3).GetComponent<MeshRenderer>()).material = GlobalReferences.tragedyMaskMat;
						Plugin.Logger.LogInfo((object)"All mask attachment meshes replaced successfully");
					}
					else
					{
						Plugin.Logger.LogWarning((object)"Failed to replace mask attachment eyes");
					}
				}
				else
				{
					Plugin.Logger.LogWarning((object)"Failed to replace mask attachment LOD");
				}
			}
			else
			{
				Plugin.Logger.LogWarning((object)"Failed to replace mask attachment mesh");
			}
		}
	}
	internal class PrivateMembers
	{
		internal static readonly FieldInfo JETPACK_ACTIVATED = typeof(JetpackItem).GetField("jetpackActivated", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static readonly FieldInfo JETPACK_ITEM_PREVIOUS_PLAYER_HELD_BY = typeof(JetpackItem).GetField("previousPlayerHeldBy", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static readonly MethodInfo GLOBAL_NUTCRACKER_CLOCK = typeof(NutcrackerEnemyAI).GetMethod("GlobalNutcrackerClock", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static readonly FieldInfo IS_LEADER_SCRIPT = typeof(NutcrackerEnemyAI).GetField("isLeaderScript", BindingFlags.Instance | BindingFlags.NonPublic);
	}
	internal class ScriptableObjectOverrides
	{
		internal static void OverrideEnemyTypes()
		{
			foreach (KeyValuePair<string, EnemyType> allEnemies in GlobalReferences.allEnemiesList)
			{
				switch (allEnemies.Key)
				{
				case "RadMech":
					allEnemies.Value.requireNestObjectsToSpawn = true;
					Plugin.Logger.LogInfo((object)"Old Birds now require \"nest\" to spawn");
					break;
				case "MaskedPlayerEnemy":
					allEnemies.Value.isOutsideEnemy = false;
					Plugin.Logger.LogInfo((object)"\"Masked\" now subtract from indoor power level");
					break;
				case "Blob":
					allEnemies.Value.canDie = false;
					Plugin.Logger.LogInfo((object)"Hygroderes won't \"die\" when crushed by spike trap");
					break;
				}
				allEnemies.Value.numberSpawned = 0;
			}
		}

		internal static void OverrideSelectableLevels()
		{
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			foreach (SelectableLevel val in levels)
			{
				if (((Object)val).name == "RendLevel")
				{
					SpawnableMapObject val2 = ((IEnumerable<SpawnableMapObject>)val.spawnableMapObjects).FirstOrDefault((Func<SpawnableMapObject, bool>)delegate(SpawnableMapObject spawnableMapObject)
					{
						GameObject prefabToSpawn = spawnableMapObject.prefabToSpawn;
						return ((prefabToSpawn != null) ? ((Object)prefabToSpawn).name : null) == "SpikeRoofTrapHazard";
					});
					if (val2 != null)
					{
						val2.requireDistanceBetweenSpawns = true;
						Plugin.Logger.LogInfo((object)"Rend now properly spaces spike traps");
					}
				}
			}
		}

		internal static void OverrideItems()
		{
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>
			{
				{ "FancyCup", true },
				{ "Flask", false },
				{ "MoldPan", true },
				{ "Shotgun", true },
				{ "SprayPaint", true }
			};
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if ((Object)(object)items == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"Encountered a missing item in StartOfRound.allItemsList; this is probably an issue with another mod");
					continue;
				}
				switch (((Object)items).name)
				{
				case "Boombox":
					items.spawnPrefab.GetComponent<BoomboxItem>().boomboxAudio.dopplerLevel = 0.3f * GlobalReferences.dopplerLevelMult;
					Plugin.Logger.LogInfo((object)"Doppler level: Boombox");
					break;
				case "Cog1":
				case "EasterEgg":
				case "FishTestProp":
				case "MapDevice":
				case "RedLocustHive":
				case "ZapGun":
					items.spawnPrefab.GetComponent<AudioSource>().rolloffMode = (AudioRolloffMode)1;
					Plugin.Logger.LogInfo((object)("Audio rolloff: " + items.itemName));
					break;
				case "ExtensionLadder":
				case "RadarBooster":
					items.canBeInspected = false;
					Plugin.Logger.LogInfo((object)("Inspectable: " + items.itemName + " (False)"));
					break;
				case "Key":
				{
					if (Plugin.configKeysAreScrap.Value)
					{
						items.isScrap = true;
						Plugin.Logger.LogInfo((object)"Scrap: Key");
						break;
					}
					((GrabbableObject)items.spawnPrefab.GetComponent<KeyItem>()).scrapValue = 0;
					ScanNodeProperties componentInChildren = items.spawnPrefab.GetComponentInChildren<ScanNodeProperties>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						componentInChildren.subText = string.Empty;
						Plugin.Logger.LogInfo((object)"Scan node: Key");
					}
					break;
				}
				case "Knife":
				{
					KnifeItem component = items.spawnPrefab.GetComponent<KnifeItem>();
					((GrabbableObject)component).SetScrapValue(((GrabbableObject)component).scrapValue);
					Plugin.Logger.LogInfo((object)"Scan node: Kitchen knife");
					break;
				}
				case "MagnifyingGlass":
				case "PillBottle":
					items.canBeInspected = true;
					Plugin.Logger.LogInfo((object)("Inspectable: " + items.itemName + " (True)"));
					break;
				case "TragedyMask":
				{
					GlobalReferences.tragedyMaskRandomClips = items.spawnPrefab.GetComponent<RandomPeriodicAudioPlayer>()?.randomClips;
					Transform obj = items.spawnPrefab.transform.Find("MaskMesh");
					MeshFilter val = ((obj != null) ? ((Component)obj).GetComponent<MeshFilter>() : null);
					if (!((Object)(object)val != (Object)null))
					{
						break;
					}
					Transform obj2 = ((Component)val).transform.Find("EyesFilled");
					MeshFilter val2 = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshFilter>() : null);
					if ((Object)(object)val2 != (Object)null && (Object)(object)GlobalReferences.tragedyMaskEyesFilled != (Object)null)
					{
						val2.mesh = GlobalReferences.tragedyMaskEyesFilled;
						Transform obj3 = ((Component)val).transform.Find("ComedyMaskLOD");
						MeshFilter val3 = ((obj3 != null) ? ((Component)obj3).GetComponent<MeshFilter>() : null);
						if ((Object)(object)val3 != (Object)null && (Object)(object)GlobalReferences.tragedyMaskLOD != (Object)null)
						{
							val3.mesh = GlobalReferences.tragedyMaskLOD;
							Plugin.Logger.LogInfo((object)"Meshes: Tragedy");
						}
					}
					break;
				}
				}
				if ((Object)(object)items.spawnPrefab != (Object)null)
				{
					bool flag = false;
					Renderer[] componentsInChildren = items.spawnPrefab.GetComponentsInChildren<Renderer>();
					foreach (Renderer val4 in componentsInChildren)
					{
						if (val4.enabled && ((Component)val4).gameObject.layer == 13)
						{
							val4.enabled = false;
							flag = true;
						}
					}
					if (flag)
					{
						Plugin.Logger.LogInfo((object)("Invisible trigger: " + items.itemName));
					}
				}
				if (items.canBeInspected)
				{
					if (items.toolTips == null)
					{
						Plugin.Logger.LogWarning((object)("Item \"" + ((Object)items).name + "\" is missing toolTips"));
					}
					else if (items.toolTips.Length < 3)
					{
						bool flag2 = false;
						string[] toolTips = items.toolTips;
						for (int i = 0; i < toolTips.Length; i++)
						{
							if (toolTips[i].StartsWith("Inspect"))
							{
								flag2 = true;
								break;
							}
						}
						if (!flag2)
						{
							items.toolTips = CollectionExtensions.AddToArray<string>(items.toolTips, "Inspect: [Z]");
							Plugin.Logger.LogInfo((object)("Inspect tooltip: " + items.itemName));
						}
					}
				}
				if (dictionary.ContainsKey(((Object)items).name))
				{
					items.isConductiveMetal = dictionary[((Object)items).name] && Plugin.configMakeConductive.Value;
					Plugin.Logger.LogInfo((object)$"Conductive: {items.itemName} ({items.isConductiveMetal})");
				}
			}
		}

		internal static void OverrideUnlockables()
		{
			foreach (UnlockableItem unlockable in StartOfRound.Instance.unlockablesList.unlockables)
			{
				string unlockableName = unlockable.unlockableName;
				if (!(unlockableName == "Record player"))
				{
					if (unlockableName == "Disco Ball")
					{
						unlockable.prefabObject.GetComponentInChildren<CozyLights>().turnOnAudio.dopplerLevel = 0.92f * GlobalReferences.dopplerLevelMult;
						Plugin.Logger.LogInfo((object)"Doppler level: Disco ball");
					}
				}
				else
				{
					unlockable.prefabObject.GetComponentInChildren<AnimatedObjectTrigger>().thisAudioSource.dopplerLevel = GlobalReferences.dopplerLevelMult;
					Plugin.Logger.LogInfo((object)"Doppler level: Record player");
				}
			}
		}
	}
}
namespace ButteryFixes.Patches
{
	[HarmonyPatch]
	internal class EnemyPatches
	{
		[HarmonyPatch(typeof(ButlerEnemyAI), "OnCollideWithPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ButlerEnemyAITransOnCollideWithPlayer(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo field = typeof(ButlerEnemyAI).GetField("timeSinceStealthStab", BindingFlags.Instance | BindingFlags.NonPublic);
			int num = -1;
			int num2 = -1;
			for (int i = 0; i < list.Count; i++)
			{
				if (num >= 0 && num2 >= 0)
				{
					for (int j = num; j <= num2; j++)
					{
						list[j].opcode = OpCodes.Nop;
					}
					Plugin.Logger.LogDebug((object)"Transpiler: Remove timestamp check (replace with prefix)");
					return list;
				}
				if (num == -1)
				{
					if (list[i].opcode == OpCodes.Stfld && (FieldInfo)list[i].operand == field)
					{
						num = i - 2;
					}
				}
				else if (i > num && list[i].opcode == OpCodes.Ret)
				{
					num2 = i;
				}
			}
			Plugin.Logger.LogError((object)"Butler collision transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(ButlerEnemyAI), "OnCollideWithPlayer")]
		[HarmonyPrefix]
		private static bool ButlerEnemyAIPreOnCollideWithPlayer(ButlerEnemyAI __instance, ref float ___timeSinceStealthStab)
		{
			if (!((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).currentBehaviourStateIndex != 2)
			{
				if (Time.realtimeSinceStartup - ___timeSinceStealthStab < 10f)
				{
					return false;
				}
				Plugin.Logger.LogInfo((object)"Butler rolls chance for \"stealth stab\"");
				if (Random.Range(0, 100) < 86)
				{
					___timeSinceStealthStab = Time.realtimeSinceStartup;
					Plugin.Logger.LogInfo((object)"Stealth stab chance failed (won't check for 10s)");
					return false;
				}
				Plugin.Logger.LogInfo((object)"Stealth stab chance succeeds (aggro for 3s)");
			}
			return true;
		}

		[HarmonyPatch(typeof(EnemyAI), "EnableEnemyMesh")]
		[HarmonyPrefix]
		private static void EnemyAIPreEnableEnemyMesh(EnemyAI __instance)
		{
			if (!(__instance is MaskedPlayerEnemy))
			{
				return;
			}
			if (__instance.skinnedMeshRenderers.Length != 0)
			{
				for (int i = 0; i < __instance.skinnedMeshRenderers.Length; i++)
				{
					if (__instance.skinnedMeshRenderers == null)
					{
						__instance.skinnedMeshRenderers = __instance.skinnedMeshRenderers.Where((SkinnedMeshRenderer skinnedMeshRenderer) => (Object)(object)skinnedMeshRenderer != (Object)null).ToArray();
						Plugin.Logger.LogWarning((object)("Removed all missing Skinned Mesh Renderers from enemy \"" + ((Object)__instance).name + "\""));
						break;
					}
				}
			}
			if (__instance.meshRenderers.Length == 0)
			{
				return;
			}
			for (int j = 0; j < __instance.meshRenderers.Length; j++)
			{
				if (__instance.meshRenderers == null)
				{
					__instance.meshRenderers = __instance.meshRenderers.Where((MeshRenderer meshRenderer) => (Object)(object)meshRenderer != (Object)null).ToArray();
					Plugin.Logger.LogWarning((object)("Removed all missing Mesh Renderers from enemy \"" + ((Object)__instance).name + "\""));
					break;
				}
			}
		}

		[HarmonyPatch(typeof(BlobAI), "OnCollideWithPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> BlobAITransOnCollideWithPlayer(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 2; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Bge_Un && list[i - 2].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 2].operand == typeof(BlobAI).GetField("angeredTimer", BindingFlags.Instance | BindingFlags.NonPublic))
				{
					list[i].opcode = OpCodes.Bgt_Un;
					Plugin.Logger.LogDebug((object)"Transpiler: Blob taming now possible without angering");
					return list;
				}
			}
			Plugin.Logger.LogError((object)"Hygrodere anger transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "Update")]
		[HarmonyPostfix]
		private static void NutcrackerEnemyAIPostUpdate(NutcrackerEnemyAI __instance, bool ___isLeaderScript)
		{
			if (___isLeaderScript && ((EnemyAI)__instance).isEnemyDead)
			{
				PrivateMembers.GLOBAL_NUTCRACKER_CLOCK.Invoke(__instance, null);
			}
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "Start")]
		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "Dev1A3.LethalFixes" })]
		private static void NutcrackerEnemyAIPostStart(NutcrackerEnemyAI __instance, ref bool ___isLeaderScript, ref int ___previousPlayerSeenWhenAiming)
		{
			if (((EnemyAI)__instance).updatePositionThreshold < GlobalReferences.nutcrackerSyncDistance)
			{
				GlobalReferences.nutcrackerSyncDistance = ((EnemyAI)__instance).updatePositionThreshold;
			}
			___previousPlayerSeenWhenAiming = -1;
			if (!((NetworkBehaviour)__instance).IsServer || ___isLeaderScript || ((EnemyAI)__instance).enemyType.numberSpawned <= 1)
			{
				return;
			}
			NutcrackerEnemyAI[] array = Object.FindObjectsOfType<NutcrackerEnemyAI>();
			foreach (NutcrackerEnemyAI val in array)
			{
				if ((Object)(object)val != (Object)(object)__instance && (bool)PrivateMembers.IS_LEADER_SCRIPT.GetValue(val))
				{
					Plugin.Logger.LogDebug((object)$"NUTCRACKER CLOCK: Nutcracker #{((Object)__instance).GetInstanceID()} spawned, #{((Object)val).GetInstanceID()} is already leader");
					return;
				}
			}
			___isLeaderScript = true;
			Plugin.Logger.LogInfo((object)$"NUTCRACKER CLOCK: \"Leader\" is still unassigned, promoting #{((Object)__instance).GetInstanceID()}");
		}

		[HarmonyPatch(typeof(EnemyAI), "SubtractFromPowerLevel")]
		[HarmonyPrefix]
		private static void PreSubtractFromPowerLevel(EnemyAI __instance, ref bool ___removedPowerLevel)
		{
			if (__instance is MaskedPlayerEnemy)
			{
				if (!___removedPowerLevel && (Object)(object)((MaskedPlayerEnemy)((__instance is MaskedPlayerEnemy) ? __instance : null)).mimickingPlayer != (Object)null)
				{
					Plugin.Logger.LogInfo((object)"\"Masked\" was mimicking a player; will not subtract from power level");
					___removedPowerLevel = true;
				}
			}
			else if (__instance is ButlerEnemyAI && Plugin.configMaskHornetsPower.Value)
			{
				Plugin.Logger.LogInfo((object)"Butler died, but mask hornets don't decrease power level");
				___removedPowerLevel = true;
			}
		}

		[HarmonyPatch(typeof(FlowerSnakeEnemy), "SetFlappingLocalClient")]
		[HarmonyPostfix]
		public static void PostSetFlappingLocalClient(FlowerSnakeEnemy __instance, bool isMainSnake)
		{
			if (!isMainSnake || (Object)(object)__instance.clingingToPlayer != (Object)(object)GameNetworkManager.Instance.localPlayerController || !__instance.clingingToPlayer.disablingJetpackControls)
			{
				return;
			}
			for (int i = 0; i < __instance.clingingToPlayer.ItemSlots.Length; i++)
			{
				if (!((Object)(object)__instance.clingingToPlayer.ItemSlots[i] == (Object)null) && !__instance.clingingToPlayer.ItemSlots[i].isPocketed && __instance.clingingToPlayer.ItemSlots[i] is JetpackItem)
				{
					GrabbableObject obj = __instance.clingingToPlayer.ItemSlots[i];
					JetpackItem obj2 = (JetpackItem)(object)((obj is JetpackItem) ? obj : null);
					if ((bool)PrivateMembers.JETPACK_ACTIVATED.GetValue(obj2))
					{
						__instance.clingingToPlayer.disablingJetpackControls = false;
						__instance.clingingToPlayer.maxJetpackAngle = -1f;
						__instance.clingingToPlayer.jetpackRandomIntensity = 0f;
						Plugin.Logger.LogInfo((object)"Player still using jetpack when tulip snake dropped; re-enable flight controls");
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "ReloadGunClientRpc")]
		[HarmonyPostfix]
		private static void PostReloadGunClientRpc(NutcrackerEnemyAI __instance)
		{
			if (((Renderer)__instance.gun.shotgunShellLeft).enabled)
			{
				((Renderer)__instance.gun.shotgunShellLeft).enabled = false;
				((Renderer)__instance.gun.shotgunShellRight).enabled = false;
				((MonoBehaviour)__instance.gun).StartCoroutine(NonPatchFunctions.ShellsAppearAfterDelay(__instance.gun));
				Plugin.Logger.LogInfo((object)"Shotgun was reloaded by nutcracker; animating shells");
			}
		}

		[HarmonyPatch(typeof(SandSpiderAI), "TriggerChaseWithPlayer")]
		[HarmonyPrefix]
		private static bool SandSpiderAIPreTriggerChaseWithPlayer(PlayerControllerB playerScript)
		{
			return (Object)(object)playerScript != (Object)null;
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "Update")]
		[HarmonyPostfix]
		private static void MaskedPlayerEnemyPostUpdate(MaskedPlayerEnemy __instance)
		{
			if (__instance.maskFloodParticle.isEmitting && (Object)(object)((EnemyAI)__instance).inSpecialAnimationWithPlayer != (Object)null)
			{
				((EnemyAI)__instance).inSpecialAnimationWithPlayer.bodyBloodDecals[3].SetActive(true);
				if ((Object)(object)((EnemyAI)__instance).inSpecialAnimationWithPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController && !HUDManager.Instance.HUDAnimator.GetBool("biohazardDamage"))
				{
					HUDManager.Instance.HUDAnimator.SetBool("biohazardDamage", true);
					Plugin.Logger.LogInfo((object)"Enable screen blood for mask vomit animation");
				}
			}
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "FinishKillAnimation")]
		[HarmonyPrefix]
		private static void MaskedPlayerEnemyPreFinishKillAnimation(MaskedPlayerEnemy __instance)
		{
			if ((Object)(object)((EnemyAI)__instance).inSpecialAnimationWithPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController && HUDManager.Instance.HUDAnimator.GetBool("biohazardDamage"))
			{
				if (__instance.maskFloodParticle.isEmitting)
				{
					__instance.maskFloodParticle.Stop();
				}
				HUDManager.Instance.HUDAnimator.SetBool("biohazardDamage", false);
				HUDManager.Instance.HUDAnimator.SetTrigger("HealFromCritical");
				Plugin.Logger.LogInfo((object)"Vomit animation was interrupted while blood was on screen");
			}
		}

		[HarmonyPatch(typeof(RadMechAI), "Stomp")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RadMechAITransStomp(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Ldloc_1) || !(list[i + 1].opcode == OpCodes.Ldarg_S) || !(list[i + 2].opcode == OpCodes.Bge_Un))
				{
					continue;
				}
				Label label = generator.DefineLabel();
				for (int j = i + 3; j < list.Count; j++)
				{
					if (list[j].opcode == OpCodes.Dup)
					{
						list[j - 1].labels.Add(label);
						list.InsertRange(i + 3, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
						{
							new CodeInstruction(OpCodes.Ldloc_0, (object)null),
							new CodeInstruction(OpCodes.Ldfld, (object)typeof(PlayerControllerB).GetField("isInHangarShipRoom", BindingFlags.Instance | BindingFlags.Public)),
							new CodeInstruction(OpCodes.Brtrue, (object)label)
						});
						Plugin.Logger.LogDebug((object)"Transpiler: Old Bird stomps don't damage players in ship");
						return list;
					}
				}
			}
			Plugin.Logger.LogError((object)"Old Bird stomp transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(FlowermanAI), "HitEnemy")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> FlowermanAITransHitEnemy(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 2; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Stfld) || !((FieldInfo)list[i].operand == typeof(FlowermanAI).GetField("angerMeter", BindingFlags.Instance | BindingFlags.Public)))
				{
					continue;
				}
				for (int j = i - 2; j < list.Count; j++)
				{
					if (list[j].opcode == OpCodes.Ret)
					{
						Plugin.Logger.LogDebug((object)"Transpiler: Remove bracken aggro on hit (replace with postfix)");
						return list;
					}
					list[j].opcode = OpCodes.Nop;
				}
			}
			Plugin.Logger.LogError((object)"Bracken damage transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(FlowermanAI), "HitEnemy")]
		[HarmonyPostfix]
		private static void FlowermanAIPostHitEnemy(FlowermanAI __instance, PlayerControllerB playerWhoHit)
		{
			if ((Object)(object)playerWhoHit != (Object)null)
			{
				__instance.angerMeter = 11f;
				__instance.angerCheckInterval = 1f;
			}
			else
			{
				Plugin.Logger.LogInfo((object)"Bracken was damaged by an enemy; don't max aggro");
			}
			__instance.AddToAngerMeter(0.1f);
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "HitEnemy")]
		[HarmonyPostfix]
		private static void NutcrackerEnemyAIPostHitEnemy(NutcrackerEnemyAI __instance, PlayerControllerB playerWhoHit, bool ___aimingGun, bool ___reloadingGun, float ___timeSinceSeeingTarget)
		{
			if ((Object)(object)playerWhoHit != (Object)null)
			{
				int num = (int)playerWhoHit.playerClientId;
				if (((NetworkBehaviour)__instance).IsOwner && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).currentBehaviourStateIndex == 2 && !___aimingGun && !___reloadingGun && (num == __instance.lastPlayerSeenMoving || ___timeSinceSeeingTarget > 0.5f))
				{
					__instance.SwitchTargetServerRpc(num);
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> NutcrackerEnemyAITransAimGun(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 1; i < list.Count - 1; i++)
			{
				if (list[i].opcode == OpCodes.Ldc_I4_0 && list[i + 1].opcode == OpCodes.Stfld && (FieldInfo)list[i + 1].operand == typeof(NutcrackerEnemyAI).GetField("timesSeeingSamePlayer", BindingFlags.Instance | BindingFlags.NonPublic))
				{
					list[i].opcode = OpCodes.Ldc_I4_1;
					Plugin.Logger.LogDebug((object)"Transpiler: Reset times nutcracker saw same player to 1, not 0");
				}
				else if (list[i].opcode == OpCodes.Stfld && (FieldInfo)list[i].operand == typeof(EnemyAI).GetField("inSpecialAnimation", BindingFlags.Instance | BindingFlags.Public) && list[i - 2].opcode == OpCodes.Ldloc_1)
				{
					if (list[i - 1].opcode == OpCodes.Ldc_I4_1)
					{
						list[i - 1].opcode = OpCodes.Ldc_R4;
						list[i - 1].operand = 0.3f;
						Plugin.Logger.LogDebug((object)"Transpiler: Nutcracker will sync position while tiptoeing");
					}
					else
					{
						list[i - 1].opcode = OpCodes.Ldsfld;
						list[i - 1].operand = typeof(GlobalReferences).GetField("nutcrackerSyncDistance", BindingFlags.Static | BindingFlags.NonPublic);
						Plugin.Logger.LogDebug((object)"Transpiler: Dynamic update threshold for nutcracker");
					}
					list[i].operand = typeof(EnemyAI).GetField("updatePositionThreshold", BindingFlags.Instance | BindingFlags.Public);
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(MouthDogAI), "OnCollideWithPlayer")]
		[HarmonyPrefix]
		private static bool MouthDogAIPreOnCollideWithPlayer(MouthDogAI __instance, Collider other)
		{
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((EnemyAI)__instance).isEnemyDead)
			{
				PlayerControllerB val = default(PlayerControllerB);
				if (((Component)other).TryGetComponent<PlayerControllerB>(ref val) && val.isInHangarShipRoom && StartOfRound.Instance.hangarDoorsClosed)
				{
					Bounds bounds = StartOfRound.Instance.shipInnerRoomBounds.bounds;
					if (!((Bounds)(ref bounds)).Contains(((Component)__instance).transform.position))
					{
						goto IL_004a;
					}
				}
				return true;
			}
			goto IL_004a;
			IL_004a:
			return false;
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "KillEnemy")]
		[HarmonyPostfix]
		private static void MaskedPlayerEnemyPostKillEnemy(MaskedPlayerEnemy __instance)
		{
			Transform obj = ((Component)__instance).transform.Find("Misc/MapDot");
			Animator val = ((obj != null) ? ((Component)obj).GetComponent<Animator>() : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				((Behaviour)val).enabled = false;
				Plugin.Logger.LogInfo((object)"Stop animating masked radar dot");
			}
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "SetSuit")]
		[HarmonyPostfix]
		private static void PostSetSuit(MaskedPlayerEnemy __instance, int suitId)
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Transform val = __instance.animationContainer.Find("metarig/spine");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				if (suitId >= StartOfRound.Instance.unlockablesList.unlockables.Count)
				{
					return;
				}
				UnlockableItem val2 = StartOfRound.Instance.unlockablesList.unlockables[suitId];
				if ((Object)(object)val2.headCostumeObject != (Object)null)
				{
					Transform val3 = val.Find("spine.001/spine.002/spine.003/spine.004");
					if ((Object)(object)val3 != (Object)null && (Object)(object)val3.Find(((Object)val2.headCostumeObject).name + "(Clone)") == (Object)null)
					{
						Object.Instantiate<GameObject>(val2.headCostumeObject, val3.position, val3.rotation, val3);
						Plugin.Logger.LogInfo((object)$"Mimic #{((Object)__instance).GetInstanceID()} equipped {val2.unlockableName} head");
					}
				}
				if ((Object)(object)val2.lowerTorsoCostumeObject != (Object)null && (Object)(object)val.Find(((Object)val2.lowerTorsoCostumeObject).name + "(Clone)") == (Object)null)
				{
					Object.Instantiate<GameObject>(val2.lowerTorsoCostumeObject, val.position, val.rotation, val);
					Plugin.Logger.LogInfo((object)$"Mimic #{((Object)__instance).GetInstanceID()} equipped {val2.unlockableName} torso");
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)"Encountered a non-fatal error while attaching costume pieces to mimic");
				Plugin.Logger.LogError((object)ex);
			}
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "SetEnemyOutside")]
		[HarmonyPostfix]
		private static void MaskedPlayerEnemyPostSetEnemyOutside(MaskedPlayerEnemy __instance)
		{
			if (((EnemyAI)__instance).timeSinceSpawn > 40f)
			{
				return;
			}
			Transform parent = __instance.maskTypes[0].transform.parent.parent;
			Transform obj = parent.Find("BetaBadge");
			Renderer val = ((obj != null) ? ((Component)obj).GetComponent<Renderer>() : null);
			if ((Object)(object)val != (Object)null)
			{
				val.enabled = ((Renderer)__instance.mimickingPlayer.playerBetaBadgeMesh).enabled;
				Plugin.Logger.LogInfo((object)$"Mimic #{((Object)__instance).GetInstanceID()} VIP: {val.enabled}");
			}
			Transform obj2 = parent.Find("LevelSticker");
			MeshFilter val2 = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshFilter>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.mesh = __instance.mimickingPlayer.playerBadgeMesh.mesh;
				Plugin.Logger.LogInfo((object)$"Mimic #{((Object)__instance).GetInstanceID()} updated level sticker");
			}
			try
			{
				DecalProjector[] componentsInChildren = ((Component)((Component)__instance).transform).GetComponentsInChildren<DecalProjector>();
				foreach (DecalProjector val3 in componentsInChildren)
				{
					GameObject[] bodyBloodDecals = __instance.mimickingPlayer.bodyBloodDecals;
					foreach (GameObject val4 in bodyBloodDecals)
					{
						if (((Object)val3).name == ((Object)val4).name)
						{
							((Component)val3).gameObject.SetActive(val4.activeSelf);
							Plugin.Logger.LogInfo((object)$"Mimic #{((Object)__instance).GetInstanceID()} blood: \"{((Object)val3).name}\"");
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)"Encountered a non-fatal error while enabling mimic blood");
				Plugin.Logger.LogError((object)ex);
			}
		}

		[HarmonyPatch(typeof(DoorLock), "OnTriggerStay")]
		[HarmonyPrefix]
		public static bool DoorLockPreOnTriggerStay(Collider other)
		{
			EnemyAICollisionDetect val = default(EnemyAICollisionDetect);
			if (((Component)other).CompareTag("Enemy") && ((Component)other).TryGetComponent<EnemyAICollisionDetect>(ref val))
			{
				EnemyAI mainScript = val.mainScript;
				if (!((Object)(object)((CentipedeAI)(((mainScript is CentipedeAI) ? mainScript : null)?)).clingingToPlayer != (Object)null))
				{
					EnemyAI mainScript2 = val.mainScript;
					return !((Object)(object)((FlowerSnakeEnemy)(((mainScript2 is FlowerSnakeEnemy) ? mainScript2 : null)?)).clingingToPlayer != (Object)null);
				}
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "SetMaskType")]
		[HarmonyPrefix]
		private static bool PostSetMaskType(MaskedPlayerEnemy __instance, int maskType)
		{
			if (maskType == 5 && __instance.maskTypeIndex != 1)
			{
				__instance.maskTypeIndex = 1;
				Plugin.Logger.LogInfo((object)"Mimic spawned that should be Tragedy");
				NonPatchFunctions.ConvertMaskToTragedy(__instance.maskTypes[0].transform);
				RandomPeriodicAudioPlayer component = __instance.maskTypes[0].GetComponent<RandomPeriodicAudioPlayer>();
				if ((Object)(object)component != (Object)null)
				{
					component.randomClips = GlobalReferences.tragedyMaskRandomClips;
					Plugin.Logger.LogInfo((object)"Tragedy mimic cries");
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal class GeneralPatches
	{
		[HarmonyPatch(typeof(QuickMenuManager), "Start")]
		[HarmonyPostfix]
		private static void QuickMenuManagerPostStart(QuickMenuManager __instance)
		{
			GlobalReferences.allEnemiesList.Clear();
			List<SpawnableEnemyWithRarity>[] array = new List<SpawnableEnemyWithRarity>[3]
			{
				__instance.testAllEnemiesLevel.Enemies,
				__instance.testAllEnemiesLevel.OutsideEnemies,
				__instance.testAllEnemiesLevel.DaytimeEnemies
			};
			for (int i = 0; i < array.Length; i++)
			{
				foreach (SpawnableEnemyWithRarity item in array[i])
				{
					if (GlobalReferences.allEnemiesList.ContainsKey(((Object)item.enemyType).name))
					{
						if ((Object)(object)GlobalReferences.allEnemiesList[((Object)item.enemyType).name] == (Object)(object)item.enemyType)
						{
							Plugin.Logger.LogWarning((object)("allEnemiesList: Tried to cache reference to \"" + ((Object)item.enemyType).name + "\" more than once"));
						}
						else
						{
							Plugin.Logger.LogWarning((object)("allEnemiesList: Tried to cache two different enemies by same name (" + ((Object)item.enemyType).name + ")"));
						}
					}
					else
					{
						GlobalReferences.allEnemiesList.Add(((Object)item.enemyType).name, item.enemyType);
					}
				}
			}
			ScriptableObjectOverrides.OverrideEnemyTypes();
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPostfix]
		private static void StartOfRoundPostAwake(StartOfRound __instance)
		{
			ScriptableObjectOverrides.OverrideSelectableLevels();
			switch (Plugin.configMusicDopplerLevel.Value)
			{
			case MusicDopplerLevel.None:
				GlobalReferences.dopplerLevelMult = 0f;
				break;
			case MusicDopplerLevel.Reduced:
				GlobalReferences.dopplerLevelMult = 0.3f;
				break;
			default:
				GlobalReferences.dopplerLevelMult = 1f;
				break;
			}
			__instance.speakerAudioSource.dopplerLevel = GlobalReferences.dopplerLevelMult;
			Plugin.Logger.LogInfo((object)"Doppler level: Ship speaker");
			GameObject val = ((IEnumerable<GameObject>)StartOfRound.Instance.playerRagdolls).FirstOrDefault((Func<GameObject, bool>)((GameObject playerRagdoll) => ((Object)playerRagdoll).name == "PlayerRagdollWithTragedyMask Variant"));
			if ((Object)(object)val != (Object)null)
			{
				MeshFilter[] componentsInChildren = val.GetComponentsInChildren<MeshFilter>();
				foreach (MeshFilter val2 in componentsInChildren)
				{
					switch (((Object)val2).name)
					{
					case "Mesh":
					{
						GlobalReferences.tragedyMask = val2.sharedMesh;
						MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>();
						GlobalReferences.tragedyMaskMat = ((component != null) ? ((Renderer)component).sharedMaterial : null);
						break;
					}
					case "ComedyMaskLOD1":
						GlobalReferences.tragedyMaskLOD = val2.sharedMesh;
						break;
					case "EyesFilled":
						GlobalReferences.tragedyMaskEyesFilled = val2.sharedMesh;
						break;
					}
				}
			}
			ScriptableObjectOverrides.OverrideItems();
			Transform obj = __instance.elevatorTransform.Find("StickyNoteItem");
			AudioSource val3 = ((obj != null) ? ((Component)obj).GetComponent<AudioSource>() : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.rolloffMode = (AudioRolloffMode)1;
				((GrabbableObject)((Component)val3).GetComponent<PhysicsProp>()).scrapValue = 0;
				Plugin.Logger.LogInfo((object)"Audio rolloff: Sticky note");
			}
			Transform obj2 = __instance.elevatorTransform.Find("ClipboardManual");
			AudioSource val4 = ((obj2 != null) ? ((Component)obj2).GetComponent<AudioSource>() : null);
			if ((Object)(object)val4 != (Object)null)
			{
				val4.rolloffMode = (AudioRolloffMode)1;
				((GrabbableObject)((Component)val4).GetComponent<ClipboardItem>()).scrapValue = 0;
				Plugin.Logger.LogInfo((object)"Audio rolloff: Clipboard");
			}
			ScriptableObjectOverrides.OverrideUnlockables();
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetStats")]
		[HarmonyPostfix]
		private static void StartOfRoundPostResetStats(StartOfRound __instance)
		{
			for (int i = 0; i < __instance.gameStats.allPlayerStats.Length; i++)
			{
				__instance.gameStats.allPlayerStats[i].profitable = 0;
			}
			Plugin.Logger.LogInfo((object)"Cleared \"profitable\" stat for all employees");
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShipFurniture")]
		[HarmonyPostfix]
		private static void PostResetShipFurniture(StartOfRound __instance)
		{
			if (((NetworkBehaviour)__instance).IsServer)
			{
				Terminal val = Object.FindObjectOfType<Terminal>();
				if ((Object)(object)val != (Object)null && val.orderedItemsFromTerminal.Count > 0)
				{
					val.orderedItemsFromTerminal.Clear();
					val.SyncGroupCreditsServerRpc(val.groupCredits, 0);
					Plugin.Logger.LogInfo((object)"Dropship inventory was emptied (game over)");
				}
			}
			if (__instance.isChallengeFile)
			{
				for (int i = 0; i < __instance.allPlayerScripts.Length; i++)
				{
					__instance.allPlayerScripts[i].drunkness = 0f;
					__instance.allPlayerScripts[i].drunknessInertia = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(ItemDropship), "Start")]
		[HarmonyPostfix]
		private static void ItemDropshipPostStart(ItemDropship __instance)
		{
			Transform val = ((Component)__instance).transform.Find("Music");
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).GetComponent<AudioSource>().dopplerLevel = 0.6f * GlobalReferences.dopplerLevelMult;
				Transform obj = val.Find("Music (1)");
				AudioSource val2 = ((obj != null) ? ((Component)obj).GetComponent<AudioSource>() : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.dopplerLevel = 0.6f * GlobalReferences.dopplerLevelMult;
				}
				Plugin.Logger.LogInfo((object)"Doppler level: Dropship");
			}
		}

		[HarmonyPatch(typeof(HUDManager), "ShowPlayersFiredScreen")]
		[HarmonyPostfix]
		private static void PostShowPlayersFiredScreen()
		{
			for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
			{
				StartOfRound.Instance.allPlayerScripts[i].drunkness = 0f;
				StartOfRound.Instance.allPlayerScripts[i].drunknessInertia = 0f;
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "LoadShipGrabbableItems")]
		[HarmonyPostfix]
		private static void PostLoadShipGrabbableItems()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			try
			{
				val.orderedItemsFromTerminal = ES3.Load<List<int>>("ButteryFixes_DeliveryItems", GameNetworkManager.Instance.currentSaveFileName, new List<int>());
				val.numberOfItemsInDropship = val.orderedItemsFromTerminal.Count;
				if (val.numberOfItemsInDropship > 0)
				{
					Plugin.Logger.LogInfo((object)$"Dropship inventory was restocked from save file ({val.numberOfItemsInDropship} items):");
					for (int i = 0; i < val.numberOfItemsInDropship; i++)
					{
						Plugin.Logger.LogInfo((object)$"#{i + 1} - {val.buyableItemsList[val.orderedItemsFromTerminal[i]].itemName}");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("An error occurred while fetching dropship inventory from save file \"" + GameNetworkManager.Instance.currentSaveFileName + "\""));
				Plugin.Logger.LogError((object)ex);
			}
		}

		[HarmonyPatch(typeof(GameNetworkManager), "SaveGame")]
		[HarmonyPostfix]
		private static void PostSaveGame(GameNetworkManager __instance)
		{
			if (!__instance.isHostingGame)
			{
				return;
			}
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			try
			{
				ES3.Save<List<int>>("ButteryFixes_DeliveryItems", val.orderedItemsFromTerminal, __instance.currentSaveFileName);
				Plugin.Logger.LogInfo((object)$"Dropship inventory saved ({val.numberOfItemsInDropship} items)");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("An error occurred while trying to save dropship inventory to file \"" + GameNetworkManager.Instance.currentSaveFileName + "\""));
				Plugin.Logger.LogError((object)ex);
			}
		}

		[HarmonyPatch(typeof(Terminal), "Start")]
		[HarmonyPostfix]
		private static void TerminalPostStart(Terminal __instance)
		{
			foreach (TerminalNode enemyFile in __instance.enemyFiles)
			{
				switch (((Object)enemyFile).name)
				{
				case "NutcrackerFile":
					if (enemyFile.displayText.EndsWith("house."))
					{
						enemyFile.displayText += "\n\nThey watch with one tireless eye, which only senses movement; It remembers the last creature it noticed whether they are moving or not.";
						Plugin.Logger.LogInfo((object)"Bestiary: Nutcracker");
					}
					break;
				case "RadMechFile":
					enemyFile.displayText = enemyFile.displayText.Replace("\n The subject of who developed the Old Birds has been an intense debate since their first recorded appearance on", "");
					Plugin.Logger.LogInfo((object)"Bestiary: Old Birds");
					break;
				case "MaskHornetsFile":
				{
					string text = enemyFile.creatureName[0].ToString().ToUpper();
					string creatureName = enemyFile.creatureName;
					enemyFile.creatureName = text + creatureName.Substring(1, creatureName.Length - 1);
					Plugin.Logger.LogInfo((object)"Bestiary: Mask hornets");
					break;
				}
				}
			}
		}

		[HarmonyPatch(typeof(Terminal), "TextPostProcess")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransTextPostProcess(IEnumerable<CodeInstruction> instructions)
		{
			if (Plugin.GENERAL_IMPROVEMENTS)
			{
				return instructions;
			}
			List<CodeInstruction> list = instructions.ToList();
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].opcode == OpCodes.Ldstr)
				{
					string text = (string)list[num].operand;
					if (text.Contains("\nn"))
					{
						list[num].operand = text.Replace("\nn", "\n");
						Plugin.Logger.LogDebug((object)"Transpiler: Fix \"n\" on terminal when viewing monitor");
						return list;
					}
				}
			}
			Plugin.Logger.LogDebug((object)"Terminal transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(HUDManager), "ApplyPenalty")]
		[HarmonyPostfix]
		private static void ApplyPenalty(HUDManager __instance, int playersDead, int bodiesInsured)
		{
			((TMP_Text)__instance.statsUIElements.penaltyAddition).text = $"{playersDead} casualties: -{Mathf.Clamp(20 * (playersDead - bodiesInsured) + 8 * bodiesInsured, 0, 100)}%\n({bodiesInsured} bodies recovered)";
		}

		[HarmonyPatch(typeof(RoundManager), "PredictAllOutsideEnemies")]
		[HarmonyPostfix]
		private static void PostPredictAllOutsideEnemies()
		{
			foreach (string key in GlobalReferences.allEnemiesList.Keys)
			{
				GlobalReferences.allEnemiesList[key].numberSpawned = 0;
			}
		}

		[HarmonyPatch(typeof(GameNetworkManager), "Disconnect")]
		[HarmonyPostfix]
		private static void GameNetworkManagerPostDisconnect()
		{
			GlobalReferences.allEnemiesList.Clear();
		}

		[HarmonyPatch(typeof(RoundManager), "Start")]
		[HarmonyPostfix]
		private static void RoundManagerPostStart(RoundManager __instance)
		{
			__instance.ResetEnemyVariables();
		}
	}
	[HarmonyPatch]
	internal class ItemPatches
	{
		[HarmonyPatch(typeof(JetpackItem), "DeactivateJetpack")]
		[HarmonyPostfix]
		public static void PostDeactivateJetpack(JetpackItem __instance)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			EnemyType val = GlobalReferences.allEnemiesList["FlowerSnake"];
			if (!((Object)(object)val != (Object)null) || val.numberSpawned <= 0)
			{
				return;
			}
			foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies)
			{
				if (spawnedEnemy is FlowerSnakeEnemy)
				{
					FlowerSnakeEnemy val2 = (FlowerSnakeEnemy)(object)((spawnedEnemy is FlowerSnakeEnemy) ? spawnedEnemy : null);
					if (!((EnemyAI)val2).isEnemyDead && (Object)(object)val2.clingingToPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController && val2.clingingToPlayer.disablingJetpackControls && val2.clingPosition == 4 && val2.flightPower > 0f && (Object)(PlayerControllerB)PrivateMembers.JETPACK_ITEM_PREVIOUS_PLAYER_HELD_BY.GetValue(__instance) == (Object)(object)val2.clingingToPlayer)
					{
						val2.clingingToPlayer.disablingJetpackControls = false;
						val2.clingingToPlayer.maxJetpackAngle = float.MaxValue;
						val2.clingingToPlayer.jetpackRandomIntensity = 60f;
						Plugin.Logger.LogInfo((object)"Jetpack disabled, but tulip snake is still carrying");
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(GrabbableObject), "ChargeBatteries")]
		[HarmonyPostfix]
		private static void PostChargeBatteries(GrabbableObject __instance)
		{
			if (__instance is BoomboxItem)
			{
				BoomboxItem val = (BoomboxItem)(object)((__instance is BoomboxItem) ? __instance : null);
				if (val.isPlayingMusic && val.boomboxAudio.pitch < 1f && ((GrabbableObject)val).insertedBattery.charge > 0f)
				{
					val.boomboxAudio.pitch = 1f;
					Plugin.Logger.LogInfo((object)"Boombox was recharged, correcting pitch");
				}
			}
		}

		[HarmonyPatch(typeof(JetpackItem), "EquipItem")]
		[HarmonyPostfix]
		private static void JetpackItemPostEquipItem(JetpackItem __instance)
		{
			if ((Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)(object)GameNetworkManager.Instance.localPlayerController)
			{
				__instance.jetpackAudio.dopplerLevel = 0f;
				__instance.jetpackBeepsAudio.dopplerLevel = 0f;
				Plugin.Logger.LogInfo((object)"Jetpack held by you, disable doppler effect");
			}
			else
			{
				__instance.jetpackAudio.dopplerLevel = 1f;
				__instance.jetpackBeepsAudio.dopplerLevel = 1f;
				Plugin.Logger.LogInfo((object)"Jetpack held by other player, enable doppler effect");
			}
		}

		[HarmonyPatch(typeof(JetpackItem), "Update")]
		[HarmonyPostfix]
		private static void JetpackItemPostUpdate(bool ___jetpackActivated, PlayerControllerB ___previousPlayerHeldBy)
		{
			if (___jetpackActivated && ___previousPlayerHeldBy.maxJetpackAngle >= 0f && ___previousPlayerHeldBy.maxJetpackAngle < 360f)
			{
				___previousPlayerHeldBy.maxJetpackAngle = float.MaxValue;
				___previousPlayerHeldBy.jetpackRandomIntensity = 60f;
				Plugin.Logger.LogInfo((object)"Uncap player rotation (using jetpack while tulip snakes riding)");
			}
		}

		[HarmonyPatch(typeof(ShotgunItem), "ReloadGunEffectsClientRpc")]
		[HarmonyPostfix]
		private static void PostReloadGunEffectsClientRpc(ShotgunItem __instance, bool start)
		{
			if (start && !((NetworkBehaviour)__instance).IsOwner)
			{
				((Renderer)__instance.shotgunShellLeft).enabled = __instance.shellsLoaded > 0;
				((Renderer)__instance.shotgunShellRight).enabled = false;
				((MonoBehaviour)__instance).StartCoroutine(NonPatchFunctions.ShellsAppearAfterDelay(__instance));
				Plugin.Logger.LogInfo((object)"Shotgun was reloaded by another client; animating shells");
			}
		}

		[HarmonyPatch(typeof(ShotgunItem), "Update")]
		[HarmonyPostfix]
		private static void ShotgunItemPostUpdate(ShotgunItem __instance)
		{
			if (__instance.isReloading)
			{
				((Renderer)__instance.shotgunShellLeft).forceRenderingOff = false;
				((Renderer)__instance.shotgunShellRight).forceRenderingOff = false;
			}
		}

		[HarmonyPatch(typeof(ShotgunItem), "Start")]
		[HarmonyPatch(typeof(ShotgunItem), "DiscardItem")]
		[HarmonyPostfix]
		private static void DontRenderShotgunShells(ShotgunItem __instance)
		{
			((Renderer)__instance.shotgunShellLeft).forceRenderingOff = true;
			((Renderer)__instance.shotgunShellRight).forceRenderingOff = true;
		}

		[HarmonyPatch(typeof(ShotgunItem), "ShootGun")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ShotgunItemTransShootGun(IEnumerable<CodeInstruction> instructions)
		{
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Expected O, but got Unknown
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Expected O, but got Unknown
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			bool flag = false;
			for (int i = 2; i < list.Count; i++)
			{
				if (!flag && list[i].opcode == OpCodes.Bge_Un && list[i - 2].opcode == OpCodes.Ldloc_2)
				{
					for (int j = i + 1; j < list.Count - 1; j++)
					{
						int num = -1;
						if (list[j + 1].opcode == OpCodes.Ldloc_2)
						{
							if (num >= 0 && list[j].opcode == OpCodes.Br)
							{
								list.Insert(num, new CodeInstruction(OpCodes.Br, list[j].operand));
								Plugin.Logger.LogDebug((object)"Transpiler: Fix ear-ringing severity in extremely close range");
								flag = true;
								break;
							}
							if (num < 0 && list[j].opcode == OpCodes.Stloc_S)
							{
								num = j + 1;
							}
						}
					}
				}
				else if (list[i].opcode == OpCodes.Newarr && (Type)list[i].operand == typeof(RaycastHit) && list[i - 1].opcode == OpCodes.Ldc_I4_S && (sbyte)list[i - 1].operand == 10)
				{
					list[i - 1].operand = 50;
					Plugin.Logger.LogDebug((object)"Transpiler: Resize shotgun collider array");
				}
				else if (list[i].opcode == OpCodes.Call && list[i].operand.ToString().Contains("SphereCastNonAlloc"))
				{
					list.InsertRange(i + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5]
					{
						new CodeInstruction(OpCodes.Ldarg_1, (object)null),
						new CodeInstruction(OpCodes.Ldloca_S, list[i + 1].operand),
						new CodeInstruction(OpCodes.Ldarg_0, (object)null),
						new CodeInstruction(OpCodes.Ldflda, (object)typeof(ShotgunItem).GetField("enemyColliders", BindingFlags.Instance | BindingFlags.NonPublic)),
						new CodeInstruction(OpCodes.Call, (object)typeof(NonPatchFunctions).GetMethod("ShotgunPreProcess", BindingFlags.Static | BindingFlags.Public))
					});
					Plugin.Logger.LogDebug((object)"Transpiler: Pre-process shotgun targets");
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(LungProp), "Start")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void LungPropPostStart(LungProp __instance)
		{
			ScanNodeProperties componentInChildren = ((Component)__instance).GetComponentInChildren<ScanNodeProperties>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				if (componentInChildren.headerText == "Apparatice")
				{
					componentInChildren.headerText = "Apparatus";
				}
				componentInChildren.subText = $"Value: ${((GrabbableObject)__instance).scrapValue}";
				Plugin.Logger.LogInfo((object)"Scan node: Apparatus");
			}
		}

		[HarmonyPatch(typeof(HUDManager), "GetNewStoryLogClientRpc")]
		[HarmonyPostfix]
		private static void PostGetNewStoryLogClientRpc(int logID)
		{
			StoryLog[] array = Object.FindObjectsOfType<StoryLog>();
			foreach (StoryLog val in array)
			{
				if (val.storyLogID == logID)
				{
					val.CollectLog();
					Plugin.Logger.LogInfo((object)$"Another player collected data chip #{logID}");
					break;
				}
			}
		}

		[HarmonyPatch(typeof(HauntedMaskItem), "MaskClampToHeadAnimationEvent")]
		[HarmonyPostfix]
		private static void PostMaskClampToHeadAnimationEvent(HauntedMaskItem __instance)
		{
			if (__instance.maskTypeId == 5)
			{
				Plugin.Logger.LogInfo((object)"Player is being converted by a Tragedy mask; about to replace mask prefab appearance");
				NonPatchFunctions.ConvertMaskToTragedy(((Component)__instance.currentHeadMask).transform);
			}
		}
	}
	[HarmonyPatch]
	internal class PlayerPatches
	{
		private static List<PlayerControllerB> bunnyhoppingPlayers = new List<PlayerControllerB>();

		private static bool localCostumeChanged = false;

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void PlayerControllerBPostUpdate(PlayerControllerB __instance, bool ___isWalking)
		{
			if (__instance.isClimbingLadder && !Plugin.DISABLE_LADDER_PATCH)
			{
				__instance.isSprinting = false;
				if (___isWalking)
				{
					__instance.playerBodyAnimator.SetFloat("animationSpeed", 1f);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		private static void PostConnectClientToPlayerObject(PlayerControllerB __instance)
		{
			if (Plugin.configGameResolution.Value != GameResolution.DontChange)
			{
				RenderTexture targetTexture = __instance.gameplayCamera.targetTexture;
				if (Plugin.configGameResolution.Value == GameResolution.High)
				{
					((Texture)targetTexture).width = 970;
					((Texture)targetTexture).height = 580;
					Plugin.Logger.LogInfo((object)"High resolution applied");
				}
				else
				{
					((Texture)targetTexture).width = 620;
					((Texture)targetTexture).height = 350;
					Plugin.Logger.LogInfo((object)"Low resolution applied");
				}
				Plugin.ENABLE_SCAN_PATCH = true;
			}
			else
			{
				Plugin.ENABLE_SCAN_PATCH = false;
				Plugin.Logger.LogInfo((object)"Resolution changes reverted");
			}
			Transform obj = __instance.localVisor.Find("ScavengerHelmet");
			Renderer val = ((obj != null) ? ((Component)obj).GetComponent<Renderer>() : null);
			if ((Object)(object)val != (Object)null)
			{
				val.shadowCastingMode = (ShadowCastingMode)0;
				Plugin.Logger.LogInfo((object)"\"Fake helmet\" no longer casts a shadow");
			}
			try
			{
				((Component)__instance.playerBadgeMesh).GetComponent<Renderer>().forceRenderingOff = true;
				((Renderer)__instance.playerBetaBadgeMesh).forceRenderingOff = true;
				Plugin.Logger.LogInfo((object)"Hide badges on local player");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)"Ran into error fetching local player's badges");
				Plugin.Logger.LogError((object)ex);
			}
		}

		[HarmonyPatch(typeof(HUDManager), "UpdateScanNodes")]
		[HarmonyPostfix]
		private static void PostUpdateScanNodes(HUDManager __instance, Dictionary<RectTransform, ScanNodeProperties> ___scanNodes)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ENABLE_SCAN_PATCH || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)
			{
				return;
			}
			Rect rect = ((Component)__instance.playerScreenTexture).GetComponent<RectTransform>().rect;
			for (int i = 0; i < __instance.scanElements.Length; i++)
			{
				if (___scanNodes.TryGetValue(__instance.scanElements[i], out var value))
				{
					Vector3 val = GameNetworkManager.Instance.localPlayerController.gameplayCamera.WorldToViewportPoint(((Component)value).transform.position);
					__instance.scanElements[i].anchoredPosition = new Vector2(((Rect)(ref rect)).xMin + ((Rect)(ref rect)).width * val.x, ((Rect)(ref rect)).yMin + ((Rect)(ref rect)).height * val.y);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlot")]
		[HarmonyPostfix]
		private static void PostDestroyItemInSlot(PlayerControllerB __instance, int itemSlot)
		{
			if (!((NetworkBehaviour)__instance).IsOwner && !((Behaviour)HUDManager.Instance.itemSlotIcons[itemSlot]).enabled && (Object)(object)GameNetworkManager.Instance.localPlayerController.ItemSlots[itemSlot] != (Object)null)
			{
				((Behaviour)HUDManager.Instance.itemSlotIcons[itemSlot]).enabled = true;
				Plugin.Logger.LogInfo((object)"Re-enabled inventory icon (likely that another player has just reloaded a shotgun, and it was erroneously disabled)");
			}
		}

		[HarmonyPatch(typeof(SoundManager), "Start")]
		[HarmonyPostfix]
		private static void SoundManagerPostStart(SoundManager __instance)
		{
			__instance.currentMixerSnapshotID = 4;
			__instance.SetDiageticMixerSnapshot(0, 0.2f);
		}

		[HarmonyPatch(typeof(HUDManager), "UpdateHealthUI")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransUpdateHealthUI(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Ldarg_1 && list[i + 1].opcode == OpCodes.Ldc_I4_S && (sbyte)list[i + 1].operand == 20 && list[i + 2].opcode == OpCodes.Bge)
				{
					list[i + 1].operand = 10;
					Plugin.Logger.LogDebug((object)"Transpiler: Fix critical injury popup threshold");
					return list;
				}
			}
			Plugin.Logger.LogDebug((object)"Health UI transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "PlayJumpAudio")]
		[HarmonyPostfix]
		private static void PostPlayJumpAudio(PlayerControllerB __instance, bool ___isWalking)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.configFixJumpCheese.Value || !((NetworkBehaviour)__instance).IsServer || StartOfRound.Instance.inShipPhase)
			{
				if (bunnyhoppingPlayers.Count > 0)
				{
					Plugin.Logger.LogWarning((object)"Bunnyhopping player list has some residual entries");
					bunnyhoppingPlayers.Clear();
				}
			}
			else
			{
				if (__instance.isInsideFactory || __instance.isInElevator || __instance.isInHangarShipRoom)
				{
					return;
				}
				EnemyType val = GlobalReferences.allEnemiesList["MouthDog"];
				if ((Object)(object)val == (Object)null || val.numberSpawned < 1)
				{
					return;
				}
				bool flag = false;
				if (((NetworkBehaviour)__instance).IsOwner)
				{
					flag = ___isWalking;
				}
				else if (__instance.timeSincePlayerMoving < 0.25f)
				{
					Vector3 val2 = __instance.serverPlayerPosition - __instance.oldPlayerPosition;
					val2.y = 0f;
					flag = ((Vector3)(ref val2)).magnitude > float.Epsilon;
				}
				if (flag)
				{
					Plugin.Logger.LogInfo((object)("Player \"" + __instance.playerUsername + "\" is bunnyhopping with dogs outside; creating noise"));
					NonPatchFunctions.FakeFootstepAlert(__instance);
					if (!bunnyhoppingPlayers.Contains(__instance))
					{
						bunnyhoppingPlayers.Add(__instance);
					}
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LandFromJumpClientRpc")]
		[HarmonyPostfix]
		private static void PostLandFromJumpClientRpc(PlayerControllerB __instance)
		{
			if (!bunnyhoppingPlayers.Contains(__instance))
			{
				return;
			}
			Plugin.Logger.LogInfo((object)("Player \"" + __instance.playerUsername + "\" landed from bunnyhop"));
			if (Plugin.configFixJumpCheese.Value && ((NetworkBehaviour)__instance).IsServer)
			{
				EnemyType val = GlobalReferences.allEnemiesList["MouthDog"];
				if ((Object)(object)val != (Object)null && val.numberSpawned >= 1)
				{
					NonPatchFunctions.FakeFootstepAlert(__instance);
				}
			}
			bunnyhoppingPlayers.Remove(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "PlayFootstepSound")]
		[HarmonyPostfix]
		private static void PostPlayFootstepSound(PlayerControllerB __instance)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)__instance).IsServer && !((NetworkBehaviour)__instance).IsOwner)
			{
				bool[] playerWasLastSprinting = NonPatchFunctions.playerWasLastSprinting;
				nint num = checked((nint)__instance.actualClientId);
				AnimatorStateInfo currentAnimatorStateInfo = __instance.playerBodyAnimator.GetCurrentAnimatorStateInfo(0);
				playerWasLastSprinting[num] = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsTag("Sprinting");
			}
		}

		[HarmonyPatch(typeof(UnlockableSuit), "ChangePlayerCostumeElement")]
		[HarmonyPrefix]
		private static void PreChangePlayerCostumeElement(ref Transform costumeContainer, GameObject newCostume)
		{
			if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)
			{
				return;
			}
			if ((Object)(object)costumeContainer == (Object)(object)GameNetworkManager.Instance.localPlayerController.headCostumeContainerLocal)
			{
				costumeContainer = GameNetworkManager.Instance.localPlayerController.headCostumeContainer;
				if ((Object)(object)newCostume != (Object)null)
				{
					localCostumeChanged = true;
				}
			}
			else if ((Object)(object)costumeContainer == (Object)(object)GameNetworkManager.Instance.localPlayerController.lowerTorsoCostumeContainer && (Object)(object)newCostume != (Object)null)
			{
				localCostumeChanged = true;
			}
		}

		[HarmonyPatch(typeof(UnlockableSuit), "ChangePlayerCostumeElement")]
		[HarmonyPostfix]
		private static void PostChangePlayerCostumeElement(ref Transform costumeContainer)
		{
			if (localCostumeChanged)
			{
				localCostumeChanged = false;
				Renderer[] componentsInChildren = ((Component)costumeContainer).GetComponentsInChildren<Renderer>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].shadowCastingMode = (ShadowCastingMode)3;
				}
				Plugin.Logger.LogInfo((object)("Local costume part only draws shadow - " + ((Object)costumeContainer).name));
			}
		}

		[HarmonyPatch(typeof(UnlockableSuit), "SwitchSuitForPlayer")]
		[HarmonyPostfix]
		private static void PostSwitchSuitForPlayer(PlayerControllerB player, int suitID)
		{
			if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)player)
			{
				UnlockableSuit.ChangePlayerCostumeElement(player.lowerTorsoCostumeContainer, StartOfRound.Instance.unlockablesList.unlockables[suitID].lowerTorsoCostumeObject);
			}
		}
	}
}