Decompiled source of EnemySoundFixes v1.5.10

EnemySoundFixes.dll

Decompiled 3 months 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.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[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("EnemySoundFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fixes numerous issues with missing sound effects, or SFX playing when they shouldn't.")]
[assembly: AssemblyFileVersion("1.5.10.0")]
[assembly: AssemblyInformationalVersion("1.5.10+add35d719e56c63ebd85f7c3f6c5795c0209476b")]
[assembly: AssemblyProduct("EnemySoundFixes")]
[assembly: AssemblyTitle("EnemySoundFixes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.10.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 EnemySoundFixes
{
	internal enum CruiserMute
	{
		Nothing = -1,
		NotRadio,
		All
	}
	[BepInPlugin("butterystancakes.lethalcompany.enemysoundfixes", "Enemy Sound Fixes", "1.5.10")]
	public class Plugin : BaseUnityPlugin
	{
		private const string PLUGIN_GUID = "butterystancakes.lethalcompany.enemysoundfixes";

		private const string PLUGIN_NAME = "Enemy Sound Fixes";

		private const string PLUGIN_VERSION = "1.5.10";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> configFixMasks;

		internal static ConfigEntry<bool> configThumperNoThunder;

		internal static ConfigEntry<bool> configBetterMimicSteps;

		internal static ConfigEntry<CruiserMute> configSpaceMutesCruiser;

		private void Awake()
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			configFixMasks = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "FixMasks", true, "(Host only, requires game restart) Fixes masks' broken audio intervals.\nDisabling this is useful if you use a voice mimicking mod. (Skinwalkers, Mirage, etc.)");
			configBetterMimicSteps = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "BetterMimicSteps", false, "Mimic footstep volume and distance are altered to sound more accurate to actual players.");
			configThumperNoThunder = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "ThumperNoThunder", true, "Thumpers no longer play thunder sound effects from their voice when they stop chasing after players.");
			configSpaceMutesCruiser = ((BaseUnityPlugin)this).Config.Bind<CruiserMute>("Misc", "SpaceMutesCruiser", CruiserMute.NotRadio, "What audio sources should be muted on the Cruiser when in orbit. (Engine sounds, the horn, the radio, etc.)");
			if (configFixMasks.Value)
			{
				if (((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "DontFixMasks", false, "Legacy setting, use \"FixMasks\" instead").Value)
				{
					configFixMasks.Value = false;
				}
				((BaseUnityPlugin)this).Config.Remove(((BaseUnityPlugin)this).Config["Misc", "DontFixMasks"].Definition);
				((BaseUnityPlugin)this).Config.Save();
			}
			new Harmony("butterystancakes.lethalcompany.enemysoundfixes").PatchAll();
			Logger.LogInfo((object)"Enemy Sound Fixes v1.5.10 loaded");
		}
	}
	internal class References
	{
		internal static readonly FieldInfo CREATURE_VOICE = AccessTools.Field(typeof(EnemyAI), "creatureVoice");

		internal static readonly FieldInfo IS_ENEMY_DEAD = AccessTools.Field(typeof(EnemyAI), "isEnemyDead");

		internal static readonly FieldInfo ENGINE_AUDIO_1 = AccessTools.Field(typeof(VehicleController), "engineAudio1");

		internal static readonly MethodInfo REALTIME_SINCE_STARTUP = AccessTools.DeclaredPropertyGetter(typeof(Time), "realtimeSinceStartup");

		internal static readonly MethodInfo PLAY_ONE_SHOT = AccessTools.Method(typeof(AudioSource), "PlayOneShot", new Type[1] { typeof(AudioClip) }, (Type[])null);

		internal static readonly MethodInfo STOP = AccessTools.Method(typeof(AudioSource), "Stop", Array.Empty<Type>(), (Type[])null);

		internal static readonly MethodInfo DAMAGE_PLAYER = AccessTools.Method(typeof(PlayerControllerB), "DamagePlayer", (Type[])null, (Type[])null);

		internal static readonly MethodInfo HIT_ENEMY = AccessTools.Method(typeof(EnemyAI), "HitEnemy", (Type[])null, (Type[])null);

		internal static readonly MethodInfo PLAY_RANDOM_CLIP = AccessTools.Method(typeof(RoundManager), "PlayRandomClip", (Type[])null, (Type[])null);

		internal static AudioClip baboonTakeDamage;

		internal static AudioClip hitEnemyBody;
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "EnemySoundFixes";

		public const string PLUGIN_NAME = "EnemySoundFixes";

		public const string PLUGIN_VERSION = "1.5.10";
	}
}
namespace EnemySoundFixes.Patches
{
	[HarmonyPatch]
	internal class BaboonHawkPatches
	{
		[HarmonyPatch(typeof(BaboonBirdAI), "HitEnemy")]
		[HarmonyPostfix]
		private static void BaboonBirdAIPostHitEnemy(BaboonBirdAI __instance, bool playHitSFX)
		{
			if (playHitSFX && !((EnemyAI)__instance).isEnemyDead)
			{
				if (!((EnemyAI)__instance).isEnemyDead && (Object)(object)References.baboonTakeDamage != (Object)null)
				{
					((EnemyAI)__instance).creatureVoice.PlayOneShot(References.baboonTakeDamage);
					Plugin.Logger.LogDebug((object)"Baboon hawk: Ouch");
				}
				else if ((Object)(object)References.hitEnemyBody != (Object)null)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(References.hitEnemyBody);
				}
			}
		}

