Decompiled source of WalkieTalkieMimic v1.0.11

MimicFinish.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ed811e64-2e6b-43f8-8853-cac7ec1b6b3c")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace WalkieTalkieMimic;

[BepInPlugin("com.yourname.walkietalkiemimic", "WalkieTalkieMimic", "1.0.0")]
public class WalkieTalkieMimicPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	internal static ConfigEntry<float> TransmitDistance;

	internal static ConfigEntry<float> WalkieVolume;

	internal static ConfigEntry<float> TransmitCooldownMin;

	internal static ConfigEntry<float> TransmitCooldownMax;

	internal static ConfigEntry<float> GlobalTransmitCooldown;

	internal static int NearbyMimicCount = 0;

	internal static List<MaskedPlayerEnemy> MimicQueue = new List<MaskedPlayerEnemy>();

	internal static int CurrentTurnIndex = 0;

	internal static MaskedPlayerEnemy CurrentTransmitter = null;

	internal static bool TransmitSlotFree = true;

	internal static float LastGlobalTransmitEnd = -999f;

	internal static void RegisterMimic(MaskedPlayerEnemy masked)
	{
		if (!MimicQueue.Contains(masked))
		{
			MimicQueue.Add(masked);
			Log.LogInfo((object)$"[Queue] Registered {((Object)masked).GetInstanceID()}. Queue: {MimicQueue.Count}");
		}
	}

	internal static void UnregisterMimic(MaskedPlayerEnemy masked, bool wasNear)
	{
		if (wasNear && NearbyMimicCount > 0)
		{
			NearbyMimicCount--;
		}
		int num = MimicQueue.IndexOf(masked);
		if (num >= 0)
		{
			MimicQueue.RemoveAt(num);
			if (CurrentTurnIndex >= MimicQueue.Count)
			{
				CurrentTurnIndex = 0;
			}
			Log.LogInfo((object)$"[Queue] Unregistered {((Object)masked).GetInstanceID()}. Queue: {MimicQueue.Count}");
		}
		if ((Object)(object)CurrentTransmitter == (Object)(object)masked)
		{
			CurrentTransmitter = null;
			TransmitSlotFree = true;
		}
	}

	internal static bool TryClaimTurn(MaskedPlayerEnemy masked)
	{
		if (!TransmitSlotFree)
		{
			return false;
		}
		if (MimicQueue.Count == 0)
		{
			return false;
		}
		if (NearbyMimicCount > 0)
		{
			return false;
		}
		if (Time.time - LastGlobalTransmitEnd < GlobalTransmitCooldown.Value)
		{
			return false;
		}
		MimicQueue.RemoveAll((MaskedPlayerEnemy m) => (Object)(object)m == (Object)null || ((EnemyAI)m).isEnemyDead);
		if (MimicQueue.Count == 0)
		{
			return false;
		}
		if (CurrentTurnIndex >= MimicQueue.Count)
		{
			CurrentTurnIndex = 0;
		}
		if ((Object)(object)MimicQueue[CurrentTurnIndex] != (Object)(object)masked)
		{
			return false;
		}
		TransmitSlotFree = false;
		CurrentTransmitter = masked;
		Log.LogInfo((object)$"[Queue] {((Object)masked).GetInstanceID()} claimed turn ({CurrentTurnIndex}/{MimicQueue.Count})");
		return true;
	}

	internal static void ReleaseTurn(MaskedPlayerEnemy masked)
	{
		if ((Object)(object)CurrentTransmitter == (Object)(object)masked)
		{
			CurrentTransmitter = null;
			TransmitSlotFree = true;
			LastGlobalTransmitEnd = Time.time;
			CurrentTurnIndex = (CurrentTurnIndex + 1) % Mathf.Max(1, MimicQueue.Count);
			Log.LogInfo((object)$"[Queue] {((Object)masked).GetInstanceID()} released. Next: {CurrentTurnIndex}");
		}
	}

	private void Awake()
	{
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		TransmitDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TransmitDistance", 25f, "Distance in meters. Beyond this the masked enemy's voice is routed through walkie-talkies.");
		WalkieVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "WalkieVolume", 1f, "Volume multiplier for walkie transmission (0.0 - 1.0).");
		TransmitCooldownMin = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TransmitCooldownMin", 13f, "Minimum seconds between walkie transmissions per mimic.");
		TransmitCooldownMax = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TransmitCooldownMax", 40f, "Maximum seconds between walkie transmissions per mimic.");
		GlobalTransmitCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalTransmitCooldown", 5f, "Minimum seconds between any walkie transmission globally (prevents multiple mimics from transmitting back-to-back).");
		new Harmony("com.yourname.walkietalkiemimic").PatchAll();
		Log.LogInfo((object)("WalkieTalkieMimic loaded! " + $"Distance={TransmitDistance.Value}m  " + $"CooldownMin={TransmitCooldownMin.Value}s  " + $"CooldownMax={TransmitCooldownMax.Value}s  " + $"Volume={WalkieVolume.Value}  " + $"GlobalCooldown={GlobalTransmitCooldown.Value}s"));
	}
}
internal static class WalkieInfo
{
	private static bool _initialised;

