using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using Peak;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;
using Zorro.Core;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Inversion")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Inversion")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f9d0f724-364b-47e0-bbc8-5382cf448217")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[DefaultExecutionOrder(10000)]
[BepInPlugin("com.saphir.neveraloneheartbeat", "NeverAloneHeartbeat", "1.0.0")]
public sealed class NeverAloneHeartbeat : BaseUnityPlugin
{
private const float SafeDistance = 60f;
private const float BaseBpm = 52f;
private const float ScoutmasterFarBpm = 72f;
private const float ScoutmasterNearBpm = 240f;
private const float BaseHeartbeatVolume = 1f;
private const float MaximumHeartbeatVolume = 2f;
private const float BreathOutVolume = 1f;
private const float BreathInVolume = 1f;
private const float ScoutmasterEffectStartDistance = 50f;
private const float ScoutmasterMaximumEffectDistance = 5f;
private AudioSource heartbeatSource;
private AudioSource breathOutSource;
private AudioSource breathInSource;
private AudioClip heartbeatClip;
private AudioClip breathOutClip;
private AudioClip breathInClip;
private Scoutmaster scoutmaster;
private Character scoutmasterCharacter;
private float nextBeatTime;
private float currentBpm = 52f;
private float currentHeartbeatVolume = 1f;
private bool hasDistanceState;
private bool wasOutsideSafeZone;
private bool wasGameplayActive;
private bool mixerReady;
private void Awake()
{
heartbeatSource = CreateLocalAudioSource(loop: false);
breathOutSource = CreateLocalAudioSource(loop: true);
breathInSource = CreateLocalAudioSource(loop: false);
((MonoBehaviour)this).StartCoroutine(LoadAllAudio());
nextBeatTime = Time.unscaledTime + 0.5f;
}
private AudioSource CreateLocalAudioSource(bool loop)
{
AudioSource val = ((Component)this).gameObject.AddComponent<AudioSource>();
val.playOnAwake = false;
val.loop = loop;
val.spatialBlend = 0f;
val.dopplerLevel = 0f;
val.priority = 32;
val.ignoreListenerPause = false;
val.ignoreListenerVolume = false;
val.bypassEffects = false;
val.bypassListenerEffects = false;
val.bypassReverbZones = true;
val.outputAudioMixerGroup = null;
return val;
}
private IEnumerator LoadAllAudio()
{
string heartbeatPath = FindAudioFile("Heartbeat.wav");
string breathOutPath = FindAudioFile("breathsoundout.wav");
string breathInPath = FindAudioFile("breathsoundin.wav");
if (!string.IsNullOrEmpty(heartbeatPath))
{
yield return LoadWav(heartbeatPath, delegate(AudioClip clip)
{
heartbeatClip = clip;
});
}
if (!string.IsNullOrEmpty(breathOutPath))
{
yield return LoadWav(breathOutPath, delegate(AudioClip clip)
{
breathOutClip = clip;
if ((Object)(object)breathOutSource != (Object)null)
{
breathOutSource.clip = clip;
}
});
}
if (!string.IsNullOrEmpty(breathInPath))
{
yield return LoadWav(breathInPath, delegate(AudioClip clip)
{
breathInClip = clip;
});
}
}
private string FindAudioFile(string fileName)
{
string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
if (!string.IsNullOrEmpty(directoryName))
{
string text = Path.Combine(directoryName, fileName);
if (File.Exists(text))
{
return text;
}
}
string pluginPath = Paths.PluginPath;
if (string.IsNullOrEmpty(pluginPath) || !Directory.Exists(pluginPath))
{
return null;
}
string text2 = Path.Combine(pluginPath, fileName);
if (File.Exists(text2))
{
return text2;
}
try
{
string[] files = Directory.GetFiles(pluginPath, fileName, SearchOption.AllDirectories);
if (files != null && files.Length != 0)
{
return files[0];
}
}
catch
{
}
return null;
}
private static IEnumerator LoadWav(string path, Action<AudioClip> onLoaded)
{
if (string.IsNullOrEmpty(path) || !File.Exists(path))
{
yield break;
}
string uri = new Uri(Path.GetFullPath(path)).AbsoluteUri;
UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(uri, (AudioType)20);
try
{
DownloadHandler downloadHandler = request.downloadHandler;
DownloadHandlerAudioClip handler = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null);
if (handler != null)
{
handler.streamAudio = false;
handler.compressed = false;
}
yield return request.SendWebRequest();
if ((int)request.result == 1)
{
AudioClip clip = DownloadHandlerAudioClip.GetContent(request);
if ((Object)(object)clip != (Object)null)
{
onLoaded(clip);
}
yield break;
}
}
finally
{
((IDisposable)request)?.Dispose();
}
}
private void Update()
{
UpdateSfxMixer();
if (!IsGameplayActive() || !mixerReady)
{
DisableGameplayAudio();
return;
}
if (!wasGameplayActive)
{
wasGameplayActive = true;
currentBpm = 52f;
currentHeartbeatVolume = 1f;
nextBeatTime = Time.unscaledTime + 0.25f;
hasDistanceState = false;
wasOutsideSafeZone = false;
}
CacheScoutmaster();
UpdateDistanceAudio();
UpdateHeartbeatState();
PlayHeartbeatWhenReady();
}
private void UpdateSfxMixer()
{
if ((Object)(object)SFX_Player.instance == (Object)null || (Object)(object)SFX_Player.instance.defaultMixerGroup == (Object)null)
{
mixerReady = false;
return;
}
AudioMixerGroup defaultMixerGroup = SFX_Player.instance.defaultMixerGroup;
if ((Object)(object)heartbeatSource != (Object)null && (Object)(object)heartbeatSource.outputAudioMixerGroup != (Object)(object)defaultMixerGroup)
{
heartbeatSource.outputAudioMixerGroup = defaultMixerGroup;
}
if ((Object)(object)breathOutSource != (Object)null && (Object)(object)breathOutSource.outputAudioMixerGroup != (Object)(object)defaultMixerGroup)
{
breathOutSource.outputAudioMixerGroup = defaultMixerGroup;
}
if ((Object)(object)breathInSource != (Object)null && (Object)(object)breathInSource.outputAudioMixerGroup != (Object)(object)defaultMixerGroup)
{
breathInSource.outputAudioMixerGroup = defaultMixerGroup;
}
mixerReady = (Object)(object)heartbeatSource != (Object)null && (Object)(object)breathOutSource != (Object)null && (Object)(object)breathInSource != (Object)null && (Object)(object)heartbeatSource.outputAudioMixerGroup == (Object)(object)defaultMixerGroup && (Object)(object)breathOutSource.outputAudioMixerGroup == (Object)(object)defaultMixerGroup && (Object)(object)breathInSource.outputAudioMixerGroup == (Object)(object)defaultMixerGroup;
}
private bool IsGameplayActive()
{
if (!MapHandler.ExistsAndInitialized)
{
return false;
}
Character localCharacter = Character.localCharacter;
return (Object)(object)localCharacter != (Object)null && localCharacter.IsPlayerControlled && (Object)(object)localCharacter.data != (Object)null && !localCharacter.data.dead;
}
private void UpdateDistanceAudio()
{
Character localCharacter = Character.localCharacter;
float nearestPlayerDistance = GetNearestPlayerDistance(localCharacter);
if (nearestPlayerDistance < 0f)
{
StopOutsideBreathing();
hasDistanceState = false;
wasOutsideSafeZone = false;
return;
}
bool flag = nearestPlayerDistance > 60f;
if (!hasDistanceState)
{
hasDistanceState = true;
wasOutsideSafeZone = flag;
if (flag)
{
StartOutsideBreathing();
}
return;
}
if (flag)
{
StartOutsideBreathing();
}
else
{
StopOutsideBreathing();
if (wasOutsideSafeZone)
{
PlayInsideBreathingOnce();
}
}
wasOutsideSafeZone = flag;
}
private void StartOutsideBreathing()
{
if (!((Object)(object)breathOutSource == (Object)null) && !((Object)(object)breathOutClip == (Object)null))
{
if ((Object)(object)breathOutSource.clip != (Object)(object)breathOutClip)
{
breathOutSource.clip = breathOutClip;
}
breathOutSource.volume = 1f;
if (!breathOutSource.isPlaying)
{
breathOutSource.Play();
}
}
}
private void StopOutsideBreathing()
{
if ((Object)(object)breathOutSource != (Object)null && breathOutSource.isPlaying)
{
breathOutSource.Stop();
}
}
private void PlayInsideBreathingOnce()
{
if (!((Object)(object)breathInSource == (Object)null) && !((Object)(object)breathInClip == (Object)null))
{
breathInSource.Stop();
breathInSource.volume = 1f;
breathInSource.pitch = 1f;
breathInSource.PlayOneShot(breathInClip, 1f);
}
}
private void PlayHeartbeatWhenReady()
{
if (!((Object)(object)heartbeatSource == (Object)null) && !((Object)(object)heartbeatClip == (Object)null) && !(Time.unscaledTime < nextBeatTime))
{
heartbeatSource.pitch = 1f;
heartbeatSource.volume = 1f;
heartbeatSource.PlayOneShot(heartbeatClip, currentHeartbeatVolume);
float num = 60f / Mathf.Max(1f, currentBpm);
nextBeatTime = Time.unscaledTime + num;
}
}
private void UpdateHeartbeatState()
{
//IL_0057: 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)
float num = 52f;
float num2 = 1f;
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter != (Object)null && (Object)(object)scoutmaster != (Object)null && (Object)(object)scoutmasterCharacter != (Object)null && (Object)(object)scoutmaster.currentTarget == (Object)(object)localCharacter)
{
float num3 = Vector3.Distance(scoutmasterCharacter.Center, localCharacter.Center);
float num4 = Mathf.InverseLerp(50f, 5f, num3);
num4 = Mathf.Pow(num4, 1.18f);
num = Mathf.Lerp(72f, 240f, num4);
num2 = Mathf.Lerp(1.2f, 2f, num4);
}
currentBpm = Mathf.MoveTowards(currentBpm, num, Time.unscaledDeltaTime * 95f);
currentHeartbeatVolume = Mathf.MoveTowards(currentHeartbeatVolume, num2, Time.unscaledDeltaTime * 1.2f);
}
private void CacheScoutmaster()
{
Scoutmaster val = default(Scoutmaster);
if ((Object)(object)scoutmaster != (Object)null)
{
if ((Object)(object)scoutmasterCharacter == (Object)null)
{
scoutmasterCharacter = ((Component)scoutmaster).GetComponent<Character>();
}
}
else if (Scoutmaster.GetPrimaryScoutmaster(ref val) && (Object)(object)val != (Object)null)
{
scoutmaster = val;
scoutmasterCharacter = ((Component)scoutmaster).GetComponent<Character>();
}
else
{
scoutmaster = null;
scoutmasterCharacter = null;
}
}
private static float GetNearestPlayerDistance(Character source)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
if (!IsValidPlayer(source))
{
return -1f;
}
float num = float.MaxValue;
bool flag = false;
for (int i = 0; i < Character.AllCharacters.Count; i++)
{
Character val = Character.AllCharacters[i];
if (IsValidPlayer(val) && !((Object)(object)val == (Object)(object)source))
{
float num2 = Vector3.Distance(source.Center, val.Center);
if (num2 < num)
{
num = num2;
}
flag = true;
}
}
return flag ? num : (-1f);
}
private static bool IsValidPlayer(Character character)
{
return (Object)(object)character != (Object)null && character.IsPlayerControlled && (Object)(object)character.data != (Object)null && !character.data.dead && !character.data.fullyPassedOut;
}
private void DisableGameplayAudio()
{
if ((Object)(object)heartbeatSource != (Object)null)
{
heartbeatSource.Stop();
}
StopOutsideBreathing();
if ((Object)(object)breathInSource != (Object)null)
{
breathInSource.Stop();
}
currentBpm = 52f;
currentHeartbeatVolume = 1f;
nextBeatTime = Time.unscaledTime + 0.5f;
hasDistanceState = false;
wasOutsideSafeZone = false;
wasGameplayActive = false;
scoutmaster = null;
scoutmasterCharacter = null;
}
private void OnDisable()
{
DisableGameplayAudio();
}
}
[BepInPlugin("com.saphir.neveralonecompass", "NeverAloneCompass", "1.0.0")]
public sealed class Compass : BaseUnityPlugin
{
private const ushort CompassItemId = 23;
private const string CompassPrefabName = "Compass";
private readonly HashSet<Segment> spawnedSegments = new HashSet<Segment>();
private Segment lastObservedSegment = (Segment)6;
private Segment pendingSegment = (Segment)6;
private void Update()
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Invalid comparison between Unknown and I4
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: 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_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Invalid comparison between Unknown and I4
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Invalid comparison between Unknown and I4
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || !MapHandler.ExistsAndInitialized)
{
lastObservedSegment = (Segment)6;
pendingSegment = (Segment)6;
spawnedSegments.Clear();
return;
}
Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
if ((int)lastObservedSegment == 6)
{
lastObservedSegment = currentSegmentNumber;
if ((int)currentSegmentNumber != 0 && (int)currentSegmentNumber != 6 && !spawnedSegments.Contains(currentSegmentNumber))
{
BeginSpawn(currentSegmentNumber);
}
}
else if (currentSegmentNumber != lastObservedSegment)
{
lastObservedSegment = currentSegmentNumber;
if ((int)currentSegmentNumber != 0 && (int)currentSegmentNumber != 6 && !spawnedSegments.Contains(currentSegmentNumber))
{
BeginSpawn(currentSegmentNumber);
}
}
}
private void BeginSpawn(Segment segment)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: 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_001a: Unknown result type (might be due to invalid IL or missing references)
if (pendingSegment != segment)
{
pendingSegment = segment;
((MonoBehaviour)this).StartCoroutine(SpawnCompassAtPreviousCampfire(segment));
}
}
private IEnumerator SpawnCompassAtPreviousCampfire(Segment segment)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
Campfire previousCampfire = null;
while (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && MapHandler.ExistsAndInitialized && MapHandler.CurrentSegmentNumber == segment)
{
previousCampfire = MapHandler.PreviousCampfire;
if ((Object)(object)previousCampfire != (Object)null && ((Component)previousCampfire).gameObject.activeInHierarchy)
{
break;
}
yield return null;
}
if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || !MapHandler.ExistsAndInitialized || MapHandler.CurrentSegmentNumber != segment || (Object)(object)previousCampfire == (Object)null)
{
pendingSegment = (Segment)6;
yield break;
}
Item compassPrefab = default(Item);
if (!ItemDatabase.TryGetItem("Compass", ref compassPrefab) && !ItemDatabase.TryGetItem((ushort)23, ref compassPrefab))
{
pendingSegment = (Segment)6;
yield break;
}
Vector3 spawnPosition = GetSpawnPosition(previousCampfire);
Quaternion spawnRotation = Quaternion.Euler(0f, ((Component)previousCampfire).transform.eulerAngles.y, 0f);
PhotonNetwork.InstantiateItemRoom(((Object)compassPrefab).name, spawnPosition, spawnRotation);
spawnedSegments.Add(segment);
pendingSegment = (Segment)6;
}
private static Vector3 GetSpawnPosition(Campfire campfire)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: 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_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: 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_0068: 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_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_0081: 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_00cd: 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)
Transform transform = ((Component)campfire).transform;
Vector3 val = transform.position + transform.right * 1.5f + transform.forward * 0.6f + Vector3.up * 1.5f;
RaycastHit val2 = default(RaycastHit);
if (Physics.Raycast(val, Vector3.down, ref val2, 5f, -1, (QueryTriggerInteraction)1))
{
return ((RaycastHit)(ref val2)).point + Vector3.up * 0.25f;
}
return transform.position + transform.right * 1.5f + transform.forward * 0.6f + Vector3.up * 0.5f;
}
private void OnDisable()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
((MonoBehaviour)this).StopAllCoroutines();
spawnedSegments.Clear();
lastObservedSegment = (Segment)6;
pendingSegment = (Segment)6;
}
}
[BepInPlugin("com.saphir.gloomfog", "GloomFog", "1.0.0")]
public sealed class GloomFog : BaseUnityPlugin
{
private static readonly int ExtraFogProperty = Shader.PropertyToID("EXTRAFOG");
private static readonly int FogSafeZoneProperty = Shader.PropertyToID("FogSafeZone");
private static readonly int GloomVisibilityOffsetProperty = Shader.PropertyToID("GloomVisibiltyOffset");
private static readonly int HeightFogHeightProperty = Shader.PropertyToID("HeightFogHeight");
private static readonly int FogTextureProperty = Shader.PropertyToID("FogTexture");
private static readonly Color LonelyFogColor = new Color(0.38f, 0.42f, 0.41f, 1f);
private MapHandler cachedMapHandler;
private DayNightProfile gloomProfile;
private FogShaderParams gloomFogShaderParams;
private ForceFogShaderHeight gloomHeightSource;
private void LateUpdate()
{
if (!MapHandler.ExistsAndInitialized || (Object)(object)DayNightManager.instance == (Object)null)
{
ClearCache();
return;
}
MapHandler instance = Singleton<MapHandler>.Instance;
if ((Object)(object)instance == (Object)null)
{
ClearCache();
return;
}
if ((Object)(object)cachedMapHandler != (Object)(object)instance || (Object)(object)gloomProfile == (Object)null)
{
CacheGloomSources(instance);
}
if (!((Object)(object)gloomProfile == (Object)null))
{
ApplyGloomFog();
ApplyLonelyFogColor();
if ((Object)(object)FogSafeZoneManager.instance == (Object)null || !((Behaviour)FogSafeZoneManager.instance).isActiveAndEnabled)
{
Shader.SetGlobalFloat(FogSafeZoneProperty, 0f);
Shader.SetGlobalFloat(GloomVisibilityOffsetProperty, 0f);
}
}
}
private void CacheGloomSources(MapHandler mapHandler)
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Invalid comparison between Unknown and I4
cachedMapHandler = mapHandler;
gloomProfile = null;
gloomFogShaderParams = null;
gloomHeightSource = null;
MapSegment val = FindGloomSegment(mapHandler.segments);
if (val == null)
{
val = FindGloomSegment(mapHandler.variantSegments);
}
if (val == null)
{
return;
}
gloomProfile = val.dayNightProfile;
GameObject segmentParent = val.segmentParent;
if ((Object)(object)segmentParent == (Object)null)
{
return;
}
gloomFogShaderParams = segmentParent.GetComponentInChildren<FogShaderParams>(true);
ForceFogShaderHeight[] componentsInChildren = segmentParent.GetComponentsInChildren<ForceFogShaderHeight>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if ((Object)(object)componentsInChildren[i] != (Object)null && (int)componentsInChildren[i].fogType == 0)
{
gloomHeightSource = componentsInChildren[i];
break;
}
}
}
private static MapSegment FindGloomSegment(MapSegment[] segments)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Invalid comparison between Unknown and I4
if (segments == null)
{
return null;
}
foreach (MapSegment val in segments)
{
if (val != null && (int)val.biome == 8)
{
return val;
}
}
return null;
}
private void ApplyGloomFog()
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
float timeOfDayNormalized = DayNightManager.instance.timeOfDayNormalized;
if (gloomProfile.fogGradient != null)
{
Shader.SetGlobalFloat(ExtraFogProperty, gloomProfile.fogGradient.Evaluate(timeOfDayNormalized).r);
}
ApplyShaderFloats(gloomProfile.globalShaderFloats);
ApplyShaderFloats(gloomProfile.globalStaticShaderFloats);
ApplyAnimatedShaderFloats(gloomProfile.animatedGlobalShaderFloats, timeOfDayNormalized);
if ((Object)(object)gloomFogShaderParams != (Object)null && (Object)(object)gloomFogShaderParams.fogTexture != (Object)null)
{
Shader.SetGlobalTexture(FogTextureProperty, gloomFogShaderParams.fogTexture);
}
if ((Object)(object)gloomHeightSource != (Object)null)
{
Shader.SetGlobalFloat(HeightFogHeightProperty, ((Component)gloomHeightSource).transform.position.y);
}
}
private static void ApplyLonelyFogColor()
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
string shaderValue = DayNightManager.instance.getShaderValue((ShaderParams)7);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalColor(shaderValue, LonelyFogColor);
}
}
private static void ApplyShaderFloats(ShaderParameters[] parameters)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
if (parameters == null || (Object)(object)DayNightManager.instance == (Object)null)
{
return;
}
foreach (ShaderParameters val in parameters)
{
if (val != null && IsFogFloatParameter(val.parameter))
{
string shaderValue = DayNightManager.instance.getShaderValue(val.parameter);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalFloat(shaderValue, val.paramValue);
}
}
}
}
private static void ApplyAnimatedShaderFloats(AnimatedShaderParameters[] parameters, float time)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (parameters == null || (Object)(object)DayNightManager.instance == (Object)null)
{
return;
}
foreach (AnimatedShaderParameters val in parameters)
{
if (val != null && val.paramValue != null && IsFogFloatParameter(val.parameter))
{
string shaderValue = DayNightManager.instance.getShaderValue(val.parameter);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalFloat(shaderValue, val.paramValue.Evaluate(time));
}
}
}
}
private static bool IsFogFloatParameter(ShaderParams parameter)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Invalid comparison between Unknown and I4
return (int)parameter == 3 || (int)parameter == 5 || (int)parameter == 6 || (int)parameter == 8;
}
private void ClearCache()
{
cachedMapHandler = null;
gloomProfile = null;
gloomFogShaderParams = null;
gloomHeightSource = null;
}
}
[BepInPlugin("com.saphir.scoutmasterdamage", "ScoutMasterDamage", "1.0.0")]
public sealed class ScoutMasterDamage : BaseUnityPlugin
{
private const float OriginalScoutmasterThrowDamage = 0.3f;
private const float AdditionalThrowDamage = 0.7f;
private const float DamageTolerance = 0.001f;
private Character localCharacter;
private CharacterAfflictions localAfflictions;
private Scoutmaster scoutmaster;
private bool applyingAdditionalDamage;
private void Update()
{
CacheLocalPlayer();
CacheScoutmaster();
}
private void CacheLocalPlayer()
{
Character val = Character.localCharacter;
if (!((Object)(object)val == (Object)(object)localCharacter))
{
UnsubscribeLocalAfflictions();
localCharacter = val;
if (!((Object)(object)localCharacter == (Object)null) && localCharacter.refs != null && !((Object)(object)localCharacter.refs.afflictions == (Object)null))
{
localAfflictions = localCharacter.refs.afflictions;
CharacterAfflictions obj = localAfflictions;
obj.OnAddedStatus = (Action<STATUSTYPE, float>)Delegate.Combine(obj.OnAddedStatus, new Action<STATUSTYPE, float>(OnStatusAdded));
}
}
}
private void CacheScoutmaster()
{
Scoutmaster val = default(Scoutmaster);
if (Scoutmaster.GetPrimaryScoutmaster(ref val))
{
scoutmaster = val;
}
else
{
scoutmaster = null;
}
}
private void OnStatusAdded(STATUSTYPE statusType, float amount)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Invalid comparison between Unknown and I4
if (!applyingAdditionalDamage && (int)statusType <= 0 && !(Mathf.Abs(amount - 0.3f) > 0.001f) && !((Object)(object)localCharacter == (Object)null) && !((Object)(object)localAfflictions == (Object)null) && !((Object)(object)scoutmaster == (Object)null) && !((Object)(object)scoutmaster.currentTarget != (Object)(object)localCharacter))
{
float currentStatus = localAfflictions.GetCurrentStatus((STATUSTYPE)0);
applyingAdditionalDamage = true;
localAfflictions.SetStatus((STATUSTYPE)0, currentStatus + 0.7f, true);
applyingAdditionalDamage = false;
}
}
private void UnsubscribeLocalAfflictions()
{
if ((Object)(object)localAfflictions != (Object)null)
{
CharacterAfflictions obj = localAfflictions;
obj.OnAddedStatus = (Action<STATUSTYPE, float>)Delegate.Remove(obj.OnAddedStatus, new Action<STATUSTYPE, float>(OnStatusAdded));
}
localAfflictions = null;
}
private void OnDisable()
{
UnsubscribeLocalAfflictions();
localCharacter = null;
scoutmaster = null;
applyingAdditionalDamage = false;
}
}
[DefaultExecutionOrder(10000)]
[BepInPlugin("com.saphir.scoutmasterdarkness", "ScoutmasterDarkness", "1.0.0")]
public sealed class ScoutmasterDarkness : BaseUnityPlugin
{
private const float SafeDistance = 60f;
private const float ScoutmasterCallDistance = 60f;
private const float ForcedChaseDuration = 0.75f;
private const float ForcedChaseRefreshInterval = 0.35f;
private static readonly int ExtraFogProperty = Shader.PropertyToID("EXTRAFOG");
private static readonly int FogSafeZoneProperty = Shader.PropertyToID("FogSafeZone");
private static readonly int GloomVisibilityOffsetProperty = Shader.PropertyToID("GloomVisibiltyOffset");
private static readonly int HeightFogHeightProperty = Shader.PropertyToID("HeightFogHeight");
private static readonly int FogTextureProperty = Shader.PropertyToID("FogTexture");
private static readonly Color LonelyFogColor = new Color(0.38f, 0.42f, 0.41f, 1f);
private Scoutmaster controlledScoutmaster;
private PhotonView controlledScoutmasterView;
private bool scoutmasterSuppressed;
private bool scoutmasterCalledByDistance;
private int lastForcedTargetViewId = -1;
private float lastForcedTargetTime = -100f;
private float nextForcedTargetRefreshTime;
private MapHandler cachedMapHandler;
private DayNightProfile gloomProfile;
private FogShaderParams gloomFogShaderParams;
private ForceFogShaderHeight gloomHeightSource;
private void LateUpdate()
{
CacheScoutmasterReference();
if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
{
UpdateScoutmasterCallState();
}
ApplyPersistentGloomFog();
}
private void UpdateScoutmasterCallState()
{
Character isolatedPlayer;
float isolatedDistance;
if ((Object)(object)controlledScoutmaster == (Object)null || (Object)(object)controlledScoutmasterView == (Object)null)
{
scoutmasterCalledByDistance = false;
}
else if (!TryGetMostIsolatedPlayer(out isolatedPlayer, out isolatedDistance) || (Object)(object)isolatedPlayer == (Object)null)
{
scoutmasterCalledByDistance = false;
SuppressScoutmaster();
}
else if (!scoutmasterCalledByDistance)
{
if (isolatedDistance >= 60f)
{
scoutmasterCalledByDistance = true;
ActivateScoutmaster(isolatedPlayer);
}
else
{
SuppressScoutmaster();
}
}
else if (isolatedDistance <= 60f)
{
scoutmasterCalledByDistance = false;
SuppressScoutmaster();
}
else
{
ActivateScoutmaster(isolatedPlayer);
}
}
private void ActivateScoutmaster(Character target)
{
if (!((Object)(object)target == (Object)null) && !((Object)(object)((MonoBehaviourPun)target).photonView == (Object)null) && !((Object)(object)controlledScoutmaster == (Object)null) && !((Object)(object)controlledScoutmasterView == (Object)null) && controlledScoutmasterView.IsMine)
{
if (scoutmasterSuppressed)
{
((Behaviour)controlledScoutmaster).enabled = true;
scoutmasterSuppressed = false;
}
int viewID = ((MonoBehaviourPun)target).photonView.ViewID;
bool flag = lastForcedTargetViewId != viewID;
bool flag2 = Time.time >= nextForcedTargetRefreshTime;
if ((flag || flag2) && (!flag || lastForcedTargetViewId == -1 || !(Time.time < lastForcedTargetTime + 0.75f)))
{
controlledScoutmasterView.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { viewID, 0.75f });
lastForcedTargetViewId = viewID;
lastForcedTargetTime = Time.time;
nextForcedTargetRefreshTime = Time.time + 0.35f;
}
}
}
private void SuppressScoutmaster()
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)controlledScoutmaster == (Object)null) && !((Object)(object)controlledScoutmasterView == (Object)null) && controlledScoutmasterView.IsMine)
{
if (!scoutmasterSuppressed)
{
controlledScoutmasterView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
{
(object)new Vector3(0f, 0f, 5000f),
false
});
controlledScoutmasterView.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f });
((Behaviour)controlledScoutmaster).enabled = false;
scoutmasterSuppressed = true;
}
if (Time.time >= lastForcedTargetTime + 0.75f)
{
controlledScoutmasterView.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f });
lastForcedTargetViewId = -1;
nextForcedTargetRefreshTime = 0f;
}
}
}
private void CacheScoutmasterReference()
{
if (!((Object)(object)controlledScoutmaster != (Object)null))
{
Scoutmaster val = default(Scoutmaster);
if (!Scoutmaster.GetPrimaryScoutmaster(ref val) || (Object)(object)val == (Object)null)
{
controlledScoutmasterView = null;
scoutmasterSuppressed = false;
scoutmasterCalledByDistance = false;
lastForcedTargetViewId = -1;
lastForcedTargetTime = -100f;
nextForcedTargetRefreshTime = 0f;
}
else
{
controlledScoutmaster = val;
controlledScoutmasterView = ((Component)controlledScoutmaster).GetComponent<PhotonView>();
scoutmasterSuppressed = false;
}
}
}
private static bool TryGetMostIsolatedPlayer(out Character isolatedPlayer, out float isolatedDistance)
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: 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)
isolatedPlayer = null;
isolatedDistance = -1f;
for (int i = 0; i < Character.AllCharacters.Count; i++)
{
Character val = Character.AllCharacters[i];
if (!IsValidPlayer(val))
{
continue;
}
float num = float.MaxValue;
bool flag = false;
for (int j = 0; j < Character.AllCharacters.Count; j++)
{
Character val2 = Character.AllCharacters[j];
if (IsValidPlayer(val2) && !((Object)(object)val2 == (Object)(object)val))
{
float num2 = Vector3.Distance(val.Center, val2.Center);
if (num2 < num)
{
num = num2;
}
flag = true;
}
}
if (flag && ((Object)(object)isolatedPlayer == (Object)null || num > isolatedDistance || (Mathf.Approximately(num, isolatedDistance) && val.Center.y > isolatedPlayer.Center.y)))
{
isolatedPlayer = val;
isolatedDistance = num;
}
}
return (Object)(object)isolatedPlayer != (Object)null;
}
private static bool IsValidPlayer(Character character)
{
return (Object)(object)character != (Object)null && character.IsPlayerControlled && (Object)(object)character.data != (Object)null && !character.data.dead && !character.data.fullyPassedOut;
}
private void ApplyPersistentGloomFog()
{
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
if (!MapHandler.ExistsAndInitialized || (Object)(object)DayNightManager.instance == (Object)null)
{
ClearGloomCache();
return;
}
MapHandler instance = Singleton<MapHandler>.Instance;
if ((Object)(object)instance == (Object)null)
{
ClearGloomCache();
return;
}
if ((Object)(object)cachedMapHandler != (Object)(object)instance || (Object)(object)gloomProfile == (Object)null)
{
CacheGloomSources(instance);
}
if (!((Object)(object)gloomProfile == (Object)null))
{
float timeOfDayNormalized = DayNightManager.instance.timeOfDayNormalized;
if (gloomProfile.fogGradient != null)
{
Shader.SetGlobalFloat(ExtraFogProperty, gloomProfile.fogGradient.Evaluate(timeOfDayNormalized).r);
}
ApplyGloomShaderFloats(gloomProfile.globalShaderFloats);
ApplyGloomShaderFloats(gloomProfile.globalStaticShaderFloats);
ApplyGloomAnimatedShaderFloats(gloomProfile.animatedGlobalShaderFloats, timeOfDayNormalized);
if ((Object)(object)gloomFogShaderParams != (Object)null && (Object)(object)gloomFogShaderParams.fogTexture != (Object)null)
{
Shader.SetGlobalTexture(FogTextureProperty, gloomFogShaderParams.fogTexture);
}
if ((Object)(object)gloomHeightSource != (Object)null)
{
Shader.SetGlobalFloat(HeightFogHeightProperty, ((Component)gloomHeightSource).transform.position.y);
}
string shaderValue = DayNightManager.instance.getShaderValue((ShaderParams)7);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalColor(shaderValue, LonelyFogColor);
}
Shader.SetGlobalFloat(FogSafeZoneProperty, 0f);
Shader.SetGlobalFloat(GloomVisibilityOffsetProperty, 0f);
}
}
private void CacheGloomSources(MapHandler mapHandler)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Invalid comparison between Unknown and I4
cachedMapHandler = mapHandler;
gloomProfile = null;
gloomFogShaderParams = null;
gloomHeightSource = null;
MapSegment val = FindGloomSegment(mapHandler.segments);
if (val == null)
{
val = FindGloomSegment(mapHandler.variantSegments);
}
if (val == null)
{
return;
}
gloomProfile = val.dayNightProfile;
GameObject segmentParent = val.segmentParent;
if ((Object)(object)segmentParent == (Object)null)
{
return;
}
gloomFogShaderParams = segmentParent.GetComponentInChildren<FogShaderParams>(true);
ForceFogShaderHeight[] componentsInChildren = segmentParent.GetComponentsInChildren<ForceFogShaderHeight>(true);
foreach (ForceFogShaderHeight val2 in componentsInChildren)
{
if ((Object)(object)val2 != (Object)null && (int)val2.fogType == 0)
{
gloomHeightSource = val2;
break;
}
}
}
private static MapSegment FindGloomSegment(MapSegment[] segments)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Invalid comparison between Unknown and I4
if (segments == null)
{
return null;
}
foreach (MapSegment val in segments)
{
if (val != null && (int)val.biome == 8)
{
return val;
}
}
return null;
}
private static void ApplyGloomShaderFloats(ShaderParameters[] parameters)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
if (parameters == null || (Object)(object)DayNightManager.instance == (Object)null)
{
return;
}
foreach (ShaderParameters val in parameters)
{
if (val != null && IsGloomFogFloatParameter(val.parameter))
{
string shaderValue = DayNightManager.instance.getShaderValue(val.parameter);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalFloat(shaderValue, val.paramValue);
}
}
}
}
private static void ApplyGloomAnimatedShaderFloats(AnimatedShaderParameters[] parameters, float time)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (parameters == null || (Object)(object)DayNightManager.instance == (Object)null)
{
return;
}
foreach (AnimatedShaderParameters val in parameters)
{
if (val != null && val.paramValue != null && IsGloomFogFloatParameter(val.parameter))
{
string shaderValue = DayNightManager.instance.getShaderValue(val.parameter);
if (!string.IsNullOrEmpty(shaderValue))
{
Shader.SetGlobalFloat(shaderValue, val.paramValue.Evaluate(time));
}
}
}
}
private static bool IsGloomFogFloatParameter(ShaderParams parameter)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Invalid comparison between Unknown and I4
return (int)parameter == 3 || (int)parameter == 5 || (int)parameter == 6 || (int)parameter == 8;
}
private void ClearGloomCache()
{
cachedMapHandler = null;
gloomProfile = null;
gloomFogShaderParams = null;
gloomHeightSource = null;
}
private void OnDisable()
{
if ((Object)(object)controlledScoutmaster != (Object)null && (Object)(object)controlledScoutmasterView != (Object)null && controlledScoutmasterView.IsMine)
{
if (scoutmasterSuppressed)
{
((Behaviour)controlledScoutmaster).enabled = true;
}
controlledScoutmasterView.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f });
}
controlledScoutmaster = null;
controlledScoutmasterView = null;
scoutmasterSuppressed = false;
scoutmasterCalledByDistance = false;
lastForcedTargetViewId = -1;
lastForcedTargetTime = -100f;
nextForcedTargetRefreshTime = 0f;
ClearGloomCache();
}
}
[DefaultExecutionOrder(10000)]
[BepInPlugin("com.saphir.neveralonevoice", "NeverAloneVoice", "1.0.0")]
public sealed class Voice : BaseUnityPlugin
{
private sealed class VoiceState
{
public AudioSource Source;
public float BaseVolume;
public float LastAppliedVolume;
public bool HasAppliedVolume;
}
private const float FullVolumeDistance = 10f;
private const float MuteDistance = 30f;
private readonly Dictionary<Character, VoiceState> voiceStates = new Dictionary<Character, VoiceState>();
private readonly List<Character> staleCharacters = new List<Character>();
private void LateUpdate()
{
Character localCharacter = Character.localCharacter;
if (!IsValidPlayer(localCharacter))
{
RestoreAll();
return;
}
UpdateRemoteVoices(localCharacter);
RemoveStaleCharacters();
}
private void UpdateRemoteVoices(Character localCharacter)
{
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < Character.AllCharacters.Count; i++)
{
Character val = Character.AllCharacters[i];
if (!IsValidPlayer(val) || (Object)(object)val == (Object)(object)localCharacter)
{
continue;
}
VoiceState voiceState = GetVoiceState(val);
if (voiceState != null && !((Object)(object)voiceState.Source == (Object)null))
{
AudioSource source = voiceState.Source;
float num = Vector3.Distance(localCharacter.Center, val.Center);
UpdateBaseVolume(voiceState);
if (num >= 30f)
{
source.volume = voiceState.BaseVolume;
source.mute = true;
voiceState.LastAppliedVolume = voiceState.BaseVolume;
voiceState.HasAppliedVolume = true;
}
else
{
source.mute = false;
float num2 = ((!(num <= 10f)) ? Mathf.InverseLerp(30f, 10f, num) : 1f);
float lastAppliedVolume = (source.volume = voiceState.BaseVolume * num2);
voiceState.LastAppliedVolume = lastAppliedVolume;
voiceState.HasAppliedVolume = true;
}
}
}
}
private static void UpdateBaseVolume(VoiceState state)
{
if (state != null && !((Object)(object)state.Source == (Object)null))
{
float volume = state.Source.volume;
if (!state.HasAppliedVolume)
{
state.BaseVolume = volume;
}
else if (!Mathf.Approximately(volume, state.LastAppliedVolume))
{
state.BaseVolume = volume;
}
}
}
private VoiceState GetVoiceState(Character character)
{
if (voiceStates.TryGetValue(character, out var value))
{
if (value != null && (Object)(object)value.Source != (Object)null)
{
return value;
}
voiceStates.Remove(character);
}
if (character.refs == null || (Object)(object)character.refs.voice == (Object)null)
{
return null;
}
AudioSource component = ((Component)character.refs.voice).GetComponent<AudioSource>();
if ((Object)(object)component == (Object)null)
{
return null;
}
VoiceState voiceState = new VoiceState
{
Source = component,
BaseVolume = component.volume,
LastAppliedVolume = component.volume,
HasAppliedVolume = false
};
voiceStates[character] = voiceState;
return voiceState;
}
private void RemoveStaleCharacters()
{
staleCharacters.Clear();
foreach (KeyValuePair<Character, VoiceState> voiceState in voiceStates)
{
Character key = voiceState.Key;
VoiceState value = voiceState.Value;
if ((Object)(object)key == (Object)null || !Character.AllCharacters.Contains(key))
{
RestoreVoiceState(value);
staleCharacters.Add(key);
}
}
for (int i = 0; i < staleCharacters.Count; i++)
{
voiceStates.Remove(staleCharacters[i]);
}
}
private static bool IsValidPlayer(Character character)
{
return (Object)(object)character != (Object)null && character.IsPlayerControlled && !character.isBot;
}
private static void RestoreVoiceState(VoiceState state)
{
if (state != null && !((Object)(object)state.Source == (Object)null))
{
state.Source.mute = false;
state.Source.volume = state.BaseVolume;
state.HasAppliedVolume = false;
}
}
private void RestoreAll()
{
foreach (KeyValuePair<Character, VoiceState> voiceState in voiceStates)
{
RestoreVoiceState(voiceState.Value);
}
}
private void OnDisable()
{
RestoreAll();
voiceStates.Clear();
staleCharacters.Clear();
}
}
[DefaultExecutionOrder(20000)]
[BepInPlugin("com.saphir.neveralonebinoculars", "NeverAloneBinoculars", "1.0.0")]
public sealed class Binoculars : BaseUnityPlugin
{
private const ushort BinocularItemId = 14;
private const float MaximumVisibilityBoost = 4.5f;
private const float MaximumFarFogReduction = 0.15f;
private const float VisibilityRiseSpeed = 5.5f;
private const float VisibilityFallSpeed = 8f;
private static readonly int GloomVisibilityOffsetProperty = Shader.PropertyToID("GloomVisibiltyOffset");
private static readonly int ExtraFogProperty = Shader.PropertyToID("EXTRAFOG");
private Item cachedBinocularItem;
private Action_ShowBinocularOverlay cachedBinocularOverlay;
private float currentVisibilityBoost;
private void LateUpdate()
{
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null || localCharacter.data.dead)
{
ClearState();
return;
}
bool flag = IsLocalPlayerUsingBinoculars(localCharacter);
float num = (flag ? 4.5f : 0f);
float num2 = (flag ? 5.5f : 8f);
currentVisibilityBoost = Mathf.MoveTowards(currentVisibilityBoost, num, Time.deltaTime * num2);
if (currentVisibilityBoost <= 0.001f)
{
currentVisibilityBoost = 0f;
return;
}
float strength = Mathf.Clamp01(currentVisibilityBoost / 4.5f);
ApplyNearAndMidVisibility();
ApplyFarSilhouetteVisibility(strength);
}
private void ApplyNearAndMidVisibility()
{
float globalFloat = Shader.GetGlobalFloat(GloomVisibilityOffsetProperty);
Shader.SetGlobalFloat(GloomVisibilityOffsetProperty, Mathf.Max(globalFloat, currentVisibilityBoost));
}
private void ApplyFarSilhouetteVisibility(float strength)
{
float num = 0.15f * strength;
float globalFloat = Shader.GetGlobalFloat(ExtraFogProperty);
Shader.SetGlobalFloat(ExtraFogProperty, globalFloat * (1f - num));
if (!((Object)(object)DayNightManager.instance == (Object)null))
{
string shaderValue = DayNightManager.instance.getShaderValue((ShaderParams)5);
if (!string.IsNullOrEmpty(shaderValue))
{
int num2 = Shader.PropertyToID(shaderValue);
float globalFloat2 = Shader.GetGlobalFloat(num2);
Shader.SetGlobalFloat(num2, globalFloat2 * (1f - num));
}
string shaderValue2 = DayNightManager.instance.getShaderValue((ShaderParams)3);
if (!string.IsNullOrEmpty(shaderValue2))
{
int num3 = Shader.PropertyToID(shaderValue2);
float globalFloat3 = Shader.GetGlobalFloat(num3);
Shader.SetGlobalFloat(num3, globalFloat3 * (1f - num * 0.5f));
}
}
}
private bool IsLocalPlayerUsingBinoculars(Character localCharacter)
{
Item currentItem = localCharacter.data.currentItem;
if ((Object)(object)currentItem == (Object)null || currentItem.itemID != 14)
{
cachedBinocularItem = null;
cachedBinocularOverlay = null;
return false;
}
if ((Object)(object)cachedBinocularItem != (Object)(object)currentItem || (Object)(object)cachedBinocularOverlay == (Object)null)
{
cachedBinocularItem = currentItem;
cachedBinocularOverlay = ((Component)currentItem).GetComponentInChildren<Action_ShowBinocularOverlay>(true);
}
return (Object)(object)cachedBinocularOverlay != (Object)null && cachedBinocularOverlay.binocularsActive;
}
private void ClearState()
{
cachedBinocularItem = null;
cachedBinocularOverlay = null;
currentVisibilityBoost = 0f;
}
private void OnDisable()
{
ClearState();
}
}