		[HarmonyPatch(typeof(BaboonBirdAI), "OnCollideWithEnemy")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> EnemyTransOnCollideWithEnemy(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo methodInfo = AccessTools.Method(typeof(Animator), "ResetTrigger", new Type[1] { typeof(string) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.DeclaredPropertyGetter(typeof(RoundManager), "Instance");
			for (int i = 3; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == methodInfo)
				{
					for (int j = i + 1; j < list.Count; j++)
					{
						if (list[j].opcode == OpCodes.Call && (MethodInfo)list[j].operand == methodInfo2)
						{
							Label label = generator.DefineLabel();
							list[j].labels.Add(label);
							list.InsertRange(i - 3, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
							{
								new CodeInstruction(OpCodes.Ldarg_2, (object)null),
								new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
								new CodeInstruction(OpCodes.Brtrue, (object)label)
							}));
							Plugin.Logger.LogDebug((object)"Transpiler (Baboon hawk): Don't play hit sound when attacking dead enemy (A)");
							i += 3;
							break;
						}
					}
				}
				else if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == References.HIT_ENEMY)
				{
					list.RemoveAt(i - 2);
					list.InsertRange(i - 2, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[4]
					{
						new CodeInstruction(OpCodes.Ldarg_2, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
						new CodeInstruction(OpCodes.Ldc_I4_0, (object)null),
						new CodeInstruction(OpCodes.Ceq, (object)null)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (Baboon hawk): Don't play hit sound when attacking dead enemy (B)");
					i += 4;
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class BrackenPatches
	{
		[HarmonyPatch(typeof(FlowermanAI), "HitEnemy")]
		[HarmonyPrefix]
		private static void FlowermanAIPreHitEnemy(FlowermanAI __instance, int force, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).enemyHP <= force;
		}

		[HarmonyPatch(typeof(FlowermanAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void FlowermanAIPostKillEnemy(FlowermanAI __instance, bool destroy)
		{
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX);
					Plugin.Logger.LogDebug((object)"Bracken: Play hit sound on death");
				}
			}
		}
	}
	[HarmonyPatch]
	internal class ButlerPatches
	{
		[HarmonyPatch(typeof(ButlerEnemyAI), "Update")]
		[HarmonyPostfix]
		private static void ButlerEnemyAIPostUpdate(ButlerEnemyAI __instance)
		{
			if (((EnemyAI)__instance).isEnemyDead && __instance.buzzingAmbience.isPlaying && ((EnemyAI)__instance).creatureAnimator.GetBool("popFinish"))
			{
				__instance.buzzingAmbience.Stop();
				Plugin.Logger.LogDebug((object)"Butler: Stop buzzing (bugs are free)");
			}
		}
	}
	[HarmonyPatch]
	internal class CruiserPatches
	{
		[HarmonyPatch(typeof(VehicleController), "RevCarClientRpc")]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(VehicleController), "SetIgnition")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> VehicleControllerTransEngineRev(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 4; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == References.PLAY_ONE_SHOT && list[i - 3].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 3].operand == References.ENGINE_AUDIO_1)
				{
					list.InsertRange(i - 4, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
					{
						new CodeInstruction(list[i - 4].opcode, list[i - 4].operand),
						new CodeInstruction(OpCodes.Ldfld, (object)References.ENGINE_AUDIO_1),
						new CodeInstruction(OpCodes.Callvirt, (object)References.STOP)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (Cruiser): Reset engine rev sounds");
					return list;
				}
			}
			Plugin.Logger.LogError((object)"Cruiser transpiler failed");
			return list;
		}

		[HarmonyPatch(typeof(VehicleController), "PlayCollisionAudio")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> VehicleControllerTransPlayCollisionAudio(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo fieldInfo = AccessTools.Field(typeof(VehicleController), "audio1Type");
			FieldInfo operand = AccessTools.Field(typeof(VehicleController), "audio1Time");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(VehicleController), "audio2Type");
			FieldInfo operand2 = AccessTools.Field(typeof(VehicleController), "audio2Time");
			for (int i = 0; i < list.Count - 2; i++)
			{
				if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == References.REALTIME_SINCE_STARTUP && list[i + 2].opcode == OpCodes.Ldfld)
				{
					if ((FieldInfo)list[i + 2].operand == fieldInfo)
					{
						Plugin.Logger.LogDebug((object)"Transpiler (Cruiser): Fix timestamp check for collision audio (#1)");
						list[i + 2].operand = operand;
					}
					else if ((FieldInfo)list[i + 2].operand == fieldInfo2)
					{
						Plugin.Logger.LogDebug((object)"Transpiler (Cruiser): Fix timestamp check for collision audio (#2)");
						list[i + 2].operand = operand2;
					}
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(VehicleController), "SetVehicleAudioProperties")]
		[HarmonyPrefix]
		private static void VehicleControllerPreSetVehicleAudioProperties(VehicleController __instance, AudioSource audio, ref bool audioActive)
		{
			if (audioActive && (((Object)(object)audio == (Object)(object)__instance.extremeStressAudio && __instance.magnetedToShip) || (((Object)(object)audio == (Object)(object)__instance.rollingAudio || (Object)(object)audio == (Object)(object)__instance.skiddingAudio) && (__instance.magnetedToShip || (!__instance.FrontLeftWheel.isGrounded && !__instance.FrontRightWheel.isGrounded && !__instance.BackLeftWheel.isGrounded && !__instance.FrontLeftWheel.isGrounded)))))
			{
				audioActive = false;
			}
		}

		[HarmonyPatch(typeof(VehicleController), "SetVehicleAudioProperties")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> VehicleControllerTransSetVehicleAudioProperties(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo methodInfo = AccessTools.DeclaredPropertyGetter(typeof(AudioSource), "volume");
			for (int i = 0; i < list.Count - 2; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == methodInfo && list[i + 1].opcode == OpCodes.Ldc_R4 && (float)list[i + 1].operand == 0f && list[i - 2].opcode == OpCodes.Bne_Un)
				{
					list[i + 1].operand = 0.001f;
					list[i + 2].opcode = OpCodes.Bge;
					Plugin.Logger.LogDebug((object)"Transpiler (Cruiser): Stop audio source when volume is close enough to zero");
					break;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(VehicleController), "LateUpdate")]
		[HarmonyPostfix]
		private static void VehicleControllerPostLateUpdate(VehicleController __instance)
		{
			if (__instance.magnetedToShip && Plugin.configSpaceMutesCruiser.Value > CruiserMute.Nothing && (StartOfRound.Instance.inShipPhase || !StartOfRound.Instance.shipDoorsEnabled))
			{
				__instance.hornAudio.mute = true;
				__instance.engineAudio1.mute = true;
				__instance.engineAudio2.mute = true;
				__instance.turbulenceAudio.mute = true;
				if (Plugin.configSpaceMutesCruiser.Value == CruiserMute.NotRadio)
				{
					__instance.radioAudio.mute = false;
					__instance.radioInterference.mute = false;
				}
				else
				{
					__instance.radioAudio.mute = true;
					__instance.radioInterference.mute = true;
				}
			}
			else
			{
				__instance.hornAudio.mute = false;
				__instance.engineAudio1.mute = false;
				__instance.engineAudio2.mute = false;
				__instance.turbulenceAudio.mute = false;
				__instance.radioAudio.mute = false;
				__instance.radioInterference.mute = false;
			}
		}
	}
	[HarmonyPatch]
	internal class EyelessDogPatches
	{
		private const float TIME_DROP_CARRIED_BODY = 5.01f;

		private static Dictionary<MouthDogAI, (float Pitch, float Time)> dogPitches = new Dictionary<MouthDogAI, (float, float)>();

		[HarmonyPatch(typeof(MouthDogAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void MouthDogAIPostKillEnemy(MouthDogAI __instance, bool destroy)
		{
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy && (Object)(object)References.hitEnemyBody != (Object)null)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX);
					Plugin.Logger.LogDebug((object)"Mouth dog: Play hit sound on death");
				}
			}
			if (!destroy)
			{
				((EnemyAI)__instance).creatureVoice.mute = true;
				Plugin.Logger.LogDebug((object)"Eyeless dog: Don't start breathing after death");
			}
		}

		[HarmonyPatch(typeof(MouthDogAI), "Start")]
		[HarmonyPostfix]
		private static void MouthDogAIPostStart(MouthDogAI __instance)
		{
			Random random = new Random(StartOfRound.Instance.randomMapSeed + (int)((NetworkBehaviour)__instance).NetworkObjectId);
			if (random.Next(10) < 2)
			{
				((EnemyAI)__instance).creatureVoice.pitch = 0.6f + 0.7f * (float)random.NextDouble();
			}
			else
			{
				((EnemyAI)__instance).creatureVoice.pitch = 0.9f + 0.2f * (float)random.NextDouble();
			}
			Plugin.Logger.LogDebug((object)"Eyeless dog: Reroll voice pitch (seeded random)");
		}

		[HarmonyPatch(typeof(MouthDogAI), "KillPlayerClientRpc")]
		[HarmonyPrefix]
		private static void MouthDogAIPreKillPlayerClientRpc(MouthDogAI __instance)
		{
			if (!dogPitches.ContainsKey(__instance))
			{
				dogPitches.Add(__instance, (((EnemyAI)__instance).creatureVoice.pitch, Time.timeSinceLevelLoad + 5.01f));
				Plugin.Logger.LogDebug((object)$"Eyeless dog #{((Object)__instance).GetInstanceID()}: Cached {((EnemyAI)__instance).creatureVoice.pitch}x voice pitch (kill animation will start)");
			}
			else
			{
				Plugin.Logger.LogWarning((object)$"Eyeless dog #{((Object)__instance).GetInstanceID()}: Tried to initiate kill animation before ending previous kill animation");
			}
		}

		[HarmonyPatch(typeof(MouthDogAI), "Update")]
		[HarmonyPostfix]
		private static void MouthDogAIPostUpdate(MouthDogAI __instance, bool ___inKillAnimation)
		{
			if (!((EnemyAI)__instance).isEnemyDead)
			{
				if (dogPitches.Count > 0 && !___inKillAnimation && dogPitches.TryGetValue(__instance, out (float, float) value) && Time.timeSinceLevelLoad >= value.Item2)
				{
					dogPitches.Remove(__instance);
					Plugin.Logger.LogDebug((object)$"Eyeless dog #{((Object)__instance).GetInstanceID()}: Reset voice pitch now that kill sound is done ({((EnemyAI)__instance).creatureVoice.pitch}x -> {value.Item1}x)");
					((EnemyAI)__instance).creatureVoice.pitch = value.Item1;
				}
				if (!((EnemyAI)__instance).creatureVoice.isPlaying)
				{
					((EnemyAI)__instance).creatureVoice.Play();
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> MouthDogAITransEnterChaseMode(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 1; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == References.PLAY_ONE_SHOT && list[i - 1].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 1].operand == AccessTools.Field(typeof(MouthDogAI), "breathingSFX"))
				{
					for (int j = i - 4; j <= i; j++)
					{
						list[j].opcode = OpCodes.Nop;
					}
					Plugin.Logger.LogDebug((object)"Transpiler (Eyeless dog): Fix overlapping breathing");
					break;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(EnemyAI), "SubtractFromPowerLevel")]
		[HarmonyPostfix]
		private static void EnemyAIPostSubtractFromPowerLevel(EnemyAI __instance)
		{
			MouthDogAI val = (MouthDogAI)(object)((__instance is MouthDogAI) ? __instance : null);
			if ((Object)(object)val != (Object)null && dogPitches.Remove(val))
			{
				Plugin.Logger.LogDebug((object)$"Eyeless dog #{((Object)__instance).GetInstanceID()}: Died mid kill animation (clean up cached reference)");
			}
		}

		[HarmonyPatch(typeof(RoundManager), "ResetEnemyVariables")]
		[HarmonyPostfix]
		private static void RoundManagerPostResetEnemyVariables()
		{
			dogPitches.Clear();
		}

		[HarmonyPatch(typeof(MouthDogAI), "HitEnemy")]
		[HarmonyPrefix]
		private static void MouthDogAIPreHitEnemy(MouthDogAI __instance, int force, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).enemyHP <= force;
		}
	}
	[HarmonyPatch]
	internal class ForestKeeperPatches
	{
		private const float TIME_PLAY_AUDIO_2 = 2.2f;

		[HarmonyPatch(typeof(ForestGiantAI), "Update")]
		[HarmonyPostfix]
		private static void ForestGiantAIPostUpdate(ForestGiantAI __instance)
		{
			if (((EnemyAI)__instance).stunNormalizedTimer > 0f || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).currentBehaviourStateIndex == 2)
			{
				PlayAudioAnimationEvent component = ((Component)__instance.animationContainer).GetComponent<PlayAudioAnimationEvent>();
				AudioSource audioToPlay = component.audioToPlay;
				if (audioToPlay.isPlaying)
				{
					audioToPlay.Stop();
					Plugin.Logger.LogDebug((object)"Forest keeper: Stop chewing (eating animation interrupted)");
				}
				ParticleSystem particle = component.particle;
				if (particle.isEmitting)
				{
					particle.Stop();
					Plugin.Logger.LogDebug((object)"Forest keeper: Stop spraying blood from mouth (eating animation interrupted)");
				}
			}
		}

		[HarmonyPatch(typeof(ForestGiantAI), "StopKillAnimation")]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ForestGiantAITransAnimation(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 1; i < list.Count - 1; i++)
			{
				if (list[i].opcode == OpCodes.Ldfld && (FieldInfo)list[i].operand == References.CREATURE_VOICE)
				{
					for (int j = i - 1; j <= i + 1; j++)
					{
						list[j].opcode = OpCodes.Nop;
						list[j].operand = null;
					}
					Plugin.Logger.LogDebug((object)"Transpiler (Forest Keeper): Don't interrupt voice");
					break;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(ForestGiantAI), "AnimationEventA")]
		[HarmonyPostfix]
		private static void ForestGiantAIPostAnimationEventA(ForestGiantAI __instance)
		{
			((EnemyAI)__instance).creatureSFX.PlayOneShot(__instance.giantFall);
			Plugin.Logger.LogDebug((object)"Forest keeper: Fallen down");
		}

		[HarmonyPatch(typeof(PlayAudioAnimationEvent), "PlayAudio2")]
		[HarmonyPrefix]
		private static bool PlayAudioAnimationEventPrePlayAudio2(PlayAudioAnimationEvent __instance)
		{
			if (((Object)__instance.audioClip2).name == "FGiantEatPlayerSFX")
			{
				EnemyAI mainScript = ((Component)__instance).GetComponent<EnemyAnimationEvent>().mainScript;
				ForestGiantAI val = (ForestGiantAI)(object)((mainScript is ForestGiantAI) ? mainScript : null);
				if ((Object)(object)((EnemyAI)val).inSpecialAnimationWithPlayer != (Object)null && (Object)(object)((EnemyAI)val).inSpecialAnimationWithPlayer.inAnimationWithEnemy == (Object)(object)val)
				{
					__instance.audioToPlay.PlayOneShot(__instance.audioClip2);
					Plugin.Logger.LogDebug((object)"Forest keeper: Play bite sound effect with overlap");
				}
				else
				{
					Plugin.Logger.LogDebug((object)"Forest keeper: Don't bite (player was teleported)");
				}
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayAudioAnimationEvent), "PlayParticle")]
		[HarmonyPrefix]
		private static bool PlayAudioAnimationEventPrePlayParticle(PlayAudioAnimationEvent __instance)
		{
			if ((Object)(object)__instance.audioClip2 != (Object)null && ((Object)__instance.audioClip2).name == "FGiantEatPlayerSFX")
			{
				EnemyAI mainScript = ((Component)__instance).GetComponent<EnemyAnimationEvent>().mainScript;
				if ((Object)(object)mainScript.inSpecialAnimationWithPlayer == (Object)null || (Object)(object)mainScript.inSpecialAnimationWithPlayer.inAnimationWithEnemy != (Object)(object)mainScript)
				{
					Plugin.Logger.LogDebug((object)"Forest keeper: Don't spray blood (player was teleported)");
					return false;
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(EnemyAI), "CancelSpecialAnimationWithPlayer")]
		[HarmonyPrefix]
		private static void EnemyAIPreCancelSpecialAnimationWithPlayer(EnemyAI __instance)
		{
			if (!(__instance is ForestGiantAI) || !((Object)(object)__instance.inSpecialAnimationWithPlayer != (Object)null) || !((Object)(object)__instance.inSpecialAnimationWithPlayer.inAnimationWithEnemy == (Object)(object)__instance) || __instance.inSpecialAnimationWithPlayer.isPlayerDead)
			{
				return;
			}
			PlayAudioAnimationEvent component = ((Component)((ForestGiantAI)((__instance is ForestGiantAI) ? __instance : null)).animationContainer).GetComponent<PlayAudioAnimationEvent>();
			AudioSource audioToPlay = component.audioToPlay;
			if (!audioToPlay.isPlaying)
			{
				return;
			}
			AudioClip clip = audioToPlay.clip;
			if (((clip != null) ? ((Object)clip).name : null) == "Roar" && audioToPlay.time > 2.2f)
			{
				audioToPlay.Stop();
				Plugin.Logger.LogDebug((object)"Forest keeper: Stop chewing (player was teleported)");
				ParticleSystem particle = component.particle;
				if (particle.isEmitting)
				{
					particle.Stop();
					Plugin.Logger.LogDebug((object)"Forest keeper: Stop spraying blood from mouth (player was teleported)");
				}
			}
		}
	}
	[HarmonyPatch]
	internal class GeneralPatches
	{
		internal static bool playHitSound;

		[HarmonyPatch(typeof(QuickMenuManager), "Start")]
		[HarmonyPostfix]
		private static void QuickMenuManagerPostStart(QuickMenuManager __instance)
		{
			List<SpawnableEnemyWithRarity> enemies = __instance.testAllEnemiesLevel.Enemies;
			List<SpawnableEnemyWithRarity> outsideEnemies = __instance.testAllEnemiesLevel.OutsideEnemies;
			List<SpawnableEnemyWithRarity> daytimeEnemies = __instance.testAllEnemiesLevel.DaytimeEnemies;
			List<SpawnableEnemyWithRarity> list = new List<SpawnableEnemyWithRarity>(enemies.Count + outsideEnemies.Count + daytimeEnemies.Count);
			list.AddRange(enemies);
			list.AddRange(outsideEnemies);
			list.AddRange(daytimeEnemies);
			EnemyType val = null;
			foreach (SpawnableEnemyWithRarity item in list)
			{
				switch (((Object)item.enemyType).name)
				{
				case "BaboonHawk":
					if ((Object)(object)References.baboonTakeDamage == (Object)null)
					{
						References.baboonTakeDamage = item.enemyType.hitBodySFX;
						Plugin.Logger.LogDebug((object)"Cached baboon hawk damage sound");
					}
					item.enemyType.hitBodySFX = null;
					Plugin.Logger.LogDebug((object)"Overwritten baboon hawk damage sound");
					((EnemyAI)item.enemyType.enemyPrefab.GetComponent<BaboonBirdAI>()).dieSFX = item.enemyType.deathSFX;
					Plugin.Logger.LogDebug((object)"Overwritten missing baboon hawk death sound");
					break;
				case "Centipede":
					((EnemyAI)item.enemyType.enemyPrefab.GetComponent<CentipedeAI>()).creatureSFX.loop = true;
					Plugin.Logger.LogDebug((object)"Loop snare flea walking and clinging");
					break;
				case "Crawler":
					if (Plugin.configThumperNoThunder.Value)
					{
						EnemyBehaviourState val2 = ((IEnumerable<EnemyBehaviourState>)((EnemyAI)item.enemyType.enemyPrefab.GetComponent<CrawlerAI>()).enemyBehaviourStates).FirstOrDefault((Func<EnemyBehaviourState, bool>)((EnemyBehaviourState enemyBehaviourState) => enemyBehaviourState.name == "searching"));
						if (val2 != null)
						{
							val2.VoiceClip = null;
							val2.playOneShotVoice = false;
							Plugin.Logger.LogDebug((object)"Remove thunder sound from thumper");
						}
					}
					break;
				case "ForestGiant":
				{
					ForestGiantAI component = item.enemyType.enemyPrefab.GetComponent<ForestGiantAI>();
					((EnemyAI)component).creatureSFX.spatialBlend = 1f;
					Plugin.Logger.LogDebug((object)"Fix forest giant global audio volume");
					item.enemyType.hitBodySFX = ((IEnumerable<FootstepSurface>)StartOfRound.Instance.footstepSurfaces).FirstOrDefault((Func<FootstepSurface, bool>)((FootstepSurface footstepSurface) => footstepSurface.surfaceTag == "Wood")).hitSurfaceSFX;
					Plugin.Logger.LogDebug((object)"Overwritten missing forest giant hit sound");
					component.giantBurningAudio.volume = 0f;
					Plugin.Logger.LogDebug((object)"Fix forest giant burning volume fade");
					break;
				}
				case "MouthDog":
					val = item.enemyType;
					break;
				}
				if ((Object)(object)References.hitEnemyBody == (Object)null && ((Object)item.enemyType.hitBodySFX).name == "HitEnemyBody")
				{
					References.hitEnemyBody = item.enemyType.hitBodySFX;
					Plugin.Logger.LogDebug((object)"Cached generic damage sound");
				}
			}
			if ((Object)(object)References.hitEnemyBody != (Object)null && (Object)(object)val != (Object)null)
			{
				val.hitBodySFX = References.hitEnemyBody;
				Plugin.Logger.LogDebug((object)"Overwritten missing eyeless dog hit sound");
			}
		}

		[HarmonyPatch(typeof(AnimatedObjectTrigger), "Start")]
		[HarmonyPostfix]
		private static void AnimatedObjectTriggerPostStart(AnimatedObjectTrigger __instance)
		{
			if (__instance.playAudiosInSequence && (Object)(object)__instance.playParticle == (Object)null)
			{
				__instance.playParticleOnTimesTriggered = -1;
				Plugin.Logger.LogDebug((object)("\"" + ((Object)__instance).name + ".AnimatedObjectTrigger\" doesn't have particles attached"));
			}
		}

		[HarmonyPatch(typeof(MouthDogAI), "OnCollideWithEnemy")]
		[HarmonyPatch(typeof(BushWolfEnemy), "OnCollideWithEnemy")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> EnemyTransOnCollideWithEnemy(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 2; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == References.HIT_ENEMY)
				{
					list.RemoveAt(i - 2);
					list.InsertRange(i - 2, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[4]
					{
						new CodeInstruction(OpCodes.Ldarg_2, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
						new CodeInstruction(OpCodes.Ldc_I4_0, (object)null),
						new CodeInstruction(OpCodes.Ceq, (object)null)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler: Don't play hit sound when attacking dead enemy");
					break;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(StormyWeather), "PlayThunderEffects")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransPlayThunderEffects(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo fieldInfo = AccessTools.Field(typeof(StartOfRound), "shipCreakSFX");
			for (int i = 5; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == References.PLAY_RANDOM_CLIP && list[i - 1].opcode == OpCodes.Ldc_I4 && (int)list[i - 1].operand == 1000 && list[i - 5].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 5].operand == fieldInfo)
				{
					list[i - 1].opcode = OpCodes.Ldc_I4_6;
					Plugin.Logger.LogDebug((object)"Transpiler (Stormy weather): No \"Hey\" when ship is struck");
					break;
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class HoardingBugPatches
	{
		[HarmonyPatch(typeof(HoarderBugAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void HoarderBugAIPostKillEnemy(HoarderBugAI __instance, bool destroy)
		{
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX);
					Plugin.Logger.LogDebug((object)"Hoarding bug: Play hit sound on death");
				}
			}
			if (!destroy)
			{
				((EnemyAI)__instance).creatureVoice.PlayOneShot(((EnemyAI)__instance).enemyType.deathSFX);
				Plugin.Logger.LogDebug((object)"Hoarding bug: Played backup death sound");
			}
		}

		[HarmonyPatch(typeof(HoarderBugAI), "HitEnemy")]
		[HarmonyPrefix]
		private static void HoarderBugAIPreHitEnemy(HoarderBugAI __instance, int force, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).enemyHP <= force;
		}
	}
	[HarmonyPatch]
	internal class KidnapperFoxPatches
	{
		[HarmonyPatch(typeof(BushWolfEnemy), "HitTongueLocalClient")]
		[HarmonyPostfix]
		private static void BushWolfEnemyPostHitTongueLocalClient(BushWolfEnemy __instance)
		{
			((EnemyAI)__instance).creatureVoice.PlayOneShot(__instance.hitBushWolfSFX);
			Plugin.Logger.LogDebug((object)"Kidnapper fox: Bit my tongue");
		}

		[HarmonyPatch(typeof(BushWolfEnemy), "Update")]
		[HarmonyPostfix]
		private static void BushWolfEnemyPostUpdate(BushWolfEnemy __instance, bool ___dragging)
		{
			if ((!___dragging || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).stunNormalizedTimer > 0f) && ((EnemyAI)__instance).creatureVoice.isPlaying && (Object)(object)((EnemyAI)__instance).creatureVoice.clip == (Object)(object)__instance.snarlSFX)
			{
				((EnemyAI)__instance).creatureVoice.clip = null;
				Plugin.Logger.LogDebug((object)"Kidnapper fox: Cancel snarl (failsafe)");
			}
			if (((EnemyAI)__instance).isEnemyDead && __instance.spitParticle.isEmitting)
			{
				__instance.spitParticle.Stop();
				Plugin.Logger.LogDebug((object)"Kidnapper fox: Cancel drool");
			}
		}

		[HarmonyPatch(typeof(BushWolfEnemy), "CancelReelingPlayerIn")]
		[HarmonyPrefix]
		private static void BushWolfEnemyPreCancelReelingPlayerIn(BushWolfEnemy __instance, ref bool ___dragging)
		{
			if (___dragging && ((EnemyAI)__instance).isEnemyDead)
			{
				___dragging = false;
				Plugin.Logger.LogDebug((object)"Kidnapper fox: Don't let dragging interrupt death voice");
			}
		}

		[HarmonyPatch(typeof(BushWolfEnemy), "HitEnemy")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> BushWolfEnemyTransHitEnemy(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo methodInfo = AccessTools.Method(typeof(BushWolfEnemy), "CancelReelingPlayerIn", (Type[])null, (Type[])null);
			Label label = generator.DefineLabel();
			list[list.Count - 1].labels.Add(label);
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].opcode == OpCodes.Call && (MethodInfo)list[num].operand == methodInfo)
				{
					list.InsertRange(num + 1, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
					{
						new CodeInstruction(OpCodes.Ldarg_0, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
						new CodeInstruction(OpCodes.Brtrue, (object)label)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (Kidnapper fox): Don't cry when dead");
					break;
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class ManeaterPatches
	{
		[HarmonyPatch(typeof(CaveDwellerAI), "HitEnemy")]
		[HarmonyPrefix]
		private static void CaveDwellerAIPreHitEnemy(CaveDwellerAI __instance, int force, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).enemyHP <= 1;
		}

		[HarmonyPatch(typeof(CaveDwellerAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void CaveDwellerAIPostKillEnemy(CaveDwellerAI __instance, bool destroy)
		{
			if (destroy)
			{
				return;
			}
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy)
				{
					((EnemyAI)__instance).creatureSFX.Stop();
					((EnemyAI)__instance).creatureSFX.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX);
					Plugin.Logger.LogDebug((object)"Maneater: Play hit sound on death");
				}
			}
			AudioSource[] array = (AudioSource[])(object)new AudioSource[5] { __instance.clickingAudio1, __instance.clickingAudio2, __instance.walkingAudio, __instance.screamAudio, __instance.screamAudioNonDiagetic };
			foreach (AudioSource obj in array)
			{
				obj.Stop();
				obj.mute = true;
			}
			((EnemyAI)__instance).creatureVoice.Stop();
			((EnemyAI)__instance).creatureVoice.PlayOneShot(((EnemyAI)__instance).dieSFX);
			Plugin.Logger.LogDebug((object)"Maneater: Played backup death sound");
		}
	}
	[HarmonyPatch]
	internal class MaskPatches
	{
		[HarmonyPatch(typeof(RandomPeriodicAudioPlayer), "Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RandomPeriodicAudioPlayerTransUpdate(IEnumerable<CodeInstruction> instructions)
		{
			if (!Plugin.configFixMasks.Value)
			{
				return instructions;
			}
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 1; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Add))
				{
					continue;
				}
				for (int num = i - 1; num >= 0; num--)
				{
					if (list[num].opcode == OpCodes.Call && (MethodInfo)list[num].operand == References.REALTIME_SINCE_STARTUP)
					{
						list[i].opcode = OpCodes.Nop;
						list[num].opcode = OpCodes.Nop;
						Plugin.Logger.LogDebug((object)"Transpiler (Periodic mask audio): Fix intervals");
						return list;
					}
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "Start")]
		[HarmonyPostfix]
		private static void MaskedPlayerEnemyPostStart(MaskedPlayerEnemy __instance)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.configBetterMimicSteps.Value)
			{
				return;
			}
			AudioSource val = GameNetworkManager.Instance?.localPlayerController?.movementAudio;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			((Component)__instance.movementAudio).transform.localPosition = new Vector3(0f, 0.278f, 0f);
			__instance.movementAudio.volume = val.volume;
			__instance.movementAudio.dopplerLevel = val.dopplerLevel;
			__instance.movementAudio.spread = val.spread;
			__instance.movementAudio.rolloffMode = (AudioRolloffMode)2;
			foreach (AudioSourceCurveType value in Enum.GetValues(typeof(AudioSourceCurveType)))
			{
				__instance.movementAudio.SetCustomCurve(value, val.GetCustomCurve(value));
			}
			Plugin.Logger.LogDebug((object)"Mimic: Footsteps match players");
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "HitEnemy")]
		[HarmonyPrefix]
		private static void MaskedPlayerEnemyPreHitEnemy(MaskedPlayerEnemy __instance, int force, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).enemyHP <= force;
		}

		[HarmonyPatch(typeof(MaskedPlayerEnemy), "KillEnemy")]
		[HarmonyPostfix]
		private static void MaskedPlayerEnemyPostKillEnemy(MaskedPlayerEnemy __instance, bool destroy)
		{
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX);
					Plugin.Logger.LogDebug((object)"Mimic: Play hit sound on death");
				}
			}
		}
	}
	[HarmonyPatch]
	internal class NutcrackerPatches
	{
		[HarmonyPatch(typeof(NutcrackerEnemyAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void NutcrackerEnemyAIPostKillEnemy(NutcrackerEnemyAI __instance, bool destroy)
		{
			if (!destroy)
			{
				((EnemyAI)__instance).creatureVoice.loop = false;
				((EnemyAI)__instance).creatureVoice.clip = null;
				((EnemyAI)__instance).creatureVoice.pitch = 1f;
				((EnemyAI)__instance).creatureVoice.PlayOneShot(((EnemyAI)__instance).enemyType.deathSFX);
				Plugin.Logger.LogDebug((object)"Nutcracker: Played death sound");
			}
		}
	}
	[HarmonyPatch]
	internal class PlayerPatches
	{
		[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
		[HarmonyPrefix]
		private static void PlayerControllerBPreDamagePlayer(CauseOfDeath causeOfDeath, ref bool fallDamage)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)causeOfDeath == 2 && !fallDamage)
			{
				fallDamage = true;
				Plugin.Logger.LogDebug((object)"Player: Treat Gravity damage as fall damage");
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientClientRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> PlayerControllerBTransDamagePlayerFromOtherClientClientRpc(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 3; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Call) || !((MethodInfo)list[i].operand == References.DAMAGE_PLAYER))
				{
					continue;
				}
				for (int num = i - 1; num > 0; num--)
				{
					if (list[num].opcode == OpCodes.Ldarg_1 && list[num + 1].opcode == OpCodes.Ldc_I4_1)
					{
						list[num + 1].opcode = OpCodes.Ldc_I4_0;
						Plugin.Logger.LogDebug((object)"Transpiler (Players): Melee weapons don't stack hit sounds");
						break;
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class SnareFleaPatches
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransDelayedShriek(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			Label label = generator.DefineLabel();
			for (int i = 0; i < list.Count - 1; i++)
			{
				if (list[i].opcode == OpCodes.Ldloc_1 && list[i + 1].opcode == OpCodes.Ldfld && (FieldInfo)list[i + 1].operand == References.CREATURE_VOICE)
				{
					list[i].labels.Add(label);
					list.InsertRange(i, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[5]
					{
						new CodeInstruction(OpCodes.Ldloc_1, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
						new CodeInstruction(OpCodes.Brfalse, (object)label),
						new CodeInstruction(OpCodes.Ldc_I4_0, (object)null),
						new CodeInstruction(OpCodes.Ret, (object)null)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (Snare flea): Don't shriek when dead (A)");
					break;
				}
			}
			return list;
		}

		[HarmonyPatch(typeof(CentipedeAI), "Update")]
		[HarmonyPrefix]
		private static void CentipedeAIPreUpdate(CentipedeAI __instance)
		{
			if (((EnemyAI)__instance).creatureSFX.isPlaying && (Object)(object)((EnemyAI)__instance).creatureSFX.clip == (Object)(object)((EnemyAI)__instance).enemyBehaviourStates[2].SFXClip && (((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).currentBehaviourStateIndex != 2))
			{
				((EnemyAI)__instance).creatureSFX.Stop();
				((EnemyAI)__instance).creatureSFX.clip = null;
				Plugin.Logger.LogDebug((object)"Snare flea: Stop walking while dead, clinging to player, or sneaking away");
			}
		}

		[HarmonyPatch(typeof(CentipedeAI), "KillEnemy")]
		[HarmonyPostfix]
		private static void CentipedeAIPostKillEnemy(CentipedeAI __instance)
		{
			((EnemyAI)__instance).creatureSFX.clip = null;
		}

		[HarmonyPatch(typeof(EnemyAI), "PlayAudioOfCurrentState")]
		[HarmonyPostfix]
		private static void PostPlayAudioOfCurrentState(EnemyAI __instance)
		{
			if (__instance is CentipedeAI && __instance.currentBehaviourStateIndex == 1 && __instance.creatureVoice.pitch > 1f)
			{
				__instance.creatureVoice.pitch = 1f;
				Plugin.Logger.LogDebug((object)"Snare flea: Reset \"voice\" pitch for attacking again");
			}
		}

		[HarmonyPatch(typeof(CentipedeAI), "HitEnemy")]
		[HarmonyPrefix]
		private static void CentipedeAIPreHitEnemy(CentipedeAI __instance)
		{
			if (((EnemyAI)__instance).creatureSFX.isPlaying && (Object)(object)((EnemyAI)__instance).creatureSFX.clip == (Object)(object)((EnemyAI)__instance).enemyBehaviourStates[2].SFXClip)
			{
				((EnemyAI)__instance).creatureSFX.Stop();
				((EnemyAI)__instance).creatureSFX.clip = null;
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TransFallFromCeiling(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			Label label = generator.DefineLabel();
			FieldInfo fieldInfo = AccessTools.Field(typeof(CentipedeAI), "shriekClips");
			for (int i = 8; i < list.Count - 2; i++)
			{
				if (list[i].opcode == OpCodes.Call && (MethodInfo)list[i].operand == References.PLAY_RANDOM_CLIP && list[i - 5].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 5].operand == fieldInfo)
				{
					list[i + 2].labels.Add(label);
					list.InsertRange(i - 8, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3]
					{
						new CodeInstruction(OpCodes.Ldloc_1, (object)null),
						new CodeInstruction(OpCodes.Ldfld, (object)References.IS_ENEMY_DEAD),
						new CodeInstruction(OpCodes.Brtrue, (object)label)
					}));
					Plugin.Logger.LogDebug((object)"Transpiler (Snare flea): Don't shriek when dead (B)");
					break;
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class TulipSnakePatches
	{
		[HarmonyPatch(typeof(FlowerSnakeEnemy), "Update")]
		[HarmonyPostfix]
		private static void FlowerSnakeEnemyPostUpdate(FlowerSnakeEnemy __instance)
		{
			if (!__instance.flappingAudio.isPlaying)
			{
				return;
			}
			if (((EnemyAI)__instance).isEnemyDead)
			{
				__instance.flappingAudio.Stop();
				__instance.flappingAudio.mute = true;
				Plugin.Logger.LogDebug((object)"Tulip snake: Stop making noise while dead");
			}
			else if ((Object)(object)__instance.flappingAudio.clip == (Object)(object)((EnemyAI)__instance).enemyType.audioClips[9])
			{
				if ((Object)(object)__instance.clingingToPlayer != (Object)null)
				{
					__instance.flappingAudio.Stop();
					Plugin.Logger.LogDebug((object)"Tulip snake: Stop scurrying (latched to player)");
				}
			}
			else if ((Object)(object)__instance.clingingToPlayer == (Object)null)
			{
				__instance.flappingAudio.Stop();
				Plugin.Logger.LogDebug((object)"Tulip snake: Stop flapping (no longer clinging)");
			}
		}

		[HarmonyPatch(typeof(FlowerSnakeEnemy), "StopLeapOnLocalClient")]
		[HarmonyPostfix]
		private static void PostStopLeapOnLocalClient(FlowerSnakeEnemy __instance, bool landOnGround)
		{
			if (landOnGround && !((EnemyAI)__instance).isEnemyDead)
			{
				__instance.flappingAudio.pitch = Random.Range(0.8f, 1.2f);
				Plugin.Logger.LogDebug((object)"Tulip snake: Reroll scurry pitch (landed from leap)");
			}
		}

		[HarmonyPatch(typeof(FlowerSnakeEnemy), "StopClingingOnLocalClient")]
		[HarmonyPostfix]
		private static void PostStopClingingOnLocalClient(FlowerSnakeEnemy __instance)
		{
			if (!((EnemyAI)__instance).isEnemyDead)
			{
				__instance.flappingAudio.pitch = Random.Range(0.8f, 1.2f);
				Plugin.Logger.LogDebug((object)"Tulip snake: Reroll scurry pitch (dismounted player)");
			}
		}

		[HarmonyPatch(typeof(FlowerSnakeEnemy), "HitEnemy")]
		[HarmonyPrefix]
		private static void FlowerSnakeEnemyPreHitEnemy(FlowerSnakeEnemy __instance, bool playHitSFX)
		{
			GeneralPatches.playHitSound = playHitSFX && !((EnemyAI)__instance).isEnemyDead;
		}

		[HarmonyPatch(typeof(FlowerSnakeEnemy), "KillEnemy")]
		[HarmonyPostfix]
		private static void FlowerSnakeEnemyPostKillEnemy(FlowerSnakeEnemy __instance, bool destroy)
		{
			if (GeneralPatches.playHitSound)
			{
				GeneralPatches.playHitSound = false;
				if (!destroy && (Object)(object)References.hitEnemyBody != (Object)null)
				{
					((EnemyAI)__instance).creatureSFX.PlayOneShot(References.hitEnemyBody);
					Plugin.Logger.LogDebug((object)"Tulip snake: Squish");
				}
			}
		}
	}
}
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => _items.Length;

	T IReadOnlyList<T>.this[int index] => _items[index];

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

	void ICollection.CopyTo(Array array, int index)
	{
		((ICollection)_items).CopyTo(array, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object value)
	{
		return ((IList)_items).IndexOf(value);
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		((ICollection<T>)_items).CopyTo(array, arrayIndex);
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}