	private static AudioClip _clipStart;

	private static AudioClip _clipStop;

	public static AudioClip ClipStart => _clipStart;

	public static AudioClip ClipStop => _clipStop;

	public static void Init(WalkieTalkie wt)
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Expected O, but got Unknown
		if (_initialised)
		{
			return;
		}
		_initialised = true;
		Type type = ((object)wt).GetType();
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		FieldInfo[] fields = type.GetFields(bindingAttr);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (fieldInfo.FieldType != typeof(AudioClip))
			{
				continue;
			}
			object value = fieldInfo.GetValue(wt);
			AudioClip val = (AudioClip)((value is AudioClip) ? value : null);
			if (!((Object)(object)val == (Object)null))
			{
				string text = fieldInfo.Name.ToLowerInvariant();
				if ((Object)(object)_clipStart == (Object)null && (text.Contains("on") || text.Contains("start") || text.Contains("open")))
				{
					_clipStart = val;
					WalkieTalkieMimicPlugin.Log.LogInfo((object)("[WalkieInfo] Start clip = '" + fieldInfo.Name + "'"));
				}
				else if ((Object)(object)_clipStop == (Object)null && (text.Contains("off") || text.Contains("stop") || text.Contains("close")))
				{
					_clipStop = val;
					WalkieTalkieMimicPlugin.Log.LogInfo((object)("[WalkieInfo] Stop clip = '" + fieldInfo.Name + "'"));
				}
			}
		}
		fields = type.GetFields(bindingAttr);
		foreach (FieldInfo fieldInfo2 in fields)
		{
			if (!(fieldInfo2.FieldType != typeof(AudioClip[])) && fieldInfo2.GetValue(wt) is AudioClip[] array && array.Length != 0)
			{
				string text2 = fieldInfo2.Name.ToLowerInvariant();
				if ((Object)(object)_clipStart == (Object)null && (text2.Contains("start") || text2.Contains("on") || text2.Contains("open")))
				{
					_clipStart = array[0];
					WalkieTalkieMimicPlugin.Log.LogInfo((object)("[WalkieInfo] Start clip (arr) = '" + fieldInfo2.Name + "'"));
				}
				else if ((Object)(object)_clipStop == (Object)null && (text2.Contains("stop") || text2.Contains("off") || text2.Contains("close")))
				{
					_clipStop = array[0];
					WalkieTalkieMimicPlugin.Log.LogInfo((object)("[WalkieInfo] Stop clip (arr) = '" + fieldInfo2.Name + "'"));
				}
			}
		}
	}

	public static AudioSource GetSpeaker(WalkieTalkie wt)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		string[] array = new string[4] { "thisAudio", "speakerAudio", "audio", "_audio" };
		foreach (string name in array)
		{
			FieldInfo field = ((object)wt).GetType().GetField(name, bindingAttr);
			if (field != null && field.FieldType == typeof(AudioSource))
			{
				object value = field.GetValue(wt);
				return (AudioSource)((value is AudioSource) ? value : null);
			}
		}
		return ((Component)wt).GetComponentInChildren<AudioSource>();
	}
}
[HarmonyPatch(typeof(MaskedPlayerEnemy), "Start")]
internal class MaskedStartPatch
{
	private struct MixerCapture
	{
		public AudioMixerGroup OriginalGroup;

		public bool Active;
	}

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

		private object <>2__current;

		public MaskedPlayerEnemy masked;

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

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

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

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

