Decompiled source of TimeAttack v1.1.0

TimeAttack.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("TimeAttack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TimeAttack")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("bef66bd7-b3d3-41df-a8f0-e5f682750c8e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TimeAttack;

internal class ConfigManager
{
	public static DifficultyManager.LevelTimeDifficulty levelTimeDifficulty = DifficultyManager.LevelTimeDifficulty.Standard;

	public static DifficultyManager.ExtractionBonusDifficulty extractionBonusDifficulty = DifficultyManager.ExtractionBonusDifficulty.Standard;

	public static DifficultyManager.FinalExtractionDifficulty finalExtractionDifficulty = DifficultyManager.FinalExtractionDifficulty.Standard;

	public static DifficultyManager.RemainingTimeBonus remainingTimeBonus = DifficultyManager.RemainingTimeBonus.Standard;

	public static void Set()
	{
		levelTimeDifficulty = Plugin.ltd.Value;
		extractionBonusDifficulty = Plugin.ebd.Value;
		finalExtractionDifficulty = Plugin.fed.Value;
		remainingTimeBonus = Plugin.rtb.Value;
	}
}
public class DifficultyManager
{
	public enum LevelTimeDifficulty
	{
		Merciful,
		Lenient,
		Easy,
		Standard,
		Hard,
		Extreme,
		Insane,
		Nightmare,
		Impossible
	}

	public enum ExtractionBonusDifficulty
	{
		Merciful,
		Lenient,
		Easy,
		Standard,
		Hard,
		Extreme,
		Insane,
		Nightmare,
		Impossible
	}

	public enum FinalExtractionDifficulty
	{
		Merciful,
		Lenient,
		Easy,
		Standard,
		Hard,
		Extreme,
		Insane,
		Nightmare,
		Impossible
	}

	public enum RemainingTimeBonus
	{
		None,
		Negligible,
		Little,
		Less,
		Standard,
		Extra,
		Profitable,
		Double
	}

	public static float LevelTimeDifficultyMultiplier => ConfigManager.levelTimeDifficulty switch
	{
		LevelTimeDifficulty.Merciful => 2f, 
		LevelTimeDifficulty.Lenient => 1.67f, 
		LevelTimeDifficulty.Easy => 1.33f, 
		LevelTimeDifficulty.Standard => 1f, 
		LevelTimeDifficulty.Hard => 0.8f, 
		LevelTimeDifficulty.Extreme => 0.67f, 
		LevelTimeDifficulty.Insane => 0.5f, 
		LevelTimeDifficulty.Nightmare => 0.33f, 
		LevelTimeDifficulty.Impossible => 0.17f, 
		_ => 1f, 
	};

	public static float ExtractionBonusDifficultyMultiplier => ConfigManager.extractionBonusDifficulty switch
	{
		ExtractionBonusDifficulty.Merciful => 2f, 
		ExtractionBonusDifficulty.Lenient => 1.67f, 
		ExtractionBonusDifficulty.Easy => 1.33f, 
		ExtractionBonusDifficulty.Standard => 1f, 
		ExtractionBonusDifficulty.Hard => 0.8f, 
		ExtractionBonusDifficulty.Extreme => 0.65f, 
		ExtractionBonusDifficulty.Insane => 0.5f, 
		ExtractionBonusDifficulty.Nightmare => 0.35f, 
		ExtractionBonusDifficulty.Impossible => 0.2f, 
		_ => 1f, 
	};

	public static float FinalExtractionDifficultyMultiplier => ConfigManager.finalExtractionDifficulty switch
	{
		FinalExtractionDifficulty.Merciful => 1.75f, 
		FinalExtractionDifficulty.Lenient => 1.33f, 
		FinalExtractionDifficulty.Easy => 1f, 
		FinalExtractionDifficulty.Standard => 0.8f, 
		FinalExtractionDifficulty.Hard => 0.67f, 
		FinalExtractionDifficulty.Extreme => 0.5f, 
		FinalExtractionDifficulty.Insane => 0.4f, 
		FinalExtractionDifficulty.Nightmare => 0.33f, 
		FinalExtractionDifficulty.Impossible => 0.17f, 
		_ => 1f, 
	};

	public static float RemainingTimeBonusMultiplier => ConfigManager.remainingTimeBonus switch
	{
		RemainingTimeBonus.None => 0f, 
		RemainingTimeBonus.Negligible => 0.1f, 
		RemainingTimeBonus.Little => 0.33f, 
		RemainingTimeBonus.Less => 0.67f, 
		RemainingTimeBonus.Standard => 1f, 
		RemainingTimeBonus.Extra => 1.33f, 
		RemainingTimeBonus.Profitable => 1.67f, 
		RemainingTimeBonus.Double => 2f, 
		_ => 1f, 
	};
}
internal class NotificationManager
{
	public enum NotificationEmoji
	{
		Clock,
		Money
	}

	public static float notificationTimer = 0f;

	public static string notificationText = "";

	public static NotificationEmoji notificationEmoji = NotificationEmoji.Clock;

	private static readonly Dictionary<NotificationEmoji, string> emojis = new Dictionary<NotificationEmoji, string>
	{
		{
			NotificationEmoji.Clock,
			"{clock}"
		},
		{
			NotificationEmoji.Money,
			"{$$}"
		}
	};

	public static void Update()
	{
		//IL_0055: 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)
		if (notificationTimer != 0f)
		{
			notificationTimer = Mathf.Max(0f, notificationTimer - Time.deltaTime);
			SemiFunc.UIBigMessage(notificationText, emojis[notificationEmoji], 28f, new Color(0f, 1f, 0.2f), Color.white);
		}
	}

	public static void ShowTimerExtendedMessage(float seconds, float time)
	{
		notificationTimer = time;
		notificationText = $"<size=48>+{Mathf.RoundToInt(seconds)}</size> SEC.";
		notificationEmoji = NotificationEmoji.Clock;
	}

	public static void ShowBonusMoneyMessage(int amount)
	{
		notificationTimer = 3f;
		notificationText = $"<size=48>+${Mathf.RoundToInt((float)amount)}K</size>\nTIME BONUS";
		notificationEmoji = NotificationEmoji.Money;
	}
}
internal class Patches
{
	private static float surplusBonusFactor = 1f;

	public static PlayerChatBoxState currentTruckState = (PlayerChatBoxState)0;

	public static bool mapToolActive = false;

	public static bool TruckLeaving => (int)currentTruckState == 2 || (int)currentTruckState == 3;

	[HarmonyPatch(typeof(MapToolController), "Update")]
	[HarmonyPostfix]
	private static void MapToolController_Update(ref bool ___Active, ref PhotonView ___photonView)
	{
		if (!GameManager.Multiplayer() || ___photonView.IsMine)
		{
			mapToolActive = ___Active;
		}
	}

	[HarmonyPatch(typeof(TruckScreenText), "Awake")]
	[HarmonyPostfix]
	private static void TruckScreenText_Awake()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		currentTruckState = (PlayerChatBoxState)0;
	}

	[HarmonyPatch(typeof(TruckScreenText), "PlayerChatBoxStateUpdateRPC")]
	[HarmonyPostfix]
	private static void TruckScreenText_PlayerChatBoxStateUpdateRPC(ref PlayerChatBoxState _state)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		currentTruckState = _state;
		Plugin.loggy.LogDebug((object)$"TST: changing state to {_state}");
	}

	[HarmonyPatch(typeof(GoalUI), "Start")]
	[HarmonyPostfix]
	[HarmonyPriority(1)]
	private static void GoalUI_Start()
	{
		if (SemiFunc.RunIsLevel())
		{
			Plugin.CreateCustomSemiUI();
		}
	}

	private static void OnLevelChange(int level)
	{
		if ((Object)(object)TimerUI.instance != (Object)null)
		{
			TimerUI.instance.timerRunning = false;
		}
		ConfigManager.Set();
		mapToolActive = false;
		NotificationManager.notificationTimer = 0f;
		NotificationManager.notificationText = "";
		if (!SemiFunc.RunIsLevel())
		{
			return;
		}
		TimeProperties.BaseLevelTimer = TimeProperties.GetThisLevelBaseTime(level);
		TimeProperties.BaseLevelTimerPostProcess = TimeProperties.GetThisLevelTime(level);
		if (!((Object)(object)TimerUI.instance == (Object)null))
		{
			if (TimerUI.instance.gameOverCoroutine != null)
			{
				((MonoBehaviour)TimerUI.instance).StopCoroutine(TimerUI.instance.gameOverCoroutine);
				TimerUI.instance.gameOverFinished = false;
				TimerUI.instance.gameOverStarted = false;
			}
			TimerUI.instance.SetTimer(TimeProperties.BaseLevelTimerPostProcess, pause: true);
			Plugin.loggy.LogDebug((object)"Level change, setting timer");
		}
	}

	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	[HarmonyPostfix]
	public static void RunManager_ChangeLevel(RunManager __instance)
	{
		OnLevelChange(__instance.levelsCompleted + 1);
	}

	[HarmonyPatch(typeof(RunManager), "UpdateLevel")]
	[HarmonyPostfix]
	public static void RunManager_UpdateLevel(RunManager __instance)
	{
		OnLevelChange(__instance.levelsCompleted + 1);
	}

	[HarmonyPatch(typeof(ExtractionPoint), "ButtonPress")]
	[HarmonyPostfix]
	public static void ExtractionPoint_ButtonPress()
	{
		if (SemiFunc.RunIsLevel())
		{
			if (!TimerUI.instance.timerRunning)
			{
				ConfigManager.Set();
				TimeProperties.BaseLevelTimer = TimeProperties.GetThisLevelBaseTime(RunManager.instance.levelsCompleted + 1);
				TimeProperties.BaseLevelTimerPostProcess = TimeProperties.GetThisLevelTime(RunManager.instance.levelsCompleted + 1);
				TimerUI.instance.SetTimer(TimeProperties.BaseLevelTimerPostProcess);
				TimerUI.instance.timerRunning = true;
				Plugin.loggy.LogDebug((object)"First extraction activated, starting timer...");
			}
			else
			{
				Plugin.loggy.LogDebug((object)"Extraction activated, adding time...");
				TimerUI.instance.SetTimer(TimerUI.instance.currentTimeRemaining);
				TimerUI.instance.AddTimeToTimer(TimeProperties.ExtractionActivationBonusTime);
			}
		}
	}

	[HarmonyPatch(typeof(ExtractionPoint), "StateExtracting")]
	[HarmonyPostfix]
	public static void ExtractionPoint_StateExtracting(ref ExtractionPoint __instance)
	{
		if (SemiFunc.RunIsLevel() && !((Object)(object)__instance != (Object)(object)Traverse.Create((object)RoundDirector.instance).Field("extractionPointCurrent").GetValue<ExtractionPoint>()))
		{
			MethodInfo method = typeof(ExtractionPoint).GetMethod("StateIs", BindingFlags.Instance | BindingFlags.NonPublic);
			if ((bool)method.Invoke(__instance, new object[1] { (object)(State)6 }) && Traverse.Create((object)__instance).Field("tubeHit").GetValue<bool>() && !TimerUI.instance.timerPaused)
			{
				Plugin.loggy.LogDebug((object)"Extraction started, pausing timer...");
				TimerUI.instance.SetTimer(TimerUI.instance.currentTimeRemaining, pause: true);
				int value = Traverse.Create((object)RoundDirector.instance).Field("currentHaul").GetValue<int>();
				int value2 = Traverse.Create((object)__instance).Field("haulSurplus").GetValue<int>();
				surplusBonusFactor = Mathf.Clamp((float)value / Mathf.Max(1000f, (float)value2), 1f, 10f);
			}
		}
	}

	[HarmonyPatch(typeof(RoundDirector), "ExtractionCompleted")]
	[HarmonyPostfix]
	public static void RoundDirector_ExtractionCompleted(ref RoundDirector __instance)
	{
		if (SemiFunc.RunIsLevel())
		{
			int value = Traverse.Create((object)__instance).Field("extractionPointsCompleted").GetValue<int>();
			int value2 = Traverse.Create((object)__instance).Field("extractionPoints").GetValue<int>();
			if (value >= value2)
			{
				Plugin.loggy.LogDebug((object)"All extractions done, setting final extract timer...");
				TimerUI.instance.GenerateBonusMoney(TimerUI.instance.currentTimeRemaining);
				TimerUI.instance.SetTimer(TimeProperties.GetThisLevelFinalExtractTime(RunManager.instance.levelsCompleted + 1));
			}
			else
			{
				Plugin.loggy.LogDebug((object)"Extraction completed, unpausing timer and adding time...");
				TimerUI.instance.SetTimer(TimerUI.instance.currentTimeRemaining);
				TimerUI.instance.AddTimeToTimer(TimeProperties.GetThisLevelAddedTime(RunManager.instance.levelsCompleted + 1, value2 - 1, surplusBonusFactor));
			}
		}
	}
}
[BepInPlugin("Swaggies.TimeAttack", "TimeAttack", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	private const string _guid = "Swaggies.TimeAttack";

	private const string _name = "TimeAttack";

	public const string _ver = "1.1.0";

	private readonly Harmony harmony = new Harmony("Swaggies.TimeAttack");

	public static ManualLogSource loggy;

	public static ConfigEntry<DifficultyManager.LevelTimeDifficulty> ltd;

	public static ConfigEntry<DifficultyManager.ExtractionBonusDifficulty> ebd;

	public static ConfigEntry<DifficultyManager.FinalExtractionDifficulty> fed;

	public static ConfigEntry<DifficultyManager.RemainingTimeBonus> rtb;

	private void Awake()
	{
		loggy = Logger.CreateLogSource("Swaggies.TimeAttack");
		loggy.LogMessage((object)"TimeAttack's up and runnin' on 1.1.0");
		harmony.PatchAll(typeof(Plugin));
		harmony.PatchAll(typeof(Patches));
		Syncing.Setup();
		ltd = ((BaseUnityPlugin)this).Config.Bind<DifficultyManager.LevelTimeDifficulty>("Difficulty Settings", "Level Time Difficulty", DifficultyManager.LevelTimeDifficulty.Standard, "How much time you start each level with. Higher difficulty means less time.");
		ebd = ((BaseUnityPlugin)this).Config.Bind<DifficultyManager.ExtractionBonusDifficulty>("Difficulty Settings", "Extraction Bonus Difficulty", DifficultyManager.ExtractionBonusDifficulty.Standard, "How much time you regain after completing an extraction. Higher difficulty means less time.");
		fed = ((BaseUnityPlugin)this).Config.Bind<DifficultyManager.FinalExtractionDifficulty>("Difficulty Settings", "Final Extraction Difficulty", DifficultyManager.FinalExtractionDifficulty.Standard, "How much time you have to leave the level after completing the final extraction. Higher difficulty means less time.");
		rtb = ((BaseUnityPlugin)this).Config.Bind<DifficultyManager.RemainingTimeBonus>("Difficulty Settings", "Remaining Time Bonus", DifficultyManager.RemainingTimeBonus.Standard, "How much bonus money you earn for completing a level with time to spare.");
	}

	public static void CreateCustomSemiUI()
	{
		//IL_0041: 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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		loggy.LogDebug((object)"creating TimerUI object...");
		GameObject val = GameObject.Find("Energy");
		GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
		((Object)val2).name = "TimeAttackTimerUI";
		Transform transform = val2.transform;
		transform.localPosition -= new Vector3(25f, 80f, 0f);
		EnergyUI val3 = default(EnergyUI);
		if (val2.TryGetComponent<EnergyUI>(ref val3))
		{
			Object.DestroyImmediate((Object)(object)val3);
		}
		TextMeshProUGUI component = ((Component)val2.transform.Find("EnergyMax")).GetComponent<TextMeshProUGUI>();
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
		TextMeshProUGUI[] componentsInChildren = val2.GetComponentsInChildren<TextMeshProUGUI>();
		foreach (TextMeshProUGUI val4 in componentsInChildren)
		{
			((Graphic)val4).color = Color.white;
		}
		((Behaviour)((Component)val2.transform).gameObject.GetComponentInChildren<Image>()).enabled = false;
		val2.AddComponent<TimerUI>();
	}
}
internal class Syncing
{
	public static NetworkedEvent TimerSync;

	public static NetworkedEvent TimerAdd;

	public static NetworkedEvent TimerSet;

	public static NetworkedEvent GameOverSequence;

	public static NetworkedEvent BonusMoney;

	public static void Setup()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		TimerSync = new NetworkedEvent("Timer Sync", (Action<EventData>)SyncTimer);
		TimerAdd = new NetworkedEvent("Timer Add", (Action<EventData>)AddToTimer);
		TimerSet = new NetworkedEvent("Timer Set", (Action<EventData>)SetTimer);
		GameOverSequence = new NetworkedEvent("Out Of Time Sequence", (Action<EventData>)GameOverSeq);
		BonusMoney = new NetworkedEvent("Remaining Time Bonus", (Action<EventData>)RemainingTimeBonus);
	}

	private static void SyncTimer(EventData eventData)
	{
		float num = (float)eventData.CustomData;
		if (!(Math.Abs(num - TimerUI.instance.currentTimeRemaining) < 0.33f))
		{
			TimerUI.instance.currentTimeRemaining = num;
			Plugin.loggy.LogDebug((object)$"Set timer to {num}");
			if (TimerUI.instance.currentTimeRemaining > 0f || TimerUI.instance.timerPaused)
			{
				TimerUI.instance.gameOverStarted = false;
				TimerUI.instance.gameOverFinished = false;
			}
			Plugin.loggy.LogDebug((object)$"Syncing timer to {num:0.0}");
		}
	}

	private static void AddToTimer(EventData eventData)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)eventData.CustomData;
		TimerUI.instance.gameOverStarted = false;
		TimerUI.instance.gameOverFinished = false;
		NotificationManager.ShowTimerExtendedMessage(num, 3.3f);
		TimerUI.instance.SetTimerPing(TimeProperties.timerExtendedPing, 3f);
		TimerUI.instance.currentTimeRemaining += num;
		((SemiUI)TimerUI.instance).SemiUISpringShakeY(8f, 10f, 1f);
		((SemiUI)TimerUI.instance).SemiUISpringScale(0.05f, 5f, 0.8f);
		Plugin.loggy.LogDebug((object)$"Adding {num:0.0} to timer");
	}

	private static void SetTimer(EventData eventData)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		TimerUI.instance.SetTimerPing(TimeProperties.timerNeutralPing, 2f);
		TimerUI.instance.timerPaused = (bool)eventData.CustomData;
		if (TimerUI.instance.timerPaused)
		{
			TimerUI.instance.gameOverStarted = false;
			TimerUI.instance.gameOverFinished = false;
		}
		((SemiUI)TimerUI.instance).SemiUISpringShakeY(4f, 10f, 0.5f);
		((SemiUI)TimerUI.instance).SemiUISpringScale(0.04f, 5f, 0.4f);
		Plugin.loggy.LogDebug((object)$"Setting paused to {TimerUI.instance.timerPaused}");
	}

	private static void GameOverSeq(EventData eventData)
	{
		bool flag = (bool)eventData.CustomData;
		Plugin.loggy.LogDebug((object)$"Setting game over to {flag}");
		if (flag)
		{
			TimerUI.instance.gameOverStarted = true;
			TimerUI.instance.gameOverFinished = false;
			TimerUI.instance.gameOverCoroutine = ((MonoBehaviour)TimerUI.instance).StartCoroutine(TimerUI.instance.Death());
			return;
		}
		if (TimerUI.instance.gameOverCoroutine != null)
		{
			((MonoBehaviour)TimerUI.instance).StopCoroutine(TimerUI.instance.gameOverCoroutine);
		}
		TimerUI.instance.gameOverStarted = false;
	}

	private static void RemainingTimeBonus(EventData eventData)
	{
		int moneyAmount = (int)eventData.CustomData;
		((MonoBehaviour)TimerUI.instance).StartCoroutine(RemainingTimeBonusNotification(moneyAmount));
	}

	private static IEnumerator RemainingTimeBonusNotification(int moneyAmount)
	{
		yield return (object)new WaitForSeconds(2.5f);
		Plugin.loggy.LogDebug((object)$"Adding bonus money - {moneyAmount}");
		NotificationManager.ShowBonusMoneyMessage(moneyAmount);
		SemiFunc.StatSetRunCurrency(SemiFunc.StatGetRunCurrency() + moneyAmount);
		SemiFunc.StatSetRunTotalHaul(SemiFunc.StatGetRunTotalHaul() + moneyAmount);
		CurrencyUI.instance.FetchCurrency();
	}
}
internal class TimeProperties
{
	public static Color timerExtendedPing = new Color(0f, 1f, 0.1f);

