using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BossRush.Properties;
using BossRush.UI;
using Discord;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
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: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Hydraxous")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("BossRush gamemode for ULTRAKILL")]
[assembly: AssemblyFileVersion("1.1.3.0")]
[assembly: AssemblyInformationalVersion("1.1.3+f7ee2e98863a2ab5bbc2e6a5083023b78f8f0ffc")]
[assembly: AssemblyProduct("BossRush")]
[assembly: AssemblyTitle("BossRush")]
[assembly: AssemblyMetadata("RepositoryUrl", "https:")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 BossRush
{
public static class Assets
{
public static AssetBundle assets;
public static GameObject BossRushStatsPrefab { get; private set; }
public static GameObject BossRushMenuPrefab { get; private set; }
public static GameObject BossRushDeathScreen { get; private set; }
public static void LoadAssets()
{
assets = AssetBundle.LoadFromMemory(Resources.BossRush);
BossRushStatsPrefab = assets.LoadAsset<GameObject>("BossRushStatsDisplay");
BossRushMenuPrefab = assets.LoadAsset<GameObject>("BossRushMenu");
BossRushDeathScreen = assets.LoadAsset<GameObject>("BossRushDeathScreen");
}
}
[BepInPlugin("Hydraxous.ULTRAKILL.BossRush", "BossRush", "1.1.3")]
public class BossRush : BaseUnityPlugin
{
private Harmony harmony;
private bool debug = false;
public static BossRush Instance { get; private set; }
public static ManualLogSource BepInExLogger => ((BaseUnityPlugin)Instance).Logger;
public static bool LatestVersion { get; private set; }
public static string VersionName { get; private set; }
private void Awake()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
Instance = this;
BossRushConfig.Bind();
BossRushPaths.CheckFolders();
LevelChainManager.LoadLevelChainTable();
StatRecords.LoadRecords();
harmony = new Harmony("Hydraxous.ULTRAKILL.BossRush.harmony");
harmony.PatchAll();
Assets.LoadAssets();
BossRushStats.Spawn();
VersionCheck.CheckVersion("https://api.github.com/repos/Hydraxous/bossrush/tags", "1.1.3", VersionCheckCallback);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Boss Rush 1.1.3 loaded!");
}
private void Update()
{
CheckDebugInputs();
}
private void VersionCheckCallback(bool onLatest, string versionName)
{
LatestVersion = onLatest;
VersionName = versionName;
if (versionName == "UNKNOWN")
{
LatestVersion = true;
VersionName = "1.1.3";
}
if (LatestVersion)
{
Debug.Log((object)("BOSSRUSH: You are using the latest version of BossRush (" + VersionName + ")."));
}
else
{
Debug.LogWarning((object)("BOSSRUSH: You are using an outdated version of BossRush (1.1.3). Please consider updating to " + VersionName));
}
}
private void CheckDebugInputs()
{
if (Input.GetKey((KeyCode)304) && debug)
{
if (Input.GetKeyDown((KeyCode)49) && !BossRushController.BossRushMode)
{
BossRushController.StartBossRushMode();
}
if (Input.GetKeyDown((KeyCode)50) && !BossRushController.BossRushMode)
{
BossRushController.StartBossRushMode(hardcore: true);
}
if (Input.GetKeyDown((KeyCode)51))
{
BossRushController.HardcoreMode = !BossRushController.HardcoreMode;
Debug.Log((object)$"BR: Hardcore={BossRushController.HardcoreMode}");
}
if (Input.GetKeyDown((KeyCode)52))
{
BossRushController.BossRushMode = !BossRushController.BossRushMode;
Debug.Log((object)$"BR: Enabled={BossRushController.BossRushMode}");
}
if (Input.GetKeyDown((KeyCode)53))
{
BossRushController.Laps--;
Debug.Log((object)$"BR: Laps={BossRushController.Laps}");
}
if (Input.GetKeyDown((KeyCode)54))
{
BossRushController.Laps++;
Debug.Log((object)$"BR: Laps={BossRushController.Laps}");
}
if (Input.GetKeyDown((KeyCode)55))
{
BossRushController.Laps = 0;
Debug.Log((object)$"BR: Laps={BossRushController.Laps}");
}
if (Input.GetKeyDown((KeyCode)56))
{
StatRecords.SubmitRecord(BossRushController.GetCurrentStat());
Debug.Log((object)$"BR: Laps={BossRushController.Laps}");
}
}
}
private void OnApplicationQuit()
{
StatRecords.Save();
}
}
public static class BossRushConfig
{
public static ConfigEntry<float> LapBuffMultiplier { get; private set; }
public static ConfigEntry<bool> EnemySpeedBuff { get; private set; }
public static ConfigEntry<bool> EnemyDamageBuff { get; private set; }
public static ConfigEntry<bool> EnemyHealthBuff { get; private set; }
public static ConfigEntry<bool> AlwaysShowStats { get; private set; }
public static void Bind()
{
LapBuffMultiplier = ((BaseUnityPlugin)BossRush.Instance).Config.Bind<float>("EnemyBuff", "LapBuffMultiplier", 2f, "Applies X radiance tiers to enemies for every lap completed.");
EnemySpeedBuff = ((BaseUnityPlugin)BossRush.Instance).Config.Bind<bool>("EnemyBuff", "EnemySpeedBuff", false, "Buffs enemy speed on laps.");
EnemyDamageBuff = ((BaseUnityPlugin)BossRush.Instance).Config.Bind<bool>("EnemyBuff", "EnemyDamageBuff", true, "Buffs enemy damage on laps.");
EnemyHealthBuff = ((BaseUnityPlugin)BossRush.Instance).Config.Bind<bool>("EnemyBuff", "EnemyHealthBuff", true, "Buffs enemy health on laps.");
AlwaysShowStats = ((BaseUnityPlugin)BossRush.Instance).Config.Bind<bool>("General", "AlwaysShowStats", true, "Show always or only when pressing tab.");
}
}
public static class BossRushController
{
private static float startTime;
public static bool BossRushMode { get; internal set; }
public static bool HardcoreMode { get; internal set; }
public static int Laps { get; internal set; }
public static int Deaths { get; internal set; }
public static long StartTimeEpoc { get; internal set; }
public static float TimeElapsed
{
get
{
float time = Time.time;
if (!BossRushMode)
{
startTime = time;
}
return time - startTime;
}
}
public static void StartBossRushMode(bool hardcore = false)
{
Reset();
BossRushMode = true;
HardcoreMode = hardcore;
SceneHelper.LoadScene(LevelChainManager.GetFirstLevelName(), false);
}
public static void Reset()
{
BossRushMode = false;
HardcoreMode = false;
StatRecords.HighScoreRun = false;
startTime = Time.time;
StartTimeEpoc = DateTimeOffset.Now.ToUnixTimeSeconds();
Deaths = 0;
Laps = 0;
}
public static BossRushRecord GetCurrentStat()
{
return new BossRushRecord(Laps, TimeElapsed, Deaths, HardcoreMode);
}
}
public static class BossRushPaths
{
public const string BossRushSaveFileName = "records";
public static string GameFolder => Path.GetDirectoryName(Application.dataPath);
public static string BepInExFolder => Path.Combine(GameFolder, "BepInEx");
public static string BepInExConfigFolder => Path.Combine(BepInExFolder, "config");
public static string BossRushConfigFolder => Path.Combine(BepInExConfigFolder, "BossRush");
public static string BossRushSaveFile => Path.Combine(BossRushConfigFolder, "records.json");
public static string BossRushLevelChain => Path.Combine(BossRushConfigFolder, "LevelChain.json");
public static string GetModLocation()
{
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
public static void CheckFolders()
{
CreateFolder(BossRushConfigFolder);
}
private static void CreateFolder(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
}
public static class ConstInfo
{
public const string GUID = "Hydraxous.ULTRAKILL.BossRush";
public const string NAME = "BossRush";
public const string VERSION = "1.1.3";
public const string GITHUB_URL = "https://api.github.com/repos/Hydraxous/bossrush/tags";
}
[HarmonyPatch(typeof(DiscordController))]
public static class DiscordRPCPatch
{
[HarmonyPrefix]
[HarmonyPatch("SendActivity")]
public static bool Prefix(ref Activity ___cachedActivity)
{
if (!BossRushController.BossRushMode)
{
return true;
}
___cachedActivity.Details = "BOSS RUSH: " + ParseDifficultyName(MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0));
string text = (BossRushController.HardcoreMode ? "HARDCORE" : ("DEATHS: " + BossRushController.Deaths.ToString("000")));
___cachedActivity.State = "LAPS: " + BossRushController.Laps.ToString("000") + " | " + text;
___cachedActivity.Timestamps.Start = BossRushController.StartTimeEpoc;
return true;
}
private static string ParseDifficultyName(int diff)
{
return diff switch
{
0 => "HARMLESS",
1 => "LENIENT",
2 => "STANDARD",
3 => "VIOLENT",
4 => "BRUTAL",
5 => "UKMD",
_ => "Game Journalist",
};
}
}
[HarmonyPatch(typeof(FinalRank), "LevelChange")]
public static class FinalRankPatch
{
public static bool Prefix(FinalRank __instance)
{
if (BossRushController.BossRushMode && !SceneHelper.IsPlayingCustom)
{
LevelChain chainOfLevel = LevelChainManager.GetChainOfLevel(SceneHelper.CurrentScene);
if (chainOfLevel == null)
{
BossRush.BepInExLogger.LogWarning((object)("Scene (" + SceneHelper.CurrentScene + ") has no valid chain."));
return true;
}
if (!string.IsNullOrEmpty(chainOfLevel.PitTargetFilter) && __instance.targetLevelName != chainOfLevel.PitTargetFilter)
{
BossRush.BepInExLogger.LogInfo((object)("Player entering level " + __instance.targetLevelName + " when the level chain expected " + chainOfLevel.PitTargetFilter + ". Boss Rush will now be disabled."));
MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Sequence broken, boss rush mode disabled.", "", "", 0, false);
BossRushController.Reset();
}
else if ((__instance.targetLevelName = chainOfLevel.LevelTo) == LevelChainManager.GetFirstLevelName())
{
BossRushController.Laps++;
StatRecords.SubmitRecord(BossRushController.GetCurrentStat());
}
}
return true;
}
}
[HarmonyPatch(typeof(OptionsManager))]
public static class OptionsManagerFixes
{
[HarmonyPostfix]
[HarmonyPatch("QuitMission")]
public static void Postfix()
{
BossRushController.Reset();
}
[HarmonyPrefix]
[HarmonyPatch("RestartMission")]
public static bool Prefix()
{
if (!BossRushController.BossRushMode)
{
return true;
}
if (BossRushController.HardcoreMode)
{
BossRushController.StartBossRushMode(hardcore: true);
return false;
}
BossRushController.Deaths++;
return true;
}
}
[HarmonyPatch(typeof(StatsManager))]
public static class StasManagerPatch
{
[HarmonyPostfix]
[HarmonyPatch("Restart")]
public static void Postfix()
{
if (BossRushController.BossRushMode)
{
if (BossRushController.HardcoreMode)
{
BossRushDeathScreen.Instance.Open();
}
else
{
BossRushController.Deaths++;
}
}
}
}
[HarmonyPatch(typeof(NewMovement))]
public static class HardcoreResetPatch
{
[HarmonyPrefix]
[HarmonyPatch("GetHurt")]
public static bool Prefix(NewMovement __instance, int damage, bool invincible)
{
if (!BossRushController.HardcoreMode || !BossRushController.BossRushMode)
{
return true;
}
if (((Component)__instance).gameObject.layer == 15)
{
return true;
}
if (__instance.hp - damage <= 0)
{
try
{
BossRushDeathScreen.Instance.Open();
}
catch (Exception ex)
{
Debug.LogException(ex);
return true;
}
return false;
}
return true;
}
}
[HarmonyPatch(typeof(EnemyIdentifier), "Start")]
public static class EnemyDifficultyUpPatch
{
public static void Postfix(EnemyIdentifier __instance)
{
if (BossRushController.Laps > 0 && BossRushController.BossRushMode)
{
__instance.healthBuff = BossRushConfig.EnemyHealthBuff.Value;
__instance.speedBuff = BossRushConfig.EnemySpeedBuff.Value;
__instance.damageBuff = BossRushConfig.EnemyDamageBuff.Value;
__instance.radianceTier = (float)BossRushController.Laps * BossRushConfig.LapBuffMultiplier.Value;
}
}
}
[HarmonyPatch(typeof(LevelStatsEnabler), "Start")]
public static class StatsPatch
{
public static void Postfix(LevelStatsEnabler __instance)
{
BossRushStats.UK_LevelStatsObject = ((Component)((Component)__instance).transform.GetChild(0)).gameObject;
}
}
[HarmonyPatch(typeof(CanvasController), "Awake")]
public static class MainMenuUIPatch
{
[CompilerGenerated]
private static class <>O
{
public static UnityAction <0>__Open;
}
public static void Postfix(CanvasController __instance)
{
SpawnDeathScreen(__instance);
if (SceneHelper.CurrentScene == "Main Menu")
{
SpawnMenu(__instance);
SpawnButton(__instance);
}
}
private static void SpawnMenu(CanvasController __instance)
{
RectTransform component = ((Component)__instance).GetComponent<RectTransform>();
if (!((Object)(object)component == (Object)null))
{
BossRush.BepInExLogger.LogInfo((object)"Menu Spawned");
Object.Instantiate<GameObject>(Assets.BossRushMenuPrefab, (Transform)(object)component);
}
}
private static void SpawnDeathScreen(CanvasController __instance)
{
RectTransform component = ((Component)__instance).GetComponent<RectTransform>();
if (!((Object)(object)component == (Object)null))
{
BossRush.BepInExLogger.LogInfo((object)"DeathScreen Spawned");
Object.Instantiate<GameObject>(Assets.BossRushDeathScreen, (Transform)(object)component);
}
}
private static void SpawnButton(CanvasController __instance)
{
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Expected O, but got Unknown
BossRush.BepInExLogger.LogInfo((object)"Spawning Button");
RectTransform component = ((Component)__instance).GetComponent<RectTransform>();
GameObject gameObject = ((Component)((Transform)component).Find("Chapter Select")).gameObject;
if ((Object)(object)gameObject == (Object)null)
{
Debug.LogError((object)"Chapter Select object is null");
return;
}
BossRushMenu.SetLastPage(gameObject);
RectTransform component2 = gameObject.GetComponent<RectTransform>();
GameObject gameObject2 = ((Component)gameObject.transform.Find("Sandbox")).gameObject;
if ((Object)(object)gameObject2 == (Object)null)
{
Debug.LogError((object)"Sandbox button is null");
return;
}
GameObject val = Object.Instantiate<GameObject>(gameObject2, (Transform)(object)component2);
((Object)val).name = "Boss Rush Button";
Button component3 = val.GetComponent<Button>();
ColorBlock colors = ((Selectable)component3).colors;
Object.DestroyImmediate((Object)(object)component3);
Button val2 = val.AddComponent<Button>();
((Selectable)val2).colors = colors;
RectTransform component4 = val.GetComponent<RectTransform>();
Vector3 position = ((Transform)component4).position;
position.y -= 55f;
((Transform)component4).position = position;
((TMP_Text)((Component)component4).GetComponentInChildren<TextMeshProUGUI>()).text = "BOSS RUSH";
ButtonClickedEvent onClick = val2.onClick;
object obj = <>O.<0>__Open;
if (obj == null)
{
UnityAction val3 = BossRushMenu.Open;
<>O.<0>__Open = val3;
obj = (object)val3;
}
((UnityEvent)onClick).AddListener((UnityAction)obj);
}
}
public static class LevelChainManager
{
private static LevelChainTable LevelChainTable { get; set; }
public static Dictionary<string, string> LevelChainDictionary { get; private set; }
public static void LoadLevelChainTable()
{
string bossRushLevelChain = BossRushPaths.BossRushLevelChain;
if (!File.Exists(bossRushLevelChain))
{
BossRush.BepInExLogger.LogInfo((object)"No level chain file found. Writing default level chain.");
WriteDefaultLevelChain();
LevelChainTable = JsonConvert.DeserializeObject<LevelChainTable>(Resources.levelChainDefault);
}
else
{
string text = File.ReadAllText(bossRushLevelChain);
try
{
LevelChainTable = JsonConvert.DeserializeObject<LevelChainTable>(text);
if (LevelChainTable == null)
{
throw new Exception("Invalid level chain file. Malformed Json?");
}
if (LevelChainTable.ModVersion != "1.1.3")
{
throw new Exception("Level chain file version mismatch.");
}
}
catch (Exception ex)
{
BossRush.BepInExLogger.LogFatal((object)"Error loading LevelChainTable. Details below.");
BossRush.BepInExLogger.LogFatal((object)(ex.Message + "\n" + ex.StackTrace));
BossRush.BepInExLogger.LogError((object)"Writing default level chain.");
WriteDefaultLevelChain();
LevelChainTable = JsonConvert.DeserializeObject<LevelChainTable>(Resources.levelChainDefault);
}
}
LevelChainDictionary = LevelChainTable.ToDictionary();
}
private static void WriteDefaultLevelChain()
{
string bossRushLevelChain = BossRushPaths.BossRushLevelChain;
string levelChainDefault = Resources.levelChainDefault;
File.WriteAllText(bossRushLevelChain, levelChainDefault);
}
public static string GetFirstLevelName()
{
return LevelChainTable.LevelChains[0].LevelFrom;
}
public static LevelChain GetChainOfLevel(string currentLevel)
{
return LevelChainTable.LevelChains.FirstOrDefault((LevelChain x) => x.LevelFrom == currentLevel);
}
}
[Serializable]
public class LevelChainTable
{
public string ModVersion;
public List<LevelChain> LevelChains;
public Dictionary<string, string> ToDictionary()
{
return LevelChains.ToDictionary((LevelChain x) => x.LevelFrom, (LevelChain x) => x.LevelTo);
}
}
[Serializable]
public class LevelChain
{
public string LevelFrom;
public string LevelTo;
public string PitTargetFilter;
}
public static class StatRecords
{
public delegate void OnNewScoreHandler(BossRushRecord newScore);
private static RecordLedger ledger;
public static OnNewScoreHandler OnNewHighScore;
public static OnNewScoreHandler OnNewScoreSubmitted;
public static bool HighScoreRun;
private static bool legderDirty;
public static void MarkDirty()
{
legderDirty = true;
}
public static void LoadRecords()
{
string bossRushSaveFile = BossRushPaths.BossRushSaveFile;
if (!File.Exists(bossRushSaveFile))
{
BossRush.BepInExLogger.LogInfo((object)"No BossRush Stats found. Creating new file.");
ledger = new RecordLedger(new BossRushRecord[6]);
SaveInternal();
return;
}
BossRush.BepInExLogger.LogInfo((object)"Loading records.");
try
{
string text = File.ReadAllText(bossRushSaveFile);
ledger = JsonConvert.DeserializeObject<RecordLedger>(text);
if (ledger == null || ledger.Records == null || ledger.Records.Length < 6)
{
throw new Exception("Invalid records file. Corrupt?");
}
legderDirty = false;
BossRush.BepInExLogger.LogInfo((object)"Loaded BossRush Stats.");
}
catch (Exception ex)
{
BossRush.BepInExLogger.LogFatal((object)"Failed to load BossRush Stats.");
BossRush.BepInExLogger.LogFatal((object)(ex.Message + "\n" + ex.StackTrace));
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(bossRushSaveFile);
string text2 = ".json";
int num = 0;
while (File.Exists(Path.Combine(Path.GetDirectoryName(bossRushSaveFile), fileNameWithoutExtension + "_corrupted" + num + text2)))
{
num++;
}
string destFileName = Path.Combine(Path.GetDirectoryName(bossRushSaveFile), fileNameWithoutExtension + "_corrupted" + num + text2);
File.Move(bossRushSaveFile, destFileName);
BossRush.BepInExLogger.LogError((object)"File renamed to allow for saving records.");
ledger = new RecordLedger(new BossRushRecord[6]);
SaveInternal();
}
}
public static BossRushRecord GetRecord(int difficulty = -1)
{
if (difficulty < 0)
{
difficulty = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
}
return ledger.Records[difficulty];
}
public static void SubmitRecord(BossRushRecord newRecord, int difficulty = -1)
{
if (difficulty < 0)
{
difficulty = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
}
BossRush.BepInExLogger.LogInfo((object)"Submitting new record.");
BossRushRecord record = GetRecord(difficulty);
ManualLogSource bepInExLogger = BossRush.BepInExLogger;
BossRushRecord bossRushRecord = record;
bepInExLogger.LogInfo((object)("Old Record " + bossRushRecord.ToString()));
ManualLogSource bepInExLogger2 = BossRush.BepInExLogger;
bossRushRecord = newRecord;
bepInExLogger2.LogInfo((object)("New Record " + bossRushRecord.ToString()));
if (!newRecord.IsBetterThan(record))
{
BossRush.BepInExLogger.LogInfo((object)"Record not sufficient for replacement.");
return;
}
if (!newRecord.ValidRecord())
{
BossRush.BepInExLogger.LogInfo((object)"Record invalid, discarding.");
return;
}
ledger.Records[difficulty] = newRecord;
HighScoreRun = true;
MarkDirty();
Save();
OnNewHighScore?.Invoke(newRecord);
}
private static void SaveInternal()
{
string bossRushSaveFile = BossRushPaths.BossRushSaveFile;
if (!Directory.Exists(Path.GetDirectoryName(bossRushSaveFile)))
{
BossRush.BepInExLogger.LogInfo((object)"Creating BossRush Save Directory.");
Directory.CreateDirectory(Path.GetDirectoryName(bossRushSaveFile));
}
try
{
string contents = JsonConvert.SerializeObject((object)ledger);
File.WriteAllText(bossRushSaveFile, contents);
BossRush.BepInExLogger.LogInfo((object)"Saved BossRush Stats.");
legderDirty = false;
}
catch (Exception ex)
{
BossRush.BepInExLogger.LogError((object)"Failed to save BossRush Stats.");
BossRush.BepInExLogger.LogFatal((object)(ex.Message + "\n" + ex.StackTrace));
}
}
public static void Save()
{
if (legderDirty)
{
SaveInternal();
}
}
}
[Serializable]
public class RecordLedger
{
public BossRushRecord[] Records;
public RecordLedger()
{
Records = new BossRushRecord[6];
}
public RecordLedger(BossRushRecord[] records)
{
Records = records;
}
}
[Serializable]
public struct BossRushRecord
{
public int laps;
public float time;
public int deaths;
public bool hardcore;
public BossRushRecord(int laps, float time, int deaths, bool hardcore)
{
this.laps = 0;
this.time = 0f;
this.deaths = 0;
this.laps = laps;
this.time = time;
this.deaths = deaths;
this.hardcore = hardcore;
}
public BossRushRecord(BossRushRecord record)
{
laps = 0;
time = 0f;
deaths = 0;
laps = record.laps;
time = record.time;
deaths = record.deaths;
hardcore = record.hardcore;
}
public bool IsBetterThan(BossRushRecord record)
{
if (laps > record.laps)
{
return true;
}
if (hardcore && !record.hardcore)
{
return true;
}
if (time < record.time && record.ValidRecord())
{
return true;
}
if (time == record.time && deaths < record.deaths)
{
return true;
}
return false;
}
public bool ValidRecord()
{
if (laps <= 0)
{
return false;
}
if (time <= 0f)
{
return false;
}
if (deaths < 0)
{
return false;
}
if (deaths > 0 && hardcore)
{
return false;
}
return true;
}
public override string ToString()
{
return $"Laps: {laps} Time: {time} Deaths: {deaths} HC: {hardcore}";
}
}
public static class VersionCheck
{
public class CoroutineDummy : MonoBehaviour
{
}
private static MonoBehaviour _behaviour;
private static MonoBehaviour behaviour
{
get
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_behaviour == (Object)null)
{
_behaviour = (MonoBehaviour)(object)new GameObject("VersionChecker").AddComponent<CoroutineDummy>();
}
return _behaviour;
}
}
public static void CheckVersion(string githubURL, string runningVersionName, Action<bool, string> onCheckComplete = null)
{
behaviour.StartCoroutine(CheckLatestVersion(githubURL, runningVersionName, onCheckComplete));
}
private static IEnumerator CheckLatestVersion(string githubURL, string runningVersionName, Action<bool, string> onCheckComplete = null)
{
bool usingLatest = true;
string latestVersionName = "UNKNOWN";
UnityWebRequest webRequest = UnityWebRequest.Get(githubURL);
try
{
yield return webRequest.SendWebRequest();
if (!webRequest.isNetworkError)
{
string page = webRequest.downloadHandler.text;
try
{
latestVersionName = JArray.Parse(page)[0].Value<string>((object)"name");
usingLatest = latestVersionName == runningVersionName;
}
catch (Exception ex)
{
Exception e = ex;
usingLatest = true;
latestVersionName = runningVersionName;
Debug.LogError((object)$"Error getting version info for {runningVersionName}. {e}");
}
}
}
finally
{
((IDisposable)webRequest)?.Dispose();
}
onCheckComplete(usingLatest, latestVersionName);
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "BossRush";
public const string PLUGIN_NAME = "BossRush";
public const string PLUGIN_VERSION = "1.1.3";
}
}
namespace BossRush.UI
{
public class BossRushDeathScreen : MonoBehaviour
{
[SerializeField]
private GameObject screen;
[SerializeField]
private GameObject buttons;
[SerializeField]
private GameObject highScoreFlair;
[SerializeField]
private Text lapText;
[SerializeField]
private Text timeText;
[SerializeField]
private Text deathText;
private bool open;
private bool finished;
private bool skip;
private bool canSkip;
public static BossRushDeathScreen Instance { get; private set; }
private void Awake()
{
Instance = this;
Reset();
}
public void Update()
{
if (open)
{
if (Input.anyKeyDown && canSkip && !finished)
{
skip = true;
}
if (finished && Input.GetKeyDown((KeyCode)27))
{
Quit();
}
}
}
private IEnumerator DisplayStats()
{
BossRushRecord current = StatRecords.GetRecord();
lapText.text = "";
timeText.text = "";
deathText.text = "";
int currentLaps = 0;
float lapTime = 1.5f / (float)((current.laps == 0) ? 1 : current.laps);
for (; currentLaps < current.laps + 1; currentLaps++)
{
if (skip)
{
break;
}
lapText.text = currentLaps.ToString("000");
yield return (object)new WaitForSecondsRealtime(lapTime);
}
canSkip = true;
lapText.text = current.laps.ToString("000");
float timer = 1.5f;
while (timer > 0f && !skip)
{
float time = Mathf.Lerp(0f, current.time, 1f - timer / 1.5f);
timer -= 0.016f;
yield return (object)new WaitForSecondsRealtime(0.016f);
timeText.text = StringHelper.GetTimeString(time);
}
timeText.text = StringHelper.GetTimeString(current.time);
int currentDeaths = 0;
float deathTime = 1.5f / (float)((current.deaths == 0) ? 1 : current.deaths);
for (; currentDeaths < current.deaths; currentDeaths++)
{
if (skip)
{
break;
}
deathText.text = currentDeaths.ToString("000");
yield return (object)new WaitForSecondsRealtime(deathTime);
}
deathText.text = current.deaths.ToString("000");
if (!skip)
{
yield return (object)new WaitForSecondsRealtime(0.5f);
}
highScoreFlair.SetActive(StatRecords.HighScoreRun);
if (!skip)
{
yield return (object)new WaitForSecondsRealtime(0.5f);
}
finished = true;
buttons.SetActive(true);
}
public void Retry()
{
Time.timeScale = 1f;
Reset();
BossRushController.StartBossRushMode(hardcore: true);
}
public void Quit()
{
Reset();
MonoSingleton<OptionsManager>.Instance.QuitMission();
}
public void Open()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: 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)
if (!open)
{
GameState val = new GameState("br_deathscreen", screen);
val.cursorLock = (LockMode)2;
val.playerInputLock = (LockMode)1;
val.cameraInputLock = (LockMode)1;
val.priority = 10;
GameStateManager.Instance.RegisterState(val);
Time.timeScale = 0f;
open = true;
GameObject obj = screen;
if (obj != null)
{
obj.SetActive(true);
}
((MonoBehaviour)this).StartCoroutine(DisplayStats());
}
}
private void Reset()
{
if (open)
{
GameStateManager.Instance.PopState("br_deathscreen");
}
open = false;
finished = false;
skip = false;
buttons.SetActive(false);
screen.SetActive(false);
highScoreFlair.SetActive(false);
}
}
public class BossRushMenu : MonoBehaviour
{
public static BossRushMenu Instance;
[SerializeField]
private GameObject menuScreen;
[SerializeField]
private Text hardcoreModeText;
private bool hardcoreMode;
private static GameObject lastPage;
private MenuEsc menuEsc;
private bool onViolent;
private void Awake()
{
Instance = this;
GameObject obj = menuScreen;
menuEsc = ((obj != null) ? obj.AddComponent<MenuEsc>() : null);
hardcoreMode = BossRushController.HardcoreMode;
GameObject obj2 = menuScreen;
if (obj2 != null)
{
obj2.SetActive(false);
}
}
public void StartBossRush()
{
BossRushController.StartBossRushMode(hardcoreMode);
}
public void ToggleHardcoreMode()
{
hardcoreMode = !hardcoreMode;
UpdateHardcoreText();
}
public static void SetLastPage(GameObject chapter)
{
lastPage = chapter;
}
public void OpenMenu()
{
GameObject obj = lastPage;
if (obj != null)
{
obj.SetActive(false);
}
Refresh();
GameObject obj2 = menuScreen;
if (obj2 != null)
{
obj2.SetActive(true);
}
}
public static void Open()
{
if ((Object)(object)Instance == (Object)null)
{
Debug.LogError((object)"BR: Menu is null.");
}
else
{
Instance.OpenMenu();
}
}
public void Refresh()
{
if ((Object)(object)lastPage != (Object)null)
{
menuEsc.previousPage = lastPage;
}
UpdateHardcoreText();
}
private void UpdateHardcoreText()
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)hardcoreModeText == (Object)null))
{
((Graphic)hardcoreModeText).color = (Color)(hardcoreMode ? Color.red : new Color(0.3f, 0f, 0f, 1f));
}
}
}
public class BossRushStats : MonoBehaviour
{
[SerializeField]
private Text timeText;
[SerializeField]
private Text lapsText;
[SerializeField]
private Text modeText;
[SerializeField]
private Text deathText;
[SerializeField]
private Transform container;
[SerializeField]
private Transform deathCounter;
[SerializeField]
private Transform modeDisplay;
[SerializeField]
private GameObject newScoreFlash;
internal static GameObject UK_LevelStatsObject;
private bool flashing = false;
private void Start()
{
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
StatRecords.OnNewHighScore = (StatRecords.OnNewScoreHandler)Delegate.Combine(StatRecords.OnNewHighScore, (StatRecords.OnNewScoreHandler)delegate
{
FlashNewScore();
});
newScoreFlash.SetActive(false);
}
private void Update()
{
bool flag = CheckOpenState();
Transform obj = container;
if (obj != null)
{
GameObject gameObject = ((Component)obj).gameObject;
if (gameObject != null)
{
gameObject.SetActive(flag);
}
}
if (flag)
{
UpdateLapText();
UpdateTimeText();
UpdateThirdStat();
}
}
private void FlashNewScore()
{
if (!flashing)
{
flashing = true;
((MonoBehaviour)this).StartCoroutine(FlashNewHighScoreText());
}
}
private IEnumerator FlashNewHighScoreText()
{
newScoreFlash.SetActive(true);
int flashTimes = 15;
while (flashTimes > 0)
{
newScoreFlash.SetActive(true);
yield return (object)new WaitForSecondsRealtime(0.25f);
newScoreFlash.SetActive(false);
yield return (object)new WaitForSecondsRealtime(0.25f);
int num = flashTimes - 1;
flashTimes = num;
}
newScoreFlash.SetActive(false);
flashing = false;
}
private bool CheckOpenState()
{
if ((Object)(object)UK_LevelStatsObject == (Object)null)
{
return false;
}
if (!BossRushController.BossRushMode)
{
return false;
}
if (BossRushConfig.AlwaysShowStats.Value)
{
return true;
}
return UK_LevelStatsObject.gameObject.activeInHierarchy;
}
private void UpdateTimeText()
{
if (!((Object)(object)timeText == (Object)null))
{
timeText.text = StringHelper.GetTimeString(BossRushController.TimeElapsed);
}
}
private void UpdateLapText()
{
if (!((Object)(object)lapsText == (Object)null))
{
lapsText.text = BossRushController.Laps.ToString("000");
}
}
private void UpdateThirdStat()
{
bool hardcoreMode = BossRushController.HardcoreMode;
Transform obj = deathCounter;
if (obj != null)
{
GameObject gameObject = ((Component)obj).gameObject;
if (gameObject != null)
{
gameObject.SetActive(!hardcoreMode);
}
}
Transform obj2 = modeDisplay;
if (obj2 != null)
{
GameObject gameObject2 = ((Component)obj2).gameObject;
if (gameObject2 != null)
{
gameObject2.SetActive(hardcoreMode);
}
}
if (hardcoreMode)
{
if (!((Object)(object)modeText == (Object)null))
{
modeText.text = ((!hardcoreMode) ? "<color=orange>STANDARD</color>" : "<color=red>HARDCORE</color>");
}
}
else if (!((Object)(object)deathText == (Object)null))
{
deathText.text = BossRushController.Deaths.ToString("000");
}
}
public static void Spawn()
{
if (!((Object)(object)Assets.BossRushStatsPrefab == (Object)null))
{
Object.Instantiate<GameObject>(Assets.BossRushStatsPrefab);
}
}
}
public class BossRushVersionText : MonoBehaviour
{
private Text text;
private void Awake()
{
text = ((Component)this).GetComponent<Text>();
}
private void OnEnable()
{
text.text = "BossRush - 1.1.3 - " + (BossRush.LatestVersion ? "(<color=green>Latest</color>)" : "(<color=red>Update Available</color>)");
}
}
public class HighScoreBox : MonoBehaviour
{
[SerializeField]
private Text lapText;
[SerializeField]
private Text timeText;
[SerializeField]
private Text deathsText;
[SerializeField]
private GameObject hardcoreLabel;
[SerializeField]
private GameObject subcontainer;
private void Refresh()
{
int @int = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
BossRushRecord record = StatRecords.GetRecord(@int);
if (!record.ValidRecord())
{
lapText.text = "";
timeText.text = "";
deathsText.text = "";
hardcoreLabel.SetActive(false);
subcontainer.SetActive(false);
}
else
{
lapText.text = record.laps.ToString("000");
timeText.text = StringHelper.GetTimeString(record.time);
deathsText.text = record.deaths.ToString("000");
((Component)deathsText).gameObject.SetActive(!record.hardcore);
hardcoreLabel.SetActive(record.hardcore);
subcontainer.SetActive(true);
}
}
private void OnEnable()
{
Refresh();
}
}
public static class StringHelper
{
public static string GetTimeString(float timeInSeconds)
{
int num = (int)Modulate(ref timeInSeconds, 3600f);
int num2 = (int)Modulate(ref timeInSeconds, 60f);
float num3 = timeInSeconds;
return num.ToString("00") + ":" + num2.ToString("00") + ":" + num3.ToString("00.00");
}
public static float Modulate(ref float number, float modulationAmount)
{
float num = number % modulationAmount;
float num2 = (number - num) / modulationAmount;
number -= num2 * modulationAmount;
return num2;
}
public static void DebugNull(string name, object obj)
{
Debug.Log((object)(name + " " + ((obj == null) ? "NULL" : "NOT NULL")));
}
}
}
namespace BossRush.Properties
{
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[DebuggerNonUserCode]
[CompilerGenerated]
internal class Resources
{
private static ResourceManager resourceMan;
private static CultureInfo resourceCulture;
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager
{
get
{
if (resourceMan == null)
{
ResourceManager resourceManager = new ResourceManager("BossRush.Properties.Resources", typeof(Resources).Assembly);
resourceMan = resourceManager;
}
return resourceMan;
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
internal static byte[] BossRush
{
get
{
object @object = ResourceManager.GetObject("BossRush", resourceCulture);
return (byte[])@object;
}
}
internal static string levelChainDefault => ResourceManager.GetString("levelChainDefault", resourceCulture);
internal Resources()
{
}
}
}