Decompiled source of BT G19 Hush Puppy v1.0.0

BT_G19_Hush_Puppy.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using OtherLoader;
using UnityEngine;
using UnityEngine.Audio;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace Wickedbadger.BT_G19_Hush_Puppy
{
	[BepInPlugin("Wickedbadger.BT_G19_Hush_Puppy", "BT_G19_Hush_Puppy", "1.0.0")]
	[BepInProcess("h3vr.exe")]
	[Description("Built with MeatKit")]
	[BepInDependency("h3vr.otherloader", "1.3.0")]
	public class BT_G19_Hush_PuppyPlugin : BaseUnityPlugin
	{
		private static readonly string BasePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		internal static ManualLogSource Logger;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			LoadAssets();
		}

		private void LoadAssets()
		{
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Wickedbadger.BT_G19_Hush_Puppy");
			OtherLoader.RegisterDirectLoad(BasePath, "Wickedbadger.BT_G19_Hush_Puppy", "", "", "h3vr.wickedbadger.bnthushpuppy", "");
		}
	}
}
namespace FistVR
{
	public class BaffleSuppressor : Suppressor
	{
		[Header("Shot States")]
		[Tooltip("Index 0 is active at 0 shots. Only one entry is active at a time. The same object can be listed in consecutive entries without being toggled.")]
		public List<GameObject> ShotStates;

		[Tooltip("Shots needed to advance one state. State = shots / ShotsPerState, clamped to the last entry.")]
		public int ShotsPerState = 5;

		[Tooltip("Reset the shot counter (and go back to state 0) when the suppressor is removed from the gun.")]
		public bool ResetOnDetach = true;

		[Header("Volume Ramp (optional)")]
		public bool UseVolumeRamp = true;

		public float StartVolume = 0.2f;

		public float MaxVolume = 1f;

		public int ShotsToMax = 15;

		[Tooltip("Also scale the weapon's Loudness_Suppressed (AI hearing) by the ramp. At full ramp it equals the weapon's original value.")]
		public bool ScaleLoudness = true;

		[Tooltip("BAP-style: the gun class calls TryPlayShot() in place of PlayAudioGunShot(), scaling the shot, tail and AI loudness at play time. Requires the one-line hook in your gun's Fire(). When on, the audio set is not cloned.")]
		public bool UseGunSideOverride = false;

		[Tooltip("Scale the gun's own shot/tail AudioSources after they start playing, from this suppressor's OnShot hook (no gun class edit, no audio set cloning). Ignored if UseGunSideOverride is on. Does not change AI-hearing loudness.")]
		public bool UseOnShotScaling = false;

		[Tooltip("OnShot scaling: only AudioSources within this distance (m) of the muzzle or the gun are touched.")]
		public float ScaleSearchRadius = 1.5f;

		[Tooltip("OnShot scaling: only sources that started playing this recently (seconds of clip time) are touched, so earlier shots' tails aren't scaled twice.")]
		public float ScaleMaxSourceAge = 0.1f;

		[Tooltip("OnShot scaling: only touch sources playing one of the gun's Shots_Suppressed clips or the suppressed tail clips, rather than any source near the muzzle.")]
		public bool MatchGunClips = true;

		[Tooltip("Logs binding and ramp values to the console, to help work out why the volume isn't changing.")]
		public bool DebugLogging = false;

		private int m_shotsFired;

		private int m_curState = -1;

		private FVRFireArm m_boundFirearm;

		private FVRFirearmAudioSet m_originalSet;

		private FVRFirearmAudioSet m_clonedSet;

		private float m_originalLoudnessSuppressed;

		private Vector2 m_originalVolumeRange;

		public float CurrentVolumeMultiplier => ComputeRampMultiplier();

		private bool UsesAudioSetClone => UseVolumeRamp && !UseGunSideOverride && !UseOnShotScaling;

		private float ComputeRampMultiplier()
		{
			return ComputeRampMultiplier(m_shotsFired);
		}

		private float ComputeRampMultiplier(int shots)
		{
			if (!UseVolumeRamp)
			{
				return 1f;
			}
			float num = ((ShotsToMax <= 0) ? 1f : Mathf.Clamp01((float)shots / (float)ShotsToMax));
			float num2 = Mathf.Lerp(StartVolume, MaxVolume, num);
			return (!(MaxVolume > 0f)) ? 1f : Mathf.Clamp01(num2 / MaxVolume);
		}