	public static Color timerLowPing = new Color(0.93f, 0.43f, 0.45f);

	public static Color timerNeutralPing = new Color(0.95f, 0.95f, 0.16f);

	public static Color timerNormalBase = new Color(0.12f, 0.54f, 0.83f);

	public static Color timerLowBase = new Color(0.97f, 0.12f, 0.28f);

	public static Color timerPausedBase = new Color(0.62f, 0.65f, 0.68f);

	public static int BaseLevelTimer = 0;

	public static int BaseLevelTimerPostProcess = 0;

	public static int ExtractionActivationBonusTime => RoundTo5(30f * PlayerCountMultiplier);

	public static float PlayerCountMultiplier => GameDirector.instance.PlayerList.Count switch
	{
		1 => 2f, 
		2 => 1.4f, 
		3 => 1.25f, 
		4 => 1.1f, 
		5 => 1.05f, 
		6 => 1f, 
		_ => 0.8f, 
	};

	private static int RoundTo5(float number)
	{
		return Mathf.RoundToInt(number / 5f) * 5;
	}

	public static int GetThisLevelBaseTime(int level)
	{
		if (level <= 10)
		{
			float number = 300f - 25.25f * Mathf.Pow(Mathf.Sqrt((float)(level - 1)), 1.25f);
			return RoundTo5(number);
		}
		if (level <= 100)
		{
			float number2 = 200f - 9.84f * Mathf.Pow(Mathf.Sqrt((float)(level - 10)), 1.18f);
			return RoundTo5(number2);
		}
		return 60;
	}

