Decompiled source of CombatLog v1.0.0

CombatLog.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace BubCombatLog;

internal class Step
{
	public string Label;

	public string Detail;

	public float Before;

	public float After;

	public Step(string label, string detail, float before, float after)
	{
		Label = label;
		Detail = detail;
		Before = before;
		After = after;
	}
}
internal class Half
{
	public bool IsAttack;

	public ZDOID Attacker;

	public ZDOID Victim;

	public float Key;

	public string AttackerName = "?";

	public string VictimName = "?";

	public List<Step> Steps = new List<Step>();

	public float HpBefore;

	public float HpAfter;

	public float HpMax;

	public bool Blocked;

	public bool Parry;

	public bool Timed;

	public bool GuardBroken;

	public bool Dodged;

	public bool Killed;

	public bool Staggered;

	public string BlockKind = "";

	public float Held;

	public float Stamina;

	public float StaggerBefore;

	public float StaggerAfter;

	public float StaggerMax;

	public float Instant;

	public float Dot;

	public string DamageText = "";

	public void Write(ZPackage p)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		p.Write(IsAttack);
		p.Write(Attacker);
		p.Write(Victim);
		p.Write(Key);
		p.Write(AttackerName);
		p.Write(VictimName);
		p.Write(Steps.Count);
		foreach (Step step in Steps)
		{
			p.Write(step.Label);
			p.Write(step.Detail ?? "");
			p.Write(step.Before);
			p.Write(step.After);
		}
		p.Write(HpBefore);
		p.Write(HpAfter);
		p.Write(HpMax);
		int num = (Blocked ? 1 : 0) | (Parry ? 2 : 0) | (Timed ? 4 : 0) | (GuardBroken ? 8 : 0) | (Dodged ? 16 : 0) | (Killed ? 32 : 0) | (Staggered ? 64 : 0);
		p.Write(num);
		p.Write(BlockKind);
		p.Write(Held);
		p.Write(Stamina);
		p.Write(StaggerBefore);
		p.Write(StaggerAfter);
		p.Write(StaggerMax);
		p.Write(Instant);
		p.Write(Dot);
		p.Write(DamageText);
	}

	public static Half Read(ZPackage p)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		Half half = new Half();
		half.IsAttack = p.ReadBool();
		half.Attacker = p.ReadZDOID();
		half.Victim = p.ReadZDOID();
		half.Key = p.ReadSingle();
		half.AttackerName = p.ReadString();
		half.VictimName = p.ReadString();
		int num = p.ReadInt();
		for (int i = 0; i < num; i++)
		{
			half.Steps.Add(new Step(p.ReadString(), p.ReadString(), p.ReadSingle(), p.ReadSingle()));
		}
		half.HpBefore = p.ReadSingle();
		half.HpAfter = p.ReadSingle();
		half.HpMax = p.ReadSingle();
		int num2 = p.ReadInt();
		half.Blocked = (num2 & 1) != 0;
		half.Parry = (num2 & 2) != 0;
		half.Timed = (num2 & 4) != 0;
		half.GuardBroken = (num2 & 8) != 0;
		half.Dodged = (num2 & 0x10) != 0;
		half.Killed = (num2 & 0x20) != 0;
		half.Staggered = (num2 & 0x40) != 0;
		half.BlockKind = p.ReadString();
		half.Held = p.ReadSingle();
		half.Stamina = p.ReadSingle();
		half.StaggerBefore = p.ReadSingle();
		half.StaggerAfter = p.ReadSingle();
		half.StaggerMax = p.ReadSingle();
		half.Instant = p.ReadSingle();
		half.Dot = p.ReadSingle();
		half.DamageText = p.ReadString();
		return half;
	}
}
internal static class Combat
{
	private class Ctx
	{
		public Ctx Prev;

		public Character Victim;

		public HitData Hit;

		public Half Half;

		public float StaminaBefore;

		public float BlockBefore;

		public float AfterArmor = -1f;
	}

	public static FieldInfo StaggerDamage;

	public static FieldInfo BlockTimer;

	public static FieldInfo AttackCharacter;

	public static FieldInfo AttackWeapon;

	public static FieldInfo SemanCharacter;

	public static Func<Humanoid, ItemData> GetCurrentBlocker;

	public static Func<Character, float> GetStaggerTreshold;

	private static readonly ConditionalWeakTable<HitData, Half> AttackByHit = new ConditionalWeakTable<HitData, Half>();

	private static readonly ConditionalWeakTable<object, Half> AttackBySource = new ConditionalWeakTable<object, Half>();

	private static object currentSource;

	private static readonly List<string> SiteLabels = new List<string>();

	private static Ctx current;