		public bool TryPlayShot(FVRFireArm gun, AudioSourcePool poolShot, AudioSourcePool poolTail, FVRFireArmRound round, FVRSoundEnvironment env, float globalLoudnessMultiplier)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			if (!UseGunSideOverride || !UseVolumeRamp || (Object)(object)gun == (Object)null || (Object)(object)gun.AudioClipSet == (Object)null || !gun.IsSuppressed())
			{
				return false;
			}
			FVRFirearmAudioSet audioClipSet = gun.AudioClipSet;
			float num = ComputeRampMultiplier();
			Vector3 position = ((Component)gun).transform.position;
			FVRTailSoundClass val = (FVRTailSoundClass)0;
			AudioEvent shots_Suppressed = audioClipSet.Shots_Suppressed;
			poolShot.PlayClipVolumePitchOverride(shots_Suppressed, gun.GetMuzzle().position, shots_Suppressed.VolumeRange * num, shots_Suppressed.PitchRange, (AudioMixerGroup)null);
			if (((FVRInteractiveObject)gun).IsHeld && (Object)(object)((FVRInteractiveObject)gun).m_hand != (Object)null)
			{
				((FVRInteractiveObject)gun).m_hand.ForceTubeKick(audioClipSet.FTP.Kick_Shot);
				((FVRInteractiveObject)gun).m_hand.ForceTubeRumble(audioClipSet.FTP.Rumble_Shot_Intensity, audioClipSet.FTP.Rumble_Shot_Duration);
			}
			if (audioClipSet.UsesTail_Suppressed)
			{
				val = round.TailClassSuppressed;
				AudioEvent tailSet = SM.GetTailSet(round.TailClassSuppressed, env);
				poolTail.PlayClipVolumePitchOverride(tailSet, position, tailSet.VolumeRange * globalLoudnessMultiplier * num, audioClipSet.TailPitchMod_Suppressed * tailSet.PitchRange.x, (AudioMixerGroup)null);
			}
			float num2 = ((!ScaleLoudness) ? 1f : num);
			float soundTravelDistanceMultByEnvironment = SM.GetSoundTravelDistanceMultByEnvironment(env);
			int playerIFF = GM.CurrentPlayerBody.GetPlayerIFF();
			GM.CurrentSceneSettings.OnPerceiveableSound(audioClipSet.Loudness_Suppressed * num2, audioClipSet.Loudness_Suppressed * soundTravelDistanceMultByEnvironment * 0.5f * globalLoudnessMultiplier * num2, position, playerIFF, GM.CurrentPlayerBody.PlayerEntities[0]);
			if (DebugLogging)
			{
				Debug.Log((object)("[BaffleSuppressor] TryPlayShot shots=" + m_shotsFired + " mult=" + num));
			}
			gun.RattleSuppresor();
			for (int i = 0; i < gun.MuzzleDevices.Count; i++)
			{
				gun.MuzzleDevices[i].OnShot(gun, val);
			}
			return true;
		}