	public static int GetThisLevelTime(int level)
	{
		return RoundTo5((float)GetThisLevelBaseTime(level) * DifficultyManager.LevelTimeDifficultyMultiplier * PlayerCountMultiplier);
	}

	public static int GetThisLevelAddedTime(int level, int totalExtractions, float bonus)
	{
		float num = 1.1f;
		float num2 = Mathf.Clamp(1f / Mathf.Pow(1.33f, (float)(totalExtractions - 1)), 0.25f, 1f);
		if (level > 10)
		{
			num = 1.1f - 0.0504f * Mathf.Pow(Mathf.Sqrt((float)(level - 10)), 1.2f);
		}
		else if (level > 100)
		{
			num = 0.35f;
		}
		float num3 = 1f + 0.5f * Mathf.Sqrt(Mathf.Clamp(bonus, 1f, 10f) - 1f);
		int num4 = RoundTo5((float)BaseLevelTimer * num * num2 * num3 * DifficultyManager.ExtractionBonusDifficultyMultiplier * PlayerCountMultiplier);
		Plugin.loggy.LogDebug((object)($"EXTRACTION ADDED TIME: {num4} s" + $"\n  >> Multiplier:   {num:0.00}x" + $"\n  >> ExtractMulti: {num2:0.00}x" + $"\n  >> SurplusBonus: {num3:0.00}x ({bonus:0.00}x)"));
		return num4;
	}

