Decompiled source of SmokeGrenade v1.1.1

SmokeGrenade.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
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("SmokeGrenade")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SmokeGrenade")]
[assembly: AssemblyTitle("SmokeGrenade")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 SmokeGrenade
{
	public static class EmbeddedAssets
	{
		public const string IconResource = "SmokeGrenade.smoke_grenade_icon.png";

		public const string ReleaseSoundResource = "SmokeGrenade.gas_grenade_hiss.wav";

		private static byte[] ReadBytes(string resourceName)
		{
			using Stream stream = typeof(EmbeddedAssets).Assembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				Plugin.Log.LogError((object)("Embedded asset '" + resourceName + "' is missing from the build."));
				return null;
			}
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			return array;
		}

		public static Sprite LoadSprite(string resourceName, string spriteName)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = ReadBytes(resourceName);
			if (array == null)
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				name = spriteName,
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1
			};
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogError((object)("Embedded image '" + resourceName + "' could not be decoded."));
				return null;
			}
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			((Object)obj).name = spriteName;
			return obj;
		}

		public static AudioClip LoadWav(string resourceName, string clipName)
		{
			byte[] array = ReadBytes(resourceName);
			if (array == null)
			{
				return null;
			}
			if (array.Length < 12 || BitConverter.ToUInt32(array, 0) != 1179011410 || BitConverter.ToUInt32(array, 8) != 1163280727)
			{
				Plugin.Log.LogError((object)"Embedded sound is not a RIFF/WAVE file.");
				return null;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = -1;
			int num5 = 0;
			int num6 = 12;
			while (num6 + 8 <= array.Length)
			{
				uint num7 = BitConverter.ToUInt32(array, num6);
				int num8 = BitConverter.ToInt32(array, num6 + 4);
				int num9 = num6 + 8;
				if (num7 == 544501094 && num9 + 16 <= array.Length)
				{
					num = BitConverter.ToInt16(array, num9 + 2);
					num2 = BitConverter.ToInt32(array, num9 + 4);
					num3 = BitConverter.ToInt16(array, num9 + 14);
				}
				else if (num7 == 1635017060)
				{
					num4 = num9;
					num5 = Mathf.Min(num8, array.Length - num9);
				}
				num6 = num9 + num8 + (num8 & 1);
			}
			if (num4 < 0 || num <= 0 || num2 <= 0)
			{
				Plugin.Log.LogError((object)"Embedded sound has no usable fmt/data chunks.");
				return null;
			}
			if (num3 != 16)
			{
				Plugin.Log.LogError((object)$"Embedded sound is {num3}-bit; only 16-bit PCM is supported.");
				return null;
			}
			int num10 = num5 / 2;
			float[] array2 = new float[num10];
			for (int i = 0; i < num10; i++)
			{
				array2[i] = (float)BitConverter.ToInt16(array, num4 + i * 2) / 32768f;
			}
			int num11 = num10 / num;
			if (num11 <= 0)
			{
				Plugin.Log.LogError((object)"Embedded sound decoded to zero frames.");
				return null;
			}
			AudioClip obj = AudioClip.Create(clipName, num11, num, num2, false);
			obj.SetData(array2, 0);
			return obj;
		}
	}
	public static class ModInfo
	{
		public const string Guid = "SmokeGrenade";

		public const string Name = "SmokeGrenade";

		public const string Version = "1.0.0";
	}
	[BepInPlugin("SmokeGrenade", "SmokeGrenade", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("SmokeGrenade");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"SmokeGrenade v1.0.0 loaded.");
		}
	}
	public static class SmokeAudio
	{
		private static AudioClip _bundled;

		private static bool _bundledLoaded;

		private static AudioClip _generated;

		private static AudioClip Generated
		{
			get
			{
				if ((Object)(object)_generated != (Object)null)
				{
					return _generated;
				}
				float num = 6f;
				int num2 = Mathf.Max(1024, Mathf.RoundToInt(44100f * num));
				float[] array = new float[num2];
				Random random = new Random(381134);
				float num3 = 1f - Mathf.Exp(-0.12822828f);
				float num4 = 0f;
				float num5 = 0f;
				float num6 = 0f;
				float num7 = 0.0001f;
				for (int i = 0; i < num2; i++)
				{
					float num8 = (float)(random.NextDouble() * 2.0 - 1.0);
					num4 += num3 * (num8 - num4);
					num5 += num3 * (num4 - num5);
					num6 = (array[i] = num6 + num3 * (num5 - num6));
					float num9 = Mathf.Abs(num6);
					if (num9 > num7)
					{
						num7 = num9;
					}
				}
				float num10 = 0.9f / num7;
				for (int j = 0; j < num2; j++)
				{
					float num11 = (float)j / 44100f;
					float num12 = 0.82f + 0.18f * Mathf.Sin(num11 * 3.1f) * Mathf.Sin(num11 * 1.37f + 0.9f);
					array[j] = Mathf.Clamp(array[j] * num10 * num12, -1f, 1f);
				}
				_generated = AudioClip.Create("SmokeGrenadeHiss", num2, 1, 44100, false);
				_generated.SetData(array, 0);
				return _generated;
			}
		}

		public static AudioClip GetReleaseClip()
		{
			if (!_bundledLoaded)
			{
				_bundledLoaded = true;
				_bundled = EmbeddedAssets.LoadWav("SmokeGrenade.gas_grenade_hiss.wav", "SmokeGrenadeRelease");
				if ((Object)(object)_bundled != (Object)null)
				{
					Plugin.Log.LogInfo((object)$"Loaded the release sound ({_bundled.length:0.0}s).");
				}
				else
				{
					Plugin.Log.LogWarning((object)"Falling back to a generated hiss for the smoke release.");
				}
			}
			return _bundled ?? Generated;
		}

		public static AudioSource CreateSource(GameObject host, AudioSource template)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			AudioSource val = host.AddComponent<AudioSource>();
			val.playOnAwake = false;
			val.spatialBlend = 1f;
			val.dopplerLevel = 0f;
			val.rolloffMode = (AudioRolloffMode)1;
			val.minDistance = 2f;
			val.maxDistance = 24f;
			if ((Object)(object)template != (Object)null)
			{
				val.outputAudioMixerGroup = template.outputAudioMixerGroup;
				val.rolloffMode = template.rolloffMode;
				val.minDistance = template.minDistance;
				val.maxDistance = Mathf.Max(template.maxDistance, val.maxDistance);
				val.spatialBlend = Mathf.Max(template.spatialBlend, 0.9f);
				if ((int)template.rolloffMode == 2)
				{
					val.SetCustomCurve((AudioSourceCurveType)0, template.GetCustomCurve((AudioSourceCurveType)0));
				}
			}
			return val;
		}
	}
	public class SmokeCloud : MonoBehaviour
	{
		public static readonly List<SmokeCloud> ActiveClouds = new List<SmokeCloud>();

		private const float SeedRadius = 0.4f;

		private const float InvisibleMeanFreePath = 60f;

		private const float MaxCreep = 1.35f;

		private float _age;

		private float _maxRise;

		private Vector3 _localOrigin;

		private LocalVolumetricFog _fog;

		private AudioSource _audio;

		public float Radius { get; private set; }

		public float Density { get; private set; }

		public static bool AnyActive => ActiveClouds.Count > 0;

		public static SmokeCloud Spawn(Vector3 position, Transform parent, AudioSource audioTemplate)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SmokeGrenadeCloud");
			if ((Object)(object)parent != (Object)null)
			{
				val.transform.SetParent(parent);
			}
			val.transform.position = position;
			val.transform.rotation = Quaternion.identity;
			SmokeCloud smokeCloud = val.AddComponent<SmokeCloud>();
			smokeCloud.Setup(audioTemplate);
			return smokeCloud;
		}

		private void Setup(AudioSource audioTemplate)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			_localOrigin = ((Component)this).transform.localPosition;
			_maxRise = ResolveRiseCeiling();
			Radius = 0.4f;
			Density = 0f;
			CreateFog();
			CreateAudio(audioTemplate);
		}

		private float ResolveRiseCeiling()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			int num = LayerMask.GetMask(new string[3] { "Room", "Terrain", "MiscLevelGeometry" });
			if (num == 0)
			{
				num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-1));
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(((Component)this).transform.position, Vector3.up, ref val, 6f, num, (QueryTriggerInteraction)1))
			{
				return Mathf.Clamp(((RaycastHit)(ref val)).distance - 0.6f, 0f, 5f);
			}
			return 5f;
		}

		private void CreateFog()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("Fog");
				val.transform.SetParent(((Component)this).transform, false);
				_fog = val.AddComponent<LocalVolumetricFog>();
				LocalVolumetricFogArtistParameters p = _fog.parameters;
				p.albedo = SmokeSettings.FogColor;
				p.meanFreePath = 60f;
				p.anisotropy = 0f;
				p.size = Vector3.one * (Radius * 2f);
				p.positiveFade = Vector3.one * 0.5f;
				p.negativeFade = Vector3.one * 0.5f;
				p.distanceFadeStart = 5000f;
				p.distanceFadeEnd = 5000f;
				ApplyNoise(ref p);
				_fog.parameters = p;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not create the volumetric smoke, falling back to an invisible cloud: " + ex.Message));
				_fog = null;
			}
		}

		private static void ApplyNoise(ref LocalVolumetricFogArtistParameters p)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Texture3D val = SmokeNoise.Mask();
				if (!((Object)(object)val == (Object)null))
				{
					p.maskMode = (LocalVolumetricFogMaskMode)0;
					p.volumeMask = (Texture)(object)val;
					p.textureTiling = Vector3.one * 2.2f;
					p.textureScrollingSpeed = new Vector3(0.01f, 0.04f, 0.016f);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not apply the smoke noise mask: " + ex.Message));
			}
		}

		private void CreateAudio(AudioSource audioTemplate)
		{
			try
			{
				AudioClip releaseClip = SmokeAudio.GetReleaseClip();
				if (!((Object)(object)releaseClip == (Object)null))
				{
					_audio = SmokeAudio.CreateSource(((Component)this).gameObject, audioTemplate);
					_audio.clip = releaseClip;
					_audio.loop = true;
					_audio.pitch = 0.37800002f;
					_audio.volume = Mathf.Min(1f, 0.047250003f);
					_audio.Play();
					if ((Object)(object)audioTemplate != (Object)null)
					{
						WalkieTalkie.TransmitOneShotAudio(audioTemplate, releaseClip, _audio.volume);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not play the smoke release: " + ex.Message));
			}
		}

		private void OnEnable()
		{
			if (!ActiveClouds.Contains(this))
			{
				ActiveClouds.Add(this);
			}
		}

		private void OnDisable()
		{
			ActiveClouds.Remove(this);
		}

		private void Update()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			_age += Time.deltaTime;
			if (_age >= 38.3f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Radius = Mathf.Min(RadiusAt(_age), 24.300001f);
			float num = Mathf.Clamp01(_age / 1.2f);
			float num2 = 1f - (1f - num) * (1f - num);
			if (_age > 30.3f)
			{
				num2 *= Mathf.Clamp01(1f - (_age - 30.3f) / 8f);
			}
			Density = Mathf.Clamp01(num2);
			if (_maxRise > 0f)
			{
				((Component)this).transform.localPosition = _localOrigin + Vector3.up * Mathf.Min(0.35f * _age, _maxRise);
			}
			if ((Object)(object)_fog != (Object)null)
			{
				LocalVolumetricFogArtistParameters parameters = _fog.parameters;
				parameters.size = Vector3.one * (Radius * 2f);
				parameters.meanFreePath = Mathf.Lerp(60f, 1f, Density);
				_fog.parameters = parameters;
			}
			DriveRelease();
			if (Density > 0.25f)
			{
				FogUpLocalVisor();
			}
		}

		private static float RadiusAt(float age)
		{
			if (age < 0.3f)
			{
				float num = age / 0.3f;
				return Mathf.Lerp(0.4f, 3.5f, 1f - (1f - num) * (1f - num));
			}
			float num2 = Mathf.Clamp01((age - 0.3f) / 10f);
			float num3 = num2 * num2 * (3f - 2f * num2);
			return Mathf.Lerp(3.5f, 18f, num3) + 0.15f * Mathf.Max(0f, age - 0.3f - 10f);
		}

		private void DriveRelease()
		{
			if ((Object)(object)_audio == (Object)null || !_audio.isPlaying)
			{
				return;
			}
			float num = 6f - _age;
			if (num <= 0f)
			{
				_audio.Stop();
				return;
			}
			float num2 = 0.28f;
			float num3 = 0.035f;
			if (_age < 0.7f)
			{
				float num4 = _age / 0.7f;
				num4 = 1f - (1f - num4) * (1f - num4);
				num2 = Mathf.Lerp(num2 * 1.35f, num2, num4);
				num3 = Mathf.Lerp(Mathf.Min(1f, num3 * 1.35f), num3, num4);
			}
			if (num < 2.5f)
			{
				float num5 = 1f - num / 2.5f;
				num2 = Mathf.Lerp(num2, 0.126f, num5 * num5);
				num3 *= 1f - num5;
			}
			_audio.pitch = num2;
			_audio.volume = num3;
		}

		private void FogUpLocalVisor()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)HUDManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB val = instance.localPlayerController;
			if (!((Object)(object)val == (Object)null))
			{
				if (val.isPlayerDead && (Object)(object)val.spectatedPlayerScript != (Object)null)
				{
					val = val.spectatedPlayerScript;
				}
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameplayCamera == (Object)null) && Vector3.Distance(((Component)val.gameplayCamera).transform.position, ((Component)this).transform.position) < Radius)
				{
					HUDManager.Instance.increaseHelmetCondensation = true;
				}
			}
		}

		public static bool BlocksSight(Vector3 from, Vector3 to)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < ActiveClouds.Count; i++)
			{
				SmokeCloud smokeCloud = ActiveClouds[i];
				if (!((Object)(object)smokeCloud == (Object)null) && !(smokeCloud.Density < 0.25f))
				{
					float num = PathThroughSphere(from, to, ((Component)smokeCloud).transform.position, smokeCloud.Radius);
					if (!(num <= 0f) && num >= 2.5f / Mathf.Max(0.05f, smokeCloud.Density))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static float PathThroughSphere(Vector3 a, Vector3 b, Vector3 centre, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = b - a;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.0001f)
			{
				return 0f;
			}
			Vector3 val2 = val / magnitude;
			Vector3 val3 = a - centre;
			float num = Vector3.Dot(val3, val2);
			float num2 = Vector3.Dot(val3, val3) - radius * radius;
			float num3 = num * num - num2;
			if (num3 <= 0f)
			{
				return 0f;
			}
			float num4 = Mathf.Sqrt(num3);
			float num5 = Mathf.Max(0f - num - num4, 0f);
			return Mathf.Max(Mathf.Min(0f - num + num4, magnitude) - num5, 0f);
		}
	}
	public class SmokeGrenadeBehaviour : MonoBehaviour
	{
		private bool _released;

		public void Release(StunGrenadeItem grenade)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!_released)
			{
				_released = true;
				Vector3 position = ((Component)this).transform.position + Vector3.up * 0.2f;
				SmokeCloud.Spawn(position, ResolveParent(grenade), grenade.itemAudio);
				AlertMonsters(grenade, position);
			}
		}

		private static Transform ResolveParent(StunGrenadeItem grenade)
		{
			if (((GrabbableObject)grenade).isInElevator && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				return StartOfRound.Instance.elevatorTransform;
			}
			if ((Object)(object)RoundManager.Instance != (Object)null && (Object)(object)RoundManager.Instance.mapPropsContainer != (Object)null)
			{
				return RoundManager.Instance.mapPropsContainer.transform;
			}
			return null;
		}

		private static void AlertMonsters(StunGrenadeItem grenade, Vector3 position)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)RoundManager.Instance == (Object)null))
			{
				bool flag = ((GrabbableObject)grenade).isInElevator && (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.hangarDoorsClosed;
				RoundManager.Instance.PlayAudibleNoise(position, 12f, 0.2f, 0, flag, 195301);
			}
		}
	}
	public static class SmokeGrenadeItem
	{
		public const string ItemName = "Smoke grenade";

		private static bool _built;

		public static Item Definition { get; private set; }

		public static GameObject Prefab { get; private set; }

		public static void Build()
		{
			if (_built)
			{
				return;
			}
			_built = true;
			GameObject val = FindStunGrenadePrefab();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"Could not find the vanilla stun grenade prefab; the smoke grenade will not be available.");
				return;
			}
			Item itemProperties = ((GrabbableObject)val.GetComponent<StunGrenadeItem>()).itemProperties;
			Prefab = NetworkPrefabs.CloneNetworkPrefab(val, "SmokeGrenade");
			Definition = Object.Instantiate<Item>(itemProperties);
			((Object)Definition).name = "SmokeGrenadeItem";
			Definition.itemName = "Smoke grenade";
			Definition.itemId = 195301;
			Definition.isScrap = false;
			Definition.creditsWorth = 50;
			Definition.spawnPrefab = Prefab;
			Definition.toolTips = new string[2] { "Pull pin: [RMB]", "Throw smoke: [RMB]" };
			Sprite val2 = EmbeddedAssets.LoadSprite("SmokeGrenade.smoke_grenade_icon.png", "SmokeGrenadeIcon");
			if ((Object)(object)val2 != (Object)null)
			{
				Definition.itemIcon = val2;
			}
			Prefab.GetComponent<GrabbableObject>().itemProperties = Definition;
			StunGrenadeItem component = Prefab.GetComponent<StunGrenadeItem>();
			component.TimeToExplode = 2.25f;
			component.throwString = "Throw smoke: [RMB]";
			component.stunGrenadeExplosion = null;
			component.explodeSFX = null;
			Prefab.AddComponent<SmokeGrenadeBehaviour>();
			Recolour(Prefab);
			RegisterNetworkPrefab(Prefab);
			Items.RegisterShopItem(Definition, 50);
			Plugin.Log.LogInfo((object)string.Format("Registered '{0}' for {1} credits.", "Smoke grenade", 50));
		}

		private static GameObject FindStunGrenadePrefab()
		{
			List<GameObject> list = new List<GameObject>();
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.NetworkConfig != null && singleton.NetworkConfig.Prefabs != null)
			{
				foreach (NetworkPrefabsList networkPrefabsList in singleton.NetworkConfig.Prefabs.NetworkPrefabsLists)
				{
					if ((Object)(object)networkPrefabsList == (Object)null)
					{
						continue;
					}
					foreach (NetworkPrefab prefab in networkPrefabsList.PrefabList)
					{
						if ((Object)(object)prefab?.Prefab != (Object)null)
						{
							Consider(prefab.Prefab, list);
						}
					}
				}
			}
			if (list.Count == 0)
			{
				StunGrenadeItem[] array = Resources.FindObjectsOfTypeAll<StunGrenadeItem>();
				foreach (StunGrenadeItem val in array)
				{
					if ((Object)(object)val != (Object)null)
					{
						Consider(((Component)val).gameObject, list);
					}
				}
			}
			foreach (GameObject item in list)
			{
				if (((GrabbableObject)item.GetComponent<StunGrenadeItem>()).itemProperties.itemName == "Stun grenade")
				{
					return item;
				}
			}
			if (list.Count <= 0)
			{
				return null;
			}
			return list[0];
		}

		private static void Consider(GameObject candidate, List<GameObject> candidates)
		{
			StunGrenadeItem component = candidate.GetComponent<StunGrenadeItem>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)((GrabbableObject)component).itemProperties == (Object)null) && !((Object)(object)((Component)component).GetComponent<NetworkObject>() == (Object)null) && !component.explodeOnCollision && !component.DestroyGrenade && !component.dontRequirePullingPin && !(component.chanceToExplode < 100f) && !candidates.Contains(candidate))
			{
				candidates.Add(candidate);
			}
		}

		private static void RegisterNetworkPrefab(GameObject prefab)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && singleton.NetworkConfig != null && !singleton.NetworkConfig.Prefabs.Contains(prefab))
			{
				singleton.AddNetworkPrefab(prefab);
			}
		}

		private static void Recolour(GameObject prefab)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null))
					{
						Material val2 = new Material(sharedMaterials[j])
						{
							name = ((Object)sharedMaterials[j]).name + " (Smoke)"
						};
						Tint(val2, SmokeSettings.ItemTint);
						sharedMaterials[j] = val2;
						flag = true;
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
		}

		private static void Tint(Material material, Color tint)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty("_BaseColor"))
			{
				material.SetColor("_BaseColor", tint);
			}
			if (material.HasProperty("_Color"))
			{
				material.SetColor("_Color", tint);
			}
			if (material.HasProperty("_UnlitColor"))
			{
				material.SetColor("_UnlitColor", tint);
			}
		}
	}
	public static class SmokeNoise
	{
		private const int Size = 32;

		private static Texture3D _mask;

		public static Texture3D Mask()
		{
			if ((Object)(object)_mask == (Object)null)
			{
				_mask = Build(0.6f);
			}
			return _mask;
		}

		private static Texture3D Build(float strength)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			Texture3D val = new Texture3D(32, 32, 32, (TextureFormat)1, false)
			{
				name = "SmokeGrenadeNoise",
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1
			};
			Color32[] array = (Color32[])(object)new Color32[32768];
			int num = 0;
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					for (int k = 0; k < 32; k++)
					{
						float x = (float)k / 32f;
						float y = (float)j / 32f;
						float z = (float)i / 32f;
						float num2 = Fbm(x, y, z);
						num2 = Mathf.Clamp01((num2 - 0.5f) * 1.6f + 0.5f);
						float num3 = Mathf.Lerp(1f, num2, strength);
						array[num++] = new Color32((byte)0, (byte)0, (byte)0, (byte)(Mathf.Clamp01(num3) * 255f));
					}
				}
			}
			val.SetPixels32(array);
			val.Apply(false, false);
			return val;
		}

		private static float Fbm(float x, float y, float z)
		{
			return ValueNoise(x, y, z, 4, 1) * 0.55f + ValueNoise(x, y, z, 8, 2) * 0.3f + ValueNoise(x, y, z, 16, 3) * 0.15f;
		}

		private static float ValueNoise(float x, float y, float z, int period, int seed)
		{
			x *= (float)period;
			y *= (float)period;
			z *= (float)period;
			int num = Mathf.FloorToInt(x);
			int num2 = Mathf.FloorToInt(y);
			int num3 = Mathf.FloorToInt(z);
			float num4 = Smooth(x - (float)num);
			float num5 = Smooth(y - (float)num2);
			float num6 = Smooth(z - (float)num3);
			float num7 = Corner(num, num2, num3, period, seed);
			float num8 = Corner(num + 1, num2, num3, period, seed);
			float num9 = Corner(num, num2 + 1, num3, period, seed);
			float num10 = Corner(num + 1, num2 + 1, num3, period, seed);
			float num11 = Corner(num, num2, num3 + 1, period, seed);
			float num12 = Corner(num + 1, num2, num3 + 1, period, seed);
			float num13 = Corner(num, num2 + 1, num3 + 1, period, seed);
			float num14 = Corner(num + 1, num2 + 1, num3 + 1, period, seed);
			float num15 = Mathf.Lerp(num7, num8, num4);
			float num16 = Mathf.Lerp(num9, num10, num4);
			float num17 = Mathf.Lerp(num11, num12, num4);
			float num18 = Mathf.Lerp(num13, num14, num4);
			return Mathf.Lerp(Mathf.Lerp(num15, num16, num5), Mathf.Lerp(num17, num18, num5), num6);
		}

		private static float Smooth(float t)
		{
			return t * t * (3f - 2f * t);
		}

		private static float Corner(int x, int y, int z, int period, int seed)
		{
			x = Wrap(x, period);
			y = Wrap(y, period);
			z = Wrap(z, period);
			int num = x * 374761393 + y * 668265263 + z * 1274126177 + seed * 144665123;
			int num2 = (num ^ (num >>> 13)) * 1274126177;
			return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777215f;
		}

		private static int Wrap(int value, int period)
		{
			int num = value % period;
			if (num >= 0)
			{
				return num;
			}
			return num + period;
		}
	}
	internal static class SmokeSettings
	{
		public const int Price = 50;

		public const float FuseTime = 2.25f;

		public static readonly Color ItemTint = new Color(0.644f, 0.9775f, 1.0695f, 1f);

		public const float BurstRadius = 3.5f;

		public const float BurstTime = 0.3f;

		public const float Radius = 18f;

		public const float ExpandTime = 10f;

		public const float LingerGrowth = 0.15f;

		public const float RiseSpeed = 0.35f;

		public const float MaxRise = 5f;

		public const float ThickenTime = 1.2f;

		public const float Duration = 20f;

		public const float FadeTime = 8f;

		public static readonly Color FogColor = Color32.op_Implicit(new Color32((byte)88, (byte)92, (byte)96, byte.MaxValue));

		public const float FogThickness = 1f;

		public const float NoiseStrength = 0.6f;

		public const float NoiseScale = 2.2f;

		public const float NoiseSpeed = 0.04f;

		public const float SightBlockDepth = 2.5f;

		public const float MinBlockingDensity = 0.25f;

		public const float ReleaseVolume = 0.035f;

		public const float ReleasePitch = 0.28f;

		public const float StartBoost = 1.35f;

		public const float AttackTime = 0.7f;

		public const float SpinDownTime = 2.5f;

		public const float SpinDownPitch = 0.45f;

		public const float ReleaseLength = 6f;

		public const float NoiseRange = 12f;

		public const float NoiseLoudness = 0.2f;

		public const int NoiseId = 195301;
	}
}
namespace SmokeGrenade.Patches
{
	[HarmonyPatch(typeof(EnemyAI))]
	internal static class EnemyVisionPatches
	{
		private static bool CanBeBlinded(EnemyAI enemy)
		{
			if (!SmokeCloud.AnyActive)
			{
				return false;
			}
			if ((Object)(object)enemy == (Object)null)
			{
				return false;
			}
			EnemyType enemyType = enemy.enemyType;
			if (!((Object)(object)enemyType == (Object)null))
			{
				return !enemyType.canSeeThroughFog;
			}
			return true;
		}