		public override void OnShot(FVRFireArm firearm, FVRTailSoundClass tailClass)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((MuzzleDevice)this).OnShot(firearm, tailClass);
			}
			catch (Exception ex)
			{
				if (DebugLogging)
				{
					Debug.Log((object)("[BaffleSuppressor] base.OnShot threw: " + ex.Message));
				}
			}
			if (UseOnShotScaling && !UseGunSideOverride && UseVolumeRamp && ((Behaviour)this).enabled && !((Object)(object)firearm == (Object)null))
			{
				ScaleRecentGunAudio(firearm, tailClass);
			}
		}

		private void ScaleRecentGunAudio(FVRFireArm firearm, FVRTailSoundClass tailClass)
		{
			//IL_003a: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			float num = ComputeRampMultiplier(Mathf.Max(0, m_shotsFired - 1));
			Transform muzzle = firearm.GetMuzzle();
			Vector3 val = ((!((Object)(object)muzzle != (Object)null)) ? ((Component)firearm).transform.position : muzzle.position);
			Vector3 position = ((Component)firearm).transform.position;
			float num2 = ScaleSearchRadius * ScaleSearchRadius;
			FVRFirearmAudioSet audioClipSet = firearm.AudioClipSet;
			AudioEvent val2 = ((!((Object)(object)audioClipSet != (Object)null)) ? null : audioClipSet.Shots_Suppressed);
			AudioEvent val3 = null;
			if ((Object)(object)audioClipSet != (Object)null && audioClipSet.UsesTail_Suppressed)
			{
				val3 = SM.GetTailSet(tailClass, GM.CurrentPlayerBody.GetCurrentSoundEnvironment());
			}
			int num3 = 0;
			AudioSource[] array = Object.FindObjectsOfType<AudioSource>();
			foreach (AudioSource val4 in array)
			{
				if ((Object)(object)val4 == (Object)null || !val4.isPlaying || val4.time > ScaleMaxSourceAge)
				{
					continue;
				}
				Vector3 position2 = ((Component)val4).transform.position;
				Vector3 val5 = position2 - val;
				if (((Vector3)(ref val5)).sqrMagnitude > num2)
				{
					Vector3 val6 = position2 - position;
					if (((Vector3)(ref val6)).sqrMagnitude > num2)
					{
						continue;
					}
				}
				if (MatchGunClips)
				{
					AudioClip clip = val4.clip;
					bool flag = val2 != null && val2.Clips != null && val2.Clips.Contains(clip);
					bool flag2 = val3 != null && val3.Clips != null && val3.Clips.Contains(clip);
					if (!flag && !flag2)
					{
						continue;
					}
				}
				val4.volume *= num;
				num3++;
			}
			if (DebugLogging)
			{
				Debug.Log((object)("[BaffleSuppressor] OnShot scaling: shots=" + m_shotsFired + " mult=" + num + " sourcesScaled=" + num3));
			}
		}

		public override void AttachToMount(FVRFireArmAttachmentMount m, bool playSound)
		{
			((Suppressor)this).AttachToMount(m, playSound);
			if (((Behaviour)this).enabled && UsesAudioSetClone)
			{
				BindToFirearm();
			}
		}

		public override void FVRUpdate()
		{
			((Suppressor)this).FVRUpdate();
			if ((Object)(object)m_boundFirearm != (Object)null && !((Component)this).transform.IsChildOf(((Component)m_boundFirearm).transform))
			{
				Unbind();
				if (ResetOnDetach)
				{
					m_shotsFired = 0;
					ApplyState();
				}
			}
			else if (!UsesAudioSetClone && ResetOnDetach && m_shotsFired > 0 && (Object)(object)((Component)this).GetComponentInParent<FVRFireArm>() == (Object)null)
			{
				m_shotsFired = 0;
				ApplyState();
			}
		}

		public override void ShotEffect()
		{
			((Suppressor)this).ShotEffect();
			if (((Behaviour)this).enabled)
			{
				if (UsesAudioSetClone && (Object)(object)m_boundFirearm == (Object)null)
				{
					BindToFirearm();
				}
				m_shotsFired++;
				ApplyState();
				if (UsesAudioSetClone)
				{
					ApplyVolume();
				}
			}
		}

		public void ResetShots()
		{
			m_shotsFired = 0;
			ApplyState();
			if (UsesAudioSetClone)
			{
				ApplyVolume();
			}
		}

		private void ApplyState()
		{
			if (ShotStates == null || ShotStates.Count == 0)
			{
				return;
			}
			int num = Mathf.Max(1, ShotsPerState);
			int num2 = Mathf.Clamp(m_shotsFired / num, 0, ShotStates.Count - 1);
			if (num2 == m_curState)
			{
				return;
			}
			m_curState = num2;
			GameObject val = ShotStates[num2];
			for (int i = 0; i < ShotStates.Count; i++)
			{
				GameObject val2 = ShotStates[i];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && val2.activeSelf)
				{
					val2.SetActive(false);
				}
			}
			if ((Object)(object)val != (Object)null && !val.activeSelf)
			{
				val.SetActive(true);
			}
		}

		private void BindToFirearm()
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			FVRFireArm componentInParent = ((Component)this).GetComponentInParent<FVRFireArm>();
			if (DebugLogging)
			{
				Debug.Log((object)("[BaffleSuppressor] BindToFirearm: firearm=" + ((!((Object)(object)componentInParent != (Object)null)) ? "NULL" : ((Object)componentInParent).name) + " audioSet=" + ((!((Object)(object)componentInParent != (Object)null) || !((Object)(object)componentInParent.AudioClipSet != (Object)null)) ? "NULL" : ((Object)componentInParent.AudioClipSet).name)));
			}
			if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)m_boundFirearm))
			{
				Unbind();
				if (!((Object)(object)componentInParent.AudioClipSet == (Object)null))
				{
					m_boundFirearm = componentInParent;
					m_originalSet = componentInParent.AudioClipSet;
					m_originalLoudnessSuppressed = m_originalSet.Loudness_Suppressed;
					m_originalVolumeRange = m_originalSet.Shots_Suppressed.VolumeRange;
					m_clonedSet = Object.Instantiate<FVRFirearmAudioSet>(m_originalSet);
					componentInParent.AudioClipSet = m_clonedSet;
					m_shotsFired = 0;
					ApplyState();
					ApplyVolume();
				}
			}
		}

		private void Unbind()
		{
			if ((Object)(object)m_boundFirearm != (Object)null && (Object)(object)m_boundFirearm.AudioClipSet == (Object)(object)m_clonedSet)
			{
				m_boundFirearm.AudioClipSet = m_originalSet;
			}
			if ((Object)(object)m_clonedSet != (Object)null)
			{
				Object.Destroy((Object)(object)m_clonedSet);
			}
			m_boundFirearm = null;
			m_originalSet = null;
			m_clonedSet = null;
		}

		private void ApplyVolume()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)m_clonedSet == (Object)null))
			{
				float num = ComputeRampMultiplier();
				m_clonedSet.Shots_Suppressed.VolumeRange = m_originalVolumeRange * num;
				if (DebugLogging)
				{
					Debug.Log((object)("[BaffleSuppressor] shots=" + m_shotsFired + " mult=" + num + " volumeRange=" + m_clonedSet.Shots_Suppressed.VolumeRange));
				}
				if (ScaleLoudness)
				{
					m_clonedSet.Loudness_Suppressed = m_originalLoudnessSuppressed * num;
				}
			}
		}

		private void OnEnable()
		{
			m_curState = -1;
			ApplyState();
		}

		private void OnDisable()
		{
			Unbind();
		}

		private void OnDestroy()
		{
			Unbind();
		}
	}
	public class HandgunSecondarySwitch : FVRInteractiveObject
	{
		public Handgun Weapon;

		public int CurModeIndex;

		public int ModeIndexToSub = 1;

		public Transform SelctorSwitch;

		public Axis Axis;

		public InterpStyle InterpStyle;

		public FireSelectorMode[] Modes;

		public override void Awake()
		{
			((FVRInteractiveObject)this).Awake();
			UpdateBaseGunSelector(CurModeIndex);
		}

		public override void SimpleInteraction(FVRViveHand hand)
		{
			((FVRInteractiveObject)this).SimpleInteraction(hand);
			CycleMode();
		}

		private void CycleMode()
		{
			CurModeIndex++;
			if (CurModeIndex >= Modes.Length)
			{
				CurModeIndex = 0;
			}
			UpdateBaseGunSelector(CurModeIndex);
			((FVRFireArm)Weapon).PlayAudioEvent((FirearmAudioEventType)15, 1f);
		}

		private void UpdateBaseGunSelector(int i)
		{
			//IL_001d: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			FireSelectorMode val = Modes[i];
			((FVRPhysicalObject)Weapon).SetAnimatedComponent(SelctorSwitch, val.SelectorPosition, InterpStyle, Axis);
			FireSelectorMode val2 = Weapon.FireSelectorModes[ModeIndexToSub];
			val2.ModeType = val.ModeType;
			val2.BurstAmount = val.BurstAmount;
			Weapon.ResetCamBurst();
		}
	}
	[RequireComponent(typeof(Handgun))]
	public class HandgunSlideLockAddon : MonoBehaviour
	{
		[Header("Slide Lock Addon")]
		public Handgun Handgun;

		[Tooltip("0-based index into the Handgun's 'Fire Selector Modes' array. The slide is locked forward while this element is selected.")]
		public int LockedModeIndex = 2;

		[Tooltip("Disable the physics-based slide rack (hitting the slide against things) while locked.")]
		public bool BlockPhysicsRacking = true;

		[Tooltip("Uses the Handgun's own slide lock mechanism state (m_isSlideLockMechanismEngaged) to stop the slide cycling when fired. Side effect from Handgun.Fire: shots are 0.4x loudness and 1.5x vertical recoil while engaged. If off, the slide can still be knocked back by the firing impulse.")]
		public bool UseNativeSlideLockState = true;

		private bool m_isLocked;

		private bool m_origCanPhysicsSlideRack;

		private bool m_weEngagedNativeState;

		private FieldInfo m_slideLockField;

		public bool IsSlideLocked => m_isLocked;

		private void Awake()
		{
			if ((Object)(object)Handgun == (Object)null)
			{
				Handgun = ((Component)this).GetComponent<Handgun>();
			}
			m_slideLockField = typeof(Handgun).GetField("m_isSlideLockMechanismEngaged", BindingFlags.Instance | BindingFlags.NonPublic);
			if (UseNativeSlideLockState && (object)m_slideLockField == null)
			{
				Debug.LogWarning((object)"HandgunSlideLockAddon: couldn't find m_isSlideLockMechanismEngaged; firing may still cycle the slide.");
			}
		}

		private void LateUpdate()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Handgun == (Object)null || (Object)(object)Handgun.Slide == (Object)null)
			{
				return;
			}
			bool flag = Handgun.FireSelectorModes != null && Handgun.FireSelectorModes.Length > 0 && Handgun.FireSelectorModeIndex == LockedModeIndex;
			if (flag && !m_isLocked)
			{
				if ((int)Handgun.Slide.CurPos == 0)
				{
					EngageLock();
				}
			}
			else if (!flag && m_isLocked)
			{
				ReleaseLock();
			}
			if (m_isLocked)
			{
				MaintainLock();
			}
		}

		private void EngageLock()
		{
			m_isLocked = true;
			m_origCanPhysicsSlideRack = Handgun.CanPhysicsSlideRack;
			if (BlockPhysicsRacking)
			{
				Handgun.CanPhysicsSlideRack = false;
			}
		}

		private void MaintainLock()
		{
			if ((Object)(object)((FVRInteractiveObject)Handgun.Slide).m_hand != (Object)null)
			{
				((FVRInteractiveObject)Handgun.Slide).ForceBreakInteraction();
			}
			if (UseNativeSlideLockState && (object)m_slideLockField != null && !(bool)m_slideLockField.GetValue(Handgun))
			{
				m_slideLockField.SetValue(Handgun, true);
				m_weEngagedNativeState = true;
			}
		}

		private void ReleaseLock()
		{
			m_isLocked = false;
			if (BlockPhysicsRacking)
			{
				Handgun.CanPhysicsSlideRack = m_origCanPhysicsSlideRack;
			}
			if (m_weEngagedNativeState && (object)m_slideLockField != null)
			{
				m_slideLockField.SetValue(Handgun, false);
			}
			m_weEngagedNativeState = false;
		}

		private void OnDisable()
		{
			if (m_isLocked && (Object)(object)Handgun != (Object)null)
			{
				ReleaseLock();
			}
		}
	}
	[RequireComponent(typeof(Handgun))]
	public class SafetyToSlideLock : MonoBehaviour
	{
		[Tooltip("Defaults to the Handgun on this GameObject.")]
		public Handgun Target;

		[Tooltip("If the gun has a fire selector, the slide lock follows the selector's Safe mode instead of toggling on every safety press.")]
		public bool UseFireSelectorSafeMode = true;

		private FieldInfo m_safetyField;

		private FieldInfo m_slideLockField;

		private int m_lastSelectorIndex = -1;

		private void Awake()
		{
			if ((Object)(object)Target == (Object)null)
			{
				Target = ((Component)this).GetComponent<Handgun>();
			}
			Type typeFromHandle = typeof(Handgun);
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
			m_safetyField = typeFromHandle.GetField("m_isSafetyEngaged", bindingAttr);
			m_slideLockField = typeFromHandle.GetField("m_isSlideLockMechanismEngaged", bindingAttr);
			if ((Object)(object)Target == (Object)null || (object)m_safetyField == null || (object)m_slideLockField == null)
			{
				Debug.LogWarning((object)"SafetyToSlideLock: could not find Handgun or its private fields; disabling.", (Object)(object)this);
				((Behaviour)this).enabled = false;
			}
		}

		private void LateUpdate()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Invalid comparison between Unknown and I4
			bool flag = (Object)(object)Target.Slide != (Object)null && (int)Target.Slide.CurPos == 0;
			bool flag2 = UseFireSelectorSafeMode && Target.HasFireSelector && Target.FireSelectorModes != null && Target.FireSelectorModes.Length > 0;
			if (Target.IsSafetyEngaged)
			{
				m_safetyField.SetValue(Target, false);
				if (!flag2 && flag)
				{
					SetSlideLock(!Target.IsSLideLockMechanismEngaged);
				}
			}
			if (flag2 && flag)
			{
				int fireSelectorModeIndex = Target.FireSelectorModeIndex;
				if (fireSelectorModeIndex != m_lastSelectorIndex && fireSelectorModeIndex >= 0 && fireSelectorModeIndex < Target.FireSelectorModes.Length)
				{
					m_lastSelectorIndex = fireSelectorModeIndex;
					bool slideLock = (int)Target.FireSelectorModes[fireSelectorModeIndex].ModeType == 3;
					SetSlideLock(slideLock);
				}
			}
		}

		private void SetSlideLock(bool engaged)
		{
			m_slideLockField.SetValue(Target, engaged);
		}
	}
	public class SuppressorShotStates : Suppressor
	{
		[Header("Shot States")]
		[Tooltip("Index 0 is active at 0 shots. Only one entry is active at a time.")]
		public List<GameObject> ShotStates;

		[Tooltip("Shots needed to advance one state. State = shots / ShotsPerState, clamped to the last entry.")]
		public int ShotsPerState = 5;

		[Tooltip("Reset the shot counter (and go back to state 0) when the suppressor is removed from the gun.")]
		public bool ResetOnDetach = true;

		[Header("Volume Ramp (optional)")]
		public bool UseVolumeRamp = true;

		public float StartVolume = 0.2f;

		public float MaxVolume = 1f;

		public int ShotsToMax = 15;

		[Tooltip("Also scale the weapon's Loudness_Suppressed (AI hearing) by the ramp. At full ramp it equals the weapon's original value.")]
		public bool ScaleLoudness = true;

		[Tooltip("BAP-style: the gun class calls TryPlayShot() in place of PlayAudioGunShot(), scaling the shot, tail and AI loudness at play time. Requires the one-line hook in your gun's Fire(). When on, the audio set is not cloned.")]
		public bool UseGunSideOverride = false;

		[Tooltip("Scale the gun's own shot/tail AudioSources after they start playing, from this suppressor's OnShot hook (no gun class edit, no audio set cloning). Ignored if UseGunSideOverride is on. Does not change AI-hearing loudness.")]
		public bool UseOnShotScaling = false;

		[Tooltip("OnShot scaling: only AudioSources within this distance (m) of the muzzle or the gun are touched.")]
		public float ScaleSearchRadius = 1.5f;

		[Tooltip("OnShot scaling: only sources that started playing this recently (seconds of clip time) are touched, so earlier shots' tails aren't scaled twice.")]
		public float ScaleMaxSourceAge = 0.1f;

		[Tooltip("OnShot scaling: only touch sources playing one of the gun's Shots_Suppressed clips or the suppressed tail clips, rather than any source near the muzzle.")]
		public bool MatchGunClips = true;

		[Tooltip("Logs binding and ramp values to the console, to help work out why the volume isn't changing.")]
		public bool DebugLogging = false;

		private int m_shotsFired;

		private int m_curState = -1;

		private FVRFireArm m_boundFirearm;

		private FVRFirearmAudioSet m_originalSet;

		private FVRFirearmAudioSet m_clonedSet;

		private float m_originalLoudnessSuppressed;

		private Vector2 m_originalVolumeRange;

		public float CurrentVolumeMultiplier => ComputeRampMultiplier();

		private bool UsesAudioSetClone => UseVolumeRamp && !UseGunSideOverride && !UseOnShotScaling;

		private float ComputeRampMultiplier()
		{
			return ComputeRampMultiplier(m_shotsFired);
		}

		private float ComputeRampMultiplier(int shots)
		{
			if (!UseVolumeRamp)
			{
				return 1f;
			}
			float num = ((ShotsToMax <= 0) ? 1f : Mathf.Clamp01((float)shots / (float)ShotsToMax));
			float num2 = Mathf.Lerp(StartVolume, MaxVolume, num);
			return (!(MaxVolume > 0f)) ? 1f : Mathf.Clamp01(num2 / MaxVolume);
		}

		public bool TryPlayShot(FVRFireArm gun, AudioSourcePool poolShot, AudioSourcePool poolTail, FVRFireArmRound round, FVRSoundEnvironment env, float globalLoudnessMultiplier)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			if (!UseGunSideOverride || !UseVolumeRamp || (Object)(object)gun == (Object)null || (Object)(object)gun.AudioClipSet == (Object)null || !gun.IsSuppressed())
			{
				return false;
			}
			FVRFirearmAudioSet audioClipSet = gun.AudioClipSet;
			float num = ComputeRampMultiplier();
			Vector3 position = ((Component)gun).transform.position;
			FVRTailSoundClass val = (FVRTailSoundClass)0;
			AudioEvent shots_Suppressed = audioClipSet.Shots_Suppressed;
			poolShot.PlayClipVolumePitchOverride(shots_Suppressed, gun.GetMuzzle().position, shots_Suppressed.VolumeRange * num, shots_Suppressed.PitchRange, (AudioMixerGroup)null);
			if (((FVRInteractiveObject)gun).IsHeld && (Object)(object)((FVRInteractiveObject)gun).m_hand != (Object)null)
			{
				((FVRInteractiveObject)gun).m_hand.ForceTubeKick(audioClipSet.FTP.Kick_Shot);
				((FVRInteractiveObject)gun).m_hand.ForceTubeRumble(audioClipSet.FTP.Rumble_Shot_Intensity, audioClipSet.FTP.Rumble_Shot_Duration);
			}
			if (audioClipSet.UsesTail_Suppressed)
			{
				val = round.TailClassSuppressed;
				AudioEvent tailSet = SM.GetTailSet(round.TailClassSuppressed, env);
				poolTail.PlayClipVolumePitchOverride(tailSet, position, tailSet.VolumeRange * globalLoudnessMultiplier * num, audioClipSet.TailPitchMod_Suppressed * tailSet.PitchRange.x, (AudioMixerGroup)null);
			}
			float num2 = ((!ScaleLoudness) ? 1f : num);
			float soundTravelDistanceMultByEnvironment = SM.GetSoundTravelDistanceMultByEnvironment(env);
			int playerIFF = GM.CurrentPlayerBody.GetPlayerIFF();
			GM.CurrentSceneSettings.OnPerceiveableSound(audioClipSet.Loudness_Suppressed * num2, audioClipSet.Loudness_Suppressed * soundTravelDistanceMultByEnvironment * 0.5f * globalLoudnessMultiplier * num2, position, playerIFF, GM.CurrentPlayerBody.PlayerEntities[0]);
			if (DebugLogging)
			{
				Debug.Log((object)("[SuppressorShotStates] TryPlayShot shots=" + m_shotsFired + " mult=" + num));
			}
			gun.RattleSuppresor();
			for (int i = 0; i < gun.MuzzleDevices.Count; i++)
			{
				gun.MuzzleDevices[i].OnShot(gun, val);
			}
			return true;
		}

		public override void OnShot(FVRFireArm firearm, FVRTailSoundClass tailClass)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((MuzzleDevice)this).OnShot(firearm, tailClass);
			}
			catch (Exception ex)
			{
				if (DebugLogging)
				{
					Debug.Log((object)("[SuppressorShotStates] base.OnShot threw: " + ex.Message));
				}
			}
			if (UseOnShotScaling && !UseGunSideOverride && UseVolumeRamp && ((Behaviour)this).enabled && !((Object)(object)firearm == (Object)null))
			{
				ScaleRecentGunAudio(firearm, tailClass);
			}
		}

		private void ScaleRecentGunAudio(FVRFireArm firearm, FVRTailSoundClass tailClass)
		{
			//IL_003a: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			float num = ComputeRampMultiplier(Mathf.Max(0, m_shotsFired - 1));
			Transform muzzle = firearm.GetMuzzle();
			Vector3 val = ((!((Object)(object)muzzle != (Object)null)) ? ((Component)firearm).transform.position : muzzle.position);
			Vector3 position = ((Component)firearm).transform.position;
			float num2 = ScaleSearchRadius * ScaleSearchRadius;
			FVRFirearmAudioSet audioClipSet = firearm.AudioClipSet;
			AudioEvent val2 = ((!((Object)(object)audioClipSet != (Object)null)) ? null : audioClipSet.Shots_Suppressed);
			AudioEvent val3 = null;
			if ((Object)(object)audioClipSet != (Object)null && audioClipSet.UsesTail_Suppressed)
			{
				val3 = SM.GetTailSet(tailClass, GM.CurrentPlayerBody.GetCurrentSoundEnvironment());
			}
			int num3 = 0;
			AudioSource[] array = Object.FindObjectsOfType<AudioSource>();
			foreach (AudioSource val4 in array)
			{
				if ((Object)(object)val4 == (Object)null || !val4.isPlaying || val4.time > ScaleMaxSourceAge)
				{
					continue;
				}
				Vector3 position2 = ((Component)val4).transform.position;
				Vector3 val5 = position2 - val;
				if (((Vector3)(ref val5)).sqrMagnitude > num2)
				{
					Vector3 val6 = position2 - position;
					if (((Vector3)(ref val6)).sqrMagnitude > num2)
					{
						continue;
					}
				}
				if (MatchGunClips)
				{
					AudioClip clip = val4.clip;
					bool flag = val2 != null && val2.Clips != null && val2.Clips.Contains(clip);
					bool flag2 = val3 != null && val3.Clips != null && val3.Clips.Contains(clip);
					if (!flag && !flag2)
					{
						continue;
					}
				}
				val4.volume *= num;
				num3++;
			}
			if (DebugLogging)
			{
				Debug.Log((object)("[SuppressorShotStates] OnShot scaling: shots=" + m_shotsFired + " mult=" + num + " sourcesScaled=" + num3));
			}
		}

		public override void AttachToMount(FVRFireArmAttachmentMount m, bool playSound)
		{
			((Suppressor)this).AttachToMount(m, playSound);
			if (((Behaviour)this).enabled && UsesAudioSetClone)
			{
				BindToFirearm();
			}
		}

		public override void FVRUpdate()
		{
			((Suppressor)this).FVRUpdate();
			if ((Object)(object)m_boundFirearm != (Object)null && !((Component)this).transform.IsChildOf(((Component)m_boundFirearm).transform))
			{
				Unbind();
				if (ResetOnDetach)
				{
					m_shotsFired = 0;
					ApplyState();
				}
			}
			else if (!UsesAudioSetClone && ResetOnDetach && m_shotsFired > 0 && (Object)(object)((Component)this).GetComponentInParent<FVRFireArm>() == (Object)null)
			{
				m_shotsFired = 0;
				ApplyState();
			}
		}

		public override void ShotEffect()
		{
			((Suppressor)this).ShotEffect();
			if (((Behaviour)this).enabled)
			{
				if (UsesAudioSetClone && (Object)(object)m_boundFirearm == (Object)null)
				{
					BindToFirearm();
				}
				m_shotsFired++;
				ApplyState();
				if (UsesAudioSetClone)
				{
					ApplyVolume();
				}
			}
		}

		public void ResetShots()
		{
			m_shotsFired = 0;
			ApplyState();
			if (UsesAudioSetClone)
			{
				ApplyVolume();
			}
		}

		private void ApplyState()
		{
			if (ShotStates == null || ShotStates.Count == 0)
			{
				return;
			}
			int num = Mathf.Max(1, ShotsPerState);
			int num2 = Mathf.Clamp(m_shotsFired / num, 0, ShotStates.Count - 1);
			if (num2 == m_curState)
			{
				return;
			}
			m_curState = num2;
			for (int i = 0; i < ShotStates.Count; i++)
			{
				if ((Object)(object)ShotStates[i] != (Object)null)
				{
					ShotStates[i].SetActive(i == num2);
				}
			}
		}

		private void BindToFirearm()
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			FVRFireArm componentInParent = ((Component)this).GetComponentInParent<FVRFireArm>();
			if (DebugLogging)
			{
				Debug.Log((object)("[SuppressorShotStates] BindToFirearm: firearm=" + ((!((Object)(object)componentInParent != (Object)null)) ? "NULL" : ((Object)componentInParent).name) + " audioSet=" + ((!((Object)(object)componentInParent != (Object)null) || !((Object)(object)componentInParent.AudioClipSet != (Object)null)) ? "NULL" : ((Object)componentInParent.AudioClipSet).name)));
			}
			if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)m_boundFirearm))
			{
				Unbind();
				if (!((Object)(object)componentInParent.AudioClipSet == (Object)null))
				{
					m_boundFirearm = componentInParent;
					m_originalSet = componentInParent.AudioClipSet;
					m_originalLoudnessSuppressed = m_originalSet.Loudness_Suppressed;
					m_originalVolumeRange = m_originalSet.Shots_Suppressed.VolumeRange;
					m_clonedSet = Object.Instantiate<FVRFirearmAudioSet>(m_originalSet);
					componentInParent.AudioClipSet = m_clonedSet;
					m_shotsFired = 0;
					ApplyState();
					ApplyVolume();
				}
			}
		}

		private void Unbind()
		{
			if ((Object)(object)m_boundFirearm != (Object)null && (Object)(object)m_boundFirearm.AudioClipSet == (Object)(object)m_clonedSet)
			{
				m_boundFirearm.AudioClipSet = m_originalSet;
			}
			if ((Object)(object)m_clonedSet != (Object)null)
			{
				Object.Destroy((Object)(object)m_clonedSet);
			}
			m_boundFirearm = null;
			m_originalSet = null;
			m_clonedSet = null;
		}

		private void ApplyVolume()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)m_clonedSet == (Object)null))
			{
				float num = ComputeRampMultiplier();
				m_clonedSet.Shots_Suppressed.VolumeRange = m_originalVolumeRange * num;
				if (DebugLogging)
				{
					Debug.Log((object)("[SuppressorShotStates] shots=" + m_shotsFired + " mult=" + num + " volumeRange=" + m_clonedSet.Shots_Suppressed.VolumeRange));
				}
				if (ScaleLoudness)
				{
					m_clonedSet.Loudness_Suppressed = m_originalLoudnessSuppressed * num;
				}
			}
		}

		private void OnEnable()
		{
			m_curState = -1;
			ApplyState();
		}

		private void OnDisable()
		{
			Unbind();
		}

		private void OnDestroy()
		{
			Unbind();
		}
	}
	public class SuppressorVolumeRamp : Suppressor
	{
		[Header("Volume Ramp Settings")]
		public float StartVolume = 0.2f;

		public float MaxVolume = 1f;

		public int ShotsToMax = 15;

		private int m_shotsFired;

		private FVRFireArm m_boundFirearm;

		private FVRFirearmAudioSet m_originalSet;

		private FVRFirearmAudioSet m_clonedSet;

		public override void AttachToMount(FVRFireArmAttachmentMount m, bool playSound)
		{
			((Suppressor)this).AttachToMount(m, playSound);
			if (((Behaviour)this).enabled)
			{
				BindToFirearm();
			}
		}

		public override void FVRUpdate()
		{
			((Suppressor)this).FVRUpdate();
			if ((Object)(object)m_boundFirearm != (Object)null && !((Component)this).transform.IsChildOf(((Component)m_boundFirearm).transform))
			{
				Unbind();
			}
		}

		public override void ShotEffect()
		{
			((Suppressor)this).ShotEffect();
			if (!((Behaviour)this).enabled)
			{
				return;
			}
			if ((Object)(object)m_boundFirearm == (Object)null)
			{
				BindToFirearm();
				if ((Object)(object)m_boundFirearm == (Object)null)
				{
					return;
				}
			}
			if (m_shotsFired < ShotsToMax)
			{
				m_shotsFired++;
			}
			ApplyVolume();
		}

		private void BindToFirearm()
		{
			FVRFireArm componentInParent = ((Component)this).GetComponentInParent<FVRFireArm>();
			if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)m_boundFirearm))
			{
				Unbind();
				if (!((Object)(object)componentInParent.AudioClipSet == (Object)null))
				{
					m_boundFirearm = componentInParent;
					m_originalSet = componentInParent.AudioClipSet;
					m_clonedSet = Object.Instantiate<FVRFirearmAudioSet>(m_originalSet);
					componentInParent.AudioClipSet = m_clonedSet;
					m_shotsFired = 0;
					ApplyVolume();
				}
			}
		}

		private void Unbind()
		{
			if ((Object)(object)m_boundFirearm != (Object)null && (Object)(object)m_boundFirearm.AudioClipSet == (Object)(object)m_clonedSet)
			{
				m_boundFirearm.AudioClipSet = m_originalSet;
			}
			if ((Object)(object)m_clonedSet != (Object)null)
			{
				Object.Destroy((Object)(object)m_clonedSet);
			}
			m_boundFirearm = null;
			m_originalSet = null;
			m_clonedSet = null;
			m_shotsFired = 0;
		}

		private void ApplyVolume()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)m_clonedSet == (Object)null))
			{
				float num = ((ShotsToMax <= 0) ? 1f : ((float)m_shotsFired / (float)ShotsToMax));
				float num2 = Mathf.Lerp(StartVolume, MaxVolume, num);
				m_clonedSet.Shots_Suppressed.VolumeRange = new Vector2(num2, num2);
			}
		}

		private void OnDisable()
		{
			Unbind();
		}

		private void OnDestroy()
		{
			Unbind();
		}
	}
}