Decompiled source of LastEmployeeAlive v1.0.2

plugins/LastSurvivorMod.dll

Decompiled 10 minutes ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LastSurvivorMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LastSurvivorMod")]
[assembly: AssemblyTitle("LastSurvivorMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LastSurvivorMod
{
	[BepInPlugin("com.zcode.lastsurvivor", "LastSurvivorMod", "1.0.1")]
	[BepInProcess("Lethal Company.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.zcode.lastsurvivor";

		public const string PLUGIN_NAME = "LastSurvivorMod";

		public const string PLUGIN_VERSION = "1.0.1";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			new Harmony("com.zcode.lastsurvivor").PatchAll(typeof(GameStatePatches));
			Log.LogInfo((object)"Harmony-патчи применены.");
			ConfigEntry<int> minQuotaNormal = ((BaseUnityPlugin)this).Config.Bind<int>("Gameplay", "MinQuotaNormal", 2, "Minimum quota number (1-based) for the mod to activate in NORMAL lobbies (<= LargeLobbyThreshold). On earlier quotas the mod stays silent.");
			ConfigEntry<int> largeLobbyThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("Gameplay", "LargeLobbyThreshold", 6, "Lobby size above which the mod activates from quota 1 (large lobbies skip the MinQuotaNormal restriction).");
			ConfigEntry<int> theme2Quota = ((BaseUnityPlugin)this).Config.Bind<int>("Gameplay", "Theme2Quota", 6, "Quota number (1-based) from which THEME 2 (survivor2.png / music2.ogg / bell2.ogg) is used. Falls back to theme 1 if those files are missing.");
			GameObject val = new GameObject("LastSurvivorManager");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<LastSurvivorManager>().Initialize(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), minQuotaNormal, largeLobbyThreshold, theme2Quota);
			Log.LogInfo((object)"LastSurvivorMod v1.0.1 загружен.");
		}
	}
	[HarmonyPatch]
	internal static class GameStatePatches
	{
		private static void SafeRun(string patchName, Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[{patchName}] ошибка в постфиксе (игра не затронута): {arg}");
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")]
		private static void AfterOpeningDoorsSequence()
		{
			SafeRun("openingDoorsSequence", delegate
			{
				LastSurvivorManager.Instance?.NotifyRoundStarted();
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
		private static void AfterShipLeave()
		{
			SafeRun("ShipLeave", delegate
			{
				LastSurvivorManager.Instance?.NotifyRoundEnding();
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
		private static void AfterFillEndGameStats()
		{
			SafeRun("FillEndGameStats", delegate
			{
				LastSurvivorManager.Instance?.NotifyRoundEnding();
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
		private static void AfterEndOfGame()
		{
			SafeRun("EndOfGame", delegate
			{
				LastSurvivorManager.Instance?.NotifyRoundEnding();
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "Disconnect")]
		private static void AfterDisconnect()
		{
			SafeRun("Disconnect", delegate
			{
				LastSurvivorManager.Instance?.NotifyDisconnectedFromGame();
			});
		}
	}
	public class LastSurvivorManager : MonoBehaviour
	{
		public const float IMAGE_WIDTH = 960f;

		public const float IMAGE_HEIGHT = 540f;

		public const float ANIM_FADE_IN = 0.4f;

		public const float ANIM_HOLD = 1.1f;

		public const float ANIM_FADE_OUT = 2.5f;

		public const float ANIM_TOTAL = 4f;

		public const float ANIM_SCALE_START = 1.1f;

		public const float ANIM_SCALE_END = 1.45f;

		public const float MUSIC_FADE_TIME = 3f;

		public const float BELL_VOLUME = 0.9f;

		public const float MUSIC_VOLUME = 0.7f;

		private const string ASSET_IMAGE = "survivor.png";

		private const string ASSET_BELL = "bell.ogg";

		private const string ASSET_MUSIC = "music.ogg";

		private const string ASSET_IMAGE_2 = "survivor2.png";

		private const string ASSET_BELL_2 = "bell2.ogg";

		private const string ASSET_MUSIC_2 = "music2.ogg";

		private bool hasTriggeredThisRound;

		private bool roundActive;

		private string pluginDirectory;

		private AudioSource sfxSource;

		private AudioSource musicSource;

		private Image survivorImage;

		private CanvasGroup survivorCanvasGroup;

		private RectTransform survivorRect;

		private AudioClip bellClip;

		private AudioClip musicClip;

		private Coroutine animCoroutine;

		private Coroutine musicFadeCoroutine;

		private Sprite survivorSprite;

		private Sprite survivorSprite2;

		private AudioClip bellClip2;

		private AudioClip musicClip2;

		private ConfigEntry<int> cfgMinQuotaNormal;

		private ConfigEntry<int> cfgLargeLobbyThreshold;

		private ConfigEntry<int> cfgTheme2Quota;

		public static LastSurvivorManager Instance { get; private set; }

		public void Initialize(string modDirectory, ConfigEntry<int> minQuotaNormal, ConfigEntry<int> largeLobbyThreshold, ConfigEntry<int> theme2Quota)
		{
			pluginDirectory = modDirectory;
			Instance = this;
			cfgMinQuotaNormal = minQuotaNormal;
			cfgLargeLobbyThreshold = largeLobbyThreshold;
			cfgTheme2Quota = theme2Quota;
			BuildAudioSources();
			BuildUI();
			((MonoBehaviour)this).StartCoroutine(LoadAssetsCoroutine());
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Менеджер эффектов инициализирован. Папка мода: " + pluginDirectory));
			}
		}

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else
			{
				Instance = this;
			}
		}

		private void BuildAudioSources()
		{
			sfxSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			sfxSource.playOnAwake = false;
			sfxSource.loop = false;
			sfxSource.spatialBlend = 0f;
			musicSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			musicSource.playOnAwake = false;
			musicSource.loop = true;
			musicSource.spatialBlend = 0f;
		}

		private void BuildUI()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_006c: 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_00ab: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("LastSurvivorCanvas", new Type[2]
			{
				typeof(Canvas),
				typeof(CanvasScaler)
			});
			val.transform.SetParent(((Component)this).transform, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 999;
			CanvasScaler component2 = val.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 0.5f;
			GameObject val2 = new GameObject("SurvivorImage", new Type[2]
			{
				typeof(Image),
				typeof(CanvasGroup)
			});
			val2.transform.SetParent(val.transform, false);
			survivorRect = val2.GetComponent<RectTransform>();
			survivorRect.anchorMin = new Vector2(0.5f, 0.5f);
			survivorRect.anchorMax = new Vector2(0.5f, 0.5f);
			survivorRect.pivot = new Vector2(0.5f, 0.5f);
			survivorRect.anchoredPosition = Vector2.zero;
			survivorRect.sizeDelta = new Vector2(960f, 540f);
			survivorImage = val2.GetComponent<Image>();
			((Graphic)survivorImage).raycastTarget = false;
			survivorImage.preserveAspect = true;
			survivorCanvasGroup = val2.GetComponent<CanvasGroup>();
			survivorCanvasGroup.alpha = 0f;
			survivorCanvasGroup.interactable = false;
			survivorCanvasGroup.blocksRaycasts = false;
		}

		private IEnumerator LoadAssetsCoroutine()
		{
			survivorSprite = LoadSpriteFromFile("survivor.png");
			if ((Object)(object)survivorSprite != (Object)null && (Object)(object)survivorImage != (Object)null)
			{
				survivorImage.sprite = survivorSprite;
			}
			yield return LoadAudioClipCoroutine("bell.ogg", delegate(AudioClip clip)
			{
				bellClip = clip;
			});
			yield return LoadAudioClipCoroutine("music.ogg", delegate(AudioClip clip)
			{
				musicClip = clip;
			});
			if (File.Exists(Path.Combine(pluginDirectory, "survivor2.png")))
			{
				survivorSprite2 = LoadSpriteFromFile("survivor2.png");
			}
			else
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"survivor2.png не найден — картинка темы 2 недоступна (откат на тему 1).");
				}
			}
			if (File.Exists(Path.Combine(pluginDirectory, "bell2.ogg")))
			{
				yield return LoadAudioClipCoroutine("bell2.ogg", delegate(AudioClip clip)
				{
					bellClip2 = clip;
				});
			}
			else
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"bell2.ogg не найден — для темы 2 будет использоваться обычный колокол.");
				}
			}
			if (File.Exists(Path.Combine(pluginDirectory, "music2.ogg")))
			{
				yield return LoadAudioClipCoroutine("music2.ogg", delegate(AudioClip clip)
				{
					musicClip2 = clip;
				});
			}
			else
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)"music2.ogg не найден — музыка темы 2 недоступна (откат на тему 1).");
				}
			}
			ManualLogSource log4 = Plugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)"Загрузка ассетов завершена.");
			}
		}

		private Sprite LoadSpriteFromFile(string fileName)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(pluginDirectory, fileName);
			if (!File.Exists(text))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Файл не найден: " + text));
				}
				return null;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				((Texture)val).wrapMode = (TextureWrapMode)1;
				if (!ImageConversion.LoadImage(val, array))
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("Не удалось декодировать " + fileName));
					}
					return null;
				}
				RemoveWhiteFringe(val, fileName);
				Sprite result = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"Картинка загружена: {((Texture)val).width}x{((Texture)val).height} px ({fileName})");
				}
				return result;
			}
			catch (Exception arg)
			{
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogError((object)$"Ошибка загрузки {fileName}: {arg}");
				}
				return null;
			}
		}

		private void RemoveWhiteFringe(Texture2D tex, string fileName)
		{
			//IL_0011: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0093: 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_009c: 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_00df: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			Color[] pixels = tex.GetPixels();
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < pixels.Length; i += 97)
			{
				Color val = pixels[i];
				num++;
				if (val.g > val.r + 0.08f || val.b > val.r + 0.08f)
				{
					num2++;
				}
			}
			if (num != 0 && !((float)num2 / (float)num < 0.02f))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)(fileName + ": полноцветное изображение — очистка белой каймы не применяется (только Clamp)."));
				}
				return;
			}
			for (int j = 0; j < pixels.Length; j++)
			{
				Color val2 = pixels[j];
				float num3 = Mathf.Max(val2.g, val2.b);
				val2.r = Mathf.Max(0f, val2.r - num3);
				val2.g = 0f;
				val2.b = 0f;
				val2.a *= 1f - num3;
				pixels[j] = val2;
			}
			tex.SetPixels(pixels);
			tex.Apply();
		}

		private IEnumerator LoadAudioClipCoroutine(string fileName, Action<AudioClip> onLoaded)
		{
			string text = Path.Combine(pluginDirectory, fileName);
			if (!File.Exists(text))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Аудио-файл не найден: " + text));
				}
				yield break;
			}
			string text2 = "file://" + text.Replace("\\", "/");
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(text2, (AudioType)14);
			try
			{
				yield return www.SendWebRequest();
				if ((int)www.result != 1)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("Ошибка загрузки " + fileName + ": " + www.error));
					}
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(www);
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"Аудио загружено: {fileName} ({content.length:F1} сек)");
				}
				onLoaded?.Invoke(content);
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}

		private void Update()
		{
			try
			{
				UpdateInternal();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"Ошибка в Update() (игра не затронута): {arg}");
				}
			}
		}

		private void UpdateInternal()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				if ((Object)(object)musicSource != (Object)null && musicSource.isPlaying)
				{
					musicSource.Stop();
					roundActive = false;
				}
				return;
			}
			Keyboard current = Keyboard.current;
			if (current != null && instance.connectedPlayersAmount == 0 && instance.shipHasLanded && !instance.inShipPhase)
			{
				if (((ButtonControl)current.f10Key).wasPressedThisFrame)
				{
					bool isPressed = ((ButtonControl)current.leftShiftKey).isPressed;
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"F10: принудительный тест эффекта 'Последний выживший' (тема {((!isPressed) ? 1 : 2)}).");
					}
					TriggerLastSurvivor(isPressed);
				}
				if (((ButtonControl)current.f11Key).wasPressedThisFrame)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"F11: принудительное затухание музыки.");
					}
					StopMusicWithFade();
				}
			}
			if (roundActive)
			{
				if (!hasTriggeredThisRound && instance.livingPlayers == 1)
				{
					hasTriggeredThisRound = true;
					TriggerLastSurvivor();
				}
				else if (hasTriggeredThisRound && instance.livingPlayers == 0)
				{
					roundActive = false;
					StopMusicWithFade();
				}
			}
		}

		public void NotifyRoundStarted()
		{
			hasTriggeredThisRound = false;
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				roundActive = false;
				return;
			}
			int num = instance.connectedPlayersAmount + 1;
			int currentQuota = GetCurrentQuota();
			bool flag = num >= 2;
			int num2 = ((num > cfgLargeLobbyThreshold.Value) ? 1 : cfgMinQuotaNormal.Value);
			bool flag2 = currentQuota >= num2;
			roundActive = flag && flag2;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)($"Раунд начался (двери открыты). Игроков: {num}, квота: {currentQuota} " + $"(порог: {num2}). Мультиплеер: {flag}, квота подходит: {flag2}. " + $"Мод активен: {roundActive}"));
			}
		}

		private int GetCurrentQuota()
		{
			if (!((Object)(object)TimeOfDay.Instance != (Object)null))
			{
				return 1;
			}
			return TimeOfDay.Instance.timesFulfilledQuota + 1;
		}

		public void NotifyRoundEnding()
		{
			roundActive = false;
			StopMusicWithFade();
		}

		public void NotifyDisconnectedFromGame()
		{
			roundActive = false;
			hasTriggeredThisRound = false;
			if (musicFadeCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(musicFadeCoroutine);
				musicFadeCoroutine = null;
			}
			if (animCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(animCoroutine);
				animCoroutine = null;
			}
			if ((Object)(object)musicSource != (Object)null)
			{
				musicSource.Stop();
			}
			if ((Object)(object)sfxSource != (Object)null)
			{
				sfxSource.Stop();
			}
			if ((Object)(object)survivorCanvasGroup != (Object)null)
			{
				survivorCanvasGroup.alpha = 0f;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"Отключение от игры: все эффекты немедленно остановлены, состояние раунда сброшено.");
			}
		}

		private void TriggerLastSurvivor(bool forceTheme2 = false)
		{
			int currentQuota = GetCurrentQuota();
			bool flag = forceTheme2 || currentQuota >= cfgTheme2Quota.Value;
			Sprite val = ((flag && (Object)(object)survivorSprite2 != (Object)null) ? survivorSprite2 : survivorSprite);
			AudioClip val2 = ((flag && (Object)(object)bellClip2 != (Object)null) ? bellClip2 : bellClip);
			AudioClip val3 = ((flag && (Object)(object)musicClip2 != (Object)null) ? musicClip2 : musicClip);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)($"Последний выживший! Квота: {currentQuota}, тема: {((!flag) ? 1 : 2)} " + "(картинка: " + (((Object)(object)val != (Object)null) ? "есть" : "нет") + ", музыка: " + (((Object)(object)val3 != (Object)null) ? "есть" : "нет") + "). Запускаем колокол, музыку и анимацию."));
			}
			if ((Object)(object)survivorImage != (Object)null && (Object)(object)val != (Object)null)
			{
				survivorImage.sprite = val;
			}
			if ((Object)(object)sfxSource != (Object)null && (Object)(object)val2 != (Object)null)
			{
				sfxSource.volume = 0.9f;
				sfxSource.clip = val2;
				sfxSource.Play();
			}
			if ((Object)(object)musicSource != (Object)null && (Object)(object)val3 != (Object)null)
			{
				musicSource.volume = 0.7f;
				musicSource.clip = val3;
				musicSource.loop = true;
				musicSource.Play();
			}
			if (animCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(animCoroutine);
			}
			animCoroutine = ((MonoBehaviour)this).StartCoroutine(SurvivorImageAnimation());
		}

		private IEnumerator SurvivorImageAnimation()
		{
			if ((Object)(object)survivorRect == (Object)null || (Object)(object)survivorCanvasGroup == (Object)null)
			{
				yield break;
			}
			Vector3 startScale = Vector3.one * 1.1f;
			Vector3 endScale = Vector3.one * 1.45f;
			((Transform)survivorRect).localScale = startScale;
			survivorCanvasGroup.alpha = 0f;
			float elapsed = 0f;
			while (elapsed < 4f)
			{
				elapsed += Time.unscaledDeltaTime;
				float num = Mathf.Clamp01(elapsed / 4f);
				((Transform)survivorRect).localScale = Vector3.Lerp(startScale, endScale, num);
				float alpha;
				if (elapsed <= 0.4f)
				{
					alpha = Mathf.Lerp(0f, 1f, elapsed / 0.4f);
				}
				else if (elapsed <= 1.5f)
				{
					alpha = 1f;
				}
				else
				{
					float num2 = (elapsed - 0.4f - 1.1f) / 2.5f;
					alpha = Mathf.Lerp(1f, 0f, num2);
				}
				survivorCanvasGroup.alpha = alpha;
				yield return null;
			}
			((Transform)survivorRect).localScale = endScale;
			survivorCanvasGroup.alpha = 0f;
			animCoroutine = null;
		}

		public void StopMusicWithFade()
		{
			if (!((Object)(object)musicSource == (Object)null))
			{
				if (!musicSource.isPlaying)
				{
					musicSource.volume = 0.7f;
				}
				else if (musicFadeCoroutine == null)
				{
					musicFadeCoroutine = ((MonoBehaviour)this).StartCoroutine(MusicFadeOut());
				}
			}
		}

		private IEnumerator MusicFadeOut()
		{
			float startVolume = musicSource.volume;
			float elapsed = 0f;
			while (elapsed < 3f)
			{
				elapsed += Time.unscaledDeltaTime;
				float num = Mathf.Clamp01(elapsed / 3f);
				musicSource.volume = Mathf.Lerp(startVolume, 0f, num);
				yield return null;
			}
			musicSource.Stop();
			musicSource.volume = 0.7f;
			musicFadeCoroutine = null;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "LastSurvivorMod";

		public const string PLUGIN_NAME = "LastSurvivorMod";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}