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();
}
}
}