	public static int GetThisLevelFinalExtractTime(int level)
	{
		float num = 1f - 0.0375f * Mathf.Pow(Mathf.Sqrt((float)(level - 1)), 1.25f);
		if (level > 100)
		{
			num = 1f / 3f;
		}
		return RoundTo5((float)BaseLevelTimer * num * DifficultyManager.FinalExtractionDifficultyMultiplier);
	}

	public static int GetBonusMoneyInThousands(float timeRemaining)
	{
		if (timeRemaining < 15f)
		{
			return 0;
		}
		float num = GetThisLevelTime(RunManager.instance.levelsCompleted + 1);
		float num2 = 0f;
		int value = Traverse.Create((object)RoundDirector.instance).Field("extractionPoints").GetValue<int>();
		for (int i = 0; i < value; i++)
		{
			num += (float)GetThisLevelAddedTime(RunManager.instance.levelsCompleted + 1, value, 0f) * 0.75f;
		}
		float num3 = Mathf.Clamp(timeRemaining / (num + num2), 0f, 2f);
		int num4 = ((num3 < 0.2f) ? Mathf.CeilToInt(Mathf.Lerp(0f, 5f, num3 / 0.2f)) : ((num3 < 0.5f) ? Mathf.CeilToInt(Mathf.Lerp(5f, 20f, (num3 - 0.2f) / 0.3f)) : ((!(num3 < 1f)) ? Mathf.CeilToInt(Mathf.Lerp(50f, 99f, (num3 - 1f) / 1f)) : Mathf.CeilToInt(Mathf.Lerp(20f, 50f, (num3 - 0.5f) / 0.5f)))));
		Plugin.loggy.LogDebug((object)($"BONUS MONEY: ${num4}K for {timeRemaining:0.0} seconds" + $"\n  >> MaxTimeOrig:  {num:0.0} s" + $"\n  >> MaxTimeExt:   {num2:0.0} s" + $"\n  >> TimeProgress: {num3:0.000}f"));
		return Mathf.Clamp(num4, 0, 99);
	}
}
internal class TimerUI : SemiUI
{
	public static TimerUI instance;

