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<GUILayoutOption>());
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<BuffInfo> activeBuffs = GetActiveBuffs();
if (activeBuffs.Count == 0)
{
GUILayout.Label("No active buffs", labelStyle, Array.Empty<GUILayoutOption>());
}
else
{
scrollPos = GUILayout.BeginScrollView(scrollPos, Array.Empty<GUILayoutOption>());
List<BuffInfo> list = new List<BuffInfo>(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<BuffInfo> GetActiveBuffs()
{
List<BuffInfo> list = new List<BuffInfo>();
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<string> list = new List<string>
{
"<b>" + buff.Name + "</b>",
""
};
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;
}
}