Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TimeAttack v1.1.1
TimeAttack.dll
Decompiled 9 months agousing 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("haulGoal").GetValue<int>(); surplusBonusFactor = Mathf.Clamp((float)value / Mathf.Max(1000f, (float)value2), 1f, 10f); } } } [HarmonyPatch(typeof(ExtractionPoint), "StateCancel")] [HarmonyPostfix] public static void ExtractionPoint_StateCancel(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)5 }) && TimerUI.instance.timerPaused) { TimerUI.instance.SetTimer(TimerUI.instance.currentTimeRemaining); } } } [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.1")] [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.1"; 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.1"); 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; } } }