	private TextMeshProUGUI text;

	public float lastTimerSync = 0f;

	public float currentTimeRemaining = 0f;

	public int lastTimeRemaining = 0;

	public float timerPingLerp = 0f;

	public float timerPingLerpMax = 0f;

	public bool timerRunning = false;

	public bool timerPaused = false;

	public bool gameOverStarted = false;

	public bool gameOverFinished = false;

	private Color pingColor = Color.white;

	public Coroutine gameOverCoroutine;

	private float DisplayTimer => Mathf.Clamp(currentTimeRemaining, 0f, 5999.999f);

	private int IntSeconds => Mathf.CeilToInt(DisplayTimer);

	private int IntSecondsFloor => (int)DisplayTimer;

	private int DisplayMilliseconds => Mathf.CeilToInt(DisplayTimer * 1000f) % 1000;

	private int DisplaySeconds => IntSecondsFloor % 60;

	private int DisplayMinutes => IntSecondsFloor / 60;

	private bool ShouldCancelGameOver => !timerRunning || timerPaused || currentTimeRemaining > 0f;

	protected override void Start()
	{
		//IL_002e: 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)
		((SemiUI)this).Start();
		instance = this;
		text = ((Component)this).GetComponent<TextMeshProUGUI>();
		((TMP_Text)text).richText = true;
		TextMeshProUGUI obj = text;
		((TMP_Text)obj).margin = ((TMP_Text)obj).margin + new Vector4(0f, 0f, -500f, 0f);
		TextMeshProUGUI obj2 = text;
		((TMP_Text)obj2).fontSize = ((TMP_Text)obj2).fontSize * 0.833f;
		((SemiUI)this).Hide();
		BigMessageUI val = Object.FindObjectOfType<BigMessageUI>();
		if (!((Object)(object)val == (Object)null))
		{
			((TMP_Text)text).spriteAsset = ((TMP_Text)Traverse.Create((object)val).Field("emojiText").GetValue<TextMeshProUGUI>()).spriteAsset;
		}
	}