	public static void Patch(Harmony h)
	{
		StaggerDamage = AccessTools.Field(typeof(Character), "m_staggerDamage");
		BlockTimer = AccessTools.Field(typeof(Humanoid), "m_blockTimer");
		AttackCharacter = AccessTools.Field(typeof(Attack), "m_character");
		AttackWeapon = AccessTools.Field(typeof(Attack), "m_weapon");
		SemanCharacter = AccessTools.Field(typeof(SEMan), "m_character");
		GetCurrentBlocker = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetCurrentBlocker", (Type[])null, (Type[])null), (object)null, true);
		GetStaggerTreshold = AccessTools.MethodDelegate<Func<Character, float>>(AccessTools.Method(typeof(Character), "GetStaggerTreshold", (Type[])null, (Type[])null), (object)null, true);
		h.Patch((MethodBase)AccessTools.Method(typeof(Attack), "ModifyDamage", (Type[])null, (Type[])null), Hm("ModifyDamagePrefix"), Hm("ModifyDamagePostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(SEMan), "ModifyAttack", (Type[])null, (Type[])null), Hm("ModifyAttackPrefix"), Hm("ModifyAttackPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Projectile), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, Hm("SourceSetup"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Aoe), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, Hm("SourceSetup"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Projectile), "OnHit", (Type[])null, (Type[])null), Hm("SourceHitPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, Hm("SourceHitFinalizer"), (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Aoe), "OnHit", (Type[])null, (Type[])null), Hm("SourceHitPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, Hm("SourceHitFinalizer"), (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Character), "Damage", (Type[])null, (Type[])null), Hm("DeliverPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val = Hm("DefenseTranspiler");
		MethodInfo methodInfo = AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null);
		HarmonyMethod obj = Hm("DefensePrefix");
		HarmonyMethod obj2 = Hm("DefensePostfix");
		HarmonyMethod val2 = Hm("DefenseFinalizer");
		h.Patch((MethodBase)methodInfo, obj, obj2, val, val2, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Character), "ApplyDamage", (Type[])null, (Type[])null), Hm("ApplyDamagePrefix"), Hm("ApplyDamagePostfix"), val, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Humanoid), "BlockAttack", (Type[])null, (Type[])null), Hm("BlockPrefix"), Hm("BlockPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Character), "Stagger", (Type[])null, (Type[])null), (HarmonyMethod)null, Hm("StaggerPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Character), "AddStaggerDamage", (Type[])null, (Type[])null), Hm("AddStaggerPrefix"), Hm("AddStaggerPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		h.Patch((MethodBase)AccessTools.Method(typeof(Player), "OnDeath", (Type[])null, (Type[])null), Hm("DeathPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static HarmonyMethod Hm(string name)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		return new HarmonyMethod(typeof(Combat).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic));
	}

	public static string Name(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return "ambiente";
		}
		if (c is Player)
		{
			return c.GetHoverName();
		}
		string text = ((Localization.instance != null) ? Localization.instance.Localize(c.m_name) : c.m_name);
		int num = c.GetLevel() - 1;
		if (num <= 0)
		{
			return text;
		}
		return text + " " + new string('★', num);
	}

	public static float Total(HitData hit)
	{
		//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)
		DamageTypes damage = hit.m_damage;
		return damage.m_damage + damage.m_blunt + damage.m_slash + damage.m_pierce + damage.m_fire + damage.m_frost + damage.m_lightning + damage.m_poison + damage.m_spirit;
	}

	public static string Source(Character attacker, HitData hit)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected I4, but got Unknown
		if ((Object)(object)attacker != (Object)null)
		{
			return Name(attacker);
		}
		HitType hitType = hit.m_hitType;
		return (hitType - 3) switch
		{
			0 => "queda", 
			1 => "afogamento", 
			2 => "queimadura", 
			3 => "congelamento", 
			4 => "veneno", 
			5 => "água", 
			6 => "fumaça", 
			7 => "borda do mundo", 
			8 => "impacto", 
			9 => "carroça", 
			10 => "árvore caindo", 
			11 => "você mesmo", 
			12 => "estrutura caindo", 
			13 => "torreta", 
			14 => "barco", 
			15 => "estalactite", 
			16 => "catapulta", 
			17 => "fogo de brasa", 
			18 => "mar das Ashlands", 
			19 => "lava", 
			20 => "incinerador", 
			21 => "ponte levadiça", 
			_ => "ambiente", 
		};
	}

	public static float Bar(Character c)
	{
		return (float)StaggerDamage.GetValue(c);
	}

	public static ZDOID Id(Character c)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)c != (Object)null))
		{
			return ZDOID.None;
		}
		return c.GetZDOID();
	}

	public static string F(float v)
	{
		return v.ToString("0.00", CultureInfo.InvariantCulture).Replace('.', ',');
	}

	public static string N(float v)
	{
		return Mathf.RoundToInt(v).ToString();
	}

	public static string DamageText(DamageTypes d)
	{
		List<string> list = new List<string>();
		Part(list, d.m_damage, "puro");
		Part(list, d.m_blunt, "contundente");
		Part(list, d.m_slash, "corte");
		Part(list, d.m_pierce, "perfurante");
		Part(list, d.m_fire, "fogo");
		Part(list, d.m_frost, "gelo");
		Part(list, d.m_lightning, "raio");
		Part(list, d.m_poison, "veneno");
		Part(list, d.m_spirit, "espírito");
		return string.Join(", ", list.ToArray());
	}

	private static void Part(List<string> parts, float v, string name)
	{
		if (v >= 0.5f)
		{
			parts.Add(N(v) + " " + name);
		}
	}

	private static bool IsLocal(Character c)
	{
		if ((Object)(object)c != (Object)null)
		{
			return (Object)(object)c == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	private static void ModifyDamagePrefix(Attack __instance, HitData __0, float __1)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)AttackCharacter.GetValue(__instance);
		ItemData val2 = (ItemData)AttackWeapon.GetValue(__instance);
		Half half = new Half();
		half.IsAttack = true;
		half.AttackerName = Name(val);
		float num = Total(__0);
		string text = ((val2 != null && Localization.instance != null) ? Localization.instance.Localize(val2.m_shared.m_name) : "arma");
		string text2 = ((val2 != null && val2.m_quality > 1) ? (" (nível " + val2.m_quality + ")") : "");
		half.Steps.Add(new Step("Dano base: " + text + text2, DamageText(__0.m_damage), num, num));
		num = Mult(half, "Multiplicador do ataque", __instance.m_damageMultiplier, num);
		num = Mult(half, (val is Player) ? "Skill (com variação aleatória)" : "Variação aleatória", __1, num);
		if ((Object)(object)val != (Object)null)
		{
			int num2 = val.GetLevel() - 1;
			num = Mult(half, "Estrelas do atacante (" + Mathf.Max(0, num2) + "★)", 1f + (float)Mathf.Max(0, num2) * 0.5f, num);
			if (__instance.m_damageMultiplierPerMissingHP > 0f)
			{
				num = Mult(half, "Bônus por vida faltando", 1f + (val.GetMaxHealth() - val.GetHealth()) * __instance.m_damageMultiplierPerMissingHP, num);
			}
			if (__instance.m_damageMultiplierByTotalHealthMissing > 0f)
			{
				num = Mult(half, "Bônus por % de vida faltando", 1f + (1f - val.GetHealthPercentage()) * __instance.m_damageMultiplierByTotalHealthMissing, num);
			}
		}
		AttackByHit.Remove(__0);
		AttackByHit.Add(__0, half);
	}

	private static float Mult(Half t, string label, float factor, float before)
	{
		if (Mathf.Abs(factor - 1f) < 0.001f)
		{
			return before;
		}
		float num = before * factor;
		t.Steps.Add(new Step(label, "×" + F(factor), before, num));
		return num;
	}

	private static void ModifyDamagePostfix(HitData __0)
	{
		if (AttackByHit.TryGetValue(__0, out var value))
		{
			Reconcile(value, Total(__0), "Ajuste do jogo/mods");
		}
	}

	private static void Reconcile(Half t, float actual, string label)
	{
		float num = ((t.Steps.Count > 0) ? t.Steps[t.Steps.Count - 1].After : actual);
		if (!(Mathf.Abs(actual - num) < 0.05f))
		{
			string detail = ((num > 0.01f) ? ("×" + F(actual / num)) : "");
			t.Steps.Add(new Step(label, detail, num, actual));
		}
	}

	private static void ModifyAttackPrefix(ref HitData __1)
	{
		if (__1 != null && AttackByHit.TryGetValue(__1, out var value))
		{
			Reconcile(value, Total(__1), "Bônus do golpe (fim de combo)");
		}
	}

	private static void ModifyAttackPostfix(SEMan __instance, ref HitData __1)
	{
		if (__1 == null || !AttackByHit.TryGetValue(__1, out var value))
		{
			return;
		}
		float after = value.Steps[value.Steps.Count - 1].After;
		float num = Total(__1);
		if (Mathf.Abs(num - after) < 0.05f)
		{
			return;
		}
		List<string> list = new List<string>();
		foreach (StatusEffect statusEffect in __instance.GetStatusEffects())
		{
			if ((Object)(object)statusEffect != (Object)null && !string.IsNullOrEmpty(statusEffect.m_name))
			{
				list.Add((Localization.instance != null) ? Localization.instance.Localize(statusEffect.m_name) : statusEffect.m_name);
			}
		}
		value.Steps.Add(new Step("Efeitos no atacante", "×" + F(num / Mathf.Max(0.01f, after)) + ((list.Count > 0) ? (" (" + string.Join(", ", list.ToArray()) + ")") : ""), after, num));
	}

	private static void SourceSetup(object __instance, HitData __3)
	{
		if (__3 != null && AttackByHit.TryGetValue(__3, out var value))
		{
			AttackBySource.Remove(__instance);
			AttackBySource.Add(__instance, value);
		}
	}

	private static string SourceName(object source)
	{
		Component val = (Component)((source is Component) ? source : null);
		if (!((Object)(object)val != (Object)null))
		{
			return "?";
		}
		return ((Object)val.gameObject).name.Replace("(Clone)", "").Trim();
	}

	private static void SourceHitPrefix(object __instance, out object __state)
	{
		__state = currentSource;
		currentSource = __instance;
	}

	private static Exception SourceHitFinalizer(Exception __exception, object __state)
	{
		currentSource = __state;
		return __exception;
	}

	private static void DeliverPrefix(Character __instance, HitData __0)
	{
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		if (__0 == null)
		{
			return;
		}
		Character attacker = __0.GetAttacker();
		if (IsLocal(attacker) || IsLocal(__instance) || __instance is Player)
		{
			if (!AttackByHit.TryGetValue(__0, out var value) && (currentSource == null || !AttackBySource.TryGetValue(currentSource, out value)))
			{
				value = new Half();
				value.AttackerName = Source(attacker, __0);
				string label = ((currentSource is Aoe) ? ("Efeito de área: " + SourceName(currentSource)) : ((currentSource is Projectile) ? ("Projétil: " + SourceName(currentSource)) : (((Object)(object)attacker == (Object)null) ? ("Causa: " + Source(null, __0)) : "Golpe sem detalhamento (origem não rastreada)")));
				float num = Total(__0);
				value.Steps.Add(new Step(label, DamageText(__0.m_damage) + ((currentSource != null) ? " (dano próprio do efeito)" : ""), num, num));
			}
			Half half = new Half();
			half.IsAttack = true;
			half.Steps.AddRange(value.Steps);
			half.AttackerName = Source(attacker, __0);
			half.VictimName = Name(__instance);
			half.Attacker = __0.m_attacker;
			half.Victim = Id(__instance);
			half.Key = Total(__0);
			Reconcile(half, half.Key, (currentSource is Projectile) ? "Ajuste do projétil" : ((currentSource is Aoe) ? "Ajuste da área" : "Ajuste do jogo/mods"));
			if (IsLocal(attacker) || IsLocal(__instance))
			{
				Log.Merge(half);
			}
			if (__instance is Player && !IsLocal(__instance))
			{
				Net.Send(__instance, half);
			}
		}
	}

	private static void DefensePrefix(Character __instance, HitData __1, out Ctx __state)
	{
		//IL_006e: 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_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		__state = null;
		if (__1 != null && !((Object)(object)Player.m_localPlayer == (Object)null))
		{
			Character attacker = __1.GetAttacker();
			if ((IsLocal(__instance) || attacker is Player) && !__instance.IsDead() && !__instance.IsTeleporting() && !__instance.InCutscene())
			{
				Ctx ctx = new Ctx();
				ctx.Prev = current;
				ctx.Victim = __instance;
				ctx.Hit = __1;
				Half half = new Half();
				half.Attacker = __1.m_attacker;
				half.Victim = Id(__instance);
				half.Key = Total(__1);
				half.AttackerName = Source(attacker, __1);
				half.VictimName = Name(__instance);
				half.DamageText = DamageText(__1.m_damage);
				half.HpBefore = __instance.GetHealth();
				half.HpMax = __instance.GetMaxHealth();
				half.StaggerBefore = Bar(__instance);
				half.StaggerMax = GetStaggerTreshold(__instance);
				ctx.Half = half;
				ctx.StaminaBefore = (IsLocal(__instance) ? Player.m_localPlayer.GetStamina() : 0f);
				current = ctx;
				__state = ctx;
			}
		}
	}

	private static Exception DefenseFinalizer(Exception __exception, Ctx __state)
	{
		if (__state != null)
		{
			current = __state.Prev;
		}
		return __exception;
	}

	private static void DefensePostfix(Character __instance, Ctx __state)
	{
		if (__state != null)
		{
			Half half = __state.Half;
			half.HpAfter = __instance.GetHealth();
			half.StaggerAfter = Bar(__instance);
			half.Killed = __instance.IsDead() || half.HpAfter <= 0f;
			if (IsLocal(__instance))
			{
				half.Stamina = __state.StaminaBefore - Player.m_localPlayer.GetStamina();
			}
			if (half.Steps.Count == 0 && half.HpAfter >= half.HpBefore)
			{
				half.Dodged = true;
			}
			Character attacker = __state.Hit.GetAttacker();
			if (IsLocal(attacker) || IsLocal(__instance))
			{
				Log.Merge(half);
			}
			if (attacker is Player && !IsLocal(attacker))
			{
				Net.Send(attacker, half);
			}
		}
	}

	private static Ctx Active(HitData hit)
	{
		Ctx ctx = current;
		if (ctx == null || ctx.Hit != hit)
		{
			return null;
		}
		return ctx;
	}

	private static IEnumerable<CodeInstruction> DefenseTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		MethodInfo methodInfo = AccessTools.Method(typeof(HitData), "ApplyModifier", new Type[1] { typeof(float) }, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(typeof(HitData), "ApplyArmor", (Type[])null, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(typeof(HitData), "ApplyResistance", (Type[])null, (Type[])null);
		MethodInfo methodInfo4 = AccessTools.Method(typeof(SEMan), "OnDamaged", (Type[])null, (Type[])null);
		for (int i = 0; i < list.Count; i++)
		{
			CodeInstruction val = list[i];
			if (CodeInstructionExtensions.Calls(val, methodInfo) || CodeInstructionExtensions.Calls(val, methodInfo2))
			{
				bool flag = CodeInstructionExtensions.Calls(val, methodInfo2);
				int count = SiteLabels.Count;
				SiteLabels.Add(flag ? ArmorLabel(list, i) : ModifierLabel(list, i));
				val.opcode = OpCodes.Call;
				val.operand = AccessTools.Method(typeof(Combat), flag ? "WArmor" : "WModifier", (Type[])null, (Type[])null);
				CodeInstruction val2 = new CodeInstruction(OpCodes.Ldc_I4, (object)count);
				val2.labels.AddRange(val.labels);
				val.labels.Clear();
				list.Insert(i, val2);
				i++;
			}
			else if (CodeInstructionExtensions.Calls(val, methodInfo3))
			{
				val.opcode = OpCodes.Call;
				val.operand = AccessTools.Method(typeof(Combat), "WResistance", (Type[])null, (Type[])null);
			}
			else if (CodeInstructionExtensions.Calls(val, methodInfo4))
			{
				val.opcode = OpCodes.Call;
				val.operand = AccessTools.Method(typeof(Combat), "WOnDamaged", (Type[])null, (Type[])null);
			}
		}
		return list;
	}

	private static bool Back(List<CodeInstruction> code, int i, int range, Func<CodeInstruction, bool> test)
	{
		int num = i - 1;
		while (num >= 0 && num >= i - range)
		{
			if (test(code[num]))
			{
				return true;
			}
			num--;
		}
		return false;
	}

	private static bool LoadsField(CodeInstruction ci, string name)
	{
		FieldInfo fieldInfo = ci.operand as FieldInfo;
		if (fieldInfo != null)
		{
			return fieldInfo.Name == name;
		}
		return false;
	}

	private static bool CallsNamed(CodeInstruction ci, string name)
	{
		MethodInfo methodInfo = ci.operand as MethodInfo;
		if (methodInfo != null)
		{
			return methodInfo.Name == name;
		}
		return false;
	}

	private static string ModifierLabel(List<CodeInstruction> code, int i)
	{
		if (Back(code, i, 2, (CodeInstruction c) => LoadsField(c, "m_enemyDamageRate")))
		{
			return "Mundo: dano dos inimigos";
		}
		if (Back(code, i, 2, (CodeInstruction c) => LoadsField(c, "m_playerDamageRate")))
		{
			return "Mundo: dano dos jogadores";
		}
		if (Back(code, i, 2, (CodeInstruction c) => LoadsField(c, "m_localDamgeTakenRate")))
		{
			return "Dano recebido (dificuldade)";
		}
		if (Back(code, i, 2, (CodeInstruction c) => LoadsField(c, "m_backstabBonus")))
		{
			return "Ataque furtivo (backstab)";
		}
		if (Back(code, i, 3, (CodeInstruction c) => CallsNamed(c, "GetDifficultyDamageScalePlayer")))
		{
			return "Escala por nº de jogadores (contra jogador)";
		}
		if (Back(code, i, 6, (CodeInstruction c) => CallsNamed(c, "GetDifficultyDamageScaleEnemy")))
		{
			return "Escala por nº de jogadores (contra inimigo)";
		}
		if (Back(code, i, 2, (CodeInstruction c) => c.opcode == OpCodes.Ldc_R4 && c.operand is float && (float)c.operand == 2f))
		{
			return "Alvo em stagger";
		}
		return "Modificador";
	}

	private static string ArmorLabel(List<CodeInstruction> code, int i)
	{
		if (Back(code, i, 3, (CodeInstruction c) => CallsNamed(c, "GetBodyArmor")))
		{
			return "Armadura";
		}
		if (Back(code, i, 4, (CodeInstruction c) => LoadsField(c, "m_worldLevelEnemyBaseAC")))
		{
			return "Armadura base (nível do mundo)";
		}
		return "Armadura";
	}

	private static void WModifier(HitData hit, float factor, int site)
	{
		float before = Total(hit);
		hit.ApplyModifier(factor);
		Ctx ctx = Active(hit);
		if (ctx != null && Mathf.Abs(factor - 1f) > 0.001f)
		{
			ctx.Half.Steps.Add(new Step(SiteLabels[site], "×" + F(factor), before, Total(hit)));
		}
	}

	private static void WArmor(HitData hit, float armor, int site)
	{
		float num = Total(hit);
		hit.ApplyArmor(armor);
		Ctx ctx = Active(hit);
		if (ctx != null)
		{
			if (armor > 0f || num - Total(hit) > 0.05f)
			{
				ctx.Half.Steps.Add(new Step(SiteLabels[site] + " " + N(armor), "", num, Total(hit)));
			}
			ctx.AfterArmor = Total(hit);
		}
	}

	private static void WResistance(HitData hit, DamageModifiers mods, out DamageModifier significant)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		float num = Total(hit);
		DamageTypes damage = hit.m_damage;
		hit.ApplyResistance(mods, ref significant);
		Ctx ctx = Active(hit);
		if (ctx != null)
		{
			List<string> list = new List<string>();
			Res(list, damage.m_blunt, mods.m_blunt, "contundente");
			Res(list, damage.m_slash, mods.m_slash, "corte");
			Res(list, damage.m_pierce, mods.m_pierce, "perfurante");
			Res(list, damage.m_fire, mods.m_fire, "fogo");
			Res(list, damage.m_frost, mods.m_frost, "gelo");
			Res(list, damage.m_lightning, mods.m_lightning, "raio");
			Res(list, damage.m_poison, mods.m_poison, "veneno");
			Res(list, damage.m_spirit, mods.m_spirit, "espírito");
			string label = ((hit.m_weakSpot >= 0) ? "Resistências (ponto fraco)" : "Resistências");
			if (list.Count > 0 || Mathf.Abs(num - Total(hit)) > 0.05f)
			{
				ctx.Half.Steps.Add(new Step(label, string.Join(", ", list.ToArray()), num, Total(hit)));
			}
		}
	}

	private static void Res(List<string> parts, float amount, DamageModifier mod, string type)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected I4, but got Unknown
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		if (!(amount < 0.5f) && (int)mod != 0)
		{
			parts.Add(type + " " + (mod - 1) switch
			{
				0 => "resistente", 
				4 => "muito resistente", 
				6 => "pouco resistente", 
				1 => "fraco", 
				5 => "muito fraco", 
				7 => "pouco fraco", 
				2 => "imune", 
				3 => "ignora", 
				_ => ((object)mod).ToString(), 
			});
		}
	}

	private static void WOnDamaged(SEMan seman, HitData hit, Character attacker)
	{
		float num = Total(hit);
		seman.OnDamaged(hit, attacker);
		Ctx ctx = Active(hit);
		if (ctx != null && Mathf.Abs(num - Total(hit)) > 0.05f)
		{
			ctx.Half.Steps.Add(new Step("Efeitos no alvo", "", num, Total(hit)));
		}
	}

	private static void BlockPrefix(Humanoid __instance, HitData __0)
	{
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Invalid comparison between Unknown and I4
		Ctx ctx = Active(__0);
		if (ctx != null && !((Object)(object)ctx.Victim != (Object)(object)__instance))
		{
			ItemData val = GetCurrentBlocker(__instance);
			if (val != null)
			{
				float timedBlockBonus = val.m_shared.m_timedBlockBonus;
				float num = (float)BlockTimer.GetValue(__instance);
				Half half = ctx.Half;
				half.Timed = num >= 0f && num < 0.25f;
				half.Parry = half.Timed && timedBlockBonus > 1f;
				half.BlockKind = (((int)val.m_shared.m_itemType != 5) ? "com arma" : ((timedBlockBonus <= 1f) ? "tower" : ((timedBlockBonus >= 2f) ? "buckler" : "redondo")));
				ctx.BlockBefore = Total(__0);
			}
		}
	}

	private static void BlockPostfix(Humanoid __instance, HitData __0, bool __result)
	{
		Ctx ctx = Active(__0);
		if (ctx != null && !((Object)(object)ctx.Victim != (Object)(object)__instance) && __result && ctx.Half.BlockKind.Length != 0)
		{
			Half half = ctx.Half;
			half.Blocked = true;
			half.Held = ctx.BlockBefore - Total(__0);
			string label = (half.Parry ? "Parry " : "Bloqueio ") + half.BlockKind + ((half.Timed && !half.Parry) ? " no tempo" : "");
			half.Steps.Add(new Step(label, half.GuardBroken ? "GUARDA QUEBRADA" : "", ctx.BlockBefore, Total(__0)));
		}
	}

	private static void ApplyDamagePrefix(Character __instance, HitData __0, out float __state)
	{
		__state = __instance.GetHealth();
		Ctx ctx = Active(__0);
		if (ctx != null)
		{
			float num = Total(__0);
			if (ctx.AfterArmor >= 0f && ctx.AfterArmor - num > 0.05f)
			{
				ctx.Half.Dot = ctx.AfterArmor - num;
				ctx.Half.Steps.Add(new Step("Vira dano contínuo (fogo/veneno/espírito)", "", ctx.AfterArmor, num));
			}
		}
	}

	private static void ApplyDamagePostfix(Character __instance, HitData __0, float __state)
	{
		float num = __state - __instance.GetHealth();
		Ctx ctx = Active(__0);
		if (ctx != null)
		{
			ctx.Half.Instant = num;
			float num2 = ((ctx.Half.Steps.Count > 0) ? ctx.Half.Steps[ctx.Half.Steps.Count - 1].After : ctx.Half.Key);
			if (Mathf.Abs(num2 - num) > 0.5f && num >= 0f)
			{
				ctx.Half.Steps.Add(new Step("Limite de vida/outros", "", num2, num));
			}
		}
		else if (num > 0f && (IsLocal(__instance) || IsLocal(__0.GetAttacker())))
		{
			Log.DotTick(__instance, __0, num);
		}
	}

	private static void StaggerPostfix(Character __instance)
	{
		Ctx ctx = current;
		if (ctx != null && (Object)(object)ctx.Victim == (Object)(object)__instance)
		{
			ctx.Half.Staggered = true;
			if (ctx.Half.BlockKind.Length > 0)
			{
				ctx.Half.GuardBroken = true;
			}
		}
		else if (Log.Near(__instance))
		{
			Log.Event(Log.Color(Name(__instance) + " CAMBALEOU", "ffcc40"));
		}
	}

	private static void AddStaggerPrefix(Character __instance, out float __state)
	{
		__state = Bar(__instance);
	}

	private static void AddStaggerPostfix(Character __instance, float __state, float __0)
	{
		Ctx ctx = current;
		if ((ctx == null || !((Object)(object)ctx.Victim == (Object)(object)__instance)) && !(__instance is Player) && Log.Near(__instance) && !(__0 <= 0f))
		{
			Log.Event(Log.Color(Name(__instance) + " +" + N(__0) + " stagger", "d0a0ff") + " (stagger " + N(__state) + "→" + N(Bar(__instance)) + "/" + N(GetStaggerTreshold(__instance)) + ")");
		}
	}

	private static void DeathPrefix(Player __instance)
	{
		if (IsLocal((Character)(object)__instance))
		{
			Log.Death();
		}
	}
}
internal static class Net
{
	private const string Rpc = "bub_CombatLog_Half";

