using System; 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.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BuffClickOff")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BuffClickOff")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7f6e3433-2753-41bf-a02d-3ba713d12866")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace BuffClickOff; [BepInPlugin("com.erenshor.buffclickoff", "Buff Click Off", "1.29.0")] public class Plugin : BaseUnityPlugin { private class BuffInfo { public int Index; public string Name; public Spell Spell; public StatusEffect StatusEffect; } internal static ManualLogSource Log; private static bool showWindow = false; private static Rect windowRect = new Rect(40f, 120f, 340f, 420f); private static Vector2 scrollPos; private static float autoOpenTimer = 12f; private static bool hasAutoOpened = false; private static FieldInfo effectField; private static PropertyInfo statusEffectsProp; private static ConstructorInfo emptyStatusEffectCtor; private static string hoverText = null; private static Rect hoverRect; private static GUIStyle buttonStyle; private static GUIStyle labelStyle; private static GUIStyle windowStyle; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; CacheReflection(); Log.LogInfo((object)"Buff Click Off 1.29.0 loaded – modern GUI + 1.7.0 style click-off"); } private void CacheReflection() { statusEffectsProp = typeof(Stats).GetProperty("StatusEffects", BindingFlags.Instance | BindingFlags.Public); Type typeFromHandle = typeof(StatusEffect); effectField = AccessTools.Field(typeFromHandle, "Effect") ?? AccessTools.Field(typeFromHandle, "MySpell") ?? AccessTools.Field(typeFromHandle, "spell"); emptyStatusEffectCtor = AccessTools.Constructor(typeFromHandle, new Type[4] { typeof(Spell), typeof(bool), typeof(bool), typeof(Character) }, false); if (emptyStatusEffectCtor == null) { emptyStatusEffectCtor = AccessTools.Constructor(typeFromHandle, new Type[4] { typeof(Spell), typeof(bool), typeof(bool), typeof(object) }, false); } } private void Update() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) && Input.GetKeyDown((KeyCode)98)) { showWindow = !showWindow; } if (Input.GetKeyDown((KeyCode)289)) { showWindow = true; windowRect = new Rect(40f, 120f, 340f, 420f); } if (!hasAutoOpened && (Object)(object)GameData.PlayerStats != (Object)null) { autoOpenTimer -= Time.deltaTime; if (autoOpenTimer <= 0f) { showWindow = true; hasAutoOpened = true; Log.LogInfo((object)"Buff window auto-opened (delayed)"); } } } private void OnGUI() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0058: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_0098: 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_00c4: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) if (showWindow) { if (buttonStyle == null) { buttonStyle = new GUIStyle(GUI.skin.button) { fontSize = Mathf.RoundToInt((float)GUI.skin.button.fontSize * 1.1f) }; labelStyle = new GUIStyle(GUI.skin.label) { fontSize = Mathf.RoundToInt((float)GUI.skin.label.fontSize * 1.1f) }; windowStyle = new GUIStyle(GUI.skin.window) { fontSize = Mathf.RoundToInt((float)GUI.skin.window.fontSize * 1.1f) }; } windowRect = SanitizeRect(windowRect); windowRect = GUI.Window(987654, windowRect, new WindowFunction(DrawWindow), "Buffs (Left-click = Remove) Press Shift + B to Toggle", windowStyle); if (!string.IsNullOrEmpty(hoverText)) { GUI.Box(hoverRect, hoverText); } } } private void DrawWindow(int id) { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Close", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { showWindow = false; } GUILayout.FlexibleSpace(); if (GUILayout.Button("Small", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { ((Rect)(ref windowRect)).width = 280f; ((Rect)(ref windowRect)).height = 320f; } if (GUILayout.Button("Medium", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { ((Rect)(ref windowRect)).width = 340f; ((Rect)(ref windowRect)).height = 420f; } if (GUILayout.Button("Large", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { ((Rect)(ref windowRect)).width = 420f; ((Rect)(ref windowRect)).height = 560f; } GUILayout.EndHorizontal(); GUILayout.Space(8f); List activeBuffs = GetActiveBuffs(); if (activeBuffs.Count == 0) { GUILayout.Label("No active buffs", labelStyle, Array.Empty()); } else { scrollPos = GUILayout.BeginScrollView(scrollPos, Array.Empty()); List list = new List(activeBuffs); foreach (BuffInfo item in list) { if (GUILayout.Button(item.Name, buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { if (RemoveEffect(item)) { Log.LogInfo((object)("[BuffClickOff] Removed: " + item.Name)); } else { Log.LogWarning((object)("[BuffClickOff] Failed to remove: " + item.Name)); } } Rect lastRect = GUILayoutUtility.GetLastRect(); if (((Rect)(ref lastRect)).Contains(Event.current.mousePosition)) { hoverText = BuildTooltip(item); hoverRect = new Rect(((Rect)(ref windowRect)).x + ((Rect)(ref windowRect)).width + 10f, ((Rect)(ref windowRect)).y + ((Rect)(ref lastRect)).y + 30f, 320f, 180f); } } GUILayout.EndScrollView(); } GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f)); } private List GetActiveBuffs() { List list = new List(); if ((Object)(object)GameData.PlayerStats == (Object)null) { return list; } try { if (!(statusEffectsProp?.GetValue(GameData.PlayerStats) is StatusEffect[] array)) { return list; } for (int i = 0; i < array.Length; i++) { StatusEffect val = array[i]; if (val == null) { continue; } object? obj = effectField?.GetValue(val); Spell val2 = (Spell)((obj is Spell) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { string spellName = val2.SpellName; if (!string.IsNullOrEmpty(spellName) && !(spellName == "Unknown") && !(spellName == "StatusEffect")) { list.Add(new BuffInfo { Index = i, Name = spellName, Spell = val2, StatusEffect = val }); } } } } catch { } return list; } private string BuildTooltip(BuffInfo buff) { if ((Object)(object)buff.Spell == (Object)null) { return buff.Name; } List list = new List { "" + buff.Name + "", "" }; if (!string.IsNullOrEmpty(buff.Spell.SpellDesc)) { list.Add(buff.Spell.SpellDesc); } if (!string.IsNullOrEmpty(buff.Spell.SpecialDescriptor)) { list.Add(buff.Spell.SpecialDescriptor); } if (buff.Spell.HP != 0) { list.Add($"HP: {buff.Spell.HP}"); } if (buff.Spell.AC != 0) { list.Add($"AC: {buff.Spell.AC}"); } if (buff.Spell.Mana != 0) { list.Add($"Mana: {buff.Spell.Mana}"); } if (buff.Spell.Str != 0) { list.Add($"Str: {buff.Spell.Str}"); } if (buff.Spell.End != 0) { list.Add($"End: {buff.Spell.End}"); } if (buff.Spell.Dex != 0) { list.Add($"Dex: {buff.Spell.Dex}"); } if (buff.Spell.Agi != 0) { list.Add($"Agi: {buff.Spell.Agi}"); } if (buff.Spell.Int != 0) { list.Add($"Int: {buff.Spell.Int}"); } if (buff.Spell.Wis != 0) { list.Add($"Wis: {buff.Spell.Wis}"); } if (buff.Spell.Cha != 0) { list.Add($"Cha: {buff.Spell.Cha}"); } if (buff.Spell.Haste != 0f) { list.Add($"Haste: {buff.Spell.Haste}"); } if (buff.Spell.MovementSpeed != 0f) { list.Add($"Movement: {buff.Spell.MovementSpeed}"); } if (buff.Spell.SpellDurationInTicks > 0) { list.Add($"Duration: {buff.Spell.SpellDurationInTicks} ticks"); } return string.Join("\n", list); } private bool RemoveEffect(BuffInfo buff) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown if ((Object)(object)GameData.PlayerStats == (Object)null || buff.StatusEffect == null) { return false; } try { if (emptyStatusEffectCtor != null) { object obj = emptyStatusEffectCtor.Invoke(new object[4] { null, false, false, null }); if (statusEffectsProp?.GetValue(GameData.PlayerStats) is StatusEffect[] array && buff.Index >= 0 && buff.Index < array.Length) { array[buff.Index] = (StatusEffect)obj; ForceCalcStats(); return true; } } } catch (Exception ex) { Log.LogWarning((object)("[BuffClickOff] Remove failed: " + ex.Message)); } return false; } private void ForceCalcStats() { try { AccessTools.Method(typeof(Stats), "CalcStats", (Type[])null, (Type[])null)?.Invoke(GameData.PlayerStats, null); } catch { } } private static Rect SanitizeRect(Rect r) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) ((Rect)(ref r)).width = Mathf.Clamp(((Rect)(ref r)).width, 260f, (float)(Screen.width - 20)); ((Rect)(ref r)).height = Mathf.Clamp(((Rect)(ref r)).height, 200f, (float)(Screen.height - 20)); ((Rect)(ref r)).x = Mathf.Clamp(((Rect)(ref r)).x, 0f, (float)Screen.width - ((Rect)(ref r)).width); ((Rect)(ref r)).y = Mathf.Clamp(((Rect)(ref r)).y, 0f, (float)Screen.height - ((Rect)(ref r)).height); return r; } }