		private bool MoveNext()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 2;
				return true;
			case 2:
			{
				<>1__state = -1;
				WalkieTalkieMimicPlugin.RegisterMimic(masked);
				Component val = null;
				Component[] componentsInChildren = ((Component)masked).GetComponentsInChildren<Component>(true);
				foreach (Component val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().FullName.Contains("AudioStream"))
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					WalkieTalkieMimicPlugin.Log.LogWarning((object)$"[{((Object)masked).GetInstanceID()}] AudioStream not found.");
					return false;
				}
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				AudioSource val3 = null;
				FieldInfo[] fields = ((object)val).GetType().GetFields(bindingAttr);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.FieldType == typeof(AudioSource))
					{
						object value = fieldInfo.GetValue(val);
						val3 = (AudioSource)((value is AudioSource) ? value : null);
						if ((Object)(object)val3 != (Object)null)
						{
							break;
						}
					}
				}
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = val.GetComponent<AudioSource>();
				}
				if ((Object)(object)val3 == (Object)null)
				{
					WalkieTalkieMimicPlugin.Log.LogWarning((object)$"[{((Object)masked).GetInstanceID()}] Mirage AudioSource not found.");
					return false;
				}
				WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Setup complete.");
				((MonoBehaviour)masked).StartCoroutine(WalkieTransmitter(masked, val3));
				return false;
			}
			}
		}

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

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

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

		private object <>2__current;

		public AudioSource mirageAudio;

		public MaskedPlayerEnemy masked;

		private OccludeAudio <occlude>5__2;

		private float <lastTransmitEnd>5__3;

		private float <nextCooldown>5__4;

		private bool <weHoldTurn>5__5;

		private bool <wasNear>5__6;

		private MixerCapture <mixerCapture>5__7;

		private AudioLowPassFilter <fallbackLpf>5__8;

		private AudioHighPassFilter <fallbackHpf>5__9;

		private AudioSource <walkieSpeaker>5__10;

		private AudioSource <crossZoneSource>5__11;

		private AudioClip <lastSeenClip>5__12;

		private WalkieTalkie <walkie>5__13;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<occlude>5__2 = null;
			<mixerCapture>5__7 = default(MixerCapture);
			<fallbackLpf>5__8 = null;
			<fallbackHpf>5__9 = null;
			<walkieSpeaker>5__10 = null;
			<crossZoneSource>5__11 = null;
			<lastSeenClip>5__12 = null;
			<walkie>5__13 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0736: Unknown result type (might be due to invalid IL or missing references)
			//IL_0740: Expected O, but got Unknown
			//IL_0530: Unknown result type (might be due to invalid IL or missing references)
			//IL_053a: Expected O, but got Unknown
			AudioClip clip;
			bool flag;
			bool num;
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<occlude>5__2 = ((Component)mirageAudio).GetComponent<OccludeAudio>();
				<lastTransmitEnd>5__3 = -999f;
				<nextCooldown>5__4 = WalkieTalkieMimicPlugin.TransmitCooldownMin.Value;
				<weHoldTurn>5__5 = false;
				<wasNear>5__6 = false;
				<mixerCapture>5__7 = default(MixerCapture);
				<fallbackLpf>5__8 = null;
				<fallbackHpf>5__9 = null;
				<walkieSpeaker>5__10 = null;
				<crossZoneSource>5__11 = null;
				<lastSeenClip>5__12 = null;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				goto IL_0750;
			case 2:
				<>1__state = -1;
				goto IL_054a;
			case 3:
				<>1__state = -1;
				goto IL_0750;
			case 4:
				{
					<>1__state = -1;
					goto IL_0750;
				}
				IL_0750:
				if (!((Object)(object)masked != (Object)null) || ((EnemyAI)masked).isEnemyDead)
				{
					break;
				}
				clip = mirageAudio.clip;
				if ((Object)(object)clip != (Object)null && (Object)(object)clip != (Object)(object)<lastSeenClip>5__12)
				{
					<lastSeenClip>5__12 = clip;
					WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Clip detected: '{((Object)clip).name}' ({clip.length:F2}s)");
				}
				flag = NearestPlayerDist(masked) > WalkieTalkieMimicPlugin.TransmitDistance.Value;
				num = !flag;
				if (num && !<wasNear>5__6)
				{
					WalkieTalkieMimicPlugin.NearbyMimicCount++;
					<wasNear>5__6 = true;
					WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Now near. NearbyCount={WalkieTalkieMimicPlugin.NearbyMimicCount}");
				}
				else if (flag & <wasNear>5__6)
				{
					if (WalkieTalkieMimicPlugin.NearbyMimicCount > 0)
					{
						WalkieTalkieMimicPlugin.NearbyMimicCount--;
					}
					<wasNear>5__6 = false;
					WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Moved far. NearbyCount={WalkieTalkieMimicPlugin.NearbyMimicCount}");
				}
				if (num)
				{
					if (<weHoldTurn>5__5)
					{
						if ((Object)(object)<walkieSpeaker>5__10 != (Object)null && (Object)(object)WalkieInfo.ClipStop != (Object)null)
						{
							<walkieSpeaker>5__10.PlayOneShot(WalkieInfo.ClipStop, 1f);
						}
						ExitWalkieMode(mirageAudio, <occlude>5__2, ref <mixerCapture>5__7, ref <fallbackLpf>5__8, ref <fallbackHpf>5__9);
						if ((Object)(object)<crossZoneSource>5__11 != (Object)null && <crossZoneSource>5__11.isPlaying)
						{
							<crossZoneSource>5__11.Stop();
						}
						WalkieTalkieMimicPlugin.ReleaseTurn(masked);
						<weHoldTurn>5__5 = false;
						<walkieSpeaker>5__10 = null;
						WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Walked near — stopped walkie tx.");
					}
					else if ((Object)(object)<occlude>5__2 != (Object)null && !((Behaviour)<occlude>5__2).enabled)
					{
						((Behaviour)<occlude>5__2).enabled = true;
					}
				}
				else if (<weHoldTurn>5__5)
				{
					mirageAudio.volume = WalkieTalkieMimicPlugin.WalkieVolume.Value;
					if ((!IsCrossZone(masked)) ? (!mirageAudio.isPlaying) : ((Object)(object)<crossZoneSource>5__11 == (Object)null || !<crossZoneSource>5__11.isPlaying))
					{
						if ((Object)(object)<walkieSpeaker>5__10 != (Object)null && (Object)(object)WalkieInfo.ClipStop != (Object)null)
						{
							<walkieSpeaker>5__10.PlayOneShot(WalkieInfo.ClipStop, 1f);
						}
						ExitWalkieMode(mirageAudio, <occlude>5__2, ref <mixerCapture>5__7, ref <fallbackLpf>5__8, ref <fallbackHpf>5__9);
						<lastTransmitEnd>5__3 = Time.time;
						<nextCooldown>5__4 = Random.Range(WalkieTalkieMimicPlugin.TransmitCooldownMin.Value, WalkieTalkieMimicPlugin.TransmitCooldownMax.Value);
						WalkieTalkieMimicPlugin.ReleaseTurn(masked);
						<weHoldTurn>5__5 = false;
						<walkieSpeaker>5__10 = null;
						WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Walkie done. Next cooldown: {<nextCooldown>5__4:F1}s");
					}
				}
				else
				{
					mirageAudio.volume = 0f;
					if ((mirageAudio.isPlaying || (IsCrossZone(masked) && (Object)(object)mirageAudio.clip != (Object)null)) && !(Time.time - <lastTransmitEnd>5__3 < <nextCooldown>5__4) && WalkieTalkieMimicPlugin.TryClaimTurn(masked))
					{
						<walkie>5__13 = FindWalkie(masked);
						if ((Object)(object)<walkie>5__13 == (Object)null)
						{
							WalkieTalkieMimicPlugin.Log.LogWarning((object)$"[{((Object)masked).GetInstanceID()}] No walkie found — skipping.");
							WalkieTalkieMimicPlugin.ReleaseTurn(masked);
							goto IL_0708;
						}
						WalkieInfo.Init(<walkie>5__13);
						<walkieSpeaker>5__10 = WalkieInfo.GetSpeaker(<walkie>5__13);
						<weHoldTurn>5__5 = true;
						WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Walkie transmission started.");
						if ((Object)(object)<walkieSpeaker>5__10 != (Object)null && (Object)(object)WalkieInfo.ClipStart != (Object)null)
						{
							<walkieSpeaker>5__10.PlayOneShot(WalkieInfo.ClipStart, 1f);
							<>2__current = (object)new WaitForSeconds(WalkieInfo.ClipStart.length);
							<>1__state = 2;
							return true;
						}
						goto IL_054a;
					}
				}
				goto IL_070f;
				IL_054a:
				EnterWalkieMode(mirageAudio, <occlude>5__2, <walkieSpeaker>5__10, ref <mixerCapture>5__7, ref <fallbackLpf>5__8, ref <fallbackHpf>5__9);
				if (IsCrossZone(masked) && (Object)(object)mirageAudio.clip != (Object)null)
				{
					if ((Object)(object)<crossZoneSource>5__11 == (Object)null)
					{
						<crossZoneSource>5__11 = ((Component)<walkie>5__13).gameObject.AddComponent<AudioSource>();
						<crossZoneSource>5__11.spatialBlend = 0f;
						<crossZoneSource>5__11.loop = false;
						<crossZoneSource>5__11.playOnAwake = false;
					}
					<crossZoneSource>5__11.outputAudioMixerGroup = (((Object)(object)<walkieSpeaker>5__10 != (Object)null) ? <walkieSpeaker>5__10.outputAudioMixerGroup : null);
					AudioHighPassFilter val = ((Component)<crossZoneSource>5__11).GetComponent<AudioHighPassFilter>();
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)<crossZoneSource>5__11).gameObject.AddComponent<AudioHighPassFilter>();
					}
					val.cutoffFrequency = 300f;
					val.highpassResonanceQ = 1f;
					((Behaviour)val).enabled = true;
					AudioLowPassFilter val2 = ((Component)<crossZoneSource>5__11).GetComponent<AudioLowPassFilter>();
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = ((Component)<crossZoneSource>5__11).gameObject.AddComponent<AudioLowPassFilter>();
					}
					val2.cutoffFrequency = 3000f;
					val2.lowpassResonanceQ = 1f;
					((Behaviour)val2).enabled = true;
					<crossZoneSource>5__11.volume = WalkieTalkieMimicPlugin.WalkieVolume.Value;
					<crossZoneSource>5__11.clip = mirageAudio.clip;
					mirageAudio.volume = 0f;
					<crossZoneSource>5__11.Play();
					WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Cross-zone: playing on own AudioSource");
				}
				goto IL_0708;
				IL_0708:
				<walkie>5__13 = null;
				goto IL_070f;
				IL_070f:
				if (<weHoldTurn>5__5)
				{
					<>2__current = null;
					<>1__state = 3;
					return true;
				}
				<>2__current = (object)new WaitForSeconds(0.1f);
				<>1__state = 4;
				return true;
			}
			WalkieTalkieMimicPlugin.Log.LogInfo((object)$"[{((Object)masked).GetInstanceID()}] Masked dead — cleaning up.");
			WalkieTalkieMimicPlugin.UnregisterMimic(masked, <wasNear>5__6);
			if ((Object)(object)<crossZoneSource>5__11 != (Object)null)
			{
				Object.Destroy((Object)(object)<crossZoneSource>5__11);
			}
			if ((Object)(object)mirageAudio != (Object)null)
			{
				ExitWalkieMode(mirageAudio, <occlude>5__2, ref <mixerCapture>5__7, ref <fallbackLpf>5__8, ref <fallbackHpf>5__9);
			}
			return false;
		}

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

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

	private static void Postfix(MaskedPlayerEnemy __instance)
	{
		((MonoBehaviour)__instance).StartCoroutine(WaitForMimicAndSetup(__instance));
	}

	[IteratorStateMachine(typeof(<WaitForMimicAndSetup>d__2))]
	private static IEnumerator WaitForMimicAndSetup(MaskedPlayerEnemy masked)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WaitForMimicAndSetup>d__2(0)
		{
			masked = masked
		};
	}

	private static float NearestPlayerDist(MaskedPlayerEnemy masked)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		float num = float.MaxValue;
		PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
		foreach (PlayerControllerB val in allPlayerScripts)
		{
			if (!((Object)(object)val == (Object)null) && val.isPlayerControlled)
			{
				float num2 = Vector3.Distance(((Component)masked).transform.position, ((Component)val).transform.position);
				if (num2 < num)
				{
					num = num2;
				}
			}
		}
		return num;
	}

	private static bool IsCrossZone(MaskedPlayerEnemy masked)
	{
		PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		return ((EnemyAI)masked).isOutside == val.isInsideFactory;
	}

	private static WalkieTalkie FindWalkie(MaskedPlayerEnemy masked)
	{
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Expected O, but got Unknown
		if ((Object)(object)masked.mimickingPlayer != (Object)null)
		{
			try
			{
				Type type = Type.GetType("ReservedWalkieSlot.Patches.WalkiePatcher, ReservedWalkieSlot");
				if (type != null)
				{
					MethodInfo method = type.GetMethod("GetReservedWalkie", BindingFlags.Static | BindingFlags.Public);
					if (method != null)
					{
						object obj = method.Invoke(null, new object[1] { masked.mimickingPlayer });
						WalkieTalkie val = (WalkieTalkie)((obj is WalkieTalkie) ? obj : null);
						if ((Object)(object)val != (Object)null && ((GrabbableObject)val).isBeingUsed)
						{
							return val;
						}
					}
				}
			}
			catch
			{
			}
			GrabbableObject[] itemSlots = masked.mimickingPlayer.ItemSlots;
			foreach (GrabbableObject val2 in itemSlots)
			{
				WalkieTalkie val3 = (WalkieTalkie)((val2 is WalkieTalkie) ? val2 : null);
				if ((Object)(object)val3 != (Object)null && ((GrabbableObject)val3).isBeingUsed)
				{
					return val3;
				}
			}
		}
		WalkieTalkie result = null;
		float num = float.MaxValue;
		WalkieTalkie[] array = Object.FindObjectsOfType<WalkieTalkie>();
		foreach (WalkieTalkie val4 in array)
		{
			if (((GrabbableObject)val4).isBeingUsed)
			{
				float num2 = Vector3.Distance(((Component)masked).transform.position, ((Component)val4).transform.position);
				if (num2 < num)
				{
					num = num2;
					result = val4;
				}
			}
		}
		return result;
	}

	private static void EnterWalkieMode(AudioSource mirageAudio, OccludeAudio occlude, AudioSource walkieSpeaker, ref MixerCapture capture, ref AudioLowPassFilter lpf, ref AudioHighPassFilter hpf)
	{
		if ((Object)(object)occlude != (Object)null)
		{
			((Behaviour)occlude).enabled = false;
		}
		mirageAudio.spatialBlend = 0f;
		mirageAudio.volume = WalkieTalkieMimicPlugin.WalkieVolume.Value;
		if ((Object)(object)walkieSpeaker != (Object)null && (Object)(object)walkieSpeaker.outputAudioMixerGroup != (Object)null)
		{
			capture.OriginalGroup = mirageAudio.outputAudioMixerGroup;
			capture.Active = true;
			mirageAudio.outputAudioMixerGroup = walkieSpeaker.outputAudioMixerGroup;
			WalkieTalkieMimicPlugin.Log.LogInfo((object)("[Walkie] Routed through LC mixer: '" + ((Object)walkieSpeaker.outputAudioMixerGroup).name + "'"));
		}
		else
		{
			capture.Active = false;
			WalkieTalkieMimicPlugin.Log.LogWarning((object)"[Walkie] No mixer group — filters only.");
		}
		if ((Object)(object)hpf == (Object)null)
		{
			hpf = ((Component)mirageAudio).GetComponent<AudioHighPassFilter>();
		}
		if ((Object)(object)hpf == (Object)null)
		{
			hpf = ((Component)mirageAudio).gameObject.AddComponent<AudioHighPassFilter>();
		}
		hpf.cutoffFrequency = 300f;
		hpf.highpassResonanceQ = 1f;
		((Behaviour)hpf).enabled = true;
		if ((Object)(object)lpf == (Object)null)
		{
			lpf = ((Component)mirageAudio).GetComponent<AudioLowPassFilter>();
		}
		if ((Object)(object)lpf == (Object)null)
		{
			lpf = ((Component)mirageAudio).gameObject.AddComponent<AudioLowPassFilter>();
		}
		lpf.cutoffFrequency = 3000f;
		lpf.lowpassResonanceQ = 1f;
		((Behaviour)lpf).enabled = true;
	}

	private static void ExitWalkieMode(AudioSource mirageAudio, OccludeAudio occlude, ref MixerCapture capture, ref AudioLowPassFilter lpf, ref AudioHighPassFilter hpf)
	{
		if (capture.Active)
		{
			mirageAudio.outputAudioMixerGroup = capture.OriginalGroup;
			capture.Active = false;
		}
		if ((Object)(object)lpf != (Object)null)
		{
			((Behaviour)lpf).enabled = false;
		}
		if ((Object)(object)hpf != (Object)null)
		{
			((Behaviour)hpf).enabled = false;
		}
		mirageAudio.spatialBlend = 1f;
		if ((Object)(object)occlude != (Object)null)
		{
			((Behaviour)occlude).enabled = true;
		}
	}

	[IteratorStateMachine(typeof(<WalkieTransmitter>d__8))]
	private static IEnumerator WalkieTransmitter(MaskedPlayerEnemy masked, AudioSource mirageAudio)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WalkieTransmitter>d__8(0)
		{
			masked = masked,
			mirageAudio = mirageAudio
		};
	}
}