	protected override void Update()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Invalid comparison between Unknown and I4
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		((SemiUI)this).Update();
		if (!SemiFunc.RunIsLevel())
		{
			((SemiUI)this).Hide();
		}
		bool flag = !SemiFunc.RunIsLevel() || !timerRunning || gameOverFinished || (int)Patches.currentTruckState == 3;
		if (flag || Patches.mapToolActive)
		{
			((SemiUI)this).SemiUIScoot(new Vector2(-220f, 0f));
		}
		if (!flag)
		{
			NotificationManager.Update();
			if (!timerPaused)
			{
				currentTimeRemaining = Mathf.Max(0f, currentTimeRemaining - Time.deltaTime);
			}
			if (Math.Abs(currentTimeRemaining - lastTimerSync) >= 10f)
			{
				SyncTimeBetweenPlayers(currentTimeRemaining);
			}
			LowTimerPingLogic();
			UILogic();
			ColorLogic();
			ShowRedEyesLowTimer();
			if (currentTimeRemaining == 0f && !timerPaused)
			{
				SyncTimeBetweenPlayers(0f);
				OutOfTime();
			}
		}
	}

	private void ColorLogic()
	{
		//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_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: 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_004a: 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)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		Color val = TimeProperties.timerNormalBase;
		if (currentTimeRemaining <= 60f)
		{
			val = TimeProperties.timerLowBase;
		}
		if (timerPaused)
		{
			val = TimeProperties.timerPausedBase;
		}
		Color color = Color.Lerp(val, pingColor, timerPingLerp / timerPingLerpMax);
		timerPingLerp = Mathf.Clamp(timerPingLerp - Time.deltaTime, 0f, timerPingLerpMax);
		((Graphic)text).color = color;
	}

	private void UILogic()
	{
		string text = "<size=120%><sprite name=clock></size>";
		string text2 = $"{DisplayMinutes:00}";
		string text3 = $"{DisplaySeconds:00}";
		string text4 = $"{DisplayMilliseconds:000}";
		((TMP_Text)this.text).text = text + " <b>" + text2 + ":" + text3 + "." + text4 + "</b>";
	}

	private void LowTimerPingLogic()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if (IntSeconds <= 60 && lastTimeRemaining != IntSeconds)
		{
			SetTimerPing(TimeProperties.timerLowPing, 0.8f);
			if (IntSeconds <= 30)
			{
				((SemiUI)this).SemiUISpringShakeY(4f, 12f, 0.4f);
				((SemiUI)this).SemiUISpringScale(0.03f, 8f, 0.3f);
			}
		}
		lastTimeRemaining = IntSeconds;
	}

	public void SetTimerPing(Color color, float time)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		timerPingLerp = time;
		timerPingLerpMax = time;
		pingColor = color;
	}

	private void SyncTimeBetweenPlayers(float seconds)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			Syncing.TimerSync.RaiseEvent((object)seconds, NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			currentTimeRemaining = seconds;
			lastTimerSync = seconds;
		}
	}

	public void SetTimer(float seconds, bool pause = false)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			Syncing.TimerSet.RaiseEvent((object)pause, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
			SyncTimeBetweenPlayers(seconds);
		}
	}

	public void AddTimeToTimer(float seconds)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			Syncing.TimerAdd.RaiseEvent((object)seconds, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
		}
	}

	public void GenerateBonusMoney(float secondsRemaining)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer())
		{
			int bonusMoneyInThousands = TimeProperties.GetBonusMoneyInThousands(secondsRemaining);
			int num = Mathf.CeilToInt((float)bonusMoneyInThousands * DifficultyManager.RemainingTimeBonusMultiplier);
			if (num > 0)
			{
				Syncing.BonusMoney.RaiseEvent((object)num, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
			}
		}
	}

	public void ShowRedEyesLowTimer()
	{
		if (currentTimeRemaining > 15f || !SemiFunc.FPSImpulse5() || timerPaused)
		{
			return;
		}
		foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
		{
			if (!Traverse.Create((object)player).Field("isDisabled").GetValue<bool>())
			{
				if (Patches.TruckLeaving && Traverse.Create((object)player.RoomVolumeCheck).Field("inTruck").GetValue<bool>())
				{
					Plugin.loggy.LogDebug((object)"a player is inside truck while its starting, skipping them for red eyes...");
				}
				else
				{
					player.playerHealth.EyeMaterialOverride((EyeOverrideState)1, 1f, 2);
				}
			}
		}
		Plugin.loggy.LogDebug((object)"Setting red eyes...");
	}

	private void OutOfTime()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if (SemiFunc.IsMasterClientOrSingleplayer() && !gameOverStarted)
		{
			Plugin.loggy.LogDebug((object)"Time's up!");
			Syncing.GameOverSequence.RaiseEvent((object)true, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
		}
	}

	private bool CancelGameOver()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		if (!ShouldCancelGameOver || !SemiFunc.IsMasterClientOrSingleplayer() || !gameOverStarted)
		{
			return false;
		}
		Syncing.GameOverSequence.RaiseEvent((object)false, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
		return true;
	}

	public IEnumerator Death()
	{
		if (CancelGameOver())
		{
			yield break;
		}
		yield return (object)new WaitForSeconds(0.5f);
		if (CancelGameOver())
		{
			yield break;
		}
		Plugin.loggy.LogDebug((object)"Killing self...");
		PlayerAvatar localPlayer = null;
		foreach (PlayerAvatar avatar in GameDirector.instance.PlayerList)
		{
			if (SemiFunc.IsMultiplayer() && !avatar.photonView.IsMine)
			{
				continue;
			}
			localPlayer = avatar;
			break;
		}
		if ((Object)(object)localPlayer == (Object)null)
		{
			gameOverStarted = false;
			gameOverFinished = true;
		}
		else if (Traverse.Create((object)localPlayer).Field("isDisabled").GetValue<bool>())
		{
			gameOverStarted = false;
			gameOverFinished = true;
		}
		else if (Patches.TruckLeaving && Traverse.Create((object)localPlayer.RoomVolumeCheck).Field("inTruck").GetValue<bool>())
		{
			Plugin.loggy.LogDebug((object)"a player is inside truck while its starting, skipping them for death...");
			gameOverStarted = false;
			gameOverFinished = true;
		}
		else
		{
			localPlayer.PlayerDeath(-1);
			gameOverStarted = false;
			gameOverFinished = true;
		}
	}
}