Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ParanoidCompany v2.0.1
BepInEx/plugins/ParanoidCompany/ParanoidCompany.dll
Decompiled 4 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using UnityEngine; using UnityEngine.Audio; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Networking; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace ParanoidCompany; public class DarknessSensor { private Light[] _cached = (Light[])(object)new Light[0]; private float _nextScan; private bool _wasInsideFactory; private bool _dirty = true; private readonly HashSet<Transform> _playerRoots = new HashSet<Transform>(); private readonly List<Light> _keep = new List<Light>(256); private readonly HashSet<Light> _ownCarried = new HashSet<Light>(); public bool OwnLightActive { get; private set; } public void Invalidate() { _dirty = true; } private void Rescan() { _dirty = false; _nextScan = Time.time + Mathf.Max(2f, ModConfig.LightScanInterval.Value); _playerRoots.Clear(); StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.allPlayerScripts != null) { for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if ((Object)(object)val != (Object)null) { _playerRoots.Add(((Component)val).transform); } } } RescanCarriedLights(((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); Light[] array = Object.FindObjectsOfType<Light>(); _keep.Clear(); foreach (Light val2 in array) { if (!((Object)(object)val2 == (Object)null) && !IsUnderPlayer(((Component)val2).transform, _playerRoots) && !_ownCarried.Contains(val2)) { _keep.Add(val2); } } _cached = _keep.ToArray(); if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Light scan: " + _cached.Length + " world light(s) tracked.")); } } private static bool IsUnderPlayer(Transform t, HashSet<Transform> playerRoots) { if (playerRoots.Count == 0) { return false; } int num = 0; while ((Object)(object)t != (Object)null && num < 12) { if (playerRoots.Contains(t)) { return true; } t = t.parent; num++; } return false; } private void RescanCarriedLights(PlayerControllerB me) { _ownCarried.Clear(); if ((Object)(object)me == (Object)null) { return; } FlashlightItem[] array = Object.FindObjectsOfType<FlashlightItem>(); if (array == null) { return; } foreach (FlashlightItem val in array) { if (!((Object)(object)val == (Object)null) && ((GrabbableObject)val).isHeld && !((Object)(object)((GrabbableObject)val).playerHeldBy != (Object)(object)me)) { if ((Object)(object)val.flashlightBulb != (Object)null) { _ownCarried.Add(val.flashlightBulb); } if ((Object)(object)val.flashlightBulbGlow != (Object)null) { _ownCarried.Add(val.flashlightBulbGlow); } } } } public float Evaluate(PlayerControllerB local, Vector3 eyePos) { //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Invalid comparison between Unknown and I4 //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)local == (Object)null) { return 1f; } if (local.isInsideFactory != _wasInsideFactory) { _wasInsideFactory = local.isInsideFactory; _dirty = true; } if (_dirty || Time.time >= _nextScan) { Rescan(); } OwnLightActive = IsOwnLightOn(local); float value = ModConfig.LightMaxConsiderDistance.Value; float maxConsiderSqr = value * value; bool value2 = ModConfig.RequireLineOfSight.Value; int num = 0; if (value2 && (Object)(object)StartOfRound.Instance != (Object)null) { num = StartOfRound.Instance.collidersAndRoomMask; } float num2 = 0f; for (int i = 0; i < _cached.Length; i++) { Light val = _cached[i]; if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || val.intensity <= 0f) { continue; } if ((int)val.type == 1) { if (ModConfig.DirectionalLightCountsAsLit.Value && !local.isInsideFactory && !local.isPlayerDead && val.intensity > 0.05f) { return 1f; } continue; } float num3 = ScoreLight(val, eyePos, maxConsiderSqr); if (!(num3 <= num2) && (!value2 || num == 0 || !Physics.Linecast(eyePos, ((Component)val).transform.position, num, (QueryTriggerInteraction)1))) { num2 = num3; if (num2 >= 0.999f) { break; } } } return Mathf.Max(num2, ScoreOtherPlayerLights(local, eyePos, maxConsiderSqr)); } private static float ScoreLight(Light l, Vector3 eyePos, float maxConsiderSqr) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)l).transform.position; Vector3 val = eyePos - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude > maxConsiderSqr) { return 0f; } float range = l.range; if (range <= 0.01f) { return 0f; } if (sqrMagnitude > range * range) { return 0f; } float num = Mathf.Sqrt(sqrMagnitude); if ((int)l.type == 0 && num > 0.01f) { float num2 = Vector3.Angle(((Component)l).transform.forward, val / num); float num3 = Mathf.Max(1f, l.spotAngle * 0.5f); if (num2 > num3) { return 0f; } } return 1f - num / range; } private static float ScoreOtherPlayerLights(PlayerControllerB local, Vector3 eyePos, float maxConsiderSqr) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return 0f; } float num = 0f; for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)local || !val.isPlayerControlled || val.isPlayerDead) { continue; } Light helmetLight = val.helmetLight; if (!((Object)(object)helmetLight == (Object)null) && ((Behaviour)helmetLight).isActiveAndEnabled && !(helmetLight.intensity <= 0f)) { float num2 = ScoreLight(helmetLight, eyePos, maxConsiderSqr); if (num2 > num) { num = num2; } } } return num; } private static bool IsOwnLightOn(PlayerControllerB local) { if ((Object)(object)local == (Object)null) { return false; } if ((Object)(object)local.helmetLight != (Object)null && ((Behaviour)local.helmetLight).isActiveAndEnabled && local.helmetLight.intensity > 0f) { return true; } if (local.allHelmetLights != null) { for (int i = 0; i < local.allHelmetLights.Length; i++) { Light val = local.allHelmetLights[i]; if ((Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled && val.intensity > 0f) { return true; } } } GrabbableObject currentlyHeldObject = local.currentlyHeldObject; FlashlightItem val2 = (FlashlightItem)(object)((currentlyHeldObject is FlashlightItem) ? currentlyHeldObject : null); if ((Object)(object)val2 == (Object)null) { GrabbableObject currentlyHeldObjectServer = local.currentlyHeldObjectServer; val2 = (FlashlightItem)(object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null); } if ((Object)(object)val2 != (Object)null && ((GrabbableObject)val2).isBeingUsed) { return true; } return false; } } public static class DoorSensor { private static DoorLock[] _doors; private static float _nextScan; private static readonly List<Transform> _candidates = new List<Transform>(); private static readonly List<Transform> _behind = new List<Transform>(); private const float RescanSeconds = 20f; private const float EmptyRescanSeconds = 4f; public static void Invalidate() { _doors = null; _nextScan = 0f; _candidates.Clear(); _behind.Clear(); } private static void EnsureScan() { if (_doors == null || !(Time.time < _nextScan)) { _nextScan = Time.time + 20f; try { _doors = Object.FindObjectsOfType<DoorLock>(); } catch { _doors = (DoorLock[])(object)new DoorLock[0]; } if (_doors == null) { _doors = (DoorLock[])(object)new DoorLock[0]; } if (_doors.Length == 0) { _nextScan = Time.time + 4f; } } } public static bool TryPickDoor(Vector3 eye, Vector3 lookForward, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_00a1: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; EnsureScan(); if (_doors == null || _doors.Length == 0) { return false; } float value = ModConfig.DoorMinDistance.Value; float num = ModConfig.DoorMaxDistance.Value; if (num < value + 0.5f) { num = value + 0.5f; } _candidates.Clear(); _behind.Clear(); for (int i = 0; i < _doors.Length; i++) { DoorLock val = _doors[i]; if ((Object)(object)val == (Object)null) { continue; } Transform transform = ((Component)val).transform; if ((Object)(object)transform == (Object)null || !((Component)transform).gameObject.activeInHierarchy) { continue; } Vector3 val2 = transform.position - eye; float magnitude = ((Vector3)(ref val2)).magnitude; if (!(magnitude < value) && !(magnitude > num)) { _candidates.Add(transform); if (Vector3.Dot(((Vector3)(ref val2)).normalized, lookForward) < 0.35f) { _behind.Add(transform); } } } List<Transform> list = ((_behind.Count > 0) ? _behind : _candidates); if (list.Count == 0) { return false; } Transform val3 = list[Random.Range(0, list.Count)]; if ((Object)(object)val3 == (Object)null) { return false; } position = val3.position + Vector3.up * 1.1f; return true; } } public class HallucinationPlayer : MonoBehaviour { private class Voice { public AudioSource Source; public AudioLowPassFilter LowPass; public AudioHighPassFilter HighPass; public AudioDistortionFilter Distortion; public bool Busy; public int Token; } private Voice[] _voices; private const float MaxHoldSeconds = 12f; public const int DefaultPriority = 110; public const int CriticalPriority = 0; public AudioMixerGroup MixerGroup { get; set; } public bool AnythingPlaying { get { if (_voices == null) { return false; } for (int i = 0; i < _voices.Length; i++) { Voice voice = _voices[i]; if (voice != null && !((Object)(object)voice.Source == (Object)null) && (voice.Busy || voice.Source.isPlaying)) { return true; } } return false; } } public void Build(int count) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) count = Mathf.Clamp(count, 1, 16); if (_voices != null && _voices.Length == count) { return; } if (_voices != null) { for (int i = 0; i < _voices.Length; i++) { Voice voice = _voices[i]; if (voice != null && (Object)(object)voice.Source != (Object)null && (voice.Busy || voice.Source.isPlaying)) { return; } } ((MonoBehaviour)this).StopAllCoroutines(); for (int j = 0; j < _voices.Length; j++) { if (_voices[j] != null && (Object)(object)_voices[j].Source != (Object)null) { Object.Destroy((Object)(object)((Component)_voices[j].Source).gameObject); } } } _voices = new Voice[count]; for (int k = 0; k < count; k++) { GameObject val = new GameObject("SchizoVoice_" + k); val.transform.SetParent(((Component)this).transform, false); AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.spatialBlend = 1f; val2.rolloffMode = (AudioRolloffMode)1; val2.dopplerLevel = 0f; val2.priority = 110; AudioLowPassFilter val3 = val.AddComponent<AudioLowPassFilter>(); ((Behaviour)val3).enabled = false; AudioHighPassFilter val4 = val.AddComponent<AudioHighPassFilter>(); ((Behaviour)val4).enabled = false; AudioDistortionFilter val5 = val.AddComponent<AudioDistortionFilter>(); ((Behaviour)val5).enabled = false; _voices[k] = new Voice { Source = val2, LowPass = val3, HighPass = val4, Distortion = val5 }; } } private Voice FindFreeVoice() { if (_voices == null) { return null; } for (int i = 0; i < _voices.Length; i++) { Voice voice = _voices[i]; if (voice != null && !((Object)(object)voice.Source == (Object)null) && !voice.Busy && !voice.Source.isPlaying) { return voice; } } return null; } private void Configure(Voice v, Vector3 pos, bool insideHead, float volume, float pitch, bool radioEffect, float falloffDistance, float lowPassCutoff, int priority = 110, bool dry = false) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) v.Token++; AudioSource source = v.Source; ((Component)source).transform.position = pos; source.spatialBlend = (insideHead ? 0f : 1f); source.minDistance = 2f; source.maxDistance = Mathf.Max(6f, falloffDistance); source.volume = Mathf.Clamp01(volume); source.pitch = Mathf.Clamp(pitch, 0.25f, 3f); source.outputAudioMixerGroup = (dry ? null : MixerGroup); source.priority = Mathf.Clamp(priority, 0, 256); if ((Object)(object)v.LowPass != (Object)null) { float num = (radioEffect ? 2600f : lowPassCutoff); ((Behaviour)v.LowPass).enabled = num < 19000f; v.LowPass.cutoffFrequency = Mathf.Clamp(num, 180f, 22000f); } if ((Object)(object)v.HighPass != (Object)null) { ((Behaviour)v.HighPass).enabled = radioEffect; if (radioEffect) { v.HighPass.cutoffFrequency = 520f; } } if ((Object)(object)v.Distortion != (Object)null) { ((Behaviour)v.Distortion).enabled = radioEffect; if (radioEffect) { v.Distortion.distortionLevel = 0.28f; } } } public bool Play(AudioClip clip, Vector3 worldPos, bool insideHead, float volume, float pitch, bool radioEffect, float falloffDistance, float lowPassCutoff, float startTime, float maxPlaySeconds = 0f, int priority = 110, bool dry = false, float minDistance = 2f) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)clip == (Object)null) { return false; } if (!EnsureLoaded(clip)) { return false; } Voice voice = FindFreeVoice(); if (voice == null) { return false; } Configure(voice, worldPos, insideHead, volume, pitch, radioEffect, falloffDistance, lowPassCutoff, priority, dry); voice.Source.minDistance = Mathf.Max(0.5f, minDistance); voice.Source.clip = clip; if (startTime > 0.01f && startTime < clip.length - 0.35f) { try { voice.Source.time = startTime; } catch { } } voice.Source.Play(); float num = (clip.length - startTime) / Mathf.Max(0.05f, Mathf.Abs(voice.Source.pitch)); float num2 = ((maxPlaySeconds > 0.1f) ? maxPlaySeconds : 12f); if (num > num2) { ((MonoBehaviour)this).StartCoroutine(FadeOutAfter(voice, voice.Token, num2, volume)); } return true; } private static bool EnsureLoaded(AudioClip clip) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 try { if ((int)clip.loadState == 2) { return true; } clip.LoadAudioData(); if ((int)clip.loadState == 2) { return true; } if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Skipped '" + ((Object)clip).name + "' - its audio data is still loading.")); } return false; } catch { return true; } } private IEnumerator FadeOutAfter(Voice v, int token, float seconds, float volume) { yield return (object)new WaitForSeconds(seconds); if (v != null && !((Object)(object)v.Source == (Object)null) && v.Token == token) { float t = 0f; while (t < 0.7f && (Object)(object)v.Source != (Object)null && v.Source.isPlaying && v.Token == token) { t += Time.deltaTime; v.Source.volume = Mathf.Lerp(volume, 0f, t / 0.7f); yield return null; } if ((Object)(object)v.Source != (Object)null && v.Token == token) { v.Source.Stop(); v.Source.volume = volume; } } } public bool PlayFootsteps(AudioClip[] clips, Vector3 from, Vector3 to, int steps, float interval, float volume, float pitch, float falloffDistance, float cutoffFrom, float cutoffTo, bool varyPitchPerStep = true) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (clips == null || clips.Length == 0 || steps <= 0) { return false; } bool flag = false; for (int i = 0; i < clips.Length; i++) { if ((Object)(object)clips[i] != (Object)null && EnsureLoaded(clips[i])) { flag = true; } } if (!flag) { return false; } Voice voice = FindFreeVoice(); if (voice == null) { return false; } Configure(voice, from, insideHead: false, volume, pitch, radioEffect: false, falloffDistance, cutoffFrom); voice.Source.clip = null; voice.Busy = true; try { if (((MonoBehaviour)this).StartCoroutine(StepRoutine(voice, clips, from, to, steps, interval, pitch, cutoffFrom, cutoffTo, varyPitchPerStep)) == null) { voice.Busy = false; return false; } } catch { voice.Busy = false; return false; } return true; } private IEnumerator StepRoutine(Voice v, AudioClip[] clips, Vector3 from, Vector3 to, int steps, float interval, float pitch, float cutoffFrom, float cutoffTo, bool varyPitchPerStep) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_001e: Unknown result type (might be due to invalid IL or missing references) try { for (int i = 0; i < steps; i++) { if (v == null) { break; } if ((Object)(object)v.Source == (Object)null) { break; } float num = ((steps <= 1) ? 1f : ((float)i / (float)(steps - 1))); ((Component)v.Source).transform.position = Vector3.Lerp(from, to, num); if ((Object)(object)v.LowPass != (Object)null) { float num2 = Mathf.Lerp(cutoffFrom, cutoffTo, num); ((Behaviour)v.LowPass).enabled = num2 < 19000f; v.LowPass.cutoffFrequency = Mathf.Clamp(num2, 180f, 22000f); } AudioClip val = clips[Random.Range(0, clips.Length)]; if ((Object)(object)val != (Object)null) { if (varyPitchPerStep) { v.Source.pitch = Mathf.Clamp(pitch * Random.Range(0.94f, 1.06f), 0.25f, 3f); } v.Source.PlayOneShot(val, Random.Range(0.82f, 1f)); } yield return (object)new WaitForSeconds(interval * Random.Range(0.9f, 1.1f)); } float num3 = 0.6f; for (int j = 0; j < clips.Length; j++) { if ((Object)(object)clips[j] != (Object)null && clips[j].length > num3) { num3 = clips[j].length; } } yield return (object)new WaitForSeconds(Mathf.Min(num3, 3f)); } finally { if (v != null) { v.Busy = false; } } } public void StopAll() { ((MonoBehaviour)this).StopAllCoroutines(); if (_voices == null) { return; } for (int i = 0; i < _voices.Length; i++) { Voice voice = _voices[i]; if (voice != null) { voice.Busy = false; if ((Object)(object)voice.Source != (Object)null && voice.Source.isPlaying) { voice.Source.Stop(); } } } } } public static class ModConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> CheckInterval; public static ConfigEntry<float> DarknessThreshold; public static ConfigEntry<bool> OnlyInsideFacility; public static ConfigEntry<bool> AllowInShip; public static ConfigEntry<float> FlashlightClockRate; public static ConfigEntry<bool> RequireLineOfSight; public static ConfigEntry<bool> DirectionalLightCountsAsLit; public static ConfigEntry<float> LightScanInterval; public static ConfigEntry<float> LightMaxConsiderDistance; public static ConfigEntry<float> FirstSoundAfterSeconds; public static ConfigEntry<float> Stage2AfterSeconds; public static ConfigEntry<float> Stage3AfterSeconds; public static ConfigEntry<float> LightResetSeconds; public static ConfigEntry<float> Stage1MinGap; public static ConfigEntry<float> Stage1MaxGap; public static ConfigEntry<float> Stage2MinGap; public static ConfigEntry<float> Stage2MaxGap; public static ConfigEntry<float> Stage3MinGap; public static ConfigEntry<float> Stage3MaxGap; public static ConfigEntry<bool> MixInLowerStages; public static ConfigEntry<bool> ShorterGapsWhenAlone; public static ConfigEntry<bool> PlayWhileDead; public static ConfigEntry<float> Stage1MinDistance; public static ConfigEntry<float> Stage1MaxDistance; public static ConfigEntry<float> Stage1Volume; public static ConfigEntry<float> Stage2MinDistance; public static ConfigEntry<float> Stage2MaxDistance; public static ConfigEntry<float> Stage2Volume; public static ConfigEntry<float> Stage3MinDistance; public static ConfigEntry<float> Stage3MaxDistance; public static ConfigEntry<float> Stage3Volume; public static ConfigEntry<float> InsideHeadChance; public static ConfigEntry<float> RadioEffectChance; public static ConfigEntry<float> PitchVariance; public static ConfigEntry<float> VolumeVariance; public static ConfigEntry<float> MuffleAmount; public static ConfigEntry<float> RandomStartChance; public static ConfigEntry<float> LayerChance; public static ConfigEntry<float> ThroughWallChance; public static ConfigEntry<float> MaxSoundSeconds; public static ConfigEntry<int> MaxSimultaneousSounds; public static ConfigEntry<bool> RouteThroughGameAudioMixer; public static ConfigEntry<bool> UseVanillaSounds; public static ConfigEntry<float> VanillaShare; public static ConfigEntry<bool> ExtraEnemyVoices; public static ConfigEntry<bool> FootstepsEnabled; public static ConfigEntry<bool> UseGameFootsteps; public static ConfigEntry<float> FootstepsAfterSeconds; public static ConfigEntry<float> FootstepChance; public static ConfigEntry<float> FootstepMinGap; public static ConfigEntry<float> FootstepMaxGap; public static ConfigEntry<float> FootstepStartMin; public static ConfigEntry<float> FootstepStartMax; public static ConfigEntry<float> FootstepEndDistance; public static ConfigEntry<float> FootstepAroundCornerChance; public static ConfigEntry<float> FootstepVolume; public static ConfigEntry<float> WalkStepInterval; public static ConfigEntry<float> RunStepInterval; public static ConfigEntry<bool> OneSoundAtATime; public static ConfigEntry<float> SignatureChance; public static ConfigEntry<float> CoilheadBurstChance; public static ConfigEntry<float> CoilheadBurstDistance; public static ConfigEntry<float> CoilheadLoudChance; public static ConfigEntry<float> CoilheadVolume; public static ConfigEntry<int> CoilheadClipIndex; public static ConfigEntry<float> CoilheadRunShare; public static ConfigEntry<float> CoilheadBurstShare; public static ConfigEntry<float> CoilheadRunDistance; public static ConfigEntry<float> CoilheadRunStepInterval; public static ConfigEntry<float> DoorSoundChance; public static ConfigEntry<float> DoorMinDistance; public static ConfigEntry<float> DoorMaxDistance; public static ConfigEntry<float> DoorVolume; public static ConfigEntry<float> DoorOpenShare; public static ConfigEntry<float> DoorPairChance; public static ConfigEntry<float> RunChanceAtStage3; public static ConfigEntry<float> WhisperChance; public static ConfigEntry<float> WhisperMinDistance; public static ConfigEntry<float> WhisperMaxDistance; public static ConfigEntry<float> WhisperVolume; public static ConfigEntry<float> VoiceChance; public static ConfigEntry<bool> MatchVoicesToPlayerNames; public static ConfigEntry<bool> NeverImpersonateYourself; public static ConfigEntry<bool> DebugLogging; public static ConfigEntry<bool> EnableTestKey; public static ConfigEntry<string> CoilheadKey; public static ConfigEntry<string> TestKey; public static ConfigEntry<string> StageUpKey; public static ConfigEntry<string> FootstepKey; public static void Init(ConfigFile cfg) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Expected O, but got Unknown //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Expected O, but got Unknown //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Expected O, but got Unknown //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Expected O, but got Unknown //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Expected O, but got Unknown //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Expected O, but got Unknown //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Expected O, but got Unknown //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Expected O, but got Unknown //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Expected O, but got Unknown //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Expected O, but got Unknown //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Expected O, but got Unknown //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Expected O, but got Unknown //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Expected O, but got Unknown //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Expected O, but got Unknown //IL_0529: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Expected O, but got Unknown //IL_0561: Unknown result type (might be due to invalid IL or missing references) //IL_056b: Expected O, but got Unknown //IL_0599: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Expected O, but got Unknown //IL_05d1: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Expected O, but got Unknown //IL_0609: Unknown result type (might be due to invalid IL or missing references) //IL_0613: Expected O, but got Unknown //IL_0641: Unknown result type (might be due to invalid IL or missing references) //IL_064b: Expected O, but got Unknown //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_0683: Expected O, but got Unknown //IL_06b1: Unknown result type (might be due to invalid IL or missing references) //IL_06bb: Expected O, but got Unknown //IL_06e9: Unknown result type (might be due to invalid IL or missing references) //IL_06f3: Expected O, but got Unknown //IL_0721: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Expected O, but got Unknown //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_0763: Expected O, but got Unknown //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_079b: Expected O, but got Unknown //IL_07c9: Unknown result type (might be due to invalid IL or missing references) //IL_07d3: Expected O, but got Unknown //IL_0801: Unknown result type (might be due to invalid IL or missing references) //IL_080b: Expected O, but got Unknown //IL_082e: Unknown result type (might be due to invalid IL or missing references) //IL_0838: Expected O, but got Unknown //IL_089c: Unknown result type (might be due to invalid IL or missing references) //IL_08a6: Expected O, but got Unknown //IL_0925: Unknown result type (might be due to invalid IL or missing references) //IL_092f: Expected O, but got Unknown //IL_095d: Unknown result type (might be due to invalid IL or missing references) //IL_0967: Expected O, but got Unknown //IL_0995: Unknown result type (might be due to invalid IL or missing references) //IL_099f: Expected O, but got Unknown //IL_09cd: Unknown result type (might be due to invalid IL or missing references) //IL_09d7: Expected O, but got Unknown //IL_0a05: Unknown result type (might be due to invalid IL or missing references) //IL_0a0f: Expected O, but got Unknown //IL_0a3d: Unknown result type (might be due to invalid IL or missing references) //IL_0a47: Expected O, but got Unknown //IL_0a75: Unknown result type (might be due to invalid IL or missing references) //IL_0a7f: Expected O, but got Unknown //IL_0aad: Unknown result type (might be due to invalid IL or missing references) //IL_0ab7: Expected O, but got Unknown //IL_0ae5: Unknown result type (might be due to invalid IL or missing references) //IL_0aef: Expected O, but got Unknown //IL_0b1d: Unknown result type (might be due to invalid IL or missing references) //IL_0b27: Expected O, but got Unknown //IL_0b55: Unknown result type (might be due to invalid IL or missing references) //IL_0b5f: Expected O, but got Unknown //IL_0b8d: Unknown result type (might be due to invalid IL or missing references) //IL_0b97: Expected O, but got Unknown //IL_0be0: Unknown result type (might be due to invalid IL or missing references) //IL_0bea: Expected O, but got Unknown //IL_0c18: Unknown result type (might be due to invalid IL or missing references) //IL_0c22: Expected O, but got Unknown //IL_0c50: Unknown result type (might be due to invalid IL or missing references) //IL_0c5a: Expected O, but got Unknown //IL_0c88: Unknown result type (might be due to invalid IL or missing references) //IL_0c92: Expected O, but got Unknown //IL_0cb5: Unknown result type (might be due to invalid IL or missing references) //IL_0cbf: Expected O, but got Unknown //IL_0ced: Unknown result type (might be due to invalid IL or missing references) //IL_0cf7: Expected O, but got Unknown //IL_0d25: Unknown result type (might be due to invalid IL or missing references) //IL_0d2f: Expected O, but got Unknown //IL_0d5d: Unknown result type (might be due to invalid IL or missing references) //IL_0d67: Expected O, but got Unknown //IL_0d95: Unknown result type (might be due to invalid IL or missing references) //IL_0d9f: Expected O, but got Unknown //IL_0dcd: Unknown result type (might be due to invalid IL or missing references) //IL_0dd7: Expected O, but got Unknown //IL_0e05: Unknown result type (might be due to invalid IL or missing references) //IL_0e0f: Expected O, but got Unknown //IL_0e3d: Unknown result type (might be due to invalid IL or missing references) //IL_0e47: Expected O, but got Unknown //IL_0e75: Unknown result type (might be due to invalid IL or missing references) //IL_0e7f: Expected O, but got Unknown //IL_0ead: Unknown result type (might be due to invalid IL or missing references) //IL_0eb7: Expected O, but got Unknown //IL_0ee5: Unknown result type (might be due to invalid IL or missing references) //IL_0eef: Expected O, but got Unknown //IL_0f1d: Unknown result type (might be due to invalid IL or missing references) //IL_0f27: Expected O, but got Unknown //IL_0f55: Unknown result type (might be due to invalid IL or missing references) //IL_0f5f: Expected O, but got Unknown //IL_0f8d: Unknown result type (might be due to invalid IL or missing references) //IL_0f97: Expected O, but got Unknown //IL_0fc5: Unknown result type (might be due to invalid IL or missing references) //IL_0fcf: Expected O, but got Unknown //IL_0ffd: Unknown result type (might be due to invalid IL or missing references) //IL_1007: Expected O, but got Unknown //IL_1035: Unknown result type (might be due to invalid IL or missing references) //IL_103f: Expected O, but got Unknown Enabled = cfg.Bind<bool>("1 - General", "Enabled", true, "Master switch. Turn off to disable all hallucinations without uninstalling."); CheckInterval = cfg.Bind<float>("1 - General", "CheckInterval", 0.5f, new ConfigDescription("How often (seconds) the mod re-evaluates whether you are in the dark.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())); DarknessThreshold = cfg.Bind<float>("2 - Darkness", "DarknessThreshold", 0.3f, new ConfigDescription("0 = pitch black only, 1 = anywhere. A spot counts as dark when its light score is below this. 0.3 is roughly 'no lamp within 70% of its range', which is what an unlit corridor in a powered facility actually measures. Raise it if the mod stays silent, lower it if it triggers in lit rooms.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); OnlyInsideFacility = cfg.Bind<bool>("2 - Darkness", "OnlyInsideFacility", true, "Only hallucinate inside the facility/mine/mansion. Set false to also allow the outdoor map at night."); AllowInShip = cfg.Bind<bool>("2 - Darkness", "AllowInShip", false, "Allow hallucinations while you are standing inside the ship."); FlashlightClockRate = cfg.Bind<float>("2 - Darkness", "FlashlightClockRate", 0.5f, new ConfigDescription("How fast the dark timer runs while YOUR OWN flashlight or helmet lamp is on, in an otherwise unlit room. 0 = your light stops it completely, 0.5 = it still creeps up at half speed, 1 = your light doesn't help at all. A lit room always stops the timer regardless of this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RequireLineOfSight = cfg.Bind<bool>("2 - Darkness", "RequireLineOfSight", true, "Lights behind a wall do not count as lighting you. More accurate, slightly more CPU."); DirectionalLightCountsAsLit = cfg.Bind<bool>("2 - Darkness", "DirectionalLightCountsAsLit", true, "Treat the sun / moon (directional light) as full lighting when you are outdoors."); LightScanInterval = cfg.Bind<float>("2 - Darkness", "LightScanInterval", 8f, new ConfigDescription("How often (seconds) the mod rebuilds its list of lights in the level. Raise it if you see stutter on huge maps.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())); LightMaxConsiderDistance = cfg.Bind<float>("2 - Darkness", "LightMaxConsiderDistance", 60f, new ConfigDescription("Lights farther away than this are skipped entirely.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 300f), Array.Empty<object>())); FirstSoundAfterSeconds = cfg.Bind<float>("3 - Pacing", "FirstSoundAfterSeconds", 20f, new ConfigDescription("Seconds of darkness before you hear anything at all. The timer only runs while you are actually in the dark. A Lethal Company day is only about 11 real minutes, so the defaults are sized to fit inside one round.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 900f), Array.Empty<object>())); Stage2AfterSeconds = cfg.Bind<float>("3 - Pacing", "Stage2AfterSeconds", 90f, new ConfigDescription("Total darkness needed before Stage 2 unlocks: closer whispers, walking, breathing. A minute and a half of accumulated darkness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 3600f), Array.Empty<object>())); Stage3AfterSeconds = cfg.Bind<float>("3 - Pacing", "Stage3AfterSeconds", 180f, new ConfigDescription("Total darkness needed before Stage 3 unlocks: running up behind you, coilhead snapping. Three minutes of accumulated darkness - reachable within a single day even if you carry a light.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 3600f), Array.Empty<object>())); LightResetSeconds = cfg.Bind<float>("3 - Pacing", "LightResetSeconds", 45f, new ConfigDescription("Stand in light for this long and everything resets to zero - back to Stage 1 and a fresh minute before the next sound. Shorter trips through a lit room only pause the timer, they do not reset it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); Stage1MinGap = cfg.Bind<float>("3 - Pacing", "Stage1MinGap", 12f, new ConfigDescription("Shortest gap (seconds of darkness) between Stage 1 sounds. Values below 5 are treated as 5.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 900f), Array.Empty<object>())); Stage1MaxGap = cfg.Bind<float>("3 - Pacing", "Stage1MaxGap", 26f, new ConfigDescription("Longest gap between Stage 1 sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); Stage2MinGap = cfg.Bind<float>("3 - Pacing", "Stage2MinGap", 10f, new ConfigDescription("Shortest gap between Stage 2 sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); Stage2MaxGap = cfg.Bind<float>("3 - Pacing", "Stage2MaxGap", 22f, new ConfigDescription("Longest gap between Stage 2 sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); Stage3MinGap = cfg.Bind<float>("3 - Pacing", "Stage3MinGap", 9f, new ConfigDescription("Shortest gap between Stage 3 sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); Stage3MaxGap = cfg.Bind<float>("3 - Pacing", "Stage3MaxGap", 19f, new ConfigDescription("Longest gap between Stage 3 sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 900f), Array.Empty<object>())); MixInLowerStages = cfg.Bind<bool>("3 - Pacing", "MixInLowerStages", true, "At Stage 2 and 3, still occasionally play the quieter earlier sounds so it doesn't turn into constant chaos."); ShorterGapsWhenAlone = cfg.Bind<bool>("3 - Pacing", "ShorterGapsWhenAlone", true, "Gaps are ~30% shorter when no teammate is near you."); PlayWhileDead = cfg.Bind<bool>("3 - Pacing", "PlayWhileDead", false, "Keep hallucinating while you are dead and spectating."); Stage1MinDistance = cfg.Bind<float>("4 - Distance", "Stage1MinDistance", 7f, new ConfigDescription("Stage 1 sounds spawn no closer than this, in metres. Far away is the point.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); Stage1MaxDistance = cfg.Bind<float>("4 - Distance", "Stage1MaxDistance", 17f, new ConfigDescription("Stage 1 sounds spawn no further than this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 150f), Array.Empty<object>())); Stage1Volume = cfg.Bind<float>("4 - Distance", "Stage1Volume", 0.75f, new ConfigDescription("Stage 1 loudness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); Stage2MinDistance = cfg.Bind<float>("4 - Distance", "Stage2MinDistance", 4f, new ConfigDescription("Stage 2 minimum distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); Stage2MaxDistance = cfg.Bind<float>("4 - Distance", "Stage2MaxDistance", 11f, new ConfigDescription("Stage 2 maximum distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 150f), Array.Empty<object>())); Stage2Volume = cfg.Bind<float>("4 - Distance", "Stage2Volume", 0.9f, new ConfigDescription("Stage 2 loudness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); Stage3MinDistance = cfg.Bind<float>("4 - Distance", "Stage3MinDistance", 2.5f, new ConfigDescription("Stage 3 minimum distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); Stage3MaxDistance = cfg.Bind<float>("4 - Distance", "Stage3MaxDistance", 8f, new ConfigDescription("Stage 3 maximum distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 150f), Array.Empty<object>())); Stage3Volume = cfg.Bind<float>("4 - Distance", "Stage3Volume", 1f, new ConfigDescription("Stage 3 loudness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); InsideHeadChance = cfg.Bind<float>("5 - Playback", "InsideHeadChance", 0.12f, new ConfigDescription("Chance a Stage 2 or 3 sound plays flat in both ears instead of from a direction - 'inside your head'. Stage 1 is always positional so it stays distant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RadioEffectChance = cfg.Bind<float>("5 - Playback", "RadioEffectChance", 0.3f, new ConfigDescription("Chance a voice clip is filtered to sound like it came over the walkie-talkie.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); PitchVariance = cfg.Bind<float>("5 - Playback", "PitchVariance", 0.09f, new ConfigDescription("Random pitch shift per play, so the same clip is never quite the same sound. 0 disables it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), Array.Empty<object>())); VolumeVariance = cfg.Bind<float>("5 - Playback", "VolumeVariance", 0.2f, new ConfigDescription("Random loudness shift per play. Some you barely catch, some you definitely hear.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.8f), Array.Empty<object>())); MuffleAmount = cfg.Bind<float>("5 - Playback", "MuffleAmount", 0.45f, new ConfigDescription("How much the top end is rolled off, so sounds arrive through walls and distance rather than sitting on top of the mix. 0 = crisp and obvious, 1 = very muffled and easy to dismiss. The amount is randomised around this per play, and doubles when there is real geometry between you and the sound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RandomStartChance = cfg.Bind<float>("5 - Playback", "RandomStartChance", 0.3f, new ConfigDescription("Chance a longer clip starts partway in, as if you only caught the end of it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); LayerChance = cfg.Bind<float>("5 - Playback", "LayerChance", 0f, new ConfigDescription("Chance a second, quieter sound plays alongside the first from a different direction. Off by default - two sounds at once tends to read as a bug rather than as company. Needs MaxSimultaneousSounds of at least 2 and OneSoundAtATime off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); ThroughWallChance = cfg.Bind<float>("5 - Playback", "ThroughWallChance", 0.2f, new ConfigDescription("Chance a sound is placed in the next room rather than in yours. Those get a much heavier roll-off, so they arrive as 'something is through there' instead of 'something is here'.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); MaxSoundSeconds = cfg.Bind<float>("5 - Playback", "MaxSoundSeconds", 8f, new ConfigDescription("Longest any single sound is allowed to run before it fades out. Stops one long file in a Sounds folder from holding the channel - and, with OneSoundAtATime, blocking everything else.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())); MaxSimultaneousSounds = cfg.Bind<int>("5 - Playback", "MaxSimultaneousSounds", 3, new ConfigDescription("Size of the playback channel pool. OneSoundAtATime still stops two hallucinations from being started together, but a couple of sounds finish each other off - a running coilhead ends on the coil, a door that creaks open shuts again - and those need a spare channel to land on. Never runs with fewer than two.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 16), Array.Empty<object>())); RouteThroughGameAudioMixer = cfg.Bind<bool>("5 - Playback", "RouteThroughGameAudioMixer", true, "Play through the game's own audio mixer so hallucinations obey the in-game sound slider and pick up room reverb. Turn off if the sounds come out muffled or silent."); UseVanillaSounds = cfg.Bind<bool>("6 - Game sounds", "UseVanillaSounds", true, "Borrow the game's own audio at runtime - real coilhead springs, the ghost girl's breathing, real footsteps, door and hull creaks, the insanity ambience. Nothing is copied or redistributed; the mod reads the clips already loaded in your game, so they always match your version."); VanillaShare = cfg.Bind<float>("6 - Game sounds", "VanillaShare", 0.35f, new ConfigDescription("How often a sound comes from the game rather than from the mod's own Sounds folder. 1 = only game audio, 0 = only the bundled clips. Kept low because the borrowed set is deliberately small - only the sounds you can't put a name to.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); ExtraEnemyVoices = cfg.Bind<bool>("6 - Game sounds", "ExtraEnemyVoices", false, "Also borrow voice clips from other monsters, so you occasionally hear something that isn't there at all. Off by default: a recognisable monster noise makes people think the mod is buggy rather than that the building is wrong. Vanilla enemies only, even when on."); FootstepsEnabled = cfg.Bind<bool>("6b - Footsteps", "FootstepsEnabled", true, "Phantom footsteps: a line of steps that walks across the room behind you, or straight at you, and stops. They have their own schedule, independent of every other sound."); UseGameFootsteps = cfg.Bind<bool>("6b - Footsteps", "UseGameFootsteps", true, "Use the game's real footstep audio, matched to the floor surface you are standing on. Turn off to use only your own clips from Sounds/Footsteps/."); FootstepsAfterSeconds = cfg.Bind<float>("6b - Footsteps", "FootstepsAfterSeconds", 12f, new ConfigDescription("Seconds of darkness before footsteps can start. Lower than the first voice on purpose - footsteps are the friendliest way in.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>())); FootstepChance = cfg.Bind<float>("6b - Footsteps", "FootstepChance", 0.72f, new ConfigDescription("When the footstep timer comes round, the odds it actually happens. Below 1 the rhythm stops being a rhythm - two skips in a row is a long, pointed silence, and you can't learn when to expect them. Lower for rarer and more irregular.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); FootstepMinGap = cfg.Bind<float>("6b - Footsteps", "FootstepMinGap", 36f, new ConfigDescription("Shortest gap between footstep events, in seconds of darkness. Values below 4 are treated as 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 600f), Array.Empty<object>())); FootstepMaxGap = cfg.Bind<float>("6b - Footsteps", "FootstepMaxGap", 72f, new ConfigDescription("Longest gap between footstep events.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 600f), Array.Empty<object>())); FootstepStartMin = cfg.Bind<float>("6b - Footsteps", "FootstepStartMin", 9f, new ConfigDescription("Closest the steps can begin, in metres. Lethal Company interiors are cramped, so keep this modest - too large and every walk gets blocked by a wall and never plays.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 40f), Array.Empty<object>())); FootstepStartMax = cfg.Bind<float>("6b - Footsteps", "FootstepStartMax", 20f, new ConfigDescription("Furthest the steps can begin, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())); FootstepEndDistance = cfg.Bind<float>("6b - Footsteps", "FootstepEndDistance", 5f, new ConfigDescription("How close they get before stopping, in metres. Kept at arm's length rather than on top of you - they should sound like someone in the next stretch of corridor, not someone touching you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())); RunChanceAtStage3 = cfg.Bind<float>("6b - Footsteps", "RunChanceAtStage3", 0.9f, new ConfigDescription("At Stage 3, the odds a footstep event is somebody RUNNING at you rather than walking. The first Stage 3 footsteps of a run always sprint regardless, so you never finish a round without hearing it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); FootstepAroundCornerChance = cfg.Bind<float>("6b - Footsteps", "FootstepAroundCornerChance", 0.5f, new ConfigDescription("Chance the steps begin out of sight - through a wall, around a corner - and walk into view. Those start heavily muffled and open up as they come, which is the difference between 'a sound played' and 'somebody is coming'.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); FootstepVolume = cfg.Bind<float>("6b - Footsteps", "FootstepVolume", 0.8f, new ConfigDescription("Footstep loudness.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); WalkStepInterval = cfg.Bind<float>("6b - Footsteps", "WalkStepInterval", 0.54f, new ConfigDescription("Seconds between steps when it's walking. The number of steps follows the distance walked, so this sets the pace, not the length.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1.2f), Array.Empty<object>())); RunStepInterval = cfg.Bind<float>("6b - Footsteps", "RunStepInterval", 0.28f, new ConfigDescription("Seconds between steps when it's running (Stage 3).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.12f, 0.8f), Array.Empty<object>())); OneSoundAtATime = cfg.Bind<bool>("5 - Playback", "OneSoundAtATime", true, "Never start a sound while another one is still audible. Two hallucinations at once reads as a glitch rather than as something being in the room with you."); CoilheadBurstChance = cfg.Bind<float>("6 - Game sounds", "CoilheadBurstChance", 0.8f, new ConfigDescription("When a signature sound comes up, the odds it's the coilhead rather than the ghost girl. The coilhead arrives as a rapid burst of spring noises right behind you - several in a row, closing - the way a real one sounds when it lunges. Not one polite click.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); CoilheadBurstDistance = cfg.Bind<float>("6 - Game sounds", "CoilheadBurstDistance", 1.5f, new ConfigDescription("How close the coilhead burst gets, in metres. This is meant to be right behind your head. Values above about 3 leave no room for it to close the distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 4f), Array.Empty<object>())); CoilheadLoudChance = cfg.Bind<float>("6 - Game sounds", "CoilheadLoudChance", 0.4f, new ConfigDescription("Relative share of coilhead moments that are the single loud coil, dead behind you. Weighed against CoilheadRunShare and CoilheadBurstShare rather than being a straight probability - the three are normalised, so 0.4 / 0.45 / 0.25 means roughly 36% / 41% / 23%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); CoilheadVolume = cfg.Bind<float>("6 - Game sounds", "CoilheadVolume", 1f, new ConfigDescription("How loud the coil is. This one is deliberately played dry and at full volume - unlike everything else in the mod, it is meant to be recognised the instant it happens.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1f), Array.Empty<object>())); CoilheadClipIndex = cfg.Bind<int>("6 - Game sounds", "CoilheadClipIndex", -1, new ConfigDescription("-1 picks the loudest spring clip automatically. The log lists every coilhead clip it found, numbered and with lengths, on every level load - set this to one of those numbers to always use that exact clip.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 31), Array.Empty<object>())); CoilheadRunShare = cfg.Bind<float>("6 - Game sounds", "CoilheadRunShare", 0.45f, new ConfigDescription("Relative share of coilhead moments that are one running at you - its own movement audio closing from several metres out, ending on the coil as it stops dead. Needs room to run; falls back to the other forms in a tight corridor. Weighed against CoilheadLoudChance and CoilheadBurstShare.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); CoilheadBurstShare = cfg.Bind<float>("6 - Game sounds", "CoilheadBurstShare", 0.25f, new ConfigDescription("Relative share of coilhead moments that are a rapid burst of short snaps closing in behind you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); CoilheadRunDistance = cfg.Bind<float>("6 - Game sounds", "CoilheadRunDistance", 11f, new ConfigDescription("How far away a running coilhead starts, when there is that much clear space behind you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 25f), Array.Empty<object>())); CoilheadRunStepInterval = cfg.Bind<float>("6 - Game sounds", "CoilheadRunStepInterval", 0.19f, new ConfigDescription("Seconds between the steps of a running coilhead. Lower is faster and more frantic.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.08f, 0.5f), Array.Empty<object>())); DoorSoundChance = cfg.Bind<float>("6 - Game sounds", "DoorSoundChance", 0.2f, new ConfigDescription("How often a sound is a door creaking open or slamming. It is played from the position of a door that is actually there - if nothing near you is a door, no door sound happens at all.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); DoorMinDistance = cfg.Bind<float>("6 - Game sounds", "DoorMinDistance", 3f, new ConfigDescription("Doors closer than this are skipped - a door slamming in your face is a jumpscare, not a doubt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>())); DoorMaxDistance = cfg.Bind<float>("6 - Game sounds", "DoorMaxDistance", 16f, new ConfigDescription("How far away a real door can be and still be used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 40f), Array.Empty<object>())); DoorVolume = cfg.Bind<float>("6 - Game sounds", "DoorVolume", 0.8f, new ConfigDescription("Volume of door sounds before distance and walls are applied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>())); DoorOpenShare = cfg.Bind<float>("6 - Game sounds", "DoorOpenShare", 0.6f, new ConfigDescription("Share of door sounds that are a slow creak open rather than a slam.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); DoorPairChance = cfg.Bind<float>("6 - Game sounds", "DoorPairChance", 0.45f, new ConfigDescription("After a creak, the odds the same door shuts again a second or two later. Someone came through.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); SignatureChance = cfg.Bind<float>("6 - Game sounds", "SignatureChance", 0.22f, new ConfigDescription("At Stage 3 only: chance the sound is one of the game's unmistakable ones - a coilhead's neck, the ghost girl's sting. Guaranteed a slice of the late game rather than being one clip among dozens.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); WhisperChance = cfg.Bind<float>("7 - Voices", "WhisperChance", 0.45f, new ConfigDescription("How often a sound is a close human one - whispering, breathing, humming, someone swallowing - from the Whispers folder. These are the point of the mod, so they are the most common thing you hear.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); WhisperMinDistance = cfg.Bind<float>("7 - Voices", "WhisperMinDistance", 1.5f, new ConfigDescription("Closest a whisper can be, in metres. A whisper is only unsettling at conversational range - from across a room it is simply inaudible, which is why these ignore the stage distances.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())); WhisperMaxDistance = cfg.Bind<float>("7 - Voices", "WhisperMaxDistance", 6f, new ConfigDescription("Furthest a whisper can be, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f), Array.Empty<object>())); WhisperVolume = cfg.Bind<float>("7 - Voices", "WhisperVolume", 0.85f, new ConfigDescription("Loudness of close human sounds. Quiet on purpose - you should have to stop moving to be sure you heard it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); VoiceChance = cfg.Bind<float>("7 - Voices", "VoiceChance", 0.2f, new ConfigDescription("Share of Stage 2 and 3 sounds that come from the Voices folder instead. Ignored if that folder is empty. Voices never appear at Stage 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); MatchVoicesToPlayerNames = cfg.Bind<bool>("7 - Voices", "MatchVoicesToPlayerNames", false, "Only play a voice clip if a player with that name is in the lobby. Put the clips in a subfolder named after the player, e.g. Sounds/Voices/Sam/help.ogg. Files directly in Voices/ are generic and always allowed."); NeverImpersonateYourself = cfg.Bind<bool>("7 - Voices", "NeverImpersonateYourself", true, "With name matching on, never play clips named after your own username."); DebugLogging = cfg.Bind<bool>("8 - Debug", "DebugLogging", false, "Spam the BepInEx console with light scores, stage changes and countdowns. Use this to tune DarknessThreshold."); EnableTestKey = cfg.Bind<bool>("8 - Debug", "EnableTestKey", false, "Enable the testing keys below. Off by default so a normal game has no hotkeys bound - turn it on while you are tuning the mod, then off again. The keys are ignored while you are typing in chat or using the terminal."); TestKey = cfg.Bind<string>("8 - Debug", "TestKey", "F8", "Plays a sound from your current stage immediately, anywhere. Uses Unity's new Input System key names, e.g. F8, F9, Backquote, Numpad0."); FootstepKey = cfg.Bind<string>("8 - Debug", "FootstepKey", "F10", "Forces a phantom footstep sequence immediately, so you can check they work without waiting."); CoilheadKey = cfg.Bind<string>("8 - Debug", "CoilheadKey", "F7", "Plays the loud coil immediately, wherever you are. The fastest way to confirm the coilhead audio was found on your install."); StageUpKey = cfg.Bind<string>("8 - Debug", "StageUpKey", "F9", "Jumps straight to the next stage so you can hear Stage 2 and 3 without waiting eight minutes. Press again past Stage 3 to reset to zero."); } } [BepInPlugin("com.paranoidcompany", "ParanoidCompany", "2.0.1")] public class Plugin : BaseUnityPlugin { private GameObject _host; public static ManualLogSource Log { get; private set; } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); SoundLibrary.ResolveRoot(ResolvePluginDirectory()); _host = new GameObject("ParanoidCompanyHost"); Object.DontDestroyOnLoad((Object)(object)_host); ((Object)_host).hideFlags = (HideFlags)61; _host.AddComponent<SchizoManager>(); Log.LogInfo((object)("ParanoidCompany v2.0.1 loaded. Sounds folder: " + SoundLibrary.SoundsRoot)); } private string ResolvePluginDirectory() { try { if (((BaseUnityPlugin)this).Info != null && ((BaseUnityPlugin)this).Info.Location != null && ((BaseUnityPlugin)this).Info.Location.Length > 0) { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (!string.IsNullOrEmpty(directoryName)) { return directoryName; } } } catch { } try { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { string directoryName2 = Path.GetDirectoryName(location); if (!string.IsNullOrEmpty(directoryName2)) { return directoryName2; } } } catch { } Log.LogWarning((object)"Could not determine the plugin folder; falling back to BepInEx/plugins."); return Path.Combine(Paths.PluginPath, "ParanoidCompany"); } } public static class PluginInfo { public const string GUID = "com.paranoidcompany"; public const string NAME = "ParanoidCompany"; public const string VERSION = "2.0.1"; } public class SchizoManager : MonoBehaviour { private readonly DarknessSensor _sensor = new DarknessSensor(); private HallucinationPlayer _player; private float _nextCheck; private float _lastCheckTime; private float _darkSeconds; private float _litSeconds; private int _litSamples; private float _nextEventAtDark; private float _nextFootstepAtDark; private int _lastStage; private bool _wasDead; private bool _ranAtStage3; private bool _signalledStage3; private Key _testKey = (Key)101; private Key _stageKey = (Key)102; private Key _footKey = (Key)103; private Key _coilKey = (Key)100; private int _sceneToken; private int _cutToken; private int _lastCoilForm; private int _coilKeyForm; private bool _coilKeyValid = true; private bool _testKeyValid; private bool _stageKeyValid; private bool _footKeyValid; private static bool _warnedNoEligibleVoices; private static bool _warnedNoFootsteps; private void Awake() { _player = ((Component)this).gameObject.AddComponent<HallucinationPlayer>(); _player.Build(Mathf.Max(2, ModConfig.MaxSimultaneousSounds.Value)); _testKeyValid = ParseKey(ModConfig.TestKey.Value, out _testKey); _stageKeyValid = ParseKey(ModConfig.StageUpKey.Value, out _stageKey); _footKeyValid = ParseKey(ModConfig.FootstepKey.Value, out _footKey); _coilKeyValid = ParseKey(ModConfig.CoilheadKey.Value, out _coilKey); if (ModConfig.EnableTestKey.Value) { if (!_testKeyValid) { Plugin.Log.LogWarning((object)("TestKey '" + ModConfig.TestKey.Value + "' is not a usable key name.")); } if (!_stageKeyValid) { Plugin.Log.LogWarning((object)("StageUpKey '" + ModConfig.StageUpKey.Value + "' is not a usable key name.")); } if (!_footKeyValid) { Plugin.Log.LogWarning((object)("FootstepKey '" + ModConfig.FootstepKey.Value + "' is not a usable key name.")); } if (!_coilKeyValid) { Plugin.Log.LogWarning((object)("CoilheadKey '" + ModConfig.CoilheadKey.Value + "' is not a usable key name.")); } } ResetProgress(log: false); ValidateConfig(); } private static void ValidateConfig() { float value = ModConfig.FirstSoundAfterSeconds.Value; float value2 = ModConfig.Stage2AfterSeconds.Value; float value3 = ModConfig.Stage3AfterSeconds.Value; if (value2 <= value) { Plugin.Log.LogWarning((object)("Config: Stage2AfterSeconds (" + value2 + ") is not greater than FirstSoundAfterSeconds (" + value + "), so Stage 1 will never play. Raise Stage2AfterSeconds.")); } if (value3 <= value2) { Plugin.Log.LogWarning((object)("Config: Stage3AfterSeconds (" + value3 + ") is not greater than Stage2AfterSeconds (" + value2 + "), so Stage 2 will never play. Raise Stage3AfterSeconds.")); } if (ModConfig.FootstepEndDistance.Value >= ModConfig.FootstepStartMin.Value) { Plugin.Log.LogWarning((object)("Config: FootstepEndDistance (" + ModConfig.FootstepEndDistance.Value + ") should be smaller than FootstepStartMin (" + ModConfig.FootstepStartMin.Value + ") or the steps have nowhere to walk from; it will be clamped.")); } if (ModConfig.FootstepStartMax.Value > 25f) { Plugin.Log.LogWarning((object)"Config: FootstepStartMax is large. Lethal Company interiors are cramped - walks that start far away usually get blocked by a wall and never play."); } if (ModConfig.LightResetSeconds.Value < ModConfig.CheckInterval.Value * 3f) { Plugin.Log.LogWarning((object)"Config: LightResetSeconds is very small compared to CheckInterval; progress may reset the instant you see any light."); } if (!ModConfig.OnlyInsideFacility.Value && ModConfig.DirectionalLightCountsAsLit.Value) { Plugin.Log.LogWarning((object)"Config: OnlyInsideFacility is off but DirectionalLightCountsAsLit is on, so anywhere outdoors counts as fully lit while the sun is up and you will hear nothing out there. Turn DirectionalLightCountsAsLit off as well."); } if (ModConfig.PlayWhileDead.Value && ModConfig.OnlyInsideFacility.Value) { Plugin.Log.LogInfo((object)"Config: PlayWhileDead is on. The game reports a dead player as being outside the facility, so the OnlyInsideFacility rule is skipped while you are dead."); } } private static bool ParseKey(string name, out Key key) { if (Enum.TryParse<Key>(name, ignoreCase: true, out key) && key) { return Enum.IsDefined(typeof(Key), key); } return false; } private void OnEnable() { SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; } private IEnumerator Start() { _lastCheckTime = Time.time; yield return SoundLibrary.LoadAll(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { try { HandleSceneLoaded(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Scene load handling failed: " + ex.Message)); } } private void HandleSceneLoaded() { _sceneToken++; _warnedNoEligibleVoices = false; _warnedNoFootsteps = false; _sensor.Invalidate(); VanillaSounds.Invalidate(); DoorSensor.Invalidate(); _lastCheckTime = Time.time; ResetProgress(log: false); if ((Object)(object)_player != (Object)null) { CutAudio(); } } private void ResetProgress(bool log) { _darkSeconds = 0f; _litSeconds = 0f; _litSamples = 0; _nextEventAtDark = Mathf.Max(0f, ModConfig.FirstSoundAfterSeconds.Value); _nextFootstepAtDark = Mathf.Max(0f, ModConfig.FootstepsAfterSeconds.Value); _lastStage = 0; _ranAtStage3 = false; _signalledStage3 = false; _lastCoilForm = 0; if (log) { Plugin.Log.LogInfo((object)"Back in the light long enough - everything reset."); } } private void Update() { if (!ModConfig.Enabled.Value || !SoundLibrary.FinishedLoading) { _lastCheckTime = Time.time; return; } try { HandleKeys(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Key handling failed: " + ex.Message)); } if (Time.time < _nextCheck) { return; } try { Tick(); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Tick failed: " + ex2.Message)); } } private void Tick() { //IL_00c3: 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) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.1f, ModConfig.CheckInterval.Value); float num2 = Mathf.Clamp(Time.time - _lastCheckTime, 0f, 5f); _lastCheckTime = Time.time; _nextCheck = Time.time + num; PlayerControllerB localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { AccumulateLight(num2); return; } if (VanillaSounds.NeedsHarvest) { VanillaSounds.Harvest(); } bool isPlayerDead = localPlayer.isPlayerDead; if (isPlayerDead != _wasDead) { _wasDead = isPlayerDead; _sensor.Invalidate(); if (isPlayerDead && !ModConfig.PlayWhileDead.Value && (Object)(object)_player != (Object)null) { CutAudio(); } } if (!IsEligible(localPlayer)) { AccumulateLight(num2); return; } Vector3 eyePosition = GetEyePosition(localPlayer); float num3 = _sensor.Evaluate(localPlayer, eyePosition); if (!(num3 <= ModConfig.DarknessThreshold.Value)) { AccumulateLight(num2); if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)$"lit (score {num3:0.00}) - darkClock held at {_darkSeconds:0}s, reset in {Mathf.Max(0f, ModConfig.LightResetSeconds.Value - _litSeconds):0}s"); } return; } float num4 = (_sensor.OwnLightActive ? Mathf.Clamp01(ModConfig.FlashlightClockRate.Value) : 1f); if (num4 <= 0f) { _litSeconds = 0f; _litSamples = 0; if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)("dark, but your own light is on and FlashlightClockRate is 0 - clock frozen at " + Mathf.RoundToInt(_darkSeconds) + "s")); } return; } _litSeconds = 0f; _litSamples = 0; _darkSeconds += num2 * num4; int num5 = StageFor(_darkSeconds); if (num5 != _lastStage) { bool flag = num5 > _lastStage; _lastStage = num5; if (num5 > 0) { Plugin.Log.LogInfo((object)("Stage " + num5 + " reached (" + Mathf.RoundToInt(_darkSeconds) + "s in the dark).")); } if (flag && num5 >= 1) { float num6 = _darkSeconds + RandomGap(num5, localPlayer); if (num6 < _nextEventAtDark) { _nextEventAtDark = num6; } } } if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)$"dark (score {num3:0.00}) darkClock={_darkSeconds:0}s stage={num5} next in {Mathf.Max(0f, _nextEventAtDark - _darkSeconds):0}s"); } UpdateFootsteps(localPlayer, eyePosition, num5); if (num5 < 1 || _darkSeconds < _nextEventAtDark) { return; } if (ModConfig.OneSoundAtATime.Value && (Object)(object)_player != (Object)null && _player.AnythingPlaying) { _nextEventAtDark = _darkSeconds + 2f; return; } try { TriggerHallucination(localPlayer, eyePosition, num5, forced: false); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Skipped a hallucination: " + ex.GetType().Name + " - " + ex.Message)); } finally { _nextEventAtDark = _darkSeconds + RandomGap(num5, localPlayer); } } private void UpdateFootsteps(PlayerControllerB local, Vector3 eye, int stage) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.FootstepsEnabled.Value || (Object)(object)_player == (Object)null || _darkSeconds < ModConfig.FootstepsAfterSeconds.Value || _darkSeconds < _nextFootstepAtDark) { return; } if (ModConfig.OneSoundAtATime.Value && (Object)(object)_player != (Object)null && _player.AnythingPlaying) { _nextFootstepAtDark = _darkSeconds + 2f; return; } if (Random.value >= ModConfig.FootstepChance.Value) { _nextFootstepAtDark = _darkSeconds + FootstepGap(local); if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)"Footsteps: skipped this one on purpose."); } return; } ApplyMixer(local); bool flag; try { flag = TryPhantomFootsteps(local, eye, Mathf.Max(1, stage), forced: false); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Skipped a footstep event: " + ex.GetType().Name + " - " + ex.Message)); flag = false; } if (flag) { _nextFootstepAtDark = _darkSeconds + FootstepGap(local); return; } _nextFootstepAtDark = _darkSeconds + 4f; if (ModConfig.DebugLogging.Value) { Plugin.Log.LogInfo((object)"Footsteps: no usable path from here, retrying in 4s."); } } private static float FootstepGap(PlayerControllerB local) { float value = ModConfig.FootstepMinGap.Value; float num = Mathf.Max(value, ModConfig.FootstepMaxGap.Value); float num2 = Random.Range(value, num); if (ModConfig.ShorterGapsWhenAlone.Value && (Object)(object)local != (Object)null && local.isPlayerAlone) { num2 *= 0.75f; } return Mathf.Max(4f, num2); } private void ApplyMixer(PlayerControllerB local) { if (!((Object)(object)_player == (Object)null)) { _player.MixerGroup = ((ModConfig.RouteThroughGameAudioMixer.Value && (Object)(object)local != (Object)null && (Object)(object)local.movementAudio != (Object)null) ? local.movementAudio.outputAudioMixerGroup : null); } } private void AccumulateLight(float elapsed) { _litSeconds += elapsed; _litSamples++; if (_darkSeconds > 0f && _litSamples >= 2 && _litSeconds >= ModConfig.LightResetSeconds.Value) { ResetProgress(log: true); } } private static float RandomGap(int stage, PlayerControllerB local) { float value; float value2; if (stage >= 3) { value = ModConfig.Stage3MinGap.Value; value2 = ModConfig.Stage3MaxGap.Value; } else if (stage == 2) { value = ModConfig.Stage2MinGap.Value; value2 = ModConfig.Stage2MaxGap.Value; } else { value = ModConfig.Stage1MinGap.Value; value2 = ModConfig.Stage1MaxGap.Value; } float num = Random.Range(value, Mathf.Max(value, value2)); if (ModConfig.ShorterGapsWhenAlone.Value && (Object)(object)local != (Object)null && local.isPlayerAlone) { num *= 0.7f; } return Mathf.Max(5f, num); } private static int StageFor(float darkSeconds) { float num = Mathf.Max(0f, ModConfig.FirstSoundAfterSeconds.Value); float num2 = Mathf.Max(num, ModConfig.Stage2AfterSeconds.Value); float num3 = Mathf.Max(num2, ModConfig.Stage3AfterSeconds.Value); if (darkSeconds < num) { return 0; } if (darkSeconds < num2) { return 1; } if (darkSeconds < num3) { return 2; } return 3; } private void QuietenSchedule(float seconds) { _nextEventAtDark = Mathf.Max(_nextEventAtDark, _darkSeconds + seconds); _nextFootstepAtDark = Mathf.Max(_nextFootstepAtDark, _darkSeconds + seconds); } private void HandleKeys() { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0393: 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_029b: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.EnableTestKey.Value) { return; } Keyboard current = Keyboard.current; if (current == null) { return; } PlayerControllerB localPlayer = GetLocalPlayer(); if ((Object)(object)localPlayer != (Object)null && (localPlayer.isTypingChat || localPlayer.inTerminalMenu || ((Object)(object)localPlayer.quickMenuManager != (Object)null && localPlayer.quickMenuManager.isMenuOpen))) { return; } if (_testKeyValid && Pressed(current, _testKey)) { PlayerControllerB localPlayer2 = GetLocalPlayer(); if ((Object)(object)localPlayer2 == (Object)null) { Plugin.Log.LogInfo((object)"Test key: no local player yet."); } else { Vector3 eyePosition = GetEyePosition(localPlayer2); int stage = Mathf.Max(1, StageFor(_darkSeconds)); QuietenSchedule(5f); Plugin.Log.LogInfo((object)("Test key - forcing a Stage " + stage + " sound. Light score here: " + _sensor.Evaluate(localPlayer2, eyePosition).ToString("0.00"))); if ((Object)(object)_player != (Object)null) { CutAudio(); } try { TriggerHallucination(localPlayer2, eyePosition, stage, forced: true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Test sound failed: " + ex.Message)); } } } if (_coilKeyValid && Pressed(current, _coilKey)) { PlayerControllerB localPlayer3 = GetLocalPlayer(); if ((Object)(object)localPlayer3 == (Object)null) { Plugin.Log.LogInfo((object)"Coilhead key: no local player yet."); } else if ((Object)(object)VanillaSounds.PickLoudCoil() == (Object)null) { Plugin.Log.LogWarning((object)"Coilhead key: no spring clips were harvested on this level. Check the load line for the coilhead count."); } else { CutAudio(); QuietenSchedule(6f); Vector3 eyePosition2 = GetEyePosition(localPlayer3); _coilKeyForm = _coilKeyForm % 3 + 1; try { bool flag; if (_coilKeyForm == 2) { AudioClip[] coilheadMoveClips = VanillaSounds.CoilheadMoveClips; if (coilheadMoveClips == null || coilheadMoveClips.Length == 0) { Plugin.Log.LogWarning((object)"Coilhead key (2/3 running): no movement clips at all."); flag = false; } else { Plugin.Log.LogInfo((object)"Coilhead key (2/3): running at you."); flag = TryCoilheadRun(localPlayer3, eyePosition2, coilheadMoveClips, forced: true); if (!flag) { Plugin.Log.LogWarning((object)"Not enough room to run - it needs about 5 m of clear space behind you. Playing the coil instead."); } } } else if (_coilKeyForm == 3) { AudioClip[] coilheadSnapClips = VanillaSounds.CoilheadSnapClips; if (coilheadSnapClips == null || coilheadSnapClips.Length < 2) { Plugin.Log.LogWarning((object)"Coilhead key (3/3 burst): fewer than two short spring clips were found, so there is nothing to burst."); flag = false; } else { Plugin.Log.LogInfo((object)"Coilhead key (3/3): a burst of snaps closing in."); flag = TryCoilheadBurst(localPlayer3, eyePosition2, coilheadSnapClips, forced: true); if (!flag) { Plugin.Log.LogWarning((object)"Not enough room for the burst. Playing the coil instead."); } } } else { Plugin.Log.LogInfo((object)"Coilhead key (1/3): the single loud coil."); flag = TryCoilheadLoud(localPlayer3, eyePosition2, forced: true); if (!flag) { Plugin.Log.LogWarning((object)"The loud coil could not be placed."); } } if (!flag && _coilKeyForm != 1) { TryCoilheadLoud(localPlayer3, eyePosition2, forced: true); } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Coilhead key failed: " + ex2.Message)); } } } if (_footKeyValid && Pressed(current, _footKey)) { PlayerControllerB localPlayer4 = GetLocalPlayer(); if ((Object)(object)localPlayer4 == (Object)null) { Plugin.Log.LogInfo((object)"Footstep key: no local player yet."); } else { int stage2 = Mathf.Max(1, StageFor(_darkSeconds)); QuietenSchedule(6f); Plugin.Log.LogInfo((object)("Footstep key - forcing a Stage " + stage2 + " walk.")); if ((Object)(object)_player != (Object)null) { CutAudio(); ApplyMixer(localPlayer4); } try { if (!TryPhantomFootsteps(localPlayer4, GetEyePosition(localPlayer4), stage2, forced: true)) { Plugin.Log.LogWarning((object)"No room to walk anywhere near you right now - try a wider space."); } } catch (Exception ex3) { Plugin.Log.LogWarning((object)("Footstep key failed: " + ex3.Message)); } } } if (_stageKeyValid && Pressed(current, _stageKey)) { int num = StageFor(_darkSeconds); if (num >= 3) { ResetProgress(log: false); Plugin.Log.LogInfo((object)"Stage key - reset to silence."); return; } float num2 = ((num <= 0) ? ModConfig.FirstSoundAfterSeconds.Value : ((num == 1) ? ModConfig.Stage2AfterSeconds.Value : ModConfig.Stage3AfterSeconds.Value)); _darkSeconds = Mathf.Max(_darkSeconds, num2) + 0.5f; _litSeconds = 0f; _lastStage = StageFor(_darkSeconds); _nextEventAtDark = _darkSeconds + 2f; _nextFootstepAtDark = _darkSeconds + 8f; Plugin.Log.LogInfo((object)("Stage key - jumped to Stage " + _lastStage + ". Next sound in a couple of seconds (stay in the dark).")); } } private static bool Pressed(Keyboard kb, Key k) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) try { KeyControl val = kb[k]; return val != null && ((ButtonControl)val).wasPressedThisFrame; } catch { return false; } } private static Vector3 GetEyePosition(PlayerControllerB local) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)local == (Object)null) { return Vector3.zero; } if (local.isPlayerDead) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.spectateCamera != (Object)null && ((Behaviour)instance.spectateCamera).enabled) { return ((Component)instance.spectateCamera).transform.position; } } if ((Object)(object)local.gameplayCamera != (Object)null) { return ((Component)local.gameplayCamera).transform.position; } return ((Component)local).transform.position + Vector3.up * 1.6f; } private static PlayerControllerB GetLocalPlayer() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return null; } PlayerControllerB localPlayerController = instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return null; } if (!localPlayerController.isPlayerControlled && !localPlayerController.isPlayerDead) { return null; } return localPlayerController; } private bool IsEligible(PlayerControllerB local) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } bool isPlayerDead = local.isPlayerDead; if (isPlayerDead && !ModConfig.PlayWhileDead.Value) { return false; } if (instance.inShipPhase && !ModConfig.AllowInShip.Value) { return false; } if (local.isInHangarShipRoom && !ModConfig.AllowInShip.Value) { return false; } if (ModConfig.OnlyInsideFacility.Value && !local.isInsideFactory && !isPlayerDead) { return false; } return true; } private void TriggerHallucination(PlayerControllerB local, Vector3 eye, int stage, bool forced) { //IL_00ca: 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_0072: 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) if ((Object)(object)_player == (Object)null) { return; } _player.Build(Mathf.Max(2, ModConfig.MaxSimultaneousSounds.Value)); ApplyMixer(local); bool flag = !forced && !_signalledStage3 && (Object)(object)VanillaSounds.PickLoudCoil() != (Object)null; if ((stage >= 3 && ModConfig.UseVanillaSounds.Value && (flag || Random.value < ModConfig.SignatureChance.Value) && TrySignature(local, eye, forced)) || (ModConfig.UseVanillaSounds.Value && Random.value < ModConfig.DoorSoundChance.Value && TryDoorSound(local, eye, stage, forced))) { return; } SchizoClip schizoClip = PickClip(stage); if (schizoClip == null) { if (forced) { Plugin.Log.LogWarning((object)"Nothing to play - no clips were loaded from the Sounds folders."); } } else if (PlayPick(schizoClip, local, eye, stage, 1f, forced) && !ModConfig.OneSoundAtATime.Value && Random.value < ModConfig.LayerChance.Value) { SchizoClip schizoClip2 = PickClip(Mathf.Max(1, stage - 1)); if (schizoClip2 != null && schizoClip2 != schizoClip) { PlayPick(schizoClip2, local, eye, Mathf.Max(1, stage - 1), 0.5f, forced: false); } } } private bool TrySignature(PlayerControllerB local, Vector3 eye, bool forced) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) bool flag = (Object)(object)VanillaSounds.CoilheadLoudest != (Object)null; bool flag2 = VanillaSounds.Signature.Count > 0; if (flag && !forced && !_signalledStage3 && TryCoilheadLoud(local, eye, forced)) { _signalledStage3 = true; return true; } if (flag && (!flag2 || Random.value < ModConfig.CoilheadBurstChance.Value) && TryCoilhead(local, eye, forced)) { if (!forced) { _signalledStage3 = true; } return true; } if (!flag2) { return false; } SchizoClip sting = VanillaSounds.Signature[Random.Range(0, VanillaSounds.Signature.Count)]; if (!PlaySignatureSting(sting, local, eye, forced)) { return false; } if (!forced) { _signalledStage3 = true; } return true; } private bool PlaySignatureSting(SchizoClip sting, PlayerControllerB local, Vector3 eye, bool forced) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) //IL_0068: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null || sting == null || (Object)(object)sting.Clip == (Object)null) { return false; } int mask = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMask : 0); Vector3 val = DirectionAt(local, Random.Range(70f, 290f)); Vector3 val2 = new Vector3(val.x, 0f, val.z); val = ((Vector3)(ref val2)).normalized; float num = Random.Range(2f, 4.5f); float num2 = Mathf.Clamp(ClearDistance(eye, val, num, mask) - 0.3f, 1f, num); Vector3 val3 = eye + val * num2; float lowPassCutoff = Mathf.Max(MuffleCutoff(3, eye, val3, insideHead: false), 6000f); if (!_player.Play(sting.Clip, val3, insideHead: false, Mathf.Clamp01(ModConfig.Stage3Volume.Value), 1f + Random.Range(-0.04f, 0.04f), radioEffect: false, 20f, lowPassCutoff, 0f, sting.MaxPlaySeconds, 0, dry: true, 4f)) { return false; } if (ModConfig.DebugLogging.Value || forced) { Plugin.Log.LogInfo((object)("Heard: the ghost girl - '" + sting.FileName + "' at " + num2.ToString("0.0") + "m")); } return true; } private bool TryCoilhead(PlayerControllerB local, Vector3 eye, bool forced) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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) AudioClip[] coilheadSnapClips = VanillaSounds.CoilheadSnapClips; AudioClip[] coilheadMoveClips = VanillaSounds.CoilheadMoveClips; float num = Mathf.Max(0f, ModConfig.CoilheadLoudChance.Value); float num2 = ((coilheadMoveClips != null && coilheadMoveClips.Length != 0) ? Mathf.Max(0f, ModConfig.CoilheadRunShare.Value) : 0f); float num3 = ((coilheadSnapClips != null && coilheadSnapClips.Length > 1) ? Mathf.Max(0f, ModConfig.CoilheadBurstShare.Value) : 0f); if (_lastCoilForm == 1) { num *= 0.25f; } else if (_lastCoilForm == 2) { num2 *= 0.25f; } else if (_lastCoilForm == 3) { num3 *= 0.25f; } float num4 = num + num2 + num3; int num5 = 1; if (num4 > 0f) { float num6 = Random.value * num4; num5 = ((num6 < num) ? 1 : ((!(num6 < num + num2)) ? 3 : 2)); } for (int i = 0; i < 3; i++) { int num7 = (num5 - 1 + i) % 3 + 1; if (num7 == 1 && TryCoilheadLoud(local, eye, forced)) { Remember(1, forced); return true; } if (num7 == 2 && TryCoilheadRun(local, eye, coilheadMoveClips, forced)) { Remember(2, forced); return true; } if (num7 == 3 && TryCoilheadBurst(local, eye, coilheadSnapClips, forced)) { Remember(3, forced); return true; } } return false; } private void Remember(int form, bool forced) { if (!forced) { _lastCoilForm = form; } } private bool TryCoilheadRun(PlayerControllerB local, Vector3 eye, AudioClip[] move, bool forced) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null || move == null || move.Length == 0) { return false; } int mask = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMask : 0); Vector3 val = DirectionAt(local, 180f); Vector3 val2 = new Vector3(val.x, 0f, val.z); val = ((Vector3)(ref val2)).normalized; float num = ClearDistance(eye, val, ModConfig.CoilheadRunDistance.Value, mask); for (int i = 0; i < 6; i++) { Vector3 val3 = DirectionAt(local, Random.Range(110f, 250f)); val2 = new Vector3(val3.x, 0f, val3.z); Vector3 normalized = ((Vector3)(ref val2)).normalized; float num2 = ClearDistance(eye, normalized, ModConfig.CoilheadRunDistance.Value, mask); if (num2 > num) { val = normalized; num = num2; } if (num >= ModConfig.CoilheadRunDistance.Value * 0.8f) { break; } } float num3 = num - 0.4f; if (num3 < 4f) { return false; } float num4 = 1.4f; Vector3 val4 = eye + val * num3; Vector3 val5 = eye + val * num4; float num5 = Mathf.Clamp(ModConfig.CoilheadRunStepInterval.Value, 0.08f, 0.5f); int num6 = Mathf.Clamp(Mathf.RoundToInt((num3 - num4) / 0.9f), 4, 16); float cutoffFrom = Mathf.Max(MuffleCutoff(3, eye, val4, insideHead: false), 2600f); float volume = Mathf.Clamp01(ModConfig.CoilheadVolume.Value * 0.75f); if (!_player.PlayFootsteps(move, val4, val5, num6, num5, volume, 1f + Random.Range(-0.04f, 0.04f), 26f, cutoffFrom, 19000f, varyPitchPerStep: false)) { return false; } AudioClip val6 = VanillaSounds.PickLoudCoil(); if ((Object)(object)val6 != (Object)null) { float delay = (float)num6 * num5 + Random.Range(0.05f, 0.25f); try { ((MonoBehaviour)this).StartCoroutine(PlayCoilAfter(val6, val5, delay, _sceneToken, _cutToken)); } catch { } } if (ModConfig.DebugLogging.Value || forced) { Plugin.Log.LogInfo((object)("Heard: coilhead - running in from " + num3.ToString("0.0") + "m over " + num6 + " steps, then the coil")); } return true; } private IEnumerator PlayCoilAfter(AudioClip clip, Vector3 at, float delay, int token, int cut) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) yield return (object)new WaitForSeconds(delay); if (!((Object)(object)_player == (Object)null) && !((Object)(object)clip == (Object)null) && token == _sceneToken && cut == _cutToken && ModConfig.Enabled.Value) { PlayerControllerB localPlayer = GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null) && IsEligible(localPlayer)) { _player.Play(clip, at, insideHead: false, Mathf.Clamp01(ModConfig.CoilheadVolume.Value), 1f + Random.Range(-0.03f, 0.03f), radioEffect: false, 24f, 22000f, 0f, 0f, 0, dry: true, 6f); } } } private bool TryCoilheadBurst(PlayerControllerB local, Vector3 eye, AudioClip[] springs, bool forced) { //IL_0032: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00e0: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown resul