using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; 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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BossVSIntro")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Boss VS Intro")] [assembly: AssemblyTitle("BossVSIntro")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BossVSIntro { [BepInPlugin("com.scout.bossvsintro", "Boss VS Intro", "1.2.0")] public class BossVSIntroPlugin : BaseUnityPlugin { public const string PluginGuid = "com.scout.bossvsintro"; public const string PluginName = "Boss VS Intro"; public const string PluginVersion = "1.2.0"; internal static BossVSIntroPlugin Instance; internal static ManualLogSource Log; internal static string ImagesRoot; internal static string SoundsRoot; internal static string PluginDir; private void Awake() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; PluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ImagesRoot = Path.Combine(PluginDir, "Images"); SoundsRoot = Path.Combine(PluginDir, "Sounds"); new Harmony("com.scout.bossvsintro").PatchAll(); Log.LogInfo((object)"Boss VS Intro v1.2.0 loaded."); BossVSIntroPatch.BeginPreloadSounds(); } } internal static class VSConfig { public static float introCooldown = 5f; public static float slideInDuration = 0.45f; public static float vsPopDuration = 0.35f; public static float vsStartScale = 3.5f; public static float vsHeightFraction = 0.35f; public static float shakeDuration = 0.4f; public static float shakeAmplitude = 38f; public static float holdDuration = 1f; public static float slideOutDuration = 0.4f; public static float centerGap = -1920f; public static string triggerSoundFile = "Trigger.wav"; public static float soundVolume = 1f; public static float vsDelay = 1f; public static string playerFileName = "Player.png"; public static string vsFileName = "VS.png"; public static string bossFolderName = "Bosses"; public static string bossFallbackName = "Default.png"; } public class VSRunner : MonoBehaviour { } [HarmonyPatch(typeof(BossHealthBarTemplate))] public class BossVSIntroPatch { private static bool introPlaying; private static float lastIntroTime = -9999f; private static Canvas introCanvas; private static AudioSource introAudio; private static readonly Dictionary spriteCache = new Dictionary(); private static AudioClip triggerClip; private static MonoBehaviour runner; private static MonoBehaviour Runner { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)runner == (Object)null) { GameObject val = new GameObject("BossVSIntroRunner"); Object.DontDestroyOnLoad((Object)(object)val); runner = (MonoBehaviour)(object)val.AddComponent(); } return runner; } } [HarmonyPostfix] [HarmonyPatch("Initialize", new Type[] { typeof(BossHealthBar), typeof(SliderLayer[]) })] private static void InitializePostfix(BossHealthBarTemplate __instance, BossHealthBar bossBar, SliderLayer[] colorLayers) { BossVSIntroPlugin.Log.LogInfo((object)("[VS] Initialize fired for: " + bossBar?.bossName)); if (!((Object)(object)__instance == (Object)null) && !((Object)(object)bossBar == (Object)null) && !string.IsNullOrEmpty(bossBar.bossName)) { if (introPlaying) { BossVSIntroPlugin.Log.LogWarning((object)"[VS] Bailed: introPlaying is STUCK true — last splash never finished."); return; } if (Time.unscaledTime - lastIntroTime < VSConfig.introCooldown) { BossVSIntroPlugin.Log.LogWarning((object)$"[VS] Bailed: on cooldown ({Time.unscaledTime - lastIntroTime:F1}s since last < {VSConfig.introCooldown}s)."); return; } BossVSIntroPlugin.Log.LogInfo((object)"[VS] All guards passed — starting splash coroutine."); Runner.StartCoroutine(PlayVSIntro(bossBar.bossName)); } } public static void BeginPreloadSounds() { Runner.StartCoroutine(PreloadSounds()); } private static IEnumerator PreloadSounds() { yield return LoadClip(Path.Combine(BossVSIntroPlugin.SoundsRoot, VSConfig.triggerSoundFile), delegate(AudioClip c) { triggerClip = c; }); } private static IEnumerator LoadClip(string fullPath, Action onLoaded) { if (!File.Exists(fullPath)) { BossVSIntroPlugin.Log.LogWarning((object)("Sound not found (splash will be silent for this one): " + fullPath)); onLoaded(null); yield break; } AudioType type = GuessAudioType(fullPath); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + fullPath, type); try { yield return req.SendWebRequest(); if ((int)req.result != 1) { BossVSIntroPlugin.Log.LogError((object)("Failed to load sound '" + fullPath + "': " + req.error)); onLoaded(null); yield break; } onLoaded(DownloadHandlerAudioClip.GetContent(req)); } finally { ((IDisposable)req)?.Dispose(); } } private static AudioType GuessAudioType(string path) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) string text = Path.GetExtension(path).ToLowerInvariant(); string text2 = text; if (!(text2 == ".ogg")) { if (text2 == ".mp3") { return (AudioType)13; } return (AudioType)20; } return (AudioType)14; } private static void PlaySound(AudioClip clip) { if (!((Object)(object)clip == (Object)null) && !((Object)(object)introAudio == (Object)null)) { introAudio.PlayOneShot(clip, VSConfig.soundVolume); } } private static string Sanitize(string name) { StringBuilder stringBuilder = new StringBuilder(); string text = name.ToUpperInvariant(); foreach (char c in text) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(c); } else if (c == ' ' || c == '-' || c == '_') { stringBuilder.Append('_'); } } return stringBuilder.ToString(); } private static Sprite LoadSprite(string fullPath) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (spriteCache.TryGetValue(fullPath, out var value)) { return value; } if (!File.Exists(fullPath)) { return null; } try { byte[] array = File.ReadAllBytes(fullPath); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ImageConversion.LoadImage(val, array); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); spriteCache[fullPath] = val2; return val2; } catch (Exception ex) { BossVSIntroPlugin.Log.LogError((object)("Failed to load image '" + fullPath + "': " + ex.Message)); return null; } } private static Canvas GetOrCreateCanvas() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if ((Object)(object)introCanvas != (Object)null) { return introCanvas; } GameObject val = new GameObject("BossVSIntroCanvas"); Object.DontDestroyOnLoad((Object)(object)val); introCanvas = val.AddComponent(); introCanvas.renderMode = (RenderMode)0; introCanvas.sortingOrder = 32767; CanvasScaler val2 = val.AddComponent(); val2.uiScaleMode = (ScaleMode)0; val2.scaleFactor = 1f; val.AddComponent(); introAudio = val.AddComponent(); introAudio.playOnAwake = false; introAudio.spatialBlend = 0f; introAudio.ignoreListenerPause = true; return introCanvas; } private static Image MakeImage(Transform parent, Sprite sprite, string name, float targetHeight) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); Image val2 = val.AddComponent(); val2.sprite = sprite; ((Graphic)val2).raycastTarget = false; val2.preserveAspect = true; RectTransform rectTransform = ((Graphic)val2).rectTransform; rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); float num = (float)((Texture)sprite.texture).width / (float)((Texture)sprite.texture).height; rectTransform.sizeDelta = new Vector2(targetHeight * num, targetHeight); rectTransform.anchoredPosition = Vector2.zero; ((Transform)rectTransform).localScale = Vector3.one; return val2; } private static float EaseOutCubic(float x) { return 1f - Mathf.Pow(1f - x, 3f); } private static float EaseInCubic(float x) { return x * x * x; } private static IEnumerator PlayVSIntro(string bossName) { introPlaying = true; string playerPath = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.playerFileName); string vsPath = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.vsFileName); string bossPath = Path.Combine(path3: Sanitize(bossName) + ".png", path1: BossVSIntroPlugin.ImagesRoot, path2: VSConfig.bossFolderName); string bossFallback = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.bossFolderName, VSConfig.bossFallbackName); Sprite playerSprite = LoadSprite(playerPath); Sprite vsSprite = LoadSprite(vsPath); Sprite bossSprite = LoadSprite(bossPath) ?? LoadSprite(bossFallback); if ((Object)(object)playerSprite == (Object)null) { BossVSIntroPlugin.Log.LogWarning((object)("Missing player image: " + playerPath)); } if ((Object)(object)vsSprite == (Object)null) { BossVSIntroPlugin.Log.LogWarning((object)("Missing VS image: " + vsPath)); } if ((Object)(object)bossSprite == (Object)null) { BossVSIntroPlugin.Log.LogWarning((object)("Missing boss image (and no Default.png): " + bossPath)); } if ((Object)(object)playerSprite == (Object)null || (Object)(object)vsSprite == (Object)null || (Object)(object)bossSprite == (Object)null) { introPlaying = false; yield break; } lastIntroTime = Time.unscaledTime; float previousTimeScale = Time.timeScale; Time.timeScale = 0f; Image playerImg = null; Image bossImg = null; Image vsImg = null; IEnumerator anim = AnimateCard(playerSprite, bossSprite, vsSprite, delegate(Image img) { playerImg = img; }, delegate(Image img) { bossImg = img; }, delegate(Image img) { vsImg = img; }); while (true) { object current; try { if (!anim.MoveNext()) { break; } current = anim.Current; goto IL_0295; } catch (Exception ex) { Exception e = ex; BossVSIntroPlugin.Log.LogError((object)$"[VS] Splash threw, bailing safely: {e}"); } break; IL_0295: yield return current; } if ((Object)(object)playerImg != (Object)null) { Object.Destroy((Object)(object)((Component)playerImg).gameObject); } if ((Object)(object)bossImg != (Object)null) { Object.Destroy((Object)(object)((Component)bossImg).gameObject); } if ((Object)(object)vsImg != (Object)null) { Object.Destroy((Object)(object)((Component)vsImg).gameObject); } Time.timeScale = previousTimeScale; introPlaying = false; } private static IEnumerator AnimateCard(Sprite playerSprite, Sprite bossSprite, Sprite vsSprite, Action outPlayer, Action outBoss, Action outVs) { Canvas canvas = GetOrCreateCanvas(); PlaySound(triggerClip); float screenW = Screen.width; float screenH = Screen.height; Image playerImg = MakeImage(((Component)canvas).transform, playerSprite, "VS_Player", screenH); Image bossImg = MakeImage(((Component)canvas).transform, bossSprite, "VS_Boss", screenH); Image vsImg = MakeImage(((Component)canvas).transform, vsSprite, "VS_Badge", screenH * VSConfig.vsHeightFraction); outPlayer(playerImg); outBoss(bossImg); outVs(vsImg); RectTransform playerRT = ((Graphic)playerImg).rectTransform; RectTransform bossRT = ((Graphic)bossImg).rectTransform; RectTransform vsRT = ((Graphic)vsImg).rectTransform; float halfGap = VSConfig.centerGap * 0.5f; float playerHalfW = playerRT.sizeDelta.x * 0.5f; float bossHalfW = bossRT.sizeDelta.x * 0.5f; Vector2 playerStart = new Vector2(0f - screenW, 0f); Vector2 bossStart = new Vector2(screenW, 0f); Vector2 playerEnd = new Vector2(0f - (playerHalfW + halfGap), 0f); Vector2 bossEnd = new Vector2(bossHalfW + halfGap, 0f); playerRT.anchoredPosition = playerStart; bossRT.anchoredPosition = bossStart; vsRT.anchoredPosition = Vector2.zero; ((Transform)playerRT).SetAsLastSibling(); ((Transform)bossRT).SetAsLastSibling(); ((Transform)vsRT).SetAsLastSibling(); ((Component)vsImg).gameObject.SetActive(false); float t = 0f; while (t < VSConfig.slideInDuration) { t += Time.unscaledDeltaTime; float k = EaseOutCubic(Mathf.Clamp01(t / VSConfig.slideInDuration)); playerRT.anchoredPosition = Vector2.LerpUnclamped(playerStart, playerEnd, k); bossRT.anchoredPosition = Vector2.LerpUnclamped(bossStart, bossEnd, k); yield return null; } playerRT.anchoredPosition = playerEnd; bossRT.anchoredPosition = bossEnd; t = 0f; while (t < VSConfig.vsDelay) { t += Time.unscaledDeltaTime; yield return null; } ((Component)vsImg).gameObject.SetActive(true); float impactDuration = Mathf.Max(VSConfig.vsPopDuration, VSConfig.shakeDuration); t = 0f; while (t < impactDuration) { t += Time.unscaledDeltaTime; float kv = EaseOutCubic(Mathf.Clamp01(t / VSConfig.vsPopDuration)); ((Transform)vsRT).localScale = Vector3.one * Mathf.LerpUnclamped(VSConfig.vsStartScale, 1f, kv); float decay = 1f - Mathf.Clamp01(t / VSConfig.shakeDuration); float amp = VSConfig.shakeAmplitude * decay; playerRT.anchoredPosition = playerEnd + new Vector2(Random.Range(0f - amp, amp), Random.Range(0f - amp, amp)); bossRT.anchoredPosition = bossEnd + new Vector2(Random.Range(0f - amp, amp), Random.Range(0f - amp, amp)); yield return null; } ((Transform)vsRT).localScale = Vector3.one; playerRT.anchoredPosition = playerEnd; bossRT.anchoredPosition = bossEnd; t = 0f; while (t < VSConfig.holdDuration) { t += Time.unscaledDeltaTime; yield return null; } Vector2 vsUpEnd = new Vector2(0f, screenH); t = 0f; while (t < VSConfig.slideOutDuration) { t += Time.unscaledDeltaTime; float k2 = EaseInCubic(Mathf.Clamp01(t / VSConfig.slideOutDuration)); playerRT.anchoredPosition = Vector2.LerpUnclamped(playerEnd, playerStart, k2); bossRT.anchoredPosition = Vector2.LerpUnclamped(bossEnd, bossStart, k2); vsRT.anchoredPosition = Vector2.LerpUnclamped(Vector2.zero, vsUpEnd, k2); yield return null; } } } }