	public static void Register()
	{
		if (ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.Register<ZPackage>("bub_CombatLog_Half", (Action<long, ZPackage>)OnHalf);
		}
	}

	public static void Send(Character to, Half half)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		if (ZRoutedRpc.instance != null && !((Object)(object)to == (Object)null))
		{
			ZNetView component = ((Component)to).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
			if (val != null)
			{
				ZPackage val2 = new ZPackage();
				half.Write(val2);
				ZRoutedRpc.instance.InvokeRoutedRPC(val.GetOwner(), "bub_CombatLog_Half", new object[1] { val2 });
			}
		}
	}

	private static void OnHalf(long sender, ZPackage p)
	{
		try
		{
			Log.Merge(Half.Read(p));
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[Combat Log] pacote de outro jogador inválido: " + ex.Message));
		}
	}
}
[BepInPlugin("bub.combatlog", "Combat Log", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "bub.combatlog";

	public const string Version = "1.0.0";

	internal static Plugin Instance;

	internal ConfigEntry<KeyboardShortcut> toggleKey;

	internal ConfigEntry<bool> writeFile;

	internal ConfigEntry<float> nearbyRange;

	internal ConfigEntry<float> recapSeconds;

	internal Widget widget;

	private void Awake()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Expected O, but got Unknown
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		Instance = this;
		toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Toggle key", new KeyboardShortcut((KeyCode)289, (KeyCode[])(object)new KeyCode[0]), "Shows/hides the widget (and closes the death recap).");
		writeFile = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Write file", true, "Write every hit, detailed, to BepInEx/CombatLog/<date>.log.");
		nearbyRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Nearby range", 40f, "Staggers of creatures within this distance are logged.");
		recapSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Death recap", "Seconds", 10f, new ConfigDescription("How far back the death recap looks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 60f), new object[0]));
		widget = new Widget(((BaseUnityPlugin)this).Config);
		Harmony val = new Harmony("bub.combatlog");
		Combat.Patch(val);
		val.Patch((MethodBase)AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin).GetMethod("RegisterRpc", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static void RegisterRpc()
	{
		Net.Register();
	}

	private void Update()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = toggleKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			if (Log.RecapVisible)
			{
				Log.HideRecap();
			}
			else
			{
				widget.ToggleVisible();
			}
		}
		Log.Tick();
	}

	private void OnDestroy()
	{
		Log.Close();
	}

	private void OnGUI()
	{
		widget.Draw();
	}
}
internal class Entry
{
	public Half Attack;

	public Half Defense;

	public float Created;

	public DateTime Time;

	public bool Final;

	public string Compact;

	public string Detailed;

	public Half Any => Defense ?? Attack;

	public bool Incoming
	{
		get
		{
			//IL_0015: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return Any.Victim == ((Character)localPlayer).GetZDOID();
			}
			return false;
		}
	}
}
internal static class Log
{
	public class Item
	{
		public string Compact;

		public string Detail;

		public bool Expanded;
	}

	private class Dot
	{
		public string Victim;

		public string Type;

		public string Source;

		public float Amount;

		public float HpStart;

		public float HpEnd;

		public float Started;

		public bool Incoming;
	}

	private class DotRecord
	{
		public float Time;

		public string Source;

		public float Amount;
	}

	private static readonly List<Entry> pending = new List<Entry>();

	private static readonly List<Entry> finished = new List<Entry>();

	public static readonly List<Item> Items = new List<Item>();

	public static int Added;

	private static readonly Dictionary<string, Dot> dots = new Dictionary<string, Dot>();

	private static readonly List<DotRecord> dotHistory = new List<DotRecord>();

	private static string recap;

	private static float recapShownAt = -1f;

	private static StreamWriter file;

	public static bool RecapVisible
	{
		get
		{
			if (recap != null)
			{
				return Time.time - recapShownAt < 45f;
			}
			return false;
		}
	}

