Decompiled source of RoguelikeDebugger v0.1.1

plugins/RoguelikeDebugger/RoguelikeDebugger.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using Burst2Flame;
using Burst2Flame.Observable;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("RoguelikeDebugger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Logs de investigação de mecânicas do Stolen Realm (loot, Gold, Experience, eventos).")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("RoguelikeDebugger")]
[assembly: AssemblyTitle("RoguelikeDebugger")]
[assembly: AssemblyVersion("0.1.1.0")]
namespace RoguelikeDebugger
{
	internal static class EfeitosInfo
	{
		private static readonly Dictionary<string, int> Contagem = new Dictionary<string, int>();

		private static int _total;

		private static int _naoGeneralEffect;

		public static void Zerar()
		{
			Contagem.Clear();
			_total = 0;
			_naoGeneralEffect = 0;
		}

		public static string Resumo()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("total=").Append(_total);
			stringBuilder.Append(" | porTipo={");
			bool flag = true;
			List<string> list = new List<string>(Contagem.Keys);
			list.Sort(StringComparer.Ordinal);
			foreach (string item in list)
			{
				if (!flag)
				{
					stringBuilder.Append("; ");
				}
				flag = false;
				stringBuilder.Append(item).Append('=').Append(Contagem[item]);
			}
			stringBuilder.Append("}");
			stringBuilder.Append(" | naoGeneralEffect=").Append(_naoGeneralEffect);
			return stringBuilder.ToString();
		}

		public static int Conta(Array arr)
		{
			return arr?.Length ?? 0;
		}

		public static string Descreve(Array arr)
		{
			return DescreveCore(arr, origemIEffectInfo: false);
		}

		public static string Descreve(IEffectInfo[] arr)
		{
			return DescreveCore(arr, origemIEffectInfo: true);
		}

		private static string DescreveCore(Array arr, bool origemIEffectInfo)
		{
			if (arr == null || arr.Length == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < arr.Length; i++)
			{
				object value;
				try
				{
					value = arr.GetValue(i);
				}
				catch (Exception ex)
				{
					value = null;
					stringBuilder.Append(i).Append(":<erro:").Append(ex.GetType().Name)
						.Append(">; ");
					continue;
				}
				stringBuilder.Append(i).Append(':').Append(Um(value, origemIEffectInfo))
					.Append("; ");
			}
			return stringBuilder.ToString().TrimEnd(' ', ';');
		}

		private static string Um(object o, bool origemIEffectInfo)
		{
			if (o == null)
			{
				Contagem["null"] = ((!Contagem.TryGetValue("null", out var value)) ? 1 : (value + 1));
				_total++;
				return "null";
			}
			Type type = o.GetType();
			string name = type.Name;
			Contagem[name] = ((!Contagem.TryGetValue(name, out var value2)) ? 1 : (value2 + 1));
			_total++;
			if (origemIEffectInfo && !(o is GeneralEffect))
			{
				_naoGeneralEffect++;
			}
			FieldInfo[] array;
			try
			{
				array = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
			}
			catch (Exception)
			{
				array = new FieldInfo[0];
			}
			Array.Sort(array, (FieldInfo a, FieldInfo b) => string.CompareOrdinal(a.Name, b.Name));
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(name).Append('{');
			bool flag = true;
			FieldInfo[] array2 = array;
			foreach (FieldInfo fieldInfo in array2)
			{
				if (!fieldInfo.IsStatic)
				{
					object v;
					try
					{
						v = fieldInfo.GetValue(o);
					}
					catch (Exception ex2)
					{
						v = "<erro:" + ex2.GetType().Name + ">";
					}
					if (!flag)
					{
						stringBuilder.Append(';');
					}
					flag = false;
					stringBuilder.Append(fieldInfo.Name).Append('=').Append(Valor(v));
				}
			}
			stringBuilder.Append('}');
			return stringBuilder.ToString();
		}

		private static string Valor(object v)
		{
			if (v == null)
			{
				return "-";
			}
			Object val = (Object)((v is Object) ? v : null);
			if (val != (Object)null)
			{
				return Limpa(val.name);
			}
			if (v is string text)
			{
				if (text.Length != 0)
				{
					return Limpa(text);
				}
				return "-";
			}
			if (v is Array array)
			{
				return "[" + array.Length + "]";
			}
			return Limpa(v.ToString());
		}