		private static Vector3 EyePosition(EnemyAI enemy, Transform overrideEye = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)overrideEye != (Object)null)
			{
				return overrideEye.position;
			}
			if ((Object)(object)enemy.eye != (Object)null)
			{
				return enemy.eye.position;
			}
			return ((Component)enemy).transform.position + Vector3.up * 0.5f;
		}

		private static bool Obscured(EnemyAI enemy, Vector3 target, Transform overrideEye = null)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return SmokeCloud.BlocksSight(EyePosition(enemy, overrideEye), target);
		}

		private static Vector3 HeadOf(PlayerControllerB player)
		{
			//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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player.gameplayCamera != (Object)null)
			{
				return ((Component)player.gameplayCamera).transform.position;
			}
			return ((Component)player).transform.position + Vector3.up * 1.5f;
		}

		[HarmonyPatch("CheckLineOfSightForPlayer")]
		[HarmonyPostfix]
		private static void HideFromLineOfSight(EnemyAI __instance, ref PlayerControllerB __result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, HeadOf(__result)))
			{
				__result = null;
			}
		}

		[HarmonyPatch("CheckLineOfSightForClosestPlayer")]
		[HarmonyPostfix]
		private static void HideFromClosestLineOfSight(EnemyAI __instance, ref PlayerControllerB __result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, HeadOf(__result)))
			{
				__result = null;
			}
		}

		[HarmonyPatch("CheckLineOfSightForPosition")]
		[HarmonyPostfix]
		private static void HidePosition(EnemyAI __instance, ref bool __result, Vector3 objectPosition, Transform overrideEye)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (__result && CanBeBlinded(__instance) && Obscured(__instance, objectPosition, overrideEye))
			{
				__result = false;
			}
		}

		[HarmonyPatch("CheckLineOfSight")]
		[HarmonyPostfix]
		private static void HideObject(EnemyAI __instance, ref GameObject __result, Transform useEye)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__result == (Object)null) && CanBeBlinded(__instance) && Obscured(__instance, __result.transform.position, useEye))
			{
				__result = null;
			}
		}

		[HarmonyPatch("GetAllPlayersInLineOfSightNonAlloc", new Type[]
		{
			typeof(PlayerControllerB[]),
			typeof(float),
			typeof(int),
			typeof(Transform),
			typeof(float),
			typeof(int)
		})]
		[HarmonyPostfix]
		private static void FilterProvidedArray(EnemyAI __instance, ref int __result, PlayerControllerB[] playersArray, Transform eyeObject)
		{
			if (__result > 0 && CanBeBlinded(__instance))
			{
				__result = Compact(__instance, playersArray, __result, eyeObject);
			}
		}

		[HarmonyPatch("GetAllPlayersInLineOfSightNonAlloc", new Type[]
		{
			typeof(float),
			typeof(int),
			typeof(Transform),
			typeof(float),
			typeof(int)
		})]
		[HarmonyPostfix]
		private static void FilterSharedArray(EnemyAI __instance, ref int __result, Transform eyeObject)
		{
			if (__result > 0 && CanBeBlinded(__instance) && !((Object)(object)RoundManager.Instance == (Object)null) && RoundManager.Instance.tempPlayersArray != null)
			{
				__result = Compact(__instance, RoundManager.Instance.tempPlayersArray, __result, eyeObject);
			}
		}

		[HarmonyPatch("GetAllPlayersInLineOfSight")]
		[HarmonyPostfix]
		private static void FilterResultArray(EnemyAI __instance, ref PlayerControllerB[] __result, Transform eyeObject)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (__result == null || __result.Length == 0 || !CanBeBlinded(__instance))
			{
				return;
			}
			List<PlayerControllerB> list = null;
			for (int i = 0; i < __result.Length; i++)
			{
				PlayerControllerB val = __result[i];
				bool flag = (Object)(object)val == (Object)null || Obscured(__instance, HeadOf(val), eyeObject);
				if (flag && list == null)
				{
					list = new List<PlayerControllerB>(__result.Length);
					for (int j = 0; j < i; j++)
					{
						list.Add(__result[j]);
					}
				}
				else if (!flag)
				{
					list?.Add(val);
				}
			}
			if (list != null)
			{
				__result = ((list.Count > 0) ? list.ToArray() : null);
			}
		}

		private static int Compact(EnemyAI enemy, PlayerControllerB[] players, int count, Transform eyeObject)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			count = Mathf.Min(count, players.Length);
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				PlayerControllerB val = players[i];
				if (!((Object)(object)val == (Object)null) && !Obscured(enemy, HeadOf(val), eyeObject))
				{
					players[num++] = val;
				}
			}
			for (int j = num; j < count; j++)
			{
				players[j] = null;
			}
			return num;
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal static class GameNetworkManagerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void BuildSmokeGrenade()
		{
			SmokeGrenadeItem.Build();
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void ClearClouds()
		{
			SmokeCloud.ActiveClouds.RemoveAll((SmokeCloud cloud) => (Object)(object)cloud == (Object)null);
		}
	}
	[HarmonyPatch(typeof(StunGrenadeItem))]
	internal static class StunGrenadePatches
	{
		[HarmonyPatch("ExplodeStunGrenade")]
		[HarmonyPrefix]
		private static bool ReleaseSmokeInstead(StunGrenadeItem __instance)
		{
			SmokeGrenadeBehaviour component = ((Component)__instance).GetComponent<SmokeGrenadeBehaviour>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if (__instance.hasExploded)
			{
				return false;
			}
			__instance.hasExploded = true;
			try
			{
				component.Release(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to release smoke: {arg}");
			}
			return false;
		}
	}
}