	public static void HideRecap()
	{
		recap = null;
	}

	public static string RecapText()
	{
		return recap;
	}

	public static string Color(string text, string hex)
	{
		return "<color=#" + hex + ">" + text + "</color>";
	}

	public static bool Near(Character c)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null && (Object)(object)c != (Object)null)
		{
			return Vector3.Distance(((Component)localPlayer).transform.position, ((Component)c).transform.position) <= Plugin.Instance.nearbyRange.Value;
		}
		return false;
	}

	private static string Stamp(DateTime t)
	{
		return t.ToString("HH:mm:ss");
	}

	public static void Merge(Half h)
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Entry entry = null;
		float num = float.MaxValue;
		foreach (Entry item in pending)
		{
			Half half = (h.IsAttack ? item.Defense : item.Attack);
			Half half2 = (h.IsAttack ? item.Attack : item.Defense);
			if (half2 == null && half != null && !(half.Attacker != h.Attacker) && !(half.Victim != h.Victim))
			{
				float num2 = Mathf.Abs(half.Key - h.Key);
				if (num2 < num)
				{
					num = num2;
					entry = item;
				}
			}
		}
		if (entry == null)
		{
			entry = new Entry();
			entry.Created = Time.time;
			entry.Time = DateTime.Now;
			pending.Add(entry);
		}
		if (h.IsAttack)
		{
			entry.Attack = h;
		}
		else
		{
			entry.Defense = h;
		}
		if (entry.Attack != null && entry.Defense != null)
		{
			Finish(entry);
		}
	}

	public static void Tick()
	{
		for (int num = pending.Count - 1; num >= 0; num--)
		{
			if (Time.time - pending[num].Created > 1.5f)
			{
				Finish(pending[num]);
			}
		}
		List<string> list = null;
		foreach (KeyValuePair<string, Dot> dot in dots)
		{
			if (Time.time - dot.Value.Started > 3f)
			{
				if (list == null)
				{
					list = new List<string>();
				}
				list.Add(dot.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (string item in list)
		{
			FlushDot(item);
		}
	}

	private static void Finish(Entry e)
	{
		pending.Remove(e);
		e.Final = true;
		e.Compact = CompactLine(e);
		e.Detailed = DetailedBlock(e);
		finished.Add(e);
		if (finished.Count > 300)
		{
			finished.RemoveAt(0);
		}
		AddItem(e.Compact, e.Detailed);
		WriteFile(e.Detailed);
	}

	public static void Event(string text)
	{
		string text2 = Stamp(DateTime.Now) + "  " + text;
		AddItem(text2, null);
		WriteFile(text2);
	}

	private static void AddItem(string compact, string detail)
	{
		Item item = new Item();
		item.Compact = compact;
		item.Detail = detail;
		Items.Add(item);
		Added++;
		if (Items.Count > 300)
		{
			Items.RemoveAt(0);
		}
	}

	private static string CompactLine(Entry e)
	{
		Half attack = e.Attack;
		Half defense = e.Defense;
		Half any = e.Any;
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append(Stamp(e.Time)).Append("  ");
		stringBuilder.Append(Color(any.AttackerName + " → " + Who(any.VictimName, e), e.Incoming ? "ff9a7a" : "9ad0ff")).Append(": ");
		if (defense == null)
		{
			stringBuilder.Append("golpe ").Append(Combat.N(attack.Key)).Append(Color(" (defesa calculada em outro PC sem o mod)", "999999"));
			return stringBuilder.ToString();
		}
		if (defense.Dodged)
		{
			return stringBuilder.Append(Color("IGNORADO (esquiva/invulnerável)", "8fe08f")).ToString();
		}
		float v = defense.HpBefore - defense.HpAfter;
		stringBuilder.Append(Color(Combat.N(v) + " de dano", "ff7070"));
		if (defense.Dot > 0.5f)
		{
			stringBuilder.Append(" + ").Append(Combat.N(defense.Dot)).Append(" contínuo");
		}
		if (defense.Blocked)
		{
			stringBuilder.Append(" | ").Append(Color((defense.Parry ? "parry " : "bloqueou ") + Combat.N(defense.Held) + " (" + defense.BlockKind + ((defense.Timed && !defense.Parry) ? ", no tempo" : "") + ")", "8fe08f"));
		}
		if (defense.GuardBroken)
		{
			stringBuilder.Append(" | ").Append(Color("GUARDA QUEBRADA", "ff5050"));
		}
		else if (defense.Staggered)
		{
			stringBuilder.Append(" | ").Append(Color("CAMBALEOU", "ffcc40"));
		}
		stringBuilder.Append(" | vida ").Append(Combat.N(defense.HpBefore)).Append("→")
			.Append(Combat.N(defense.HpAfter));
		if (Mathf.Abs(defense.Stamina) >= 0.5f)
		{
			stringBuilder.Append(" | stamina ").Append((defense.Stamina > 0f) ? "−" : "+").Append(Combat.N(Mathf.Abs(defense.Stamina)));
		}
		stringBuilder.Append(" | stagger ").Append(Combat.N(defense.StaggerBefore)).Append("→")
			.Append(Combat.N(defense.StaggerAfter))
			.Append("/")
			.Append(Combat.N(defense.StaggerMax));
		if (defense.Killed)
		{
			stringBuilder.Append(" | ").Append(Color("MORREU", "ff5050"));
		}
		if (attack == null)
		{
			stringBuilder.Append(Color(" (ataque calculado em outro PC sem o mod)", "999999"));
		}
		return stringBuilder.ToString();
	}

	private static string Who(string name, Entry e)
	{
		if (!e.Incoming)
		{
			return name;
		}
		return "você";
	}

	private static string DetailedBlock(Entry e)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		Half attack = e.Attack;
		Half defense = e.Defense;
		Half any = e.Any;
		StringBuilder stringBuilder = new StringBuilder();
		string text = any.AttackerName;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null && any.Attacker == ((Character)localPlayer).GetZDOID())
		{
			text = "você";
		}
		stringBuilder.Append(Stamp(e.Time)).Append("  ").Append(Color(text + " → " + Who(any.VictimName, e), e.Incoming ? "ff9a7a" : "9ad0ff"));
		if (defense != null && !defense.Dodged)
		{
			stringBuilder.Append("  —  ").Append(Color(Combat.N(defense.HpBefore - defense.HpAfter) + " de dano", "ff7070")).Append("  (vida ")
				.Append(Combat.N(defense.HpBefore))
				.Append(" → ")
				.Append(Combat.N(defense.HpAfter))
				.Append(")");
		}
		if (defense != null && defense.Dodged)
		{
			stringBuilder.Append("  —  ").Append(Color("IGNORADO (esquiva/invulnerável)", "8fe08f"));
		}
		stringBuilder.Append("\n  ").Append(Color("ATAQUE", "e0c070"));
		if (attack == null)
		{
			stringBuilder.Append("\n    ").Append(Color("indisponível (calculado em outro PC sem o mod) — golpe chegou com " + Combat.N(any.Key), "999999"));
		}
		else
		{
			foreach (Step step in attack.Steps)
			{
				stringBuilder.Append("\n    ").Append(StepLine(step));
			}
		}
		stringBuilder.Append("\n  ").Append(Color("DEFESA", "e0c070"));
		if (defense == null)
		{
			stringBuilder.Append("\n    ").Append(Color("indisponível (calculado em outro PC sem o mod)", "999999"));
		}
		else
		{
			if (defense.DamageText.Length > 0)
			{
				stringBuilder.Append("\n    Golpe recebido  ").Append(defense.DamageText).Append("  = ")
					.Append(Combat.N(defense.Key));
			}
			foreach (Step step2 in defense.Steps)
			{
				stringBuilder.Append("\n    ").Append(StepLine(step2));
			}
			if (!defense.Dodged)
			{
				stringBuilder.Append("\n  = ").Append(Combat.N(defense.Instant)).Append(" na hora");
				if (defense.Dot > 0.5f)
				{
					stringBuilder.Append(" · ").Append(Combat.N(defense.Dot)).Append(" contínuo");
				}
				if (defense.Blocked && Mathf.Abs(defense.Stamina) >= 0.5f)
				{
					stringBuilder.Append(" · stamina −").Append(Combat.N(defense.Stamina));
				}
				stringBuilder.Append(" · stagger ").Append(Combat.N(defense.StaggerBefore)).Append("→")
					.Append(Combat.N(defense.StaggerAfter))
					.Append("/")
					.Append(Combat.N(defense.StaggerMax));
				if (defense.GuardBroken)
				{
					stringBuilder.Append(" · ").Append(Color("GUARDA QUEBRADA", "ff5050"));
				}
				else if (defense.Staggered)
				{
					stringBuilder.Append(" · ").Append(Color("CAMBALEOU", "ffcc40"));
				}
				if (defense.Killed)
				{
					stringBuilder.Append(" · ").Append(Color("MORREU", "ff5050"));
				}
			}
		}
		return stringBuilder.ToString();
	}

	private static string StepLine(Step s)
	{
		string text = (string.IsNullOrEmpty(s.Detail) ? "" : ("  " + Color(s.Detail, "b8b8b8")));
		if (Mathf.Abs(s.Before - s.After) < 0.05f)
		{
			return s.Label + text + "  " + Combat.N(s.After);
		}
		string text2 = ((s.After < s.Before) ? Color(" (−" + Combat.N(s.Before - s.After) + ")", "8fe08f") : Color(" (+" + Combat.N(s.After - s.Before) + ")", "ff9a7a"));
		return s.Label + text + "  " + Combat.N(s.Before) + " → " + Combat.N(s.After) + text2;
	}

	public static void DotTick(Character victim, HitData hit, float lost)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		string text = ((hit.m_damage.m_poison > 0f) ? "veneno" : ((hit.m_damage.m_fire > 0f) ? "fogo" : ((hit.m_damage.m_spirit > 0f) ? "espírito" : ((hit.m_damage.m_frost > 0f) ? "gelo" : "dano contínuo"))));
		Character attacker = hit.GetAttacker();
		string key = ((object)victim.GetZDOID()/*cast due to .constrained prefix*/).ToString() + "|" + text;
		if (!dots.TryGetValue(key, out var value))
		{
			value = new Dot();
			value.Victim = (((Object)(object)victim == (Object)(object)Player.m_localPlayer) ? "você" : Combat.Name(victim));
			value.Type = text;
			value.Source = (((Object)(object)attacker != (Object)null) ? Combat.Name(attacker) : text);
			value.HpStart = victim.GetHealth() + lost;
			value.Started = Time.time;
			value.Incoming = (Object)(object)victim == (Object)(object)Player.m_localPlayer;
			dots[key] = value;
		}
		value.Amount += lost;
		value.HpEnd = victim.GetHealth();
		if (value.Incoming)
		{
			DotRecord dotRecord = new DotRecord();
			dotRecord.Time = Time.time;
			dotRecord.Source = value.Source + " (" + text + ")";
			dotRecord.Amount = lost;
			dotHistory.Add(dotRecord);
			if (dotHistory.Count > 400)
			{
				dotHistory.RemoveAt(0);
			}
		}
	}

	private static void FlushDot(string key)
	{
		Dot dot = dots[key];
		dots.Remove(key);
		Event(Color(dot.Victim + ": " + dot.Type, dot.Incoming ? "ff9a7a" : "9ad0ff") + " " + Combat.N(dot.Amount) + " em " + Combat.N(Mathf.Max(1f, Time.time - dot.Started)) + " s (vida " + Combat.N(dot.HpStart) + "→" + Combat.N(dot.HpEnd) + ")" + ((dot.Source != dot.Type) ? (" — de " + dot.Source) : ""));
	}

	public static void Death()
	{
		for (int num = pending.Count - 1; num >= 0; num--)
		{
			Finish(pending[num]);
		}
		float value = Plugin.Instance.recapSeconds.Value;
		DateTime dateTime = DateTime.Now.AddSeconds(0f - value);
		Dictionary<string, float[]> dictionary = new Dictionary<string, float[]>();
		Entry entry = null;
		float num2 = 0f;
		foreach (Entry item in finished)
		{
			if (item.Incoming && !(item.Time < dateTime) && item.Defense != null)
			{
				float num3 = Mathf.Max(0f, item.Defense.HpBefore - item.Defense.HpAfter);
				Add(dictionary, item.Any.AttackerName, num3, 1f);
				num2 += num3;
				entry = item;
			}
		}
		foreach (DotRecord item2 in dotHistory)
		{
			if (!(Time.time - item2.Time > value))
			{
				Add(dictionary, item2.Source, item2.Amount, 0f);
				num2 += item2.Amount;
			}
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append(Color("VOCÊ MORREU", "ff5050")).Append("  —  ").Append(Combat.N(num2))
			.Append(" de dano nos últimos ")
			.Append(Combat.N(value))
			.Append(" s");
		List<KeyValuePair<string, float[]>> list = new List<KeyValuePair<string, float[]>>(dictionary);
		list.Sort((KeyValuePair<string, float[]> x, KeyValuePair<string, float[]> y) => y.Value[0].CompareTo(x.Value[0]));
		foreach (KeyValuePair<string, float[]> item3 in list)
		{
			float v = ((num2 > 0f) ? (item3.Value[0] / num2 * 100f) : 0f);
			stringBuilder.Append("\n  ").Append(item3.Key).Append(": ")
				.Append(Combat.N(item3.Value[0]))
				.Append(" (")
				.Append(Combat.N(v))
				.Append("%)");
			if (item3.Value[1] > 0f)
			{
				stringBuilder.Append(", ").Append(Combat.N(item3.Value[1])).Append((item3.Value[1] > 1f) ? " golpes" : " golpe");
			}
		}
		if (entry != null)
		{
			stringBuilder.Append("\n\n").Append(Color("Último golpe", "e0c070")).Append("\n")
				.Append(entry.Detailed);
		}
		stringBuilder.Append("\n\n").Append(Color("F8 fecha", "999999"));
		recap = stringBuilder.ToString();
		recapShownAt = Time.time;
		WriteFile("===== RESUMO DE MORTE =====\n" + recap + "\n===========================");
	}

	private static void Add(Dictionary<string, float[]> d, string key, float dmg, float hits)
	{
		if (!d.TryGetValue(key, out var value))
		{
			value = (d[key] = new float[2]);
		}
		value[0] += dmg;
		value[1] += hits;
	}

	private static void WriteFile(string text)
	{
		if (!Plugin.Instance.writeFile.Value)
		{
			return;
		}
		try
		{
			if (file == null)
			{
				string text2 = Path.Combine(Paths.BepInExRootPath, "CombatLog");
				Directory.CreateDirectory(text2);
				file = new StreamWriter(Path.Combine(text2, DateTime.Now.ToString("yyyy-MM-dd") + ".log"), append: true, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				file.AutoFlush = true;
			}
			file.WriteLine(StripTags(text));
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[Combat Log] não consegui gravar o arquivo: " + ex.Message));
			Plugin.Instance.writeFile.Value = false;
		}
	}

	public static void Close()
	{
		if (file != null)
		{
			file.Close();
		}
	}

	public static string Plain(string s)
	{
		return StripTags(s);
	}

	private static string StripTags(string s)
	{
		StringBuilder stringBuilder = new StringBuilder(s.Length);
		bool flag = false;
		foreach (char c in s)
		{
			switch (c)
			{
			case '<':
				flag = true;
				continue;
			case '>':
				flag = false;
				continue;
			}
			if (!flag)
			{
				stringBuilder.Append(c);
			}
		}
		return stringBuilder.ToString();
	}
}
internal class Widget
{
	private const float Margin = 12f;

	private const float BarHeight = 22f;

	private const float Grip = 16f;

	private const int MaxShown = 120;

	private readonly ConfigEntry<bool> visible;

	private readonly ConfigEntry<bool> minimized;

	private readonly ConfigEntry<bool> detailAll;

	private readonly ConfigEntry<int> width;

	private readonly ConfigEntry<int> height;

	private readonly ConfigEntry<int> fontSize;

	private readonly ConfigEntry<float> opacity;

	private float curW;

	private float curH;

	private Vector2 scroll;

	private bool stick = true;

	private int seenAdded = -1;

	private float contentHeight;

	private bool resizing;

	private bool textMode;

	private string plain;

	private int plainAdded = -1;

	private bool plainDetail;

	private string toast;

	private float toastUntil;

	private Vector2 resizeMouse;

	private Vector2 resizeSize;

	private GUIStyle text;

	private GUIStyle entry;

	private GUIStyle title;

	private GUIStyle button;

	private GUIStyle area;

	private Texture2D bg;

	private Texture2D bar;

	private Texture2D hover;

	private int styledFont = -1;

	public Widget(ConfigFile config)
	{
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected O, but got Unknown
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Expected O, but got Unknown
		visible = config.Bind<bool>("Widget", "Visible", true, "Widget shown (F8 toggles).");
		minimized = config.Bind<bool>("Widget", "Minimized", false, "Only the title bar with the last line.");
		detailAll = config.Bind<bool>("Widget", "Detailed", false, "Show every hit detailed (otherwise click a hit to expand it).");
		width = config.Bind<int>("Widget", "Width", 560, "Width in pixels (drag the top-left corner to resize).");
		height = config.Bind<int>("Widget", "Height", 260, "Height in pixels.");
		fontSize = config.Bind<int>("Widget", "Font size", 13, new ConfigDescription("Text size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(9, 24), new object[0]));
		opacity = config.Bind<float>("Widget", "Background opacity", 0.6f, new ConfigDescription("0 = transparent, 1 = solid.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		curW = width.Value;
		curH = height.Value;
	}

	public void ToggleVisible()
	{
		visible.Value = !visible.Value;
	}

	private void Init()
	{
		//IL_0038: 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_0084: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Expected O, but got Unknown
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Expected O, but got Unknown
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Expected O, but got Unknown
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_0258: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0277: Expected O, but got Unknown
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Expected O, but got Unknown
		if (text == null || styledFont != fontSize.Value)
		{
			styledFont = fontSize.Value;
			text = new GUIStyle(GUI.skin.label);
			text.richText = true;
			text.wordWrap = true;
			text.fontSize = fontSize.Value;
			text.margin = new RectOffset(2, 2, 1, 1);
			text.padding = new RectOffset(4, 4, 1, 1);
			text.normal.textColor = new Color(0.92f, 0.9f, 0.85f);
			hover = Solid(new Color(1f, 1f, 1f, 0.08f));
			entry = new GUIStyle(text);
			entry.hover.background = hover;
			entry.hover.textColor = Color.white;
			entry.active.background = hover;
			entry.active.textColor = Color.white;
			title = new GUIStyle(text);
			title.wordWrap = false;
			title.clipping = (TextClipping)1;
			title.fontStyle = (FontStyle)1;
			title.alignment = (TextAnchor)3;
			area = new GUIStyle(GUI.skin.textArea);
			area.richText = false;
			area.wordWrap = true;
			area.fontSize = fontSize.Value;
			area.normal.background = null;
			area.focused.background = null;
			area.hover.background = null;
			area.normal.textColor = new Color(0.92f, 0.9f, 0.85f);
			area.focused.textColor = area.normal.textColor;
			area.hover.textColor = area.normal.textColor;
			button = new GUIStyle(GUI.skin.button);
			button.fontSize = Mathf.Max(10, fontSize.Value - 2);
			button.padding = new RectOffset(4, 4, 1, 1);
		}
	}

	private static Texture2D Solid(Color c)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(1, 1);
		val.SetPixel(0, 0, c);
		val.Apply();
		return val;
	}

	private void Backgrounds()
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)bg == (Object)null || !Mathf.Approximately(bg.GetPixel(0, 0).a, opacity.Value))
		{
			bg = Solid(new Color(0.03f, 0.03f, 0.03f, opacity.Value));
			bar = Solid(new Color(0.12f, 0.1f, 0.07f, Mathf.Min(1f, opacity.Value + 0.2f)));
		}
	}

	public void Draw()
	{
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_039a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0438: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Game.instance == (Object)null)
		{
			return;
		}
		Init();
		Backgrounds();
		if (Log.RecapVisible)
		{
			DrawRecap();
		}
		if (!visible.Value)
		{
			return;
		}
		bool flag = Cursor.visible;
		float num = Mathf.Clamp(curW, 280f, (float)Screen.width - 24f);
		float num2 = (minimized.Value ? 22f : Mathf.Clamp(curH, 82f, (float)Screen.height - 24f));
		Rect val = default(Rect);
		((Rect)(ref val))..ctor((float)Screen.width - num - 12f, (float)Screen.height - num2 - 12f, num, num2);
		if (flag && !minimized.Value)
		{
			HandleResize(val);
		}
		GUI.DrawTexture(val, (Texture)(object)bg);
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(((Rect)(ref val)).x, ((Rect)(ref val)).y, num, 22f);
		GUI.DrawTexture(val2, (Texture)(object)bar);
		float num3 = ((Rect)(ref val)).xMax - 4f;
		if (flag)
		{
			num3 -= 24f;
			if (GUI.Button(new Rect(num3, ((Rect)(ref val)).y + 2f, 22f, 18f), minimized.Value ? "▴" : "▾", button))
			{
				minimized.Value = !minimized.Value;
			}
			if (!minimized.Value)
			{
				num3 -= 82f;
				if (GUI.Button(new Rect(num3, ((Rect)(ref val)).y + 2f, 80f, 18f), detailAll.Value ? "Detalhado" : "Lista", button))
				{
					detailAll.Value = !detailAll.Value;
				}
				num3 -= 58f;
				if (GUI.Button(new Rect(num3, ((Rect)(ref val)).y + 2f, 56f, 18f), textMode ? "Normal" : "Texto", button))
				{
					textMode = !textMode;
				}
				num3 -= 62f;
				if (GUI.Button(new Rect(num3, ((Rect)(ref val)).y + 2f, 60f, 18f), "Copiar", button))
				{
					Copy(PlainText(), "log copiado");
				}
			}
		}
		string text = "Combat Log";
		if (toast != null && Time.unscaledTime < toastUntil)
		{
			text = text + "   <color=#8fe08f>" + toast + "</color>";
		}
		else if (minimized.Value && Log.Items.Count > 0)
		{
			text = text + "   " + Log.Items[Log.Items.Count - 1].Compact;
		}
		else if (!flag)
		{
			object obj = text;
			text = string.Concat(obj, "   <color=#8a8a8a><size=", Mathf.Max(9, fontSize.Value - 2), ">Tab libera o mouse</size></color>");
		}
		float num4 = ((Rect)(ref val)).x + ((flag && !minimized.Value) ? 20f : 6f);
		GUI.Label(new Rect(num4, ((Rect)(ref val)).y, num3 - num4 - 4f, 22f), text, title);
		if (flag && !minimized.Value)
		{
			GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, 16f, 16f), "<color=#c8a860>◤</color>", this.text);
		}
		if (!minimized.Value)
		{
			DrawBody(new Rect(((Rect)(ref val)).x + 2f, ((Rect)(ref val)).y + 22f + 2f, num - 4f, num2 - 22f - 4f), flag);
		}
	}

	private void HandleResize(Rect r)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Invalid comparison between Unknown and I4
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Invalid comparison between Unknown and I4
		//IL_00a6: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		Event current = Event.current;
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y, 20f, 20f);
		if ((int)current.type == 0 && current.button == 0 && ((Rect)(ref val)).Contains(current.mousePosition))
		{
			resizing = true;
			resizeMouse = current.mousePosition;
			resizeSize = new Vector2(((Rect)(ref r)).width, ((Rect)(ref r)).height);
			current.Use();
		}
		else if (resizing && (int)current.type == 3)
		{
			curW = Mathf.Clamp(resizeSize.x + (resizeMouse.x - current.mousePosition.x), 280f, (float)Screen.width - 24f);
			curH = Mathf.Clamp(resizeSize.y + (resizeMouse.y - current.mousePosition.y), 82f, (float)Screen.height - 24f);
			current.Use();
		}
		else if (resizing && (int)current.rawType == 1)
		{
			resizing = false;
			width.Value = Mathf.RoundToInt(curW);
			height.Value = Mathf.RoundToInt(curH);
			current.Use();
		}
	}

	private void DrawBody(Rect body, bool interactive)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Invalid comparison between Unknown and I4
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Invalid comparison between Unknown and I4
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		if (Log.Added != seenAdded)
		{
			seenAdded = Log.Added;
			if (stick)
			{
				scroll.y = float.MaxValue;
			}
		}
		GUILayout.BeginArea(body);
		scroll = GUILayout.BeginScrollView(scroll, false, false, GUIStyle.none, GUI.skin.verticalScrollbar, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (textMode)
		{
			GUILayout.TextArea(PlainText(), area, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		else if (Log.Items.Count == 0)
		{
			GUILayout.Label("<color=#8a8a8a>Nenhum golpe ainda.</color>", this.text, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		int num = Mathf.Max(0, Log.Items.Count - 120);
		int num2 = num;
		while (!textMode && num2 < Log.Items.Count)
		{
			Log.Item item = Log.Items[num2];
			bool flag = item.Detail != null && (detailAll.Value || item.Expanded);
			string text = (flag ? item.Detail : item.Compact);
			if (interactive && item.Detail != null && !detailAll.Value)
			{
				if (GUILayout.Button(text, entry, (GUILayoutOption[])(object)new GUILayoutOption[0]))
				{
					if (Event.current.button == 1)
					{
						Copy(Log.Plain(item.Detail), "golpe copiado");
					}
					else
					{
						item.Expanded = !item.Expanded;
					}
				}
			}
			else
			{
				GUILayout.Label(text, this.text, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			if (flag)
			{
				GUILayout.Space(4f);
			}
			num2++;
		}
		GUILayout.Label("", GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(0f) });
		if ((int)Event.current.type == 7)
		{
			Rect lastRect = GUILayoutUtility.GetLastRect();
			contentHeight = ((Rect)(ref lastRect)).yMax;
		}
		GUILayout.EndScrollView();
		GUILayout.EndArea();
		if ((int)Event.current.type == 7)
		{
			stick = scroll.y >= contentHeight - ((Rect)(ref body)).height - 8f;
		}
	}

	private string PlainText()
	{
		if (plain != null && plainAdded == Log.Added && plainDetail == detailAll.Value)
		{
			return plain;
		}
		StringBuilder stringBuilder = new StringBuilder();
		int num = Mathf.Max(0, Log.Items.Count - 120);
		for (int i = num; i < Log.Items.Count; i++)
		{
			Log.Item item = Log.Items[i];
			bool flag = item.Detail != null && (detailAll.Value || item.Expanded);
			stringBuilder.Append(Log.Plain(flag ? item.Detail : item.Compact)).AppendLine();
			if (flag)
			{
				stringBuilder.AppendLine();
			}
		}
		plain = stringBuilder.ToString();
		plainAdded = Log.Added;
		plainDetail = detailAll.Value;
		return plain;
	}

	private void Copy(string s, string what)
	{
		GUIUtility.systemCopyBuffer = s;
		toast = what;
		toastUntil = Time.unscaledTime + 2f;
	}

	private void DrawRecap()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		string text = Log.RecapText();
		float num = Mathf.Min(680f, (float)Screen.width - 24f);
		GUIContent val = new GUIContent(text);
		float num2 = this.text.CalcHeight(val, num - 16f) + 12f;
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(((float)Screen.width - num) * 0.5f, (float)Screen.height * 0.1f, num, num2);
		GUI.DrawTexture(val2, (Texture)(object)bar);
		GUI.Label(new Rect(((Rect)(ref val2)).x + 8f, ((Rect)(ref val2)).y + 6f, num - 16f, num2), val, this.text);
	}
}