		public static string Limpa(string s)
		{
			return (s ?? "").Replace("\n", " ").Replace("\r", " ").Replace("|", "/")
				.Replace("\"", "'")
				.Trim();
		}
	}
	[BepInPlugin("com.gumatos.roguelikedebugger", "Roguelike Debugger", "0.1.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Roguelike Debugger carregado.");
			AplicarPatches();
		}

		private static void AplicarPatches()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			Harmony val = new Harmony("com.gumatos.roguelikedebugger");
			List<string> list = new List<string>();
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Type[] types;
			try
			{
				types = typeof(Plugin).Assembly.GetTypes();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Roguelike Debugger: nao deu para listar os tipos do mod — nenhum gancho aplicado: " + ex));
				return;
			}
			foreach (Type type in types)
			{
				if (EhClasseDeGancho(type))
				{
					num++;
					try
					{
						int num4 = val.CreateClassProcessor(type).Patch()?.Count ?? 0;
						num3 += num4;
						num2++;
						Log.LogInfo((object)("Roguelike Debugger: gancho aplicado — " + type.Name + " (" + num4 + " metodo(s) do jogo)."));
					}
					catch (Exception ex2)
					{
						list.Add(type.Name);
						Log.LogError((object)("Roguelike Debugger: FALHA ao aplicar o gancho " + type.Name + " — " + ex2.Message));
					}
				}
			}
			string text = "Roguelike Debugger: patches Harmony aplicados (" + num2 + "/" + num + " ganchos, " + num3 + " metodos do jogo).";
			if (list.Count == 0)
			{
				Log.LogInfo((object)text);
			}
			else
			{
				Log.LogError((object)(text + " GANCHOS QUE FALHARAM: " + string.Join(", ", list.ToArray()) + ". O mod continua de pe, mas o log do recurso que dependia deles nao sai nesta sessao."));
			}
		}

		private static bool EhClasseDeGancho(Type tipo)
		{
			try
			{
				if (tipo == null || !tipo.IsClass)
				{
					return false;
				}
				return tipo.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0;
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
}
namespace RoguelikeDebugger.Patches
{
	[HarmonyPatch(typeof(Game), "get_ActionStatuses")]
	public static class ActionStatusInventoryPatch
	{
		private static bool _dumped;

		private static int _lastCount = -1;

		private static int _stableHits;

		private static string TriggersDe(ActionStatusInfo s)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s == (Object)null || s.SkillTriggers == null || s.SkillTriggers.Length == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			SkillTrigger[] skillTriggers = s.SkillTriggers;
			foreach (SkillTrigger val in skillTriggers)
			{
				if (val == null)
				{
					continue;
				}
				StringBuilder stringBuilder2 = new StringBuilder();
				if (val.ActionStatuses != null)
				{
					ActionStatusInfo[] actionStatuses = val.ActionStatuses;
					foreach (ActionStatusInfo val2 in actionStatuses)
					{
						if ((Object)(object)val2 != (Object)null)
						{
							stringBuilder2.Append(EfeitosInfo.Limpa(val2.Name)).Append(',');
						}
					}
				}
				StringBuilder stringBuilder3 = stringBuilder.Append(val.TriggerType).Append("[ef=");
				IEffectInfo[] generalEffects = (IEffectInfo[])(object)val.GeneralEffects;
				stringBuilder3.Append(EfeitosInfo.Descreve(generalEffects)).Append("~cond=").Append(EfeitosInfo.Limpa(val.Condition))
					.Append("~status=")
					.Append(stringBuilder2)
					.Append("]; ");
			}
			return stringBuilder.ToString().TrimEnd(' ', ';');
		}

		private static void Postfix(List<ActionStatusInfo> __result)
		{
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_dumped || __result == null || __result.Count <= 1)
				{
					return;
				}
				if (__result.Count == _lastCount)
				{
					_stableHits++;
				}
				else
				{
					_stableHits = 1;
					_lastCount = __result.Count;
				}
				if (_stableHits < 5)
				{
					return;
				}
				_dumped = true;
				Plugin.Log.LogInfo((object)$"[Status] Inventário: {__result.Count} status carregados.");
				EfeitosInfo.Zerar();
				foreach (ActionStatusInfo item in __result)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					string text = item.Description ?? "";
					StringBuilder stringBuilder = new StringBuilder();
					if (item.AttributeEffects != null)
					{
						CharacterEffectInfo[] attributeEffects = item.AttributeEffects;
						foreach (CharacterEffectInfo val in attributeEffects)
						{
							if (val != null && !((Object)(object)val.CharacterAttribute == (Object)null))
							{
								stringBuilder.Append(((Object)val.CharacterAttribute).name).Append(':').Append(val.CharacterEffectMethod)
									.Append(':')
									.Append(val.Amount)
									.Append(", ");
							}
						}
					}
					StringBuilder stringBuilder2 = new StringBuilder();
					int num = 0;
					if (item.Effects != null)
					{
						IEffectInfo[] effects = item.Effects;
						foreach (IEffectInfo obj in effects)
						{
							GeneralEffect val2 = (GeneralEffect)(object)((obj is GeneralEffect) ? obj : null);
							if (val2 != null)
							{
								num++;
								if (!string.IsNullOrEmpty(val2.Action))
								{
									stringBuilder2.Append(val2.Action.Replace("\n", " ").Replace("\r", " ").Replace("|", "/")
										.Replace("\"", "'")
										.Trim()).Append("; ");
								}
							}
						}
					}
					string arg = EfeitosInfo.Descreve(item.Effects);
					string arg2 = EfeitosInfo.Descreve(item.AttributeEffects);
					string text3;
					if ((Object)(object)item.ModelChangeCharacter != (Object)null)
					{
						List<SkillInfo> skills = item.ModelChangeCharacter.Skills;
						string text2 = "";
						if (skills != null)
						{
							int num2 = ((skills.Count > 14) ? 14 : skills.Count);
							for (int j = 0; j < num2; j++)
							{
								if (!((Object)(object)skills[j] == (Object)null))
								{
									text2 = text2 + ((text2.Length > 0) ? "; " : "") + ((Object)skills[j]).name;
								}
							}
							if (skills.Count > num2)
							{
								text2 = text2 + "; (+" + (skills.Count - num2) + ")";
							}
						}
						text3 = ((Object)item.ModelChangeCharacter).name + " [" + text2 + "]";
					}
					else
					{
						text3 = "-";
					}
					Plugin.Log.LogInfo((object)($"[Status] '{item.Name}' | tipo={item.StatusType} | raridade={item.Rarity} | " + $"efeitos={stringBuilder} | efeitosDano={stringBuilder2} | nEfeitosDano={num} | " + string.Format("aura={0} | raio={1} | ", item.IsAura ? "sim" : "nao", item.AuraRadius) + "auraAli=" + (item.AuraEffectsAllies ? "sim" : "nao") + " | auraIni=" + (item.AuraEffectsEnemies ? "sim" : "nao") + " | modelo=" + text3 + " | beneficio=" + (item.IsBeneficial ? "Buff" : (item.IsHarmful ? "Debuff" : "Neutro")) + " | " + $"dur={item.Duration} | maxStk={item.MaxStacks} | " + $"nEfeitosTot={EfeitosInfo.Conta(item.Effects)} | efTipos={arg} | " + $"nAttrEf={EfeitosInfo.Conta(item.AttributeEffects)} | attrTipos={arg2} | " + $"nTrig={EfeitosInfo.Conta(item.SkillTriggers)} | trigEf={TriggersDe(item)} | " + "desc=\"" + text.Replace("\n", " ") + "\""));
				}
				Plugin.Log.LogInfo((object)("[Efeitos] resumo (status): " + EfeitosInfo.Resumo()));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Status] erro no inventário: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(WorldMapGenerator), "GetRandomEvent")]
	public static class EventRollDebugPatch
	{
		private static void Postfix(NodeTypeEventSet nodeTypeEventSet, TerrainAndTime terrainAndTime, int level, PartyEvent __result)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__result == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[Event] roll retornou null (ver fallbacks no Player.log).");
				}
				else
				{
					Plugin.Log.LogInfo((object)($"[Event] '{((Object)__result).name}' | nodo={nodeTypeEventSet.nodeType} " + $"minor={nodeTypeEventSet.isMinor} spawn={nodeTypeEventSet.eventSpawnType} | " + $"terreno={terrainAndTime.TerrainType}/{terrainAndTime.TimeOfDay} | nível={level} | " + $"chance={__result.ChanceRatio} | temBatalha={__result.HasBattle}"));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Event] erro no debug: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GameLogic), "GetTotalExpValue")]
	public static class ExpDebugPatch
	{
		private static void Postfix(float modifier, ref float __result)
		{
			try
			{
				float num = ((modifier != 0f) ? (__result / modifier) : 0f);
				float experienceMod = GameLogic.instance.CurrentDifficulty.ExperienceMod;
				Plugin.Log.LogInfo((object)($"[Exp] total={__result:F1} | base(por inimigos)={num:F1} | " + $"modificador da batalha={modifier:F2} | multiplicador de dificuldade={experienceMod:F2}"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Exp] erro no debug: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Character), "GetExpValue")]
	public static class EnemyExpDebugPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			try
			{
				if (__instance != null)
				{
					Plugin.Log.LogInfo((object)($"[ExpInimigo] {((Object)__instance.CharacterInfo).name} (Lv {__instance.Level}, " + $"PointValue {__instance.PointValue}) = {__result:F1} exp"));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[ExpInimigo] erro no debug: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GameLogic), "ApplyGoldModifiers")]
	public static class GoldModifierDebugPatch
	{
		private static void Postfix(float originalGold, ref float __result)
		{
			try
			{
				NetworkingManager instance = NetworkingManager.Instance;
				List<Character> list = ((instance != null) ? instance.MyPartyCharacters : null);
				List<string> list2 = new List<string>();
				float num = 0f;
				if (list != null)
				{
					foreach (Character item in list)
					{
						float num2 = item["GoldMod"];
						num += num2;
						list2.Add($"{item.CharacterName}={num2}");
					}
				}
				Plugin.Log.LogInfo((object)(string.Format("[Gold] ouro base={0} party=[{1}] ", originalGold, (list2.Count > 0) ? string.Join(", ", list2) : "-") + $"GoldMod soma={num} ouro final={__result}"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Gold] erro no debug: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Game), "get_Items")]
	public static class ItemInventoryPatch
	{
		private static bool _itemsDumped;

		private static int _itemsLast = -1;

		private static int _itemsStable;

		private static bool _modsDumped;

		private static void Postfix(List<ItemInfo> __result)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_itemsDumped || __result == null || __result.Count <= 1)
				{
					return;
				}
				if (__result.Count == _itemsLast)
				{
					_itemsStable++;
				}
				else
				{
					_itemsStable = 1;
					_itemsLast = __result.Count;
				}
				if (_itemsStable < 5)
				{
					return;
				}
				_itemsDumped = true;
				EfeitosInfo.Zerar();
				Plugin.Log.LogInfo((object)$"[Item] Inventário: {__result.Count} itens base carregados.");
				foreach (ItemInfo item in __result)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					string text = item.OptionalDescription ?? "";
					StringBuilder stringBuilder = new StringBuilder();
					if (item.IsConsumable && (Object)(object)item.ConsumableAction != (Object)null)
					{
						stringBuilder.Append(((Object)item.ConsumableAction).name).Append("::");
						if (item.ConsumableAction.Effects != null)
						{
							IEffectInfo[] effects = item.ConsumableAction.Effects;
							foreach (IEffectInfo obj in effects)
							{
								GeneralEffect val = (GeneralEffect)(object)((obj is GeneralEffect) ? obj : null);
								if (val != null && !string.IsNullOrEmpty(val.Action))
								{
									stringBuilder.Append(val.Action).Append("; ");
								}
							}
						}
					}
					Plugin.Log.LogInfo((object)($"[Item] '{((Object)item).name}' | tipo={item.ItemType} | raridade={item.Rarity} | " + string.Format("lvlMin={0} | consumivel={1} | ", item.MinLevel, stringBuilder.ToString().Replace("|", "/").Replace("\n", " ")) + "consEf=" + EfeitosInfo.Descreve((item.IsConsumable && (Object)(object)item.ConsumableAction != (Object)null) ? item.ConsumableAction.Effects : null) + " | desc=\"" + text.Replace("\n", " ") + "\""));
				}
				Plugin.Log.LogInfo((object)("[Efeitos] resumo (itens): " + EfeitosInfo.Resumo()));
				DumpItemMods();
				PowerupInventoryPatch.Trigger();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Item] erro no inventário: " + ex.Message));
			}
		}

		private static void DumpItemMods()
		{
			//IL_007c: 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)
			try
			{
				if (_modsDumped)
				{
					return;
				}
				ItemMod[] itemMods = Game.Instance.ItemMods;
				if (itemMods == null || itemMods.Length <= 1)
				{
					return;
				}
				_modsDumped = true;
				Plugin.Log.LogInfo((object)$"[ItemMod] Inventário: {itemMods.Length} afixos carregados.");
				ItemMod[] array = itemMods;
				foreach (ItemMod val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						string text = val.Description ?? "";
						Plugin.Log.LogInfo((object)($"[ItemMod] '{((Object)val).name}' | tipo={val.ItemModType} | raridade={val.Rarity} | " + "desc=\"" + text.Replace("\n", " ") + "\""));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[ItemMod] erro no inventário: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(MessageWindowManager), "CreateBattleLogMessage")]
	public static class LifeStealDebugPatch
	{
		private static void Postfix(Character source, Character target, string message, float value)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (message == null)
				{
					return;
				}
				if (message == "[source] healed [value] health from life steal" && source != null)
				{
					List<string> list = new List<string>();
					foreach (SkillType value2 in Enum.GetValues(typeof(SkillType)))
					{
						float num = source["LifeSteal" + ((object)value2/*cast due to .constrained prefix*/).ToString()];
						if (num > 0f)
						{
							list.Add($"{(object)value2}={num:F1}");
						}
					}
					float num2 = source["LifeSteal"];
					float maxHealth = source.MaxHealth;
					_ = maxHealth * num2 / 100f;
					Plugin.Log.LogInfo((object)($"[LifeSteal] {source.CharacterName} curou {value:F1} | " + $"vidaMáxima={maxHealth:F1} | LifeSteal%={num2:F1} | nível={source.Level} | " + "porTipo=[" + string.Join(", ", list) + "] | " + $"(15% da vidaMáx seria {maxHealth * 0.15f:F1})"));
				}
				else if (message == "[source] dealt [value] Damage to [target]" && source != null && !source.IsAI && value > 0f)
				{
					Plugin.Log.LogInfo((object)($"[Dmg] {source.CharacterName} causou {value:F1} dano em " + string.Format("{0} | LifeSteal%={1:F1}", (target != null) ? target.CharacterName : "?", source["LifeSteal"])));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[LifeSteal] erro no debug: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GameLogic), "GetCharacterLootDropModifier")]
	public static class LootModifierDebugPatch
	{
		private static void Postfix(ref float __result)
		{
			try
			{
				NetworkingManager instance = NetworkingManager.Instance;
				List<Character> list = ((instance != null) ? instance.MyPartyCharacters : null);
				if (list == null)
				{
					Plugin.Log.LogInfo((object)"[Loot] Modificador de loot: party nula.");
					return;
				}
				Root root = ((Observer<Root>)(object)NetworkingManager.Instance.NetworkManager).Root;
				Plugin.Log.LogInfo((object)$"[Loot] PlayingRoguelike={((root != null) ? new bool?(root.PlayingRoguelike) : ((bool?)null))}");
				ObservableRoguelikePowerupAndLevelSet val = default(ObservableRoguelikePowerupAndLevelSet);
				foreach (Character item in list)
				{
					float num = item["DropQuantityMod"];
					List<string> list2 = new List<string>();
					if (root != null && root.RoguelikePowerupsByConnection != null && root.RoguelikePowerupsByConnection.TryGetValue(item.OwnerID, ref val) && val.PowerupAndLevels != null)
					{
						foreach (ObservableRoguelikePowerupAndLevel powerupAndLevel in val.PowerupAndLevels)
						{
							if (powerupAndLevel.Level > 0)
							{
								list2.Add(string.Format("{0} Lv{1}", Game.Instance.GetFromRoguelikePowerupDict(Game.Instance.GetGuidFromString(powerupAndLevel.Guid))?.Name ?? "?", powerupAndLevel.Level));
							}
						}
					}
					Plugin.Log.LogInfo((object)($"[Loot] {item.CharacterName}: DropQuantityMod={num}; " + string.Format("GoldMod={0}; DamageMod={1}; ", item["GoldMod"], item["DamageMod"]) + string.Format("DamageModHealing={0}; DamageReduction={1}; ", item["DamageModHealing"], item["DamageReduction"]) + string.Format("FreeMove={0}; RangeMelee={1}; ", item["FreeMovementPoints"], item["RangeTypeAdderMelee"]) + string.Format("RangeRanged={0}; SkillOpts={1}; ", item["RangeTypeAdderRanged"], item["AdditionalRoguelikeSkillOptions"]) + string.Format("AttrPtsPerLvl={0}; ", item["AdditionalRoguelikeAttributesPointsPerLevel"]) + string.Format("Resilience={0}; TakeCover={1}; ", item["Resilience"], item["TakeCover"]) + "powerups ativos: " + ((list2.Count > 0) ? string.Join(", ", list2) : "nenhum")));
				}
				Plugin.Log.LogInfo((object)$"[Loot] Multiplicador final={__result}");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Loot] erro no debug: " + ex.Message + "\n" + ex.StackTrace));
			}
		}
	}
	[HarmonyPatch(typeof(Game), "get_RoguelikePowerups")]
	public static class PowerupInventoryPatch
	{
		private static bool _dumped;

		internal static void Trigger()
		{
			try
			{
				Plugin.Log.LogInfo((object)"[Powerup] trigger chamado (forçando o load lazy).");
				RoguelikePowerup[] roguelikePowerups = Game.Instance.RoguelikePowerups;
				Plugin.Log.LogInfo((object)("[Powerup] getter retornou " + ((roguelikePowerups == null) ? "null" : (roguelikePowerups.Length + " itens")) + "."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Powerup] trigger falhou: " + ex.Message));
			}
		}

		private static void Postfix(RoguelikePowerup[] __result)
		{
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_dumped || __result == null || __result.Length <= 1)
				{
					return;
				}
				_dumped = true;
				Plugin.Log.LogInfo((object)$"[Powerup] Inventário: {__result.Length} powerups carregados.");
				foreach (RoguelikePowerup val in __result)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					if (val.PowerupLevels == null || val.PowerupLevels.Length == 0)
					{
						Plugin.Log.LogInfo((object)$"[Powerup] '{val.Name}' | guid={val.Guid} | (sem níveis)");
						continue;
					}
					for (int j = 0; j < val.PowerupLevels.Length; j++)
					{
						RoguelikePowerupLevel val2 = val.PowerupLevels[j];
						if (val2 == null)
						{
							continue;
						}
						StringBuilder stringBuilder = new StringBuilder();
						if (val2.CharacterEffects != null)
						{
							CharacterEffectInfo[] characterEffects = val2.CharacterEffects;
							foreach (CharacterEffectInfo val3 in characterEffects)
							{
								if (val3 != null && !((Object)(object)val3.CharacterAttribute == (Object)null))
								{
									stringBuilder.Append(((Object)val3.CharacterAttribute).name).Append(':').Append(val3.CharacterEffectMethod)
										.Append(':')
										.Append(val3.Amount)
										.Append(", ");
								}
							}
						}
						string arg = (val2.Description ?? "").Replace("\n", " ");
						Plugin.Log.LogInfo((object)($"[Powerup] '{val.Name}' | guid={val.Guid} | nivel={j + 1} | custo={val2.Cost} | " + $"efeitos={stringBuilder} | desc=\"{arg}\""));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Powerup] erro no inventário: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Game), "get_Skills")]
	public static class SkillInventoryPatch
	{
		private static bool _dumped;

		private static int _lastCount = -1;

		private static int _stableHits;

		private static readonly Dictionary<string, ActionInfo> _acoes = new Dictionary<string, ActionInfo>();

		private static string Limpa(string s)
		{
			return (s ?? "").Replace("\n", " ").Replace("\r", " ").Replace("|", "/")
				.Replace("\"", "'")
				.Trim();
		}

		private static string Junta(string[] itens)
		{
			if (itens == null)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string text in itens)
			{
				if (!string.IsNullOrEmpty(text))
				{
					stringBuilder.Append(Limpa(text)).Append("; ");
				}
			}
			return stringBuilder.ToString().TrimEnd(' ', ';');
		}

		private static void DespejaAcoes()
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0719: Unknown result type (might be due to invalid IL or missing references)
			//IL_0724: Unknown result type (might be due to invalid IL or missing references)
			//IL_073c: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)$"[Action] Inventário: {_acoes.Count} ações concedidas por skills.");
			EfeitosInfo.Zerar();
			Queue<string> queue = new Queue<string>(_acoes.Keys.OrderBy<string, string>((string x) => x, StringComparer.Ordinal));
			HashSet<string> hashSet = new HashSet<string>();
			while (queue.Count > 0)
			{
				string text = queue.Dequeue();
				if (!hashSet.Add(text) || !_acoes.TryGetValue(text, out var value) || (Object)(object)value == (Object)null)
				{
					continue;
				}
				ActionInfo tooltipDamageInfoRefAction = value.TooltipDamageInfoRefAction;
				ActionStatusInfo tooltipDamageInfoRefStatus = value.TooltipDamageInfoRefStatus;
				if ((Object)(object)tooltipDamageInfoRefAction != (Object)null && !string.IsNullOrEmpty(((Object)tooltipDamageInfoRefAction).name))
				{
					_acoes[((Object)tooltipDamageInfoRefAction).name] = tooltipDamageInfoRefAction;
					queue.Enqueue(((Object)tooltipDamageInfoRefAction).name);
				}
				string text2 = EfeitosDe(value);
				string text3 = (((Object)(object)tooltipDamageInfoRefAction != (Object)null) ? EfeitosDe(tooltipDamageInfoRefAction) : "");
				int num = ContaEfeitos(value);
				int num2 = (((Object)(object)tooltipDamageInfoRefAction != (Object)null) ? ContaEfeitos(tooltipDamageInfoRefAction) : 0);
				string arg = EfeitosInfo.Descreve(value.Effects);
				Plugin.Log.LogInfo((object)($"[Action] '{text}' | dano={value.DamageType} | " + $"nEfeitosTot={EfeitosInfo.Conta(value.Effects)} | efTipos={arg} | " + "efeitos=" + text2 + " | refAcao=" + (((Object)(object)tooltipDamageInfoRefAction != (Object)null) ? Limpa(((Object)tooltipDamageInfoRefAction).name) : "") + " | efeitosRef=" + text3 + " | " + $"nEfeitos={num} | nEfeitosRef={num2} | " + $"nSummons={((value.Summons == null) ? (-1) : value.Summons.Count)} | " + "refStatus=" + (((Object)(object)tooltipDamageInfoRefStatus != (Object)null) ? Limpa(tooltipDamageInfoRefStatus.Name) : "") + " | danoExpr=" + Junta(value.DamageExpressionOverrides) + " | expr=" + Junta(value.DescriptionExpressions) + " | desc=\"" + Limpa(value.Description) + "\""));
				StringBuilder stringBuilder = new StringBuilder();
				int num3 = 0;
				if (value.Targets != null)
				{
					ITargetInfo[] targets = value.Targets;
					foreach (ITargetInfo obj in targets)
					{
						TargetInfo val = (TargetInfo)(object)((obj is TargetInfo) ? obj : null);
						if (val != null)
						{
							num3++;
							stringBuilder.Append('[').Append("sel=").Append(Limpa(val.Selection))
								.Append(';')
								.Append("rsel=")
								.Append(Limpa(val.RangeSelection))
								.Append(';')
								.Append("blast=")
								.Append(Limpa(val.BlastRange))
								.Append(';')
								.Append("range=")
								.Append(val.SimpleRange)
								.Append(';')
								.Append("ali=")
								.Append(val.TargetAllies ? 1 : 0)
								.Append("ini=")
								.Append(val.TargetEnemies ? 1 : 0)
								.Append("self=")
								.Append(val.TargetSelf ? 1 : 0)
								.Append(']');
						}
					}
				}
				StringBuilder stringBuilder2 = new StringBuilder();
				if (value.ActionChances != null)
				{
					foreach (ActionChance actionChance in value.ActionChances)
					{
						if (actionChance != null)
						{
							stringBuilder2.Append(((Object)(object)actionChance.ActionInfo != (Object)null) ? Limpa(((Object)actionChance.ActionInfo).name) : "?").Append(':').Append(actionChance.Chance)
								.Append(',');
						}
					}
				}
				StringBuilder stringBuilder3 = new StringBuilder();
				if (value.StatusEffects != null)
				{
					ActionStatusInfo[] statusEffects = value.StatusEffects;
					foreach (ActionStatusInfo val2 in statusEffects)
					{
						if ((Object)(object)val2 != (Object)null)
						{
							stringBuilder3.Append(Limpa(val2.Name)).Append(',');
						}
					}
				}
				StringBuilder stringBuilder4 = new StringBuilder();
				if (value.SourceStatusEffects != null)
				{
					ActionStatusInfo[] statusEffects = value.SourceStatusEffects;
					foreach (ActionStatusInfo val3 in statusEffects)
					{
						if ((Object)(object)val3 != (Object)null)
						{
							stringBuilder4.Append(Limpa(val3.Name)).Append(',');
						}
					}
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				if (value.StatusEffects != null)
				{
					ActionStatusInfo[] statusEffects = value.StatusEffects;
					foreach (ActionStatusInfo val4 in statusEffects)
					{
						if (!((Object)(object)val4 == (Object)null))
						{
							string key = Limpa(val4.Name);
							dictionary[key] = ((!dictionary.TryGetValue(key, out var value2)) ? 1 : (value2 + 1));
						}
					}
				}
				if (value.SourceStatusEffects != null)
				{
					ActionStatusInfo[] statusEffects = value.SourceStatusEffects;
					foreach (ActionStatusInfo val5 in statusEffects)
					{
						if (!((Object)(object)val5 == (Object)null))
						{
							string key2 = Limpa(val5.Name);
							dictionary[key2] = ((!dictionary.TryGetValue(key2, out var value3)) ? 1 : (value3 + 1));
						}
					}
				}
				StringBuilder stringBuilder5 = new StringBuilder();
				foreach (KeyValuePair<string, int> item in dictionary)
				{
					stringBuilder5.Append(item.Key).Append("x").Append(item.Value)
						.Append(",");
				}
				string text4 = "-";
				if (value.UseGroundEffect)
				{
					StringBuilder stringBuilder6 = new StringBuilder();
					if (value.GroundActionStatuses != null)
					{
						ActionStatusInfo[] statusEffects = value.GroundActionStatuses;
						foreach (ActionStatusInfo val6 in statusEffects)
						{
							if ((Object)(object)val6 != (Object)null)
							{
								stringBuilder6.Append(Limpa(val6.Name)).Append(",");
							}
						}
					}
					text4 = Limpa(value.GroundTargetConditions) + " dur=" + Limpa(value.GroundDuration) + (value.GroundIsInfinite ? " infinito" : "") + " maxTrg=" + value.GroundMaxNumTriggers + " status=" + stringBuilder6;
				}
				Plugin.Log.LogInfo((object)($"[ActionProps] '{text}' | tipo={value.ActionType} | beneficio={value.BenefitType} | " + $"skillType={value.SkillType} | nAlvos={num3} | alvos={stringBuilder} | " + "alcance=" + (value.UseMaxRangeOverride ? value.MaxRangeOverride.ToString() : "-") + " | alcanceBlast=" + (value.UseMaxRangeBlastOverride ? value.MaxRangeBlastOverride.ToString() : "-") + " | knockback=" + (value.UseKnockback ? value.KnockbackAmount.ToString() : "-") + " | hits=" + (value.UseMultipleHits ? value.NumHits.ToString() : "-") + " | " + $"maxChain={value.DashMaxChainCount} | " + "colisao=" + (((Object)(object)value.KnockbackCollideAction != (Object)null) ? ((Object)value.KnockbackCollideAction).name : "-") + " | hexesAtiv=" + (string.IsNullOrEmpty(value.ActivationIndicatorHexes) ? "-" : value.ActivationIndicatorHexes.Replace('\n', ',')) + " | numHitsEq=" + (value.UseNumHitsEquation ? "Sim" : "-") + " | chainProj=" + (value.ProjectileChain ? "Sim" : "Nao") + " | " + $"chainProjN={value.ProjectileChainCount} | " + "chainProjAlvo=" + Limpa(value.ProjectileChainTarget) + " | " + $"chainMesmo={value.ChainSameTarget} | " + "chainAlvo=" + Limpa(value.DashChainTarget) + " | chainMesmoAlvo=" + (value.DashChainSameTarget ? "Sim" : "Nao") + " | " + $"remocoes={((value.StatusRemovals != null) ? value.StatusRemovals.Length : 0)} | " + $"remocoesP={((value.PostActionStatusRemovals != null) ? value.PostActionStatusRemovals.Length : 0)} | " + "remocao=" + ((value.StatusRemovals != null && value.StatusRemovals.Length != 0 && (Object)(object)value.StatusRemovals[0].ActionOnRemoval != (Object)null) ? (Limpa(((Object)value.StatusRemovals[0].ActionOnRemoval).name) + "=>" + EfeitosDe(value.StatusRemovals[0].ActionOnRemoval)) : "-") + " | remocaoTipo=" + ((value.StatusRemovals != null && value.StatusRemovals.Length != 0) ? (((object)Unsafe.As<BeneficialOrHarmful, BeneficialOrHarmful>(ref value.StatusRemovals[0].BenefitType)/*cast due to .constrained prefix*/).ToString() + "/" + Limpa(value.StatusRemovals[0].NumStatusesToRemove)) : "-") + " | exprHits=" + Limpa(value.NumHitsEquation) + " | alcanceHits=" + Limpa(value.MultipleHitRange) + " | cooldown=" + Limpa(value.Cooldown) + " | cargas=" + Limpa(value.MaxCharges) + "/" + Limpa(value.InitialCharges) + " | precisa=" + Limpa(value.UseCondition) + " | condFalha=" + Limpa(value.UseConditionFailText) + " | " + $"statusAplicados={stringBuilder3} | stacks={stringBuilder5} | ground={text4} | statusFonte={stringBuilder4} | chances={stringBuilder2}"));
				if (value.Summons == null || value.Summons.Count <= 0)
				{
					continue;
				}
				StringBuilder stringBuilder7 = new StringBuilder();
				foreach (CharacterInfo summon in value.Summons)
				{
					if ((Object)(object)summon == (Object)null)
					{
						continue;
					}
					stringBuilder7.Append(Limpa(((Object)summon).name)).Append('[');
					int num5 = 0;
					if (summon.SkillsAndAI != null)
					{
						SkillAndAI[] skillsAndAI = summon.SkillsAndAI;
						foreach (SkillAndAI val7 in skillsAndAI)
						{
							if (val7 != null && (Object)(object)val7.Skill != (Object)null && !string.IsNullOrEmpty(val7.Skill.SkillName))
							{
								stringBuilder7.Append(Limpa(val7.Skill.SkillName)).Append(',');
								num5++;
							}
						}
					}
					if (num5 == 0 && summon.Skills != null)
					{
						foreach (SkillInfo skill in summon.Skills)
						{
							if ((Object)(object)skill != (Object)null && !string.IsNullOrEmpty(skill.SkillName))
							{
								stringBuilder7.Append(Limpa(skill.SkillName)).Append(',');
							}
						}
					}
					stringBuilder7.Append("]; ");
				}
				Plugin.Log.LogInfo((object)("[Summon] '" + text + "' | sorteio=" + (value.RandomSummonFromList ? "sim" : "nao") + " | herdaStats=" + (value.BenefitFromCasterStats ? "sim" : "nao") + " | morreComCaster=" + (value.DieWhenCasterDies ? "sim" : "nao") + " | persistente=" + (value.IsPersistantSummon ? "sim" : "nao") + " | doencaDeInvocacao=" + (value.HasSummoningSickness ? "sim" : "nao") + " | " + $"criaturas={stringBuilder7}"));
			}
			Plugin.Log.LogInfo((object)("[Efeitos] resumo (acoes): " + EfeitosInfo.Resumo()));
		}

		private static int ContaEfeitos(ActionInfo ac)
		{
			int num = 0;
			if ((Object)(object)ac != (Object)null && ac.Effects != null)
			{
				IEffectInfo[] effects = ac.Effects;
				for (int i = 0; i < effects.Length; i++)
				{
					if (effects[i] is GeneralEffect)
					{
						num++;
					}
				}
			}
			return num;
		}

		private static string EfeitosDe(ActionInfo ac)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if ((Object)(object)ac != (Object)null && ac.Effects != null)
			{
				IEffectInfo[] effects = ac.Effects;
				foreach (IEffectInfo obj in effects)
				{
					GeneralEffect val = (GeneralEffect)(object)((obj is GeneralEffect) ? obj : null);
					if (val != null && !string.IsNullOrEmpty(val.Action))
					{
						stringBuilder.Append(Limpa(val.Action)).Append("; ");
					}
				}
			}
			return stringBuilder.ToString().TrimEnd(' ', ';');
		}

		private static void Postfix(List<SkillInfo> __result)
		{
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0482: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_dumped || __result == null || __result.Count <= 1)
				{
					return;
				}
				if (__result.Count == _lastCount)
				{
					_stableHits++;
				}
				else
				{
					_stableHits = 1;
					_lastCount = __result.Count;
				}
				if (_stableHits < 5)
				{
					return;
				}
				_dumped = true;
				EfeitosInfo.Zerar();
				Plugin.Log.LogInfo((object)$"[Skill] Inventário: {__result.Count} skills carregados.");
				foreach (SkillInfo item in __result)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					string text = item.Description ?? "";
					StringBuilder stringBuilder = new StringBuilder();
					if (item.ActionsGranted != null)
					{
						ActionInfo[] actionsGranted = item.ActionsGranted;
						foreach (ActionInfo val in actionsGranted)
						{
							if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name))
							{
								stringBuilder.Append(Limpa(((Object)val).name)).Append("; ");
								_acoes[((Object)val).name] = val;
							}
						}
					}
					StringBuilder stringBuilder2 = new StringBuilder();
					if (item.PassiveActionStatuses != null)
					{
						ActionStatusInfo[] passiveActionStatuses = item.PassiveActionStatuses;
						foreach (ActionStatusInfo val2 in passiveActionStatuses)
						{
							if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(val2.Name))
							{
								stringBuilder2.Append(Limpa(val2.Name)).Append("; ");
							}
						}
					}
					StringBuilder stringBuilder3 = new StringBuilder();
					if (item.AttributeEffects != null)
					{
						CharacterEffectInfo[] attributeEffects = item.AttributeEffects;
						foreach (CharacterEffectInfo val3 in attributeEffects)
						{
							if (val3 != null && !((Object)(object)val3.CharacterAttribute == (Object)null))
							{
								stringBuilder3.Append(((Object)val3.CharacterAttribute).name).Append(':').Append(val3.CharacterEffectMethod)
									.Append(':')
									.Append(val3.Amount)
									.Append(", ");
							}
						}
					}
					string arg = EfeitosInfo.Descreve(item.AttributeEffects);
					string arg2 = ((item.SkillTags != null) ? string.Join(",", item.SkillTags) : "");
					Plugin.Log.LogInfo((object)($"[Skill] '{item.SkillName}' | tipo={item.SkillType} | dano={item.DamageType} | " + $"tier={item.Tier} | tags={arg2} | skid={item.Guid} | " + "passivo=" + (item.IsPassive ? "sim" : "nao") + " | " + $"attr={stringBuilder3} | acts={stringBuilder} | pstat={stringBuilder2} | " + $"nAttrEf={EfeitosInfo.Conta(item.AttributeEffects)} | attrTipos={arg} | " + "expr=" + Junta(item.DescriptionExpressions) + " | danoExpr=" + Junta(item.DamageExpressionOverrides) + " | upg=" + Limpa(item.UpgradeText) + " | desc=\"" + text.Replace("\n", " ") + "\""));
					if (item.SkillTriggers == null)
					{
						continue;
					}
					SkillTrigger[] skillTriggers = item.SkillTriggers;
					foreach (SkillTrigger val4 in skillTriggers)
					{
						if (val4 == null)
						{
							continue;
						}
						StringBuilder stringBuilder4 = new StringBuilder();
						if (val4.Actions != null)
						{
							ActionInfo[] actionsGranted = val4.Actions;
							foreach (ActionInfo val5 in actionsGranted)
							{
								if ((Object)(object)val5 != (Object)null && !string.IsNullOrEmpty(((Object)val5).name))
								{
									stringBuilder4.Append(Limpa(((Object)val5).name)).Append(',');
									_acoes[((Object)val5).name] = val5;
								}
							}
						}
						StringBuilder stringBuilder5 = new StringBuilder();
						if (val4.ActionStatuses != null)
						{
							ActionStatusInfo[] passiveActionStatuses = val4.ActionStatuses;
							foreach (ActionStatusInfo val6 in passiveActionStatuses)
							{
								if ((Object)(object)val6 != (Object)null)
								{
									stringBuilder5.Append(Limpa(val6.Name)).Append(',');
								}
							}
						}
						Plugin.Log.LogInfo((object)($"[Trigger] '{item.SkillName}' | tipo={val4.TriggerType} | " + "cond=" + Limpa(val4.Condition) + " | addBasicAttack=" + (val4.AddBasicAttackToActionList ? "sim" : "nao") + " | garanteUm=" + (val4.GauranteeOneAction ? "sim" : "nao") + " | chanceIgual=" + (val4.GiveAllActionsEqualChance ? "sim" : "nao") + " | " + $"chances={Junta(val4.ActionChanceEquations)} | acoes={stringBuilder4} | " + $"status={stringBuilder5} | chancesStatus={Junta(val4.ActionStatusChanceEquations)} | " + $"nEfeitos={((val4.GeneralEffects != null) ? val4.GeneralEffects.Length : 0)} | " + $"cooldownTrig={val4.Cooldown}"));
					}
				}
				Plugin.Log.LogInfo((object)("[Efeitos] resumo (skills): " + EfeitosInfo.Resumo()));
				DespejaAcoes();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Skill] erro no inventário: " + ex.Message));
			}
		}
	}
}