Decompiled source of MayheimMiticas v0.1.3

plugins\MayheimMiticas\MayheimMiticas.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MayheimMiticas.Chaves;
using MayheimMiticas.Compat;
using MayheimMiticas.Core;
using MayheimMiticas.Corridas;
using MayheimMiticas.Mercado;
using MayheimMiticas.Reliquias;
using MayheimMiticas.Testing;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MayheimMiticas")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("MayheimMiticas")]
[assembly: AssemblyTitle("MayheimMiticas")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MayheimMiticas
{
	internal static class Cfg
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> KeyDropChance;

		public static ConfigEntry<int> KeyDropLevel;

		public static ConfigEntry<string> KeyBiomeWeights;

		public static ConfigEntry<float> HpPerLevel;

		public static ConfigEntry<float> DamagePerLevel;

		public static ConfigEntry<float> AreaRadius;

		public static ConfigEntry<int> RunMaxDays;

		public static ConfigEntry<string> BossByBiome;

		public static ConfigEntry<string> BossBaseHp;

		public static ConfigEntry<float> BossPerPlayer;

		public static ConfigEntry<string>[] RelicItems = new ConfigEntry<string>[4];

		public static ConfigEntry<float> RelicChanceBase;

		public static ConfigEntry<float> RelicChancePerLevel;

		public static ConfigEntry<int> GoldBase;

		public static ConfigEntry<int> GoldPerLevel;

		public static ConfigEntry<float> RelicMultPerLevel;

		public static ConfigEntry<float> RelicMultMax;

		public static ConfigEntry<int> RelicAttrMin;

		public static ConfigEntry<int> RelicAttrMax;

		public static ConfigEntry<float> RelicElementChance;

		public static ConfigEntry<float> ElementBase;

		public static ConfigEntry<float> ElementPerLevel;

		public static ConfigEntry<string> CategoryWeights;

		public static ConfigEntry<float> StyleChance;

		public static ConfigEntry<float> StaffEitrPerLevel;

		public static ConfigEntry<float> StaffEitrMax;

		public static ConfigEntry<bool> VersionCheck;

		public static ConfigEntry<bool> ConfigSync;

		internal const string SecRede = "9 - Rede";

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("1 - Geral", "Enabled", true, "Liga as dungeons miticas (chaves, corridas e reliquias).");
			KeyDropChance = cfg.Bind<float>("2 - Chaves", "DropChance", 0.25f, "Chance (0-1) de um chefe deixar uma Chave Mitica ao morrer: chefe mundial, chefe principal do jogo (inclusive o das raids) e chefe de dungeon.");
			KeyDropLevel = cfg.Bind<int>("2 - Chaves", "DropLevel", 2, "Nivel da chave que cai de chefe.");
			KeyBiomeWeights = cfg.Bind<string>("2 - Chaves", "BiomeWeights", "Montanha=1,Mistlands=1,Cinzas=1,Norte=1", "Peso do sorteio do bioma da chave. O bioma NAO depende do chefe: qualquer chefe pode deixar qualquer chave.");
			HpPerLevel = cfg.Bind<float>("3 - Escala", "HpPerLevel", 0.12f, "Vida extra dos monstros e do chefe por nivel da chave (0,12 = +12% por nivel).");
			DamagePerLevel = cfg.Bind<float>("3 - Escala", "DamagePerLevel", 0.08f, "Dano extra dos monstros por nivel da chave.");
			AreaRadius = cfg.Bind<float>("3 - Escala", "AreaRadius", 80f, "Raio (m, na horizontal) em volta do gerador da dungeon que conta como 'dentro' da corrida.");
			RunMaxDays = cfg.Bind<int>("3 - Escala", "RunMaxDays", 5, "Dias do mundo ate uma corrida parada ser encerrada (a chave volta ao dono no mesmo nivel).");
			BossByBiome = cfg.Bind<string>("3 - Escala", "BossByBiome", "Montanha=Fenring_Cultist,Mistlands=SeekerBrute,Cinzas=Morgen,Norte=GoblinDeepNorth", "Criatura do chefe mitico de cada bioma (prefab). A chave cria o chefe na sala mais distante da dungeon; matar ele conclui a corrida.");
			BossBaseHp = cfg.Bind<string>("3 - Escala", "BossBaseHp", "Montanha=4000,Mistlands=6000,Cinzas=8000,Norte=10000", "Vida base do chefe mitico por bioma, antes da escala do nivel (HpPerLevel).");
			BossPerPlayer = cfg.Bind<float>("3 - Escala", "BossPerPlayer", 0.5f, "Vida extra do chefe por jogador a mais dentro da dungeon na ativacao. So vale SEM o Mayheim: com ele, a escala de chefe do Mayheim faz isso.");
			RelicItems[0] = cfg.Bind<string>("4 - Recompensas", "ItensMontanha", "SwordSilver,MaceSilver,SpearWolfFang,KnifeSilver,FistFenrirClaw,BowDraugrFang,ShieldSilver,ShieldSerpentscale,HelmetDrake,ArmorWolfChest,ArmorWolfLegs,HelmetFenring,ArmorFenringChest,ArmorFenringLegs,CapeWolf", "Reliquias da Chave da Montanha (prefabs separados por virgula).");
			RelicItems[1] = cfg.Bind<string>("4 - Recompensas", "ItensMistlands", "SwordMistwalker,AxeJotunBane,SledgeDemolisher,SpearCarapace,KnifeSkollAndHati,AtgeirHimminAfl,BowSpineSnap,CrossbowArbalest,StaffFireball,StaffIceShards,ShieldCarapace,ShieldCarapaceBuckler,HelmetCarapace,ArmorCarapaceChest,ArmorCarapaceLegs,HelmetMage,ArmorMageChest,ArmorMageLegs,CapeFeather", "Reliquias da Chave das Terras Nebulosas.");
			RelicItems[2] = cfg.Bind<string>("4 - Recompensas", "ItensCinzas", "SwordNiedhogg,SwordNiedhoggBlood,SwordNiedhoggLightning,SwordNiedhoggNature,THSwordSlayer,THSwordSlayerBlood,THSwordSlayerLightning,THSwordSlayerNature,THSwordKrom,AxeBerzerkr,AxeBerzerkrBlood,AxeBerzerkrLightning,AxeBerzerkrNature,SpearSplitner,SpearSplitner_Blood,SpearSplitner_Lightning,SpearSplitner_Nature,BowAshlands,BowAshlandsBlood,BowAshlandsStorm,BowAshlandsRoot,CrossbowRipper,CrossbowRipperBlood,CrossbowRipperLightning,CrossbowRipperNature,StaffLightning,StaffClusterbomb,StaffGreenRoots,ShieldFlametal,ShieldFlametalTower,HelmetFlametal,ArmorFlametalChest,ArmorFlametalLegs,HelmetAshlandsMediumHood,ArmorAshlandsMediumChest,ArmorAshlandsMediumlegs,HelmetMage_Ashlands,ArmorMageChest_Ashlands,ArmorMageLegs_Ashlands,CapeAsh", "Reliquias da Chave das Terras das Cinzas.");
			RelicItems[3] = cfg.Bind<string>("4 - Recompensas", "ItensNorte", "SwordGold,THSwordGold,AtgeirGold,MaceGold,SledgeGold,AxeGold,BattleaxeGold,SpearGold,KnifeGold,FistGold,BowGold,CrossbowGold,SwordGold_FrostFire,THSwordGold_FrostFire,AtgeirGold_FrostFire,MaceGold_FrostFire,SledgeGold_FrostFire,AxeGold_FrostFire,BattleaxeGold_FrostFire,SpearGold_FrostFire,KnifeGold_FrostFire,FistGold_FrostFire,BowGold_FrostFire,CrossbowGold_FrostFire,SwordGold_BloodLightning,THSwordGold_BloodLightning,AtgeirGold_BloodLightning,MaceGold_BloodLightning,SledgeGold_BloodLightning,AxeGold_BloodLightning,BattleaxeGold_BloodLightning,SpearGold_BloodLightning,KnifeGold_BloodLightning,FistGold_BloodLightning,BowGold_BloodLightning,CrossbowGold_BloodLightning,StaffOrbofAhri,StaffSpiritCaller,StaffFrostOrbs,StaffThunderBlood,ShieldGold,HelmetDNHeavy,ArmorDeepNorthHeavyChest,ArmorDeepNorthHeavylegs,HelmetDNMediumHood,ArmorDeepNorthMediumChest,ArmorDeepNorthMediumlegs,HelmetDNMage,ArmorDeepNorthMageChest,ArmorDeepNorthMagelegs,CapeDeepNorth,CapeDeepNorthMage", "Reliquias da Chave do Norte Profundo.");
			RelicChanceBase = cfg.Bind<float>("4 - Recompensas", "RelicChanceBase", 0.35f, "Chance de reliquia de cada participante no nivel 0.");
			RelicChancePerLevel = cfg.Bind<float>("4 - Recompensas", "RelicChancePerLevel", 0.05f, "Chance extra de reliquia por nivel. Toda corrida entrega pelo menos uma reliquia no grupo.");
			GoldBase = cfg.Bind<int>("4 - Recompensas", "GoldBase", 500, "Moedas para cada participante ao concluir.");
			GoldPerLevel = cfg.Bind<int>("4 - Recompensas", "GoldPerLevel", 250, "Moedas extras por nivel da chave.");
			RelicMultPerLevel = cfg.Bind<float>("4 - Recompensas", "RelicMultPerLevel", 0.04f, "Multiplicador de dano, armadura e bloqueio da reliquia por nivel da chave.");
			RelicMultMax = cfg.Bind<float>("4 - Recompensas", "RelicMultMax", 1.6f, "Teto do multiplicador da reliquia.");
			RelicAttrMin = cfg.Bind<int>("4 - Recompensas", "RelicAttrMin", 1, "Pontos de atributo extras (minimo).");
			RelicAttrMax = cfg.Bind<int>("4 - Recompensas", "RelicAttrMax", 3, "Pontos de atributo extras (maximo).");
			RelicElementChance = cfg.Bind<float>("4 - Recompensas", "RelicElementChance", 0.6f, "Chance de uma ARMA reliquia vir com bonus elemental permanente.");
			ElementBase = cfg.Bind<float>("4 - Recompensas", "ElementBase", 8f, "Dano elemental base por golpe (a resina das Adagas usa 10 por 5 minutos).");
			ElementPerLevel = cfg.Bind<float>("4 - Recompensas", "ElementPerLevel", 1f, "Dano elemental extra por nivel da chave.");
			CategoryWeights = cfg.Bind<string>("4 - Recompensas", "PesosCategoria", "Corpo=30,Armadura=25,Distancia=15,Cajado=15,Escudo=10,Capa=5", "Sorteio da reliquia em duas etapas: primeiro a CATEGORIA por estes pesos, depois o item dentro dela. Categorias: Corpo (arma corpo a corpo), Distancia (arco e besta), Cajado, Armadura, Escudo, Capa. Categoria sem item na lista da chave fica de fora do sorteio.");
			StyleChance = cfg.Bind<float>("4 - Recompensas", "ChanceEstilo", 0.5f, "Chance de a reliquia seguir o estilo de quem recebe (a maior habilidade de combate: corpo a corpo, arco/besta ou magia). Vale tambem para armadura: quem usa magia puxa armadura de mago, os outros puxam armadura comum.");
			StaffEitrPerLevel = cfg.Bind<float>("4 - Recompensas", "CajadoEitrPorNivel", 0.02f, "Cajado reliquia nao leva infusao elemental (ela somaria a cada projetil). No lugar, gasta menos eitr: 0,02 = -2% por nivel da chave.");
			StaffEitrMax = cfg.Bind<float>("4 - Recompensas", "CajadoEitrMax", 0.3f, "Teto da economia de eitr do cajado reliquia (0,30 = -30%).");
			VersionCheck = cfg.Bind<bool>("9 - Rede", "VersionCheck", true, "Servidor recusa cliente sem o mod ou com versao diferente.");
			ConfigSync = cfg.Bind<bool>("9 - Rede", "ConfigSync", true, "Servidor envia esta config aos clientes (so em memoria).");
		}
	}
	internal static class Comandos
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			public static ConsoleEvent <>9__1_1;

			public static ConsoleEvent <>9__1_2;

			public static ConsoleEvent <>9__1_7;

			public static ConsoleEvent <>9__1_8;

			public static ConsoleEvent <>9__1_3;

			public static ConsoleEvent <>9__1_4;

			public static ConsoleEvent <>9__1_5;

			public static ConsoleEvent <>9__1_6;

			internal void <Registrar>b__1_0(ConsoleEventArgs args)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString("Entre em um mundo primeiro.");
					return;
				}
				CorridaInfo corridaInfo = Cliente.Em(((Component)localPlayer).transform.position);
				args.Context.AddString((corridaInfo != null) ? $"Corrida mítica aqui: {Biomas.Nome(corridaInfo.Bioma)} +{corridaInfo.Nivel} (chave de {corridaInfo.Dono})." : "Nenhuma corrida mítica onde você está.");
				args.Context.AddString($"Corridas ativas no mundo: {Cliente.Corridas.Count}.");
				foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
				{
					if (MayheimMiticas.Chaves.Chaves.EhChave(allItem, out var b))
					{
						args.Context.AddString($"  chave: {Biomas.Nome(b)} +{MayheimMiticas.Chaves.Chaves.Nivel(allItem)}");
					}
				}
			}

			internal void <Registrar>b__1_1(ConsoleEventArgs args)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString("Entre em um mundo primeiro.");
					return;
				}
				foreach (string item in Cliente.Diagnostico(((Component)localPlayer).transform.position))
				{
					args.Context.AddString(item);
					Plugin.Log.LogInfo((object)("[Miticas] aqui: " + item));
				}
			}

			internal void <Registrar>b__1_2(ConsoleEventArgs args)
			{
				if (args.Length < 3)
				{
					args.Context.AddString("Uso: myth_chave <montanha|mistlands|cinzas|norte> <nivel>");
				}
				else
				{
					Pede("chave " + args[1] + " " + args[2], args.Context);
				}
			}

			internal void <Registrar>b__1_7(ConsoleEventArgs args)
			{
				if (args.Length < 2)
				{
					args.Context.AddString("Uso: myth_kit <montanha|mistlands|cinzas|norte> [nivel]");
				}
				else
				{
					Pede("kit " + args[1] + " " + ((args.Length >= 3) ? args[2] : "5"), args.Context);
				}
			}

			internal void <Registrar>b__1_8(ConsoleEventArgs args)
			{
				if (args.Length < 2)
				{
					args.Context.AddString("Uso: myth_armas <montanha|mistlands|cinzas|norte> [nivel]");
				}
				else
				{
					Pede("armas " + args[1] + " " + ((args.Length >= 3) ? args[2] : "5"), args.Context);
				}
			}

			internal void <Registrar>b__1_3(ConsoleEventArgs args)
			{
				Pede("chefe", args.Context);
			}

			internal void <Registrar>b__1_4(ConsoleEventArgs args)
			{
				Pede("encerrar", args.Context);
			}

			internal void <Registrar>b__1_5(ConsoleEventArgs args)
			{
				Pede("estado", args.Context);
			}

			internal void <Registrar>b__1_6(ConsoleEventArgs args)
			{
				string text = ((args.Length >= 2) ? args[1] : "");
				if (!T.Disponivel)
				{
					args.Context.AddString("A suite de teste precisa do Mayheim instalado.");
					return;
				}
				T.Iniciar(string.IsNullOrEmpty(text) ? "miticas" : text);
				args.Context.AddString("Suite iniciada; resultado no log com o prefixo [MMOTEST].");
			}
		}

		private static bool _feito;

		internal static void Registrar()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			if (_feito)
			{
				return;
			}
			_feito = true;
			object obj = <>c.<>9__1_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						args.Context.AddString("Entre em um mundo primeiro.");
						return;
					}
					CorridaInfo corridaInfo = Cliente.Em(((Component)localPlayer).transform.position);
					args.Context.AddString((corridaInfo != null) ? $"Corrida mítica aqui: {Biomas.Nome(corridaInfo.Bioma)} +{corridaInfo.Nivel} (chave de {corridaInfo.Dono})." : "Nenhuma corrida mítica onde você está.");
					args.Context.AddString($"Corridas ativas no mundo: {Cliente.Corridas.Count}.");
					foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
					{
						if (MayheimMiticas.Chaves.Chaves.EhChave(allItem, out var b))
						{
							args.Context.AddString($"  chave: {Biomas.Nome(b)} +{MayheimMiticas.Chaves.Chaves.Nivel(allItem)}");
						}
					}
				};
				<>c.<>9__1_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("myth", "Dungeons miticas: corrida ativa onde voce esta e as suas chaves.", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__1_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						args.Context.AddString("Entre em um mundo primeiro.");
						return;
					}
					foreach (string item in Cliente.Diagnostico(((Component)localPlayer).transform.position))
					{
						args.Context.AddString(item);
						Plugin.Log.LogInfo((object)("[Miticas] aqui: " + item));
					}
				};
				<>c.<>9__1_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("myth_aqui", "Diagnostico: as dungeons que a chave enxerga daqui (dentro, tipo, tier, chefe).", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj3 = <>c.<>9__1_2;
			if (obj3 == null)
			{
				ConsoleEvent val3 = delegate(ConsoleEventArgs args)
				{
					if (args.Length < 3)
					{
						args.Context.AddString("Uso: myth_chave <montanha|mistlands|cinzas|norte> <nivel>");
					}
					else
					{
						Pede("chave " + args[1] + " " + args[2], args.Context);
					}
				};
				<>c.<>9__1_2 = val3;
				obj3 = (object)val3;
			}
			new ConsoleCommand("myth_chave", "Admin: cria uma chave. Uso: myth_chave <montanha|mistlands|cinzas|norte> <nivel>", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			string[] array = new string[2] { "myth_", "mith_" };
			foreach (string obj4 in array)
			{
				string text = obj4 + "kit";
				object obj5 = <>c.<>9__1_7;
				if (obj5 == null)
				{
					ConsoleEvent val4 = delegate(ConsoleEventArgs args)
					{
						if (args.Length < 2)
						{
							args.Context.AddString("Uso: myth_kit <montanha|mistlands|cinzas|norte> [nivel]");
						}
						else
						{
							Pede("kit " + args[1] + " " + ((args.Length >= 3) ? args[2] : "5"), args.Context);
						}
					};
					<>c.<>9__1_7 = val4;
					obj5 = (object)val4;
				}
				new ConsoleCommand(text, "Admin: armaduras e capas reliquia do bioma. Uso: myth_kit <montanha|mistlands|cinzas|norte> [nivel=5]", (ConsoleEvent)obj5, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				string text2 = obj4 + "armas";
				object obj6 = <>c.<>9__1_8;
				if (obj6 == null)
				{
					ConsoleEvent val5 = delegate(ConsoleEventArgs args)
					{
						if (args.Length < 2)
						{
							args.Context.AddString("Uso: myth_armas <montanha|mistlands|cinzas|norte> [nivel]");
						}
						else
						{
							Pede("armas " + args[1] + " " + ((args.Length >= 3) ? args[2] : "5"), args.Context);
						}
					};
					<>c.<>9__1_8 = val5;
					obj6 = (object)val5;
				}
				new ConsoleCommand(text2, "Admin: armas, cajados, arcos, bestas e escudos reliquia do bioma, cada arma com um elemento. Uso: myth_armas <bioma> [nivel=5]", (ConsoleEvent)obj6, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
			object obj7 = <>c.<>9__1_3;
			if (obj7 == null)
			{
				ConsoleEvent val6 = delegate(ConsoleEventArgs args)
				{
					Pede("chefe", args.Context);
				};
				<>c.<>9__1_3 = val6;
				obj7 = (object)val6;
			}
			new ConsoleCommand("myth_chefe", "Admin: traz o chefe mitico da corrida onde voce esta ate voce (chefe preso ou perdido).", (ConsoleEvent)obj7, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj8 = <>c.<>9__1_4;
			if (obj8 == null)
			{
				ConsoleEvent val7 = delegate(ConsoleEventArgs args)
				{
					Pede("encerrar", args.Context);
				};
				<>c.<>9__1_4 = val7;
				obj8 = (object)val7;
			}
			new ConsoleCommand("myth_encerrar", "Admin: encerra a corrida onde voce esta (a chave volta ao dono no mesmo nivel).", (ConsoleEvent)obj8, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj9 = <>c.<>9__1_5;
			if (obj9 == null)
			{
				ConsoleEvent val8 = delegate(ConsoleEventArgs args)
				{
					Pede("estado", args.Context);
				};
				<>c.<>9__1_5 = val8;
				obj9 = (object)val8;
			}
			new ConsoleCommand("myth_estado", "Admin: corridas ativas e chaves pendentes no servidor.", (ConsoleEvent)obj9, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj10 = <>c.<>9__1_6;
			if (obj10 == null)
			{
				ConsoleEvent val9 = delegate(ConsoleEventArgs args)
				{
					string text3 = ((args.Length >= 2) ? args[1] : "");
					if (!T.Disponivel)
					{
						args.Context.AddString("A suite de teste precisa do Mayheim instalado.");
					}
					else
					{
						T.Iniciar(string.IsNullOrEmpty(text3) ? "miticas" : text3);
						args.Context.AddString("Suite iniciada; resultado no log com o prefixo [MMOTEST].");
					}
				};
				<>c.<>9__1_6 = val9;
				obj10 = (object)val9;
			}
			new ConsoleCommand("myth_teste", "Roda a suite de teste do MayheimMiticas. Uso: myth_teste [filtro]", (ConsoleEvent)obj10, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void Pede(string cmd, Terminal ctx)
		{
			if (ZRoutedRpc.instance == null)
			{
				ctx.AddString("Entre em um mundo primeiro.");
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(Rede.Servidor, "Myth_Admin", new object[1] { cmd });
			ctx.AddString("Pedido enviado ao servidor; a resposta aparece na tela.");
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class Terminal_InitTerminal_MythPatch
	{
		private static void Postfix()
		{
			Comandos.Registrar();
		}
	}
	[BepInPlugin("com.mayheim.miticas", "MayheimMiticas", "0.1.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginId = "com.mayheim.miticas";

		public const string PluginName = "MayheimMiticas";

		public const string PluginVersion = "0.1.3";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static readonly List<string> PatchesComFalha = new List<string>();

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.mayheim.miticas");
			PatchIsolated();
			MythTests.Registrar();
			DuoTests.Registrar();
			SorteioTests.Registrar();
			Log.LogInfo((object)"MayheimMiticas v0.1.3 carregado.");
		}

		private void PatchIsolated()
		{
			int num = 0;
			PatchesComFalha.Clear();
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0)
				{
					try
					{
						_harmony.CreateClassProcessor(type).Patch();
						num++;
					}
					catch (Exception ex)
					{
						PatchesComFalha.Add(type.FullName + ": " + ex.Message);
						Log.LogError((object)("Falha ao aplicar patch " + type.FullName + ": " + ex.Message));
					}
				}
			}
			Log.LogInfo((object)($"Patches aplicados: {num} classes" + ((PatchesComFalha.Count > 0) ? $", {PatchesComFalha.Count} com falha." : ".")));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace MayheimMiticas.Testing
{
	internal static class DuoTests
	{
		private const string RpcPergunta = "MythTeste_QualMina";

		private const string RpcResposta = "MythTeste_Mina";

		private static Vector3? _minaParaVisita;

		private static Vector3? _minaRecebida;

		private static bool _registrado;

		private static Player Eu => Player.m_localPlayer;

		internal static void Registrar()
		{
			T.Registrar("duo-host", "refazer da mina visto por outro jogador", Anfitriao);
			T.Registrar("duo-join", "cliente usa a chave e refaz a mina", Visita);
		}

		private static void GaranteRpc()
		{
			if (_registrado || ZRoutedRpc.instance == null)
			{
				return;
			}
			_registrado = true;
			ZRoutedRpc.instance.Register("MythTeste_QualMina", (Action<long>)delegate(long sender)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if (_minaParaVisita.HasValue)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(sender, "MythTeste_Mina", new object[1] { _minaParaVisita.Value });
				}
			});
			ZRoutedRpc.instance.Register<Vector3>("MythTeste_Mina", (Action<long, Vector3>)delegate(long sender, Vector3 pos)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				_minaRecebida = pos;
			});
		}

		private static IEnumerator VaiAte(Vector3 alvo)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			yield return T.EsperaAte(() => (Object)(object)Game.instance != (Object)null && !((MonoBehaviour)Game.instance).IsInvoking("_RequestRespawn") && (Object)(object)Eu != (Object)null && !((Character)Eu).IsDead() && !((Character)Eu).IsTeleporting(), 40f, "personagem vivo e parado");
			Player eu = Eu;
			if (eu != null)
			{
				eu.SetGodMode(true);
			}
			bool foi = false;
			yield return T.EsperaAte(() => foi = foi || ((Object)(object)Eu != (Object)null && ((Character)Eu).TeleportTo(alvo + Vector3.up * 1.5f, ((Component)Eu).transform.rotation, true)), 20f, "teleporte aceito");
		}

		private static IEnumerator EsperaMina(Action<Cliente.Achado> achou)
		{
			Cliente.Achado a = null;
			yield return T.EsperaAte(delegate
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Eu == (Object)null)
				{
					return false;
				}
				a = Cliente.Dungeons(((Component)Eu).transform.position).Find((Cliente.Achado d) => d.NaEntrada && d.Mitica && d.Bioma == Bioma.Mistlands);
				return a != null;
			}, 90f, "mina carregada, na entrada");
			achou(a);
		}

		private static string Assinatura(DungeonGenerator g)
		{
			if ((Object)(object)g == (Object)null || (Object)(object)g.m_nview == (Object)null || !g.m_nview.IsValid())
			{
				return "";
			}
			byte[] array = default(byte[]);
			g.m_nview.GetZDO().GetByteArray(ZDOVars.s_roomData, ref array);
			using MD5 mD = MD5.Create();
			return (array == null) ? "" : Convert.ToBase64String(mD.ComputeHash(array));
		}

		private static int SalasNaCena(DungeonGenerator g)
		{
			if (!((Object)(object)g != (Object)null))
			{
				return 0;
			}
			return ((Component)g).GetComponentsInChildren<Room>(true).Length;
		}

		private static IEnumerator Anfitriao()
		{
			GaranteRpc();
			Vector3? mina = null;
			float num = float.MaxValue;
			foreach (LocationInstance value in ZoneSystem.instance.m_locationInstances.Values)
			{
				if (value.m_location?.m_prefabName != null && value.m_location.m_prefabName.Contains("DvergrTown"))
				{
					Vector3 position = value.m_position;
					float magnitude = ((Vector3)(ref position)).magnitude;
					if (magnitude < num)
					{
						num = magnitude;
						mina = value.m_position;
					}
				}
			}
			T.Ok(mina.HasValue, "mina infestada no mundo de teste");
			if (!mina.HasValue)
			{
				yield break;
			}
			yield return VaiAte(mina.Value);
			Cliente.Achado a = null;
			yield return EsperaMina(delegate(Cliente.Achado x)
			{
				a = x;
			});
			if (a == null)
			{
				yield break;
			}
			yield return T.Espera(3f);
			Servidor_.Ativas.RemoveAll((Corrida r) => Area.Dentro(r.Pos, a.Centro, a.Tamanho) || r.Gerador == a.Gen.m_nview.GetZDO().m_uid);
			Servidor_.Grava();
			DungeonGenerator g = a.Gen;
			ZDOID genId = g.m_nview.GetZDO().m_uid;
			string antes = Assinatura(g);
			List<ZDOID> conteudoAntes = new List<ZDOID>();
			List<ZDO> list = new List<ZDO>();
			List<ZDO> list2 = new List<ZDO>();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(a.Centro), new SimulationDistance(2, 0, true), list, list2);
			list.AddRange(list2);
			HashSet<int> hashSet = Refazer.PrefabsDaDungeon(g);
			foreach (ZDO item in list)
			{
				if (item != null && Area.Dentro(item.GetPosition(), a.Centro, a.Tamanho) && hashSet.Contains(item.GetPrefab()))
				{
					conteudoAntes.Add(item.m_uid);
				}
			}
			int salasCenaAntes = SalasNaCena(g);
			T.Nota($"antes: {salasCenaAntes} sala(s) na cena, {conteudoAntes.Count} objeto(s) da mina no servidor");
			_minaParaVisita = mina.Value;
			yield return T.EsperaAte(() => Servidor_.Ativas.Exists((Corrida r) => r.Gerador == genId && r.Chefe != ZDOID.None), 240f, "a visita ativou a chave e o chefe foi registrado");
			Corrida corrida = Servidor_.Ativas.Find((Corrida r) => r.Gerador == genId);
			T.Ok(corrida != null, "SERVIDOR: corrida registrada para a mina");
			if (corrida == null)
			{
				yield break;
			}
			yield return T.EsperaAte(() => ZDOMan.instance.GetZDO(corrida.Chefe) != null, 20f, "ZDO do chefe no servidor");
			T.Ok(ZDOMan.instance.GetZDO(corrida.Chefe) != null, "SERVIDOR: o ZDO do chefe mitico chegou");
			yield return T.EsperaAte(() => Assinatura(g) != antes, 30f, "lista de salas nova chegou ao servidor");
			T.Ok(Assinatura(g) != antes, "SERVIDOR: a lista de salas no ZDO mudou");
			int num2 = 0;
			foreach (ZDOID item2 in conteudoAntes)
			{
				if (ZDOMan.instance.GetZDO(item2) != null)
				{
					num2++;
				}
			}
			T.Igual(0, num2, "SERVIDOR: nenhum objeto antigo da mina sobrou");
			yield return T.EsperaAte(() => (Object)(object)g != (Object)null && SalasNaCena(g) == NaLista() && NaLista() > 0, 40f, "salas recarregadas na cena do outro jogador");
			if ((Object)(object)g != (Object)null)
			{
				T.Igual(NaLista(), SalasNaCena(g), "OUTRO JOGADOR: as salas na cena sao as da lista nova");
				T.Nota($"depois: {SalasNaCena(g)} sala(s) na cena (antes {salasCenaAntes})");
			}
			_minaParaVisita = null;
			Player eu = Eu;
			if (eu != null)
			{
				eu.SetGodMode(false);
			}
			int NaLista()
			{
				byte[] array = default(byte[]);
				if ((Object)(object)g == (Object)null || !g.m_nview.GetZDO().GetByteArray(ZDOVars.s_roomData, ref array) || array == null)
				{
					return -1;
				}
				return new BinaryReader(new MemoryStream(array)).ReadInt32();
			}
		}

		private static IEnumerator Visita()
		{
			GaranteRpc();
			float proxima = 0f;
			yield return T.EsperaAte(delegate
			{
				if (_minaRecebida.HasValue)
				{
					return true;
				}
				if (Time.time > proxima)
				{
					proxima = Time.time + 2f;
					ZRoutedRpc.instance.InvokeRoutedRPC(Rede.Servidor, "MythTeste_QualMina", Array.Empty<object>());
				}
				return false;
			}, 240f, "anfitriao pronto na entrada da mina");
			if (!_minaRecebida.HasValue)
			{
				yield break;
			}
			yield return VaiAte(_minaRecebida.Value);
			Cliente.Achado a = null;
			yield return EsperaMina(delegate(Cliente.Achado x)
			{
				a = x;
			});
			if (a == null)
			{
				yield break;
			}
			yield return T.Espera(3f);
			string antes = Assinatura(a.Gen);
			Player eu = Eu;
			MayheimMiticas.Chaves.Chaves.Entrega(eu, Bioma.Mistlands, 3);
			ItemData val = null;
			foreach (ItemData allItem in ((Humanoid)eu).GetInventory().GetAllItems())
			{
				if (MayheimMiticas.Chaves.Chaves.EhChave(allItem, out var b) && b == Bioma.Mistlands)
				{
					val = allItem;
				}
			}
			T.Ok(val != null, "chave na mochila");
			if (val == null)
			{
				yield break;
			}
			((Humanoid)eu).ConsumeItem(((Humanoid)eu).GetInventory(), val, false);
			yield return T.EsperaAte(() => Cliente.Em(a.Centro) != null, 30f, "servidor aceitou e anunciou a corrida");
			T.Ok(Cliente.Em(a.Centro) != null, "CLIENTE: a corrida esta ativa na mina");
			yield return T.EsperaAte(() => Assinatura(a.Gen) != antes, 10f, "mina refeita");
			T.Ok(Assinatura(a.Gen) != antes, "CLIENTE: quem usou a chave refez a mina");
			ZDO chefe = null;
			yield return T.EsperaAte(delegate
			{
				foreach (Character allCharacter in Character.GetAllCharacters())
				{
					if (ChefeMitico.Eh(allCharacter))
					{
						chefe = allCharacter.m_nview.GetZDO();
						return true;
					}
				}
				return false;
			}, 15f, "chefe mitico na mina");
			T.Ok(chefe != null && Area.Dentro(chefe.GetPosition(), a.Centro, a.Tamanho), "CLIENTE: o chefe mitico nasceu dentro da mina");
			yield return T.Espera(25f);
			Player eu2 = Eu;
			if (eu2 != null)
			{
				eu2.SetGodMode(false);
			}
		}
	}
	internal static class MythTests
	{
		private const string G = "miticas";

		private static Player Eu => Player.m_localPlayer;

		internal static void Registrar()
		{
			T.Registrar("miticas", "patches do mod aplicados", Patches);
			T.Registrar("miticas", "chaves registradas e com nivel", ChavesOk);
			T.Registrar("miticas", "equipamento de reliquia nos quatro biomas", PoolOk);
			T.Registrar("miticas", "reliquia sobrevive a gravar e carregar", Persistencia);
			T.Registrar("miticas", "reliquia: poder no dano, armadura e atributos do Mayheim", Poder);
			T.Registrar("miticas", "reliquia: infusao permanente soma dano", Infusao);
			T.Registrar("miticas", "reliquia e chave fora da venda do mercador", ForaDaVenda);
			T.Registrar("miticas", "corrida concluida: premio e chave +1", Conclusao);
			T.Registrar("miticas", "corrida abandonada: chave volta no mesmo nivel", Abandono);
			T.Registrar("miticas", "escalador: vida sobe na corrida e volta depois", EscaladorOk);
			T.Registrar("miticas", "ativacao pelo servidor: bioma pelo prefab, segunda chave, conclusao", Ativacao);
			T.Registrar("miticas", "melhoria na bancada preserva a reliquia", MelhoriaOk);
			T.Registrar("miticas", "chefe de verdade deixa a chave (chance 100% no teste)", DropDeChefe);
			T.Registrar("miticas", "chefe mitico da chave: criado, escalado e a morte conclui", ChefeProprio);
			T.Registrar("miticas", "reliquia equipada nao pesa no recalculo de atributos", Desempenho);
			T.Registrar("miticas", "morte na corrida: sem lapide e renasce na entrada", MorteNaCorrida);
			T.Registrar("miticas", "dentro da corrida todos ficam do mesmo lado (dvergr e buscador)", MesmoLado);
			T.Registrar("miticas", "chave refaz a mina de verdade: estrutura nova e conteudo renovado", RefazMina);
			T.Registrar("miticas", "chave refaz a caverna de gelo: chefe num ponto alcancavel", RefazCaverna);
			T.Registrar("miticas", "brilho da reliquia em arma de duas maos e armadura", Brilho);
			T.Registrar("miticas", "chefe do Mayheim nao fica dentro da corrida", SemChefeDoMayheim);
			T.Registrar("miticas", "comandos de teste: myth_kit e myth_armas", KitsDeTeste);
		}

		private static IEnumerator Brilho()
		{
			Player p = Eu;
			if ((Object)(object)p == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Inventory inv = ((Humanoid)p).GetInventory();
			ItemData arma = inv.AddItem("AtgeirHimminAfl", 1, 1, 0, 0L, "", false, false);
			ItemData peito = inv.AddItem("ArmorCarapaceChest", 1, 1, 0, 0L, "", false, false);
			if (arma == null || peito == null)
			{
				T.Ok(c: false, "itens na mochila");
				yield break;
			}
			arma.m_customData["myth_relic"] = "1";
			arma.m_customData["myth_elem"] = 4.ToString();
			arma.m_customData["myth_elem_dano"] = "10";
			peito.m_customData["myth_relic"] = "1";
			peito.m_customData["myth_bioma"] = 1.ToString();
			((Humanoid)p).EquipItem(arma, true);
			((Humanoid)p).EquipItem(peito, true);
			ZDO zdo = ((Character)p).m_nview.GetZDO();
			string ka = "myth_vis_" + StringExtensionMethods.GetStableHashCode("AtgeirHimminAfl");
			string kp = "myth_vis_" + StringExtensionMethods.GetStableHashCode("ArmorCarapaceChest");
			yield return T.EsperaAte(() => zdo.GetInt(ka, -1) == 4 && zdo.GetInt(kp, -1) == Particulas.DoBioma(Bioma.Mistlands), 6f, "brilho publicado na rede");
			T.Igual(4, zdo.GetInt(ka, -1), "atgeir de duas maos publica o elemento (veneno)");
			T.Igual(Particulas.DoBioma(Bioma.Mistlands), zdo.GetInt(kp, -1), "peitoral reliquia das Terras Nebulosas publica o brilho de nevoa");
			int num = 0;
			Transform[] componentsInChildren = ((Component)p).GetComponentsInChildren<Transform>(true);
			for (int num2 = 0; num2 < componentsInChildren.Length; num2++)
			{
				if (((Object)componentsInChildren[num2]).name == "MYTH_BrilhoReliquia")
				{
					num++;
				}
			}
			T.Ok(num > 0, $"particulas penduradas nas pecas ({num})");
			int num3 = 0;
			componentsInChildren = ((Component)p).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == "MYTH_BrilhoReliquia" && (Object)(object)val.parent != (Object)null && (((Object)val.parent).name == "Spine1" || ((Object)val.parent).name == "Spine2"))
				{
					num3++;
				}
			}
			T.Ok(num3 >= 2, $"brilho do peitoral preso aos ossos do tronco, nao a malha ({num3})");
			((Humanoid)p).UnequipItem(arma, true);
			((Humanoid)p).UnequipItem(peito, true);
			yield return T.Espera(1.5f);
			inv.RemoveItem(arma);
			inv.RemoveItem(peito);
		}

		private static List<ItemData> ReliquiasComigo(Player p)
		{
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (Reliquia.Eh(allItem))
				{
					list.Add(allItem);
				}
			}
			return list;
		}

		private static List<ItemDrop> ReliquiasNoChao(Vector3 perto)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			List<ItemDrop> list = new List<ItemDrop>();
			ItemDrop[] array = Object.FindObjectsByType<ItemDrop>((FindObjectsSortMode)0);
			foreach (ItemDrop val in array)
			{
				if ((Object)(object)val != (Object)null && Reliquia.Eh(val.m_itemData) && Vector3.Distance(((Component)val).transform.position, perto) < 6f)
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static void LimpaReliquias(Player p)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemData item in ReliquiasComigo(p))
			{
				((Humanoid)p).GetInventory().RemoveItem(item);
			}
			foreach (ItemDrop item2 in ReliquiasNoChao(((Component)p).transform.position))
			{
				ZNetScene.instance.Destroy(((Component)item2).gameObject);
			}
		}

		private static IEnumerator KitsDeTeste()
		{
			Player p = Eu;
			if ((Object)(object)p == (Object)null || !Rede.SouServidor)
			{
				T.Ok(c: false, "precisa ser host");
				yield break;
			}
			LimpaReliquias(p);
			yield return T.Espera(0.5f);
			Servidor_.AoAdmin(Rede.MeuId, "kit montanha 3");
			yield return T.Espera(1f);
			List<ItemData> list = ReliquiasComigo(p);
			int num = 0;
			foreach (ItemData item in list)
			{
				ItemType itemType = item.m_shared.m_itemType;
				if ((int)itemType == 6 || (int)itemType == 7 || (int)itemType == 11 || (int)itemType == 17)
				{
					num++;
				}
			}
			T.Ok(num >= 7 && num == list.Count, $"myth_kit montanha: {num} peca(s) de armadura e capa, nada alem disso");
			T.Ok(list.TrueForAll((ItemData it) => Reliquia.Nivel(it) == 3 && Reliquia.BiomaDe(it) == Bioma.Montanha), "todas reliquia da Montanha no nivel +3");
			LimpaReliquias(p);
			yield return T.Espera(0.5f);
			Servidor_.AoAdmin(Rede.MeuId, "armas mistlands 2");
			yield return T.Espera(1.5f);
			List<ItemData> list2 = ReliquiasComigo(p);
			foreach (ItemDrop item2 in ReliquiasNoChao(((Component)p).transform.position))
			{
				list2.Add(item2.m_itemData);
			}
			int num2 = 0;
			HashSet<Elemento> hashSet = new HashSet<Elemento>();
			foreach (ItemData item3 in list2)
			{
				if (item3.IsWeapon() && Reliquia.ElementoDe(item3) != Elemento.Nenhum)
				{
					num2++;
					hashSet.Add(Reliquia.ElementoDe(item3));
				}
				ItemType itemType2 = item3.m_shared.m_itemType;
				bool c = (int)itemType2 != 6 && (int)itemType2 != 7 && (int)itemType2 != 11 && (int)itemType2 != 17;
				GameObject dropPrefab = item3.m_dropPrefab;
				T.Ok(c, ((dropPrefab != null) ? ((Object)dropPrefab).name : null) + " nao e armadura");
			}
			int count = hashSet.Count;
			T.Ok(list2.Count >= 10, $"myth_armas mistlands: {list2.Count} item(ns)");
			T.Ok(count >= 8, $"as armas vieram com os oito elementos em rodizio ({count})");
			LimpaReliquias(p);
		}

		private static IEnumerator SemChefeDoMayheim()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Vector3 val = ((Component)eu).transform.position + ((Component)eu).transform.forward * 25f;
			LimpaCorridasEm(val);
			CorridaInfo info = new CorridaInfo
			{
				Gerador = new ZDOID(1L, 999994u),
				Pos = val,
				Bioma = Bioma.Mistlands,
				Nivel = 3,
				Dono = "teste"
			};
			Cliente.Corridas.Add(info);
			Character component = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Dverger"), val, Quaternion.identity).GetComponent<Character>();
			component.m_nview.GetZDO().Set("mmo_dboss", 5);
			ZDOID id = component.m_nview.GetZDO().m_uid;
			yield return T.EsperaAte(() => ZDOMan.instance.GetZDO(id) == null, 6f, "chefe do Mayheim removido");
			T.Ok(ZDOMan.instance.GetZDO(id) == null, "o chefe de dungeon do Mayheim sai de dentro da corrida");
			Cliente.Corridas.Remove(info);
			MethodInfo methodInfo = AccessTools.Method(Mayheim.Tipo("ValheimMMO.Dungeons.DungeonKeeper"), "Handle", (Type[])null, (Type[])null);
			T.Ok(((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null)?.Prefixes.Any((Patch x) => x.owner == "com.mayheim.miticas") ?? false, "o guardiao do Mayheim (servidor) pula dungeon em corrida");
			MethodInfo methodInfo2 = AccessTools.Method(Mayheim.Tipo("ValheimMMO.Dungeons.DungeonKeeper"), "OnSpawnRequest", (Type[])null, (Type[])null);
			T.Ok(((methodInfo2 != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo2) : null)?.Prefixes.Any((Patch x) => x.owner == "com.mayheim.miticas") ?? false, "o pedido de chefe do Mayheim (cliente) e barrado em corrida");
		}

		private static IEnumerator MesmoLado()
		{
			Player p = Eu;
			if ((Object)(object)p == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Vector3 val = ((Component)p).transform.position + ((Component)p).transform.forward * 30f;
			LimpaCorridasEm(val);
			Character buscador = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Seeker"), val, Quaternion.identity).GetComponent<Character>();
			Character dvergr = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Dverger"), val + Vector3.right * 3f, Quaternion.identity).GetComponent<Character>();
			Faction faction = buscador.m_faction;
			Faction origDvergr = dvergr.m_faction;
			T.Ok(BaseAI.IsEnemy(buscador, dvergr), $"fora de corrida, buscador ({faction}) e dvergr ({origDvergr}) sao inimigos -- o problema existe");
			CorridaInfo info = new CorridaInfo
			{
				Gerador = new ZDOID(1L, 999995u),
				Pos = val,
				Bioma = Bioma.Mistlands,
				Nivel = 2,
				Dono = "teste"
			};
			Cliente.Corridas.Add(info);
			Faction alvo = ChefeMitico.Faccao(Bioma.Mistlands);
			yield return T.EsperaAte(() => (Object)(object)buscador != (Object)null && (Object)(object)dvergr != (Object)null && buscador.m_faction == alvo && dvergr.m_faction == alvo, 5f, "faccao da corrida aplicada");
			if ((Object)(object)buscador == (Object)null || (Object)(object)dvergr == (Object)null)
			{
				T.Ok(c: false, "criaturas vivas");
				yield break;
			}
			T.Ok(!BaseAI.IsEnemy(buscador, dvergr), $"dentro da corrida os dois ficam do mesmo lado ({alvo})");
			T.Ok(BaseAI.IsEnemy(dvergr, (Character)(object)p), "e o dvergr vira inimigo do jogador, como chefe");
			Cliente.Corridas.Remove(info);
			yield return T.EsperaAte(() => (Object)(object)dvergr == (Object)null || dvergr.m_faction == origDvergr, 5f, "faccao original de volta");
			if ((Object)(object)dvergr != (Object)null)
			{
				T.Igual(origDvergr, dvergr.m_faction, "fim da corrida: o dvergr volta a faccao dele");
			}
			if ((Object)(object)buscador != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)buscador).gameObject);
			}
			if ((Object)(object)dvergr != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)dvergr).gameObject);
			}
		}

		private static IEnumerator MorteNaCorrida()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Inventory inventory = ((Humanoid)eu).GetInventory();
			ItemData val = inventory.AddItem("Wood", 7, 1, 0, 0L, "", false, false);
			int count = inventory.GetAllItems().Count;
			Vector3 position = ((Component)eu).transform.position;
			LimpaCorridasEm(position);
			Vector3 val2 = position + Vector3.forward * 3f;
			CorridaInfo item = new CorridaInfo
			{
				Gerador = new ZDOID(1L, 999996u),
				Pos = position,
				Entrada = val2,
				Bioma = Bioma.Mistlands,
				Nivel = 2,
				Dono = "teste"
			};
			Cliente.Corridas.Add(item);
			try
			{
				Morte.AoMorrer(eu);
				T.Ok(Morte.SemLapide, "morte dentro da corrida: marcada para nao criar lapide");
				eu.CreateTombStone();
				T.Igual(count, inventory.GetAllItems().Count, "a mochila continua com tudo (nenhuma lapide criada)");
				bool respawnAfterDeath = Game.instance.m_respawnAfterDeath;
				float respawnWait = Game.instance.m_respawnWait;
				Game.instance.m_respawnAfterDeath = true;
				Vector3 val3 = default(Vector3);
				bool flag = default(bool);
				bool c = Game.instance.FindSpawnPoint(ref val3, ref flag, 999f);
				Game.instance.m_respawnAfterDeath = respawnAfterDeath;
				Game.instance.m_respawnWait = respawnWait;
				T.Ok(c, "o jogo aceita o ponto de renascer");
				T.Perto(0f, Vector3.Distance(val3, val2), 0.01f, "renasce no comeco da dungeon, nao na cama");
				T.Ok(!Morte.RenascerEm.HasValue, "o desvio vale uma vez so");
			}
			finally
			{
				Cliente.Corridas.Remove(item);
				Morte.SemLapide = false;
				Morte.RenascerEm = null;
				if (val != null)
				{
					inventory.RemoveItem(val);
				}
			}
			Morte.AoMorrer(eu);
			T.Ok(!Morte.SemLapide && !Morte.RenascerEm.HasValue, "fora de corrida a morte e a do jogo");
		}

		private static IEnumerator RefazMina()
		{
			return RefazDungeon("DvergrTown", Bioma.Mistlands, "mina");
		}

		private static IEnumerator RefazCaverna()
		{
			return RefazDungeon("MountainCave", Bioma.Montanha, "caverna");
		}

		private static IEnumerator RefazDungeon(string local, Bioma bioma, string nome)
		{
			yield return T.EsperaAte(() => (Object)(object)Game.instance != (Object)null && !((MonoBehaviour)Game.instance).IsInvoking("_RequestRespawn") && (Object)(object)Eu != (Object)null && !((Character)Eu).IsDead() && !((Character)Eu).IsTeleporting(), 30f, "personagem vivo e parado");
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Vector3? alvo = null;
			float num = float.MaxValue;
			foreach (LocationInstance value in ZoneSystem.instance.m_locationInstances.Values)
			{
				if (value.m_location != null && value.m_location.m_prefabName != null && value.m_location.m_prefabName.Contains(local))
				{
					float num2 = Vector3.Distance(value.m_position, ((Component)eu).transform.position);
					if (num2 < num)
					{
						num = num2;
						alvo = value.m_position;
					}
				}
			}
			T.Ok(alvo.HasValue, nome + " (" + local + ") no mundo de teste");
			if (!alvo.HasValue)
			{
				yield break;
			}
			eu.SetGodMode(true);
			bool foi = false;
			yield return T.EsperaAte(() => foi = foi || ((Object)(object)Eu != (Object)null && ((Character)Eu).TeleportTo(alvo.Value + Vector3.up * 1.5f, ((Component)Eu).transform.rotation, true)), 15f, "teleporte aceito");
			DungeonGenerator g = null;
			yield return T.EsperaAte(delegate
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				foreach (Cliente.Achado item in Cliente.Dungeons(((Component)Eu).transform.position))
				{
					if (item.NaEntrada && item.Mitica && item.Bioma == bioma)
					{
						g = item.Gen;
						return true;
					}
				}
				return false;
			}, 60f, nome + " carregada, jogador na entrada");
			Player eu2 = Eu;
			if (eu2 != null)
			{
				eu2.SetGodMode(false);
			}
			if ((Object)(object)g == (Object)null)
			{
				yield break;
			}
			yield return T.Espera(3f);
			Area.CaixaDe(g, out var centro, out var tam);
			string assinaturaAntes = Assinatura(g);
			List<ZDOID> conteudoAntes = ConteudoDe(centro, tam, Refazer.PrefabsDaDungeon(g));
			T.Ok(conteudoAntes.Count > 0, $"mina com conteudo antes ({conteudoAntes.Count} objeto(s))");
			int apagados = Refazer.Refaz(g, centro, tam);
			yield return T.Espera(2f);
			T.Ok(Assinatura(g) != assinaturaAntes, "a lista de salas mudou (estrutura nova)");
			T.Ok(((Component)g).transform.childCount > 0, $"salas novas na cena ({((Component)g).transform.childCount})");
			T.Ok(apagados >= conteudoAntes.Count, $"conteudo antigo apagado ({apagados})");
			int num3 = 0;
			foreach (ZDOID item2 in conteudoAntes)
			{
				if (ZDOMan.instance.GetZDO(item2) != null)
				{
					num3++;
				}
			}
			T.Igual(0, num3, "nenhum objeto antigo da mina sobrou");
			List<ZDOID> list = ConteudoDe(centro, tam, Refazer.PrefabsDaDungeon(g));
			T.Ok(list.Count > 0, $"conteudo novo criado ({list.Count} objeto(s): spawners, baus, portas)");
			Vector3 val = Cliente.EntradaDe(centro, tam, ((Component)Eu).transform.position);
			T.Ok(Area.Dentro(val, centro, tam), $"comeco da dungeon (renascimento) achado pela porta, DENTRO da mina: {val:F1}");
			T.Ok(Physics.Raycast(val + Vector3.up, Vector3.down, 4f), "ha chao sob o ponto de renascimento");
			Vector3 val2 = ChefeMitico.PontoDeNascer(centro, tam, val);
			T.Ok(Area.Dentro(val2, centro, tam), $"o chefe nasceria dentro da {nome} ({val2:F0}, a {Vector3.Distance(val2, val):0} m da entrada)");
			float num4 = float.MaxValue;
			CreatureSpawner[] array = Object.FindObjectsByType<CreatureSpawner>((FindObjectsSortMode)0);
			foreach (CreatureSpawner val3 in array)
			{
				if ((Object)(object)val3 != (Object)null && Area.Dentro(((Component)val3).transform.position, centro, tam))
				{
					num4 = Mathf.Min(num4, Vector3.Distance(((Component)val3).transform.position, val2));
				}
			}
			T.Ok(num4 < 3f, $"o chefe nasce num ponto de spawn de monstro da propria dungeon (a {num4:0.0} m de um), alcancavel");
		}

		private static string Assinatura(DungeonGenerator g)
		{
			byte[] array = default(byte[]);
			g.m_nview.GetZDO().GetByteArray(ZDOVars.s_roomData, ref array);
			if (array != null)
			{
				return Convert.ToBase64String(MD5.Create().ComputeHash(array));
			}
			return "";
		}

		private static List<ZDOID> ConteudoDe(Vector3 centro, Vector3 tam, HashSet<int> prefabs)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			List<ZDO> list = new List<ZDO>();
			List<ZDO> list2 = new List<ZDO>();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(centro), new SimulationDistance(2, 0, true), list, list2);
			list.AddRange(list2);
			List<ZDOID> list3 = new List<ZDOID>();
			foreach (ZDO item in list)
			{
				if (item != null && Area.Dentro(item.GetPosition(), centro, tam) && prefabs.Contains(item.GetPrefab()))
				{
					list3.Add(item.m_uid);
				}
			}
			return list3;
		}

		private static IEnumerator MelhoriaOk()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Inventory inventory = ((Humanoid)eu).GetInventory();
			Reliquia.Spec spec = Reliquia.Sorteia(Bioma.Montanha, 5);
			spec.Dados["myth_teste"] = "melhoria";
			ItemData val = Reliquia.Materializa(eu, spec);
			T.Ok(val != null, "reliquia criada");
			if (val == null)
			{
				yield break;
			}
			Vector2i gridPos = val.m_gridPos;
			string name = ((Object)val.m_dropPrefab).name;
			Melhoria.Comecar(val);
			inventory.RemoveItem(val);
			ItemData val2 = inventory.AddItem(name, 1, 2, 0, 0L, "", gridPos, false, false, true);
			Melhoria.Terminar();
			T.Ok(val2 != null, "item melhorado criado");
			if (val2 != null)
			{
				T.Igual(2, val2.m_quality, "qualidade subiu para 2");
				T.Ok(Reliquia.Eh(val2) && val2.m_customData.TryGetValue("myth_teste", out var value) && value == "melhoria", "as marcas da reliquia vieram para o item novo");
				T.Igual(5, Reliquia.Nivel(val2), "nivel da reliquia preservado");
				ItemData val3 = inventory.AddItem(name, 1, 1, 0, 0L, "", false, false);
				T.Ok(val3 != null && !Reliquia.Eh(val3), "item comum criado depois continua comum");
				inventory.RemoveItem(val2);
				if (val3 != null)
				{
					inventory.RemoveItem(val3);
				}
			}
		}

		private static IEnumerator DropDeChefe()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab("Eikthyr") : null);
			if ((Object)(object)val == (Object)null)
			{
				T.Ok(c: false, "prefab Eikthyr");
				yield break;
			}
			float chanceAntes = Cfg.KeyDropChance.Value;
			bool salvaAntes = ((BaseUnityPlugin)Plugin.Instance).Config.SaveOnConfigSet;
			((BaseUnityPlugin)Plugin.Instance).Config.SaveOnConfigSet = false;
			Cfg.KeyDropChance.Value = 1f;
			try
			{
				Vector3 pos = ((Component)eu).transform.position + ((Component)eu).transform.forward * 6f;
				Character chefe = Object.Instantiate<GameObject>(val, pos, Quaternion.identity).GetComponent<Character>();
				yield return T.Espera(1f);
				T.Ok((Object)(object)chefe != (Object)null && chefe.IsBoss(), "Eikthyr e chefe (m_boss)");
				if ((Object)(object)chefe == (Object)null)
				{
					yield break;
				}
				HitData val2 = new HitData();
				val2.m_damage.m_damage = 1E+10f;
				val2.m_point = ((Component)chefe).transform.position;
				chefe.Damage(val2);
				ItemDrop achada = null;
				yield return T.EsperaAte(delegate
				{
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					//IL_002a: Unknown result type (might be due to invalid IL or missing references)
					ItemDrop[] array = Object.FindObjectsByType<ItemDrop>((FindObjectsSortMode)0);
					foreach (ItemDrop val3 in array)
					{
						if (MayheimMiticas.Chaves.Chaves.EhChave(val3.m_itemData, out var _) && Vector3.Distance(((Component)val3).transform.position, pos) < 15f)
						{
							achada = val3;
							return true;
						}
					}
					return false;
				}, 8f, "chave no chao perto do chefe");
				T.Ok((Object)(object)achada != (Object)null, "o chefe deixou uma Chave Mitica");
				if ((Object)(object)achada != (Object)null)
				{
					T.Igual(Cfg.KeyDropLevel.Value, MayheimMiticas.Chaves.Chaves.Nivel(achada.m_itemData), "a chave cai no nivel configurado");
					ZNetScene.instance.Destroy(((Component)achada).gameObject);
				}
			}
			finally
			{
				Cfg.KeyDropChance.Value = chanceAntes;
				((BaseUnityPlugin)Plugin.Instance).Config.SaveOnConfigSet = salvaAntes;
			}
		}

		private static IEnumerator Desempenho()
		{
			MethodInfo methodInfo = AccessTools.Method(Mayheim.Tipo("ValheimMMO.Progression.ItemBonuses"), "For", new Type[1] { typeof(ItemData) }, (Type[])null);
			if (methodInfo == null)
			{
				T.Ok(c: false, "ItemBonuses.For do Mayheim");
				yield break;
			}
			ItemData val = Cria("HelmetCarapace");
			val.m_customData["myth_relic"] = "1";
			val.m_customData["myth_mult"] = "1.2";
			val.m_customData["myth_attr"] = "3:2";
			object[] parameters = new object[1] { val };
			methodInfo.Invoke(null, parameters);
			Stopwatch stopwatch = Stopwatch.StartNew();
			for (int i = 0; i < 5000; i++)
			{
				methodInfo.Invoke(null, parameters);
			}
			stopwatch.Stop();
			T.Ok(stopwatch.ElapsedMilliseconds < 100, $"5000 recalculos numa reliquia em {stopwatch.ElapsedMilliseconds} ms (limite 100)");
		}

		private static int PrefabDeGerador(Bioma b)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				DungeonGenerator val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<DungeonGenerator>(true) : null);
				if ((Object)(object)val != (Object)null && Biomas.DoTema(val.m_themes, out var b2) && b2 == b)
				{
					return StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
				}
			}
			return 0;
		}

		private static IEnumerator Ativacao()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null || !Rede.SouServidor || ZDOMan.instance == null)
			{
				T.Ok(c: false, "precisa ser host");
				yield break;
			}
			TiraChaves(Eu);
			int num = PrefabDeGerador(Bioma.Mistlands);
			T.Ok(num != 0, "achei um prefab de gerador de mina infestada");
			if (num != 0)
			{
				Vector3 pos = ((Component)eu).transform.position + new Vector3(4000f, 0f, 4000f);
				ZDO gen = ZDOMan.instance.CreateNewZDO(pos, num);
				gen.SetPrefab(num);
				gen.Persistent = true;
				Servidor_.AoAtivar(Rede.MeuId, Rede.PacoteAtivar(gen.m_uid, Bioma.Cinzas, 5, pos, Vector3.zero, Vector3.zero));
				yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Cinzas) > 0, 5f, "chave recusada de volta");
				T.Igual(5, NivelDaChave(Eu, Bioma.Cinzas), "chave de outro bioma recusada pelo servidor e devolvida no mesmo nivel");
				T.Ok(!Servidor_.Ativas.Exists((Corrida r) => r.Gerador == gen.m_uid), "sem corrida depois da recusa");
				TiraChaves(Eu);
				Servidor_.AoAtivar(Rede.MeuId, Rede.PacoteAtivar(gen.m_uid, Bioma.Mistlands, 3, pos, Vector3.zero, Vector3.zero));
				T.Ok(Servidor_.Ativas.Exists((Corrida r) => r.Gerador == gen.m_uid && r.Nivel == 3), "corrida Mistlands +3 ativa sem chefe do Mayheim");
				yield return T.EsperaAte(() => Cliente.Em(pos) != null, 3f, "cliente sabe da corrida");
				CorridaInfo corridaInfo = Cliente.Em(pos);
				T.Ok(corridaInfo != null && corridaInfo.Nivel == 3, "o cliente recebeu a lista com o nivel certo");
				Servidor_.AoAtivar(Rede.MeuId, Rede.PacoteAtivar(gen.m_uid, Bioma.Mistlands, 8, pos, Vector3.zero, Vector3.zero));
				yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Mistlands) > 0, 5f, "segunda chave de volta");
				T.Igual(8, NivelDaChave(Eu, Bioma.Mistlands), "segunda chave na mesma dungeon e recusada");
				TiraChaves(Eu);
				Servidor_.AoChefeMorrer(Rede.MeuId, gen.m_uid);
				yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Mistlands) > 0, 5f, "chave +1");
				T.Igual(4, NivelDaChave(Eu, Bioma.Mistlands), "chefe morto: chave volta +4");
				T.Ok(Cliente.Em(pos) == null, "a corrida sumiu da lista do cliente");
				TiraChaves(Eu);
				ZDOMan.instance.DestroyZDO(gen);
			}
		}

		private static IEnumerator ChefeProprio()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null || !Rede.SouServidor)
			{
				T.Ok(c: false, "precisa ser host");
				yield break;
			}
			TiraChaves(Eu);
			ZDOID gerador = default(ZDOID);
			((ZDOID)(ref gerador))..ctor(1L, 999997u);
			Vector3 position = ((Component)eu).transform.position;
			LimpaCorridasEm(position);
			string nome;
			Corrida r = new Corrida
			{
				Gerador = gerador,
				Pos = position,
				Bioma = Bioma.Mistlands,
				Nivel = 4,
				Dono = Rede.IdDe(Rede.MeuId, out nome),
				DonoNome = nome,
				Chefe = ZDOID.None,
				DiaInicio = Dia.Hoje()
			};
			Servidor_.Ativas.Add(r);
			ZDOID val = ChefeMitico.Cria(Bioma.Mistlands, 4, position + ((Component)eu).transform.forward * 7f, gerador, 1);
			T.Ok(val != ZDOID.None, "chefe mitico criado (" + ChefeMitico.Prefab(Bioma.Mistlands) + ")");
			if (val == ZDOID.None)
			{
				yield break;
			}
			Servidor_.AoChefeCriado(Rede.MeuId, gerador, val);
			T.Igual(val, r.Chefe, "o servidor registrou o chefe da corrida");
			GameObject val2 = ZNetScene.instance.FindInstance(val);
			Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Character>() : null);
			T.Ok((Object)(object)val3 != (Object)null && val3.IsBoss(), "e chefe de verdade (barra de chefe)");
			if (!((Object)(object)val3 == (Object)null))
			{
				T.Ok(val3.m_name.Contains("Chefe Mítico"), "nome proprio: " + val3.m_name);
				T.Perto(ChefeMitico.VidaBase(Bioma.Mistlands) * Escala.Vida(4), val3.GetMaxHealth(), 1f, "vida = base do bioma x escala do nivel +4");
				HitData val4 = new HitData();
				val4.m_damage.m_damage = 1E+10f;
				val4.m_point = ((Component)val3).transform.position;
				val3.Damage(val4);
				yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Mistlands) > 0, 8f, "chave +1 depois da morte do chefe");
				T.Igual(5, NivelDaChave(Eu, Bioma.Mistlands), "matar o chefe mitico conclui: chave volta +5");
				T.Ok(!Servidor_.Ativas.Contains(r), "corrida concluida");
				TiraChaves(Eu);
			}
		}

		private static IEnumerator Patches()
		{
			T.Ok(Plugin.PatchesComFalha.Count == 0, "nenhum patch recusado: " + string.Join(" | ", Plugin.PatchesComFalha));
			yield break;
		}

		private static IEnumerator ChavesOk()
		{
			Bioma[] todos = Biomas.Todos;
			foreach (Bioma b in todos)
			{
				ObjectDB instance = ObjectDB.instance;
				T.Ok((Object)(object)((instance != null) ? instance.GetItemPrefab(Biomas.Prefab(b)) : null) != (Object)null, "prefab " + Biomas.Prefab(b) + " no ObjectDB");
			}
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			ItemData val = ((Humanoid)eu).GetInventory().AddItem(Biomas.Prefab(Bioma.Mistlands), 1, 1, 0, 0L, "", false, false);
			T.Ok(val != null, "chave entra na mochila");
			if (val != null)
			{
				MayheimMiticas.Chaves.Chaves.DefineNivel(val, 7);
				T.Igual(7, MayheimMiticas.Chaves.Chaves.Nivel(val), "nivel gravado na chave");
				T.Ok(MayheimMiticas.Chaves.Chaves.EhChave(val, out var b2) && b2 == Bioma.Mistlands, "chave reconhecida com o bioma certo");
				((Humanoid)eu).GetInventory().RemoveItem(val);
			}
		}

		private static IEnumerator PoolOk()
		{
			Bioma[] todos = Biomas.Todos;
			foreach (Bioma b in todos)
			{
				List<string> list = Pool.Do(b);
				T.Ok(list.Count > 0, $"{Biomas.Nome(b)}: {list.Count} item(ns) na lista");
				foreach (string item in list)
				{
					ItemData itemData = ObjectDB.instance.GetItemPrefab(item).GetComponent<ItemDrop>().m_itemData;
					ItemType itemType = itemData.m_shared.m_itemType;
					int c;
					if ((int)itemType != 6 && (int)itemType != 7 && (int)itemType != 11 && (int)itemType != 5 && (int)itemType != 17)
					{
						if (itemData.IsWeapon())
						{
							DamageTypes damage = itemData.GetDamage(1, 0f);
							c = ((((DamageTypes)(ref damage)).GetTotalDamage() > 0f) ? 1 : 0);
						}
						else
						{
							c = 0;
						}
					}
					else
					{
						c = 1;
					}
					T.Ok((byte)c != 0, $"{item} e arma com dano, armadura ou escudo ({itemType})");
				}
				T.Nota(Biomas.Nome(b) + ": " + string.Join(", ", list));
			}
			yield break;
		}

		private static ItemData Achar(Player p, string marca, string valor)
		{
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (allItem.m_customData != null && allItem.m_customData.TryGetValue(marca, out var value) && value == valor)
				{
					return allItem;
				}
			}
			return null;
		}

		private static IEnumerator Persistencia()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Reliquia.Spec spec = Reliquia.Sorteia(Bioma.Mistlands, 9);
			T.Ok(spec != null, "sorteio de reliquia");
			if (spec != null)
			{
				spec.Dados["myth_teste"] = "persist";
				ItemData val = Reliquia.Materializa(eu, spec);
				T.Ok(val != null && Reliquia.Eh(val), "reliquia criada na mochila");
				ZPackage val2 = new ZPackage();
				eu.Save(val2);
				val2.SetPos(0);
				eu.m_knownStations.Clear();
				eu.Load(val2);
				ItemData val3 = Achar(eu, "myth_teste", "persist");
				T.Ok(val3 != null, "reliquia continua na mochila depois de gravar e carregar");
				if (val3 != null)
				{
					T.Igual(9, Reliquia.Nivel(val3), "nivel preservado");
					T.Perto(Escala.MultReliquia(9), Reliquia.Mult(val3), 0.001f, "multiplicador preservado");
					T.Igual(1, val3.m_quality, "nasce na qualidade 1 (pode ser melhorada)");
					((Humanoid)eu).GetInventory().RemoveItem(val3);
				}
			}
		}

		private static ItemData Cria(string prefab)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			ItemData obj = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
			obj.m_dropPrefab = itemPrefab;
			obj.m_quality = 1;
			obj.m_customData = new Dictionary<string, string>();
			return obj;
		}

		private static IEnumerator Poder()
		{
			ItemData obj = Cria("SwordMistwalker");
			ItemData val = Cria("SwordMistwalker");
			obj.m_customData["myth_relic"] = "1";
			obj.m_customData["myth_mult"] = "1.4";
			obj.m_customData["myth_attr"] = "0:2";
			DamageTypes damage = val.GetDamage();
			float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
			damage = obj.GetDamage();
			float totalDamage2 = ((DamageTypes)(ref damage)).GetTotalDamage();
			T.Perto(totalDamage * 1.4f, totalDamage2, 0.5f, $"dano da reliquia x1,4 ({totalDamage:0} -> {totalDamage2:0})");
			ItemData val2 = Cria("HelmetCarapace");
			ItemData obj2 = Cria("HelmetCarapace");
			val2.m_customData["myth_relic"] = "1";
			val2.m_customData["myth_mult"] = "1.4";
			T.Perto(obj2.GetArmor() * 1.4f, val2.GetArmor(), 0.05f, "armadura da reliquia x1,4");
			int[] array = T.BonusDoMayheim(val);
			int[] array2 = T.BonusDoMayheim(obj);
			int num = 0;
			int num2 = 0;
			int[] array3 = array;
			foreach (int num3 in array3)
			{
				num += num3;
			}
			array3 = array2;
			foreach (int num4 in array3)
			{
				num2 += num4;
			}
			T.Ok(array2[0] >= array[0] + 2, $"+2 de Vitalidade extra somado ao bonus do Mayheim ({array[0]} -> {array2[0]})");
			T.Ok(num2 >= num + 2, $"bonus total de atributos sobe ({num} -> {num2})");
			yield break;
		}

		private static IEnumerator Infusao()
		{
			HitData val = new HitData();
			Attack_ModifyDamage_ReliquiaPatch.Aplica(val, Elemento.Fogo, 10f, 1, null);
			T.Perto(20f, val.m_damage.m_fire, 0.01f, "fogo 10 x combo 2,0 = 20");
			HitData val2 = new HitData();
			Attack_ModifyDamage_ReliquiaPatch.Aplica(val2, Elemento.Raio, 10f, 0, null);
			T.Perto(13f, val2.m_damage.m_lightning, 0.01f, "raio 10 x combo 1,3 = 13");
			yield break;
		}

		private static IEnumerator ForaDaVenda()
		{
			ItemData obj = Cria("SwordMistwalker");
			obj.m_customData["myth_relic"] = "1";
			T.Ok(!T.MercadorVende(obj), "reliquia nao aparece para vender");
			T.Ok(!T.MercadorVende(Cria(Biomas.Prefab(Bioma.Cinzas))), "chave nao aparece para vender");
			yield break;
		}

		private static int NivelDaChave(Player p, Bioma b)
		{
			int num = 0;
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (MayheimMiticas.Chaves.Chaves.EhChave(allItem, out var b2) && b2 == b)
				{
					num = Mathf.Max(num, MayheimMiticas.Chaves.Chaves.Nivel(allItem));
				}
			}
			return num;
		}

		private static void TiraChaves(Player p)
		{
			foreach (ItemData item in new List<ItemData>(((Humanoid)p).GetInventory().GetAllItems()))
			{
				if (MayheimMiticas.Chaves.Chaves.EhChave(item, out var _))
				{
					((Humanoid)p).GetInventory().RemoveItem(item);
				}
			}
		}

		private static void LimpaCorridasEm(Vector3 pos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			int num = Servidor_.Ativas.RemoveAll((Corrida r) => Area.Dentro(pos, r.Pos));
			num += Cliente.Corridas.RemoveAll((CorridaInfo c) => Area.Dentro(pos, c.Pos));
			if (num > 0)
			{
				Servidor_.Grava();
				T.Nota($"{num} corrida(s) de rodada anterior removida(s) do ponto de teste");
			}
		}

		private static Corrida CorridaFalsa(Player p, int nivel)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			string nome;
			string dono = Rede.IdDe(Rede.MeuId, out nome);
			return new Corrida
			{
				Gerador = new ZDOID(1L, 999999u),
				Pos = ((Component)p).transform.position,
				Bioma = Bioma.Norte,
				Nivel = nivel,
				Dono = dono,
				DonoNome = nome,
				Chefe = ZDOID.None,
				DiaReset = 0,
				DiaInicio = Dia.Hoje()
			};
		}

		private static IEnumerator Conclusao()
		{
			Player p = Eu;
			if ((Object)(object)p == (Object)null || !Rede.SouServidor)
			{
				T.Ok(c: false, "precisa ser host (servidor local)");
				yield break;
			}
			TiraChaves(Eu);
			int reliquiasAntes = 0;
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (Reliquia.Eh(allItem))
				{
					reliquiasAntes++;
				}
			}
			Corrida r = CorridaFalsa(p, 6);
			Servidor_.Ativas.Add(r);
			Servidor_.Conclui(r);
			yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Norte) > 0, 5f, "chave de volta");
			T.Igual(7, NivelDaChave(Eu, Bioma.Norte), "a chave voltou um nivel acima (+6 -> +7)");
			int num = 0;
			foreach (ItemData allItem2 in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (Reliquia.Eh(allItem2))
				{
					num++;
				}
			}
			T.Ok(num > reliquiasAntes, "sozinho na corrida, a reliquia garantida veio para mim");
			T.Ok(!Servidor_.Ativas.Contains(r), "corrida saiu da lista");
			TiraChaves(Eu);
		}

		private static IEnumerator Abandono()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null || !Rede.SouServidor)
			{
				T.Ok(c: false, "precisa ser host (servidor local)");
				yield break;
			}
			TiraChaves(Eu);
			Corrida corrida = CorridaFalsa(eu, 4);
			Servidor_.Ativas.Add(corrida);
			Servidor_.Abandona(corrida, "teste");
			yield return T.EsperaAte(() => NivelDaChave(Eu, Bioma.Norte) > 0, 5f, "chave de volta");
			T.Igual(4, NivelDaChave(Eu, Bioma.Norte), "a chave voltou no MESMO nivel");
			TiraChaves(Eu);
		}

		private static IEnumerator EscaladorOk()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab("Skeleton") : null);
			if ((Object)(object)val == (Object)null)
			{
				T.Ok(c: false, "prefab Skeleton");
				yield break;
			}
			Vector3 pos = ((Component)eu).transform.position + ((Component)eu).transform.forward * 4f;
			LimpaCorridasEm(pos);
			GameObject val2 = Object.Instantiate<GameObject>(val, pos, Quaternion.identity);
			Character c = val2.GetComponent<Character>();
			yield return T.Espera(1f);
			float original = c.GetMaxHealth();
			CorridaInfo info = new CorridaInfo
			{
				Gerador = new ZDOID(1L, 999998u),
				Pos = pos,
				Bioma = Bioma.Montanha,
				Nivel = 5,
				Dono = "teste"
			};
			Cliente.Corridas.Add(info);
			yield return T.EsperaAte(() => (Object)(object)c != (Object)null && c.m_nview.GetZDO().GetInt("myth_nivel", 0) == 5, 6f, "escala aplicada");
			if ((Object)(object)c != (Object)null)
			{
				T.Perto(original * Escala.Vida(5), c.GetMaxHealth(), 1f, $"vida x{Escala.Vida(5):0.00} dentro da corrida");
			}
			Cliente.Corridas.Remove(info);
			yield return T.EsperaAte(() => (Object)(object)c != (Object)null && c.m_nview.GetZDO().GetInt("myth_nivel", 0) == 0, 6f, "escala desfeita");
			if ((Object)(object)c != (Object)null)
			{
				T.Perto(original, c.GetMaxHealth(), 1f, "vida volta ao normal quando a corrida acaba");
			}
			if ((Object)(object)c != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)c).gameObject);
			}
		}
	}
	internal static class SorteioTests
	{
		private const string G = "miticas";

		private static Player Eu => Player.m_localPlayer;

		internal static void Registrar()
		{
			T.Registrar("miticas", "sorteio: categoria de cada item da lista", Categorias);
			T.Registrar("miticas", "sorteio: pesos por categoria, nao por quantidade de itens", Pesos);
			T.Registrar("miticas", "sorteio: estilo puxa cajado e armadura de mago", EstiloPuxa);
			T.Registrar("miticas", "sorteio: maior habilidade de combate define o estilo", EstiloDoJogador);
			T.Registrar("miticas", "cajado reliquia: sem infusao, gasta menos eitr", CajadoEitr);
		}

		private static IEnumerator Categorias()
		{
			T.Igual(Categoria.Corpo, Pool.Categoria("SwordMistwalker"), "espada = corpo a corpo");
			T.Igual(Categoria.Corpo, Pool.Categoria("KnifeSkollAndHati"), "faca = corpo a corpo");
			T.Igual(Categoria.Distancia, Pool.Categoria("BowSpineSnap"), "arco = distancia");
			T.Igual(Categoria.Distancia, Pool.Categoria("CrossbowArbalest"), "besta = distancia");
			T.Igual(Categoria.Cajado, Pool.Categoria("StaffFireball"), "cajado = cajado");
			T.Igual(Categoria.Escudo, Pool.Categoria("ShieldCarapace"), "escudo = escudo");
			T.Igual(Categoria.Capa, Pool.Categoria("CapeFeather"), "capa = capa");
			T.Igual(Categoria.Armadura, Pool.Categoria("HelmetMage"), "capuz de mago = armadura");
			T.Igual(Categoria.Nenhuma, Pool.Categoria("NaoExisteNoJogo"), "prefab inexistente = nenhuma");
			T.Ok(Pool.EhDeMago("ArmorMageChest"), "tunica de mago e armadura de mago");
			T.Ok(!Pool.EhDeMago("ArmorCarapaceChest"), "peitoral de carapaca nao e de mago");
			yield break;
		}

		private static Dictionary<Categoria, int> Amostra(Bioma b, Categoria estilo, int n, out int armaduraMago, out int armaduras)
		{
			Dictionary<Categoria, int> dictionary = new Dictionary<Categoria, int>();
			armaduraMago = 0;
			armaduras = 0;
			for (int i = 0; i < n; i++)
			{
				List<string> list = Reliquia.EscolheItens(b, estilo);
				string prefab = list[Random.Range(0, list.Count)];
				Categoria categoria = Pool.Categoria(prefab);
				dictionary[categoria] = (dictionary.TryGetValue(categoria, out var value) ? value : 0) + 1;
				if (categoria == Categoria.Armadura)
				{
					armaduras++;
					if (Pool.EhDeMago(prefab))
					{
						armaduraMago++;
					}
				}
			}
			return dictionary;
		}

		private static float Parte(Dictionary<Categoria, int> d, Categoria c, int n)
		{
			int value;
			return (float)(d.TryGetValue(c, out value) ? value : 0) / (float)n;
		}

		private static IEnumerator Pesos()
		{
			Dictionary<Categoria, float> dictionary = Reliquia.Pesos();
			float num = 0f;
			foreach (float value2 in dictionary.Values)
			{
				num += value2;
			}
			T.Ok(num > 0f, "pesos lidos da config (" + Cfg.CategoryWeights.Value + ")");
			if (!(num <= 0f))
			{
				int armaduraMago;
				int armaduras;
				Dictionary<Categoria, int> d = Amostra(Bioma.Norte, Categoria.Nenhuma, 4000, out armaduraMago, out armaduras);
				Categoria[] array = new Categoria[6]
				{
					Categoria.Corpo,
					Categoria.Distancia,
					Categoria.Cajado,
					Categoria.Armadura,
					Categoria.Escudo,
					Categoria.Capa
				};
				foreach (Categoria categoria in array)
				{
					T.Perto((dictionary.TryGetValue(categoria, out var value) ? value : 0f) / num, Parte(d, categoria, 4000), 0.04f, $"Norte: {categoria} sai na proporcao do peso");
				}
			}
			yield break;
		}

		private static IEnumerator EstiloPuxa()
		{
			float num = Mathf.Clamp01(Cfg.StyleChance.Value);
			Dictionary<Categoria, float> dictionary = Reliquia.Pesos();
			float num2 = 0f;
			foreach (float value3 in dictionary.Values)
			{
				num2 += value3;
			}
			float value;
			float num3 = ((num2 > 0f && dictionary.TryGetValue(Categoria.Cajado, out value)) ? (value / num2) : 0f);
			int armaduraMago;
			int armaduras;
			Dictionary<Categoria, int> d = Amostra(Bioma.Mistlands, Categoria.Cajado, 4000, out armaduraMago, out armaduras);
			T.Perto(num + (1f - num) * num3, Parte(d, Categoria.Cajado, 4000), 0.04f, "mago: cajado vem pela chance do estilo + o sorteio livre");
			T.Ok(armaduras > 0 && (float)armaduraMago / (float)armaduras > 0.65f, $"mago: armadura puxa a de mago ({armaduraMago}/{armaduras})");
			T.Ok(Parte(Amostra(Bioma.Mistlands, Categoria.Corpo, 4000, out var armaduraMago2, out var armaduras2), Categoria.Cajado, 4000) < num3 + 0.03f, "guerreiro: cajado so pelo sorteio livre");
			T.Ok(armaduras2 > 0 && (float)armaduraMago2 / (float)armaduras2 < 0.35f, $"guerreiro: armadura puxa a comum ({armaduraMago2}/{armaduras2})");
			int armaduraMago3;
			int armaduras3;
			Dictionary<Categoria, int> dictionary2 = Amostra(Bioma.Montanha, Categoria.Cajado, 500, out armaduraMago3, out armaduras3);
			T.Igual(0, dictionary2.TryGetValue(Categoria.Cajado, out var value2) ? value2 : 0, "Montanha: nenhum cajado mesmo para o mago");
			yield break;
		}

		private static IEnumerator EstiloDoJogador()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Skills skills = ((Character)eu).GetSkills();
			Dictionary<SkillType, float> dictionary = new Dictionary<SkillType, float>();
			foreach (Skill skill in skills.GetSkillList())
			{
				dictionary[skill.m_info.m_skill] = skill.m_level;
			}
			try
			{
				foreach (Skill skill2 in skills.GetSkillList())
				{
					skill2.m_level = 0f;
				}
				T.Igual(Categoria.Nenhuma, Estilo.Calcula(eu), "tudo zerado: sem estilo");
				skills.GetSkill((SkillType)1).m_level = 20f;
				skills.GetSkill((SkillType)9).m_level = 35f;
				skills.GetSkill((SkillType)12).m_level = 90f;
				T.Igual(Categoria.Cajado, Estilo.Calcula(eu), "magia elemental maior: estilo cajado");
				skills.GetSkill((SkillType)14).m_level = 40f;
				T.Igual(Categoria.Distancia, Estilo.Calcula(eu), "besta maior: estilo distancia");
			}
			finally
			{
				foreach (Skill skill3 in skills.GetSkillList())
				{
					if (dictionary.TryGetValue(skill3.m_info.m_skill, out var value))
					{
						skill3.m_level = value;
					}
					else
					{
						skill3.m_level = 0f;
					}
				}
			}
		}

		private static IEnumerator CajadoEitr()
		{
			Player eu = Eu;
			if ((Object)(object)eu == (Object)null)
			{
				T.Ok(c: false, "personagem ativo");
				yield break;
			}
			Reliquia.Spec spec = Reliquia.Cria(Bioma.Mistlands, 10, "StaffFireball", 3);
			T.Ok(spec != null, "reliquia de cajado criada");
			if (spec == null)
			{
				yield break;
			}
			T.Ok(!spec.Dados.ContainsKey("myth_elem"), "cajado sem infusao elemental");
			T.Perto(Escala.EconomiaEitr(10), Txt.F(spec.Dados.TryGetValue("myth_eitr", out var value) ? value : "0"), 0.001f, "economia de eitr pelo nivel");
			ItemData val = Reliquia.Materializa(eu, spec);
			ItemData val2 = ((Humanoid)eu).GetInventory().AddItem("StaffFireball", 1, 1, 0, 0L, "", false, false);
			try
			{
				T.Ok(val != null && val2 != null, "cajados na mochila");
				if (val != null && val2 != null)
				{
					Attack attack = val2.m_shared.m_attack;
					float attackEitr = attack.GetAttackEitr((Character)(object)eu, val2);
					float attackEitr2 = attack.GetAttackEitr((Character)(object)eu, val);
					T.Ok(attackEitr > 0f, $"cajado comum gasta eitr ({attackEitr:0.0})");
					T.Perto(attackEitr * (1f - Escala.EconomiaEitr(10)), attackEitr2, 0.01f, $"reliquia gasta menos ({attackEitr2:0.0})");
					T.Ok(Reliquia.Tooltip(val).Contains("Economia de eitr"), "tooltip mostra a economia");
					Reliquia.Spec spec2 = Reliquia.Cria(Bioma.Mistlands, 50, "StaffFireball");
					T.Perto(Mathf.Clamp01(Cfg.StaffEitrMax.Value), Txt.F(spec2.Dados["myth_eitr"]), 0.001f, "economia para no teto");
					Reliquia.Spec spec3 = Reliquia.Cria(Bioma.Mistlands, 10, "SwordMistwalker", 3);
					T.Ok(spec3.Dados.ContainsKey("myth_elem") && !spec3.Dados.ContainsKey("myth_eitr"), "espada segue com infusao e sem economia");
				}
			}
			finally
			{
				if (val != null)
				{
					((Humanoid)eu).GetInventory().RemoveItem(val);
				}
				if (val2 != null)
				{
					((Humanoid)eu).GetInventory().RemoveItem(val2);
				}
			}
		}
	}
	internal static class T
	{
		private static Type _tipo;

		private static Type Tipo => _tipo ?? (_tipo = Mayheim.Tipo("ValheimMMO.Testing.MmoTest"));

		public static bool Disponivel => Tipo != null;

		private static object Chama(string nome, Type[] tipos, params object[] args)
		{
			return AccessTools.Method(Tipo, nome, tipos, (Type[])null)?.Invoke(null, args);
		}

		public static void Registrar(string grupo, string nome, Func<IEnumerator> caso)
		{
			if (!(Tipo == null))
			{
				Type type = AccessTools.Inner(Tipo, "Caso");
				Delegate obj = Delegate.CreateDelegate(type, caso.Target, caso.Method);
				Chama("Registrar", new Type[3]
				{
					typeof(string),
					typeof(string),
					type
				}, grupo, nome, obj);
			}
		}

		public static void Iniciar(string filtro)
		{
			Chama("Iniciar", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, filtro, false);
		}

		public static void Ok(bool c, string o)
		{
			Chama("Ok", new Type[2]
			{
				typeof(bool),
				typeof(string)
			}, c, o);
		}

		public static void Nota(string t)
		{
			Chama("Nota", new Type[1] { typeof(string) }, t);
		}

		public static void Igual(object e, object o, string oq)
		{
			Chama("Igual", new Type[3]
			{
				typeof(object),
				typeof(object),
				typeof(string)
			}, e, o, oq);
		}

		public static void Perto(float e, float o, float tol, string oq)
		{
			Chama("Perto", new Type[4]
			{
				typeof(float),
				typeof(float),
				typeof(float),
				typeof(string)
			}, e, o, tol, oq);
		}

		public static IEnumerator Espera(float s)
		{
			return (IEnumerator)Chama("Espera", new Type[1] { typeof(float) }, s);
		}

		public static IEnumerator EsperaAte(Func<bool> c, float lim, string oq)
		{
			return (IEnumerator)Chama("EsperaAte", new Type[3]
			{
				typeof(Func<bool>),
				typeof(float),
				typeof(string)
			}, c, lim, oq);
		}

		public static int[] BonusDoMayheim(ItemData item)
		{
			return ((int[])AccessTools.Method(Mayheim.Tipo("ValheimMMO.Progression.ItemBonuses"), "For", new Type[1] { typeof(ItemData) }, (Type[])null)?.Invoke(null, new object[1] { item })) ?? new int[4];
		}

		public static bool MercadorVende(ItemData item)
		{
			MethodInfo methodInfo = MerchantSellUI_CanSell_MythPatch.Alvo() as MethodInfo;
			if (methodInfo != null)
			{
				return (bool)methodInfo.Invoke(null, new object[1] { item });
			}
			return false;
		}
	}
}
namespace MayheimMiticas.Reliquias
{
	internal static class Estilo
	{
		private static readonly Dictionary<long, Categoria> _servidor = new Dictionary<long, Categoria>();

		private static Categoria _enviado = Categoria.Nenhuma;

		private static bool _jaEnviou;

		public static Categoria De(long uid)
		{
			if (!_servidor.TryGetValue(uid, out var value))
			{
				return Categoria.Nenhuma;
			}
			return value;
		}

		internal static void AoReceber(long sender, int cat)
		{
			if (Rede.SouServidor)
			{
				Categoria categoria = ((cat >= 0 && cat <= 5) ? ((Categoria)cat) : Categoria.Nenhuma);
				_servidor[sender] = categoria;
				Plugin.Log.LogInfo((object)$"[Reliquias] estilo de {sender}: {categoria}.");
			}
		}

		public static Categoria Calcula(Player p)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			Skills val = (((Object)(object)p != (Object)null) ? ((Character)p).GetSkills() : null);
			if ((Object)(object)val == (Object)null)
			{
				return Categoria.Nenhuma;
			}
			Categoria result = Categoria.Nenhuma;
			float num = 0f;
			foreach (Skill skill in val.GetSkillList())
			{
				if (skill?.m_info != null)
				{
					Categoria categoria = Pool.DoSkill(skill.m_info.m_skill);
					if (categoria != Categoria.Nenhuma && !(skill.m_level <= num))
					{
						num = skill.m_level;
						result = categoria;
					}
				}
			}
			return result;
		}

		internal static void Informa(Player p, bool forca)
		{
			if (!((Object)(object)p == (Object)null) && !((Object)(object)p != (Object)(object)Player.m_localPlayer) && ZRoutedRpc.instance != null)
			{
				Categoria categoria = Calcula(p);
				if (forca || !_jaEnviou || categoria != _enviado)
				{
					_enviado = categoria;
					_jaEnviou = true;
					ZRoutedRpc.instance.InvokeRoutedRPC(Rede.Servidor, "Myth_Estilo", new object[1] { (int)categoria });
				}
			}
		}

		internal static void Reset()
		{
			_servidor.Clear();
			_jaEnviou = false;
			_enviado = Categoria.Nenhuma;
		}
	}
	[HarmonyPatch(typeof(Player), "OnSkillLevelup")]
	internal static class Player_OnSkillLevelup_EstiloPatch
	{
		private static void Postfix(Player __instance)
		{
			Estilo.Informa(__instance, forca: false);
		}
	}
	internal static class Melhoria
	{
		private static string _prefab;

		private static Dictionary<string, string> _marcas;

		internal static void Comecar(ItemData antigo)
		{
			_prefab = null;
			_marcas = null;
			if (Reliquia.Eh(antigo) && !((Object)(object)antigo.m_dropPrefab == (Object)null))
			{
				_prefab = ((Object)antigo.m_dropPrefab).name;
				_marcas = new Dictionary<string, string>(antigo.m_customData);
			}
		}

		internal static void Terminar()
		{
			_prefab = null;
			_marcas = null;
		}

		internal static void AoCriar(string nome, ItemData novo)
		{
			if (_marcas == null || novo == null || nome != _prefab)
			{
				return;
			}
			if (novo.m_customData == null)
			{
				novo.m_customData = new Dictionary<string, string>();
			}
			foreach (KeyValuePair<string, string> marca in _marcas)
			{
				novo.m_customData[marca.Key] = marca.Value;
			}
			Plugin.Log.LogInfo((object)$"[Reliquias] melhoria na bancada: marcas da reliquia preservadas em {nome} q{novo.m_quality}.");
			Terminar();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class InventoryGui_DoCrafting_MelhoriaPatch
	{
		private static void Prefix(InventoryGui __instance)
		{
			Melhoria.Comecar(__instance.m_craftUpgradeItem);
		}

		private static void Finalizer()
		{
			Melhoria.Terminar();
		}
	}
	[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(int),
		typeof(int),
		typeof(long),
		typeof(string),
		typeof(Vector2i),
		typeof(bool),
		typeof(bool),
		typeof(bool)
	})]
	internal static class Inventory_AddItem_MelhoriaPatch
	{
		private static void Postfix(string name, ItemData __result)
		{
			Melhoria.AoCriar(name, __result);
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetDamage", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class ItemData_GetDamage_ReliquiaPatch
	{
		private static void Postfix(ItemData __instance, ref DamageTypes __result)
		{
			float num = Reliquia.Mult(__instance);
			if (num > 1.0001f)
			{
				((DamageTypes)(ref __result)).Modify(num);
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetArmor", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class ItemData_GetArmor_ReliquiaPatch
	{
		private static void Postfix(ItemData __instance, ref float __result)
		{
			float num = Reliquia.Mult(__instance);
			if (num > 1.0001f)
			{
				__result *= num;
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetBlockPower", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class ItemData_GetBlockPower_ReliquiaPatch
	{
		private static void Postfix(ItemData __instance, ref float __result)
		{
			float num = Reliquia.Mult(__instance);
			if (num > 1.0001f)
			{
				__result *= num;
			}
		}
	}
	[HarmonyPatch(typeof(Attack), "GetAttackEitr", new Type[]
	{
		typeof(Character),
		typeof(ItemData)
	})]
	internal static class Attack_GetAttackEitr_ReliquiaPatch
	{
		private static void Postfix(ItemData weapon, ref float __result)
		{
			float num = Reliquia.EconomiaEitr(weapon);
			if (num > 0f && __result > 0f)
			{
				__result *= 1f - num;
			}
		}
	}
	[HarmonyPatch]
	internal static class ItemBonuses_For_ReliquiaPatch
	{
		private static MethodBase Alvo()
		{
			return AccessTools.Method(Mayheim.Tipo("ValheimMMO.Progression.ItemBonuses"), "For", new Type[3]
			{
				typeof(ItemData),
				typeof(int),
				typeof(float)
			}, (Type[])null);
		}

		private static bool Prepare()
		{
			return Alvo() != null;
		}

		private static MethodBase TargetMethod()
		{
			return Alvo();
		}

		private static void Postfix(ItemData item, ref int[] __result)
		{
			if (__result == null || !Reliquia.Eh(item) || !Mayheim.TemAtributos())
			{
				return;
			}
			foreach (KeyValuePair<int, int> item2 in Reliquia.Atributos(item))
			{
				if (item2.Key >= 0 && item2.Key < __result.Length)
				{
					__result[item2.Key] += item2.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemData_GetTooltip_ReliquiaPatch
	{
		private static void Postfix(ItemData item, bool crafting, ref string __result)
		{
			if (!crafting && Reliquia.Eh(item))
			{
				__result += Reliquia.Tooltip(item);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")]
	internal static class InventoryGrid_CreateItemTooltip_ReliquiaPatch
	{
		private static bool Prefix(InventoryGrid __instance, ItemData item, UITooltip tooltip)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!Reliquia.Eh(item) || (Object)(object)tooltip == (Object)null)
			{
				return true;
			}
			tooltip.Set("<color=#E8B04B>" + Reliquia.Nome(item) + "</color>", item.GetTooltip(-1), __instance.m_tooltipAnchor, default(Vector2));
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "GetHoverName")]
	internal static class ItemDrop_GetHoverName_ReliquiaPatch
	{
		private static void Postfix(ItemDrop __instance, ref string __result)
		{
			if (Reliquia.Eh(__instance?.m_itemData))
			{
				__result = "<color=#E8B04B>" + Reliquia.Nome(__instance.m_itemData) + "</color>";
			}
		}
	}
	[HarmonyPatch(typeof(Attack), "ModifyDamage")]
	internal static class Attack_ModifyDamage_ReliquiaPatch
	{
		private static readonly float[] Combo = new float[3] { 1.3f, 2f, 1.5f };

		private static void Postfix(HitData hitData, int ___m_currentAttackCainLevel, ItemData ___m_weapon, Humanoid ___m_character)
		{
			try
			{
				if (hitData != null && ___m_character is Player)
				{
					Elemento elemento = Reliquia.ElementoDe(___m_weapon);
					if (elemento != Elemento.Nenhum)
					{
						Aplica(hitData, elemento, Reliquia.DanoElemental(___m_weapon), Mathf.Clamp(___m_currentAttackCainLevel, 0, Combo.Length - 1), (Character)(object)___m_character);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Reliquias] infusao: " + ex.Message));
			}
		}

		internal static void Aplica(HitData hit, Elemento e, float dano, int combo, Character atacante)
		{
			float num = Combo[Mathf.Clamp(combo, 0, Combo.Length - 1)];
			switch (e)
			{
			case Elemento.Fogo:
				hit.m_damage.m_fire += dano * num;
				break;
			case Elemento.Gelo:
				hit.m_damage.m_frost += dano * num;
				break;
			case Elemento.Raio:
				hit.m_damage.m_lightning += dano * num;
				break;
			case Elemento.Espirito:
				hit.m_damage.m_spirit += dano * num;
				break;
			case Elemento.Veneno:
				hit.m_damage.m_poison += dano * num;
				break;
			case Elemento.Lentidao:
				Status(hit, "AC_SE_Slowed");
				break;
			case Elemento.Sangramento:
				Status(hit, "AC_SE_Bleed");
				break;
			case Elemento.Vampirismo:
				if ((Object)(object)atacante != (Object)null)
				{
					float num2 = ((DamageTypes)(ref hit.m_damage)).GetTotalDamage();
					if (combo == Combo.Length - 1)
					{
						num2 *= 2f;
					}
					atacante.Heal(num2 * 0.15f, true);
				}
				break;
			}
		}

		private static void Status(HitData hit, string nome)
		{
			if (hit.m_statusEffectHash == 0 && !(Random.value >= 0.5f))
			{
				StatusEffect val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(nome)) : null);
				if ((Object)(object)val != (Object)null)
				{
					hit.m_statusEffectHash = val.NameHash();
				}
			}
		}
	}
	internal enum Elemento
	{
		Nenhum = -1,
		Fogo,
		Gelo,
		Raio,
		Espirito,
		Veneno,
		Vampirismo,
		Lentidao,
		Sangramento
	}
	internal enum Categoria
	{
		Nenhuma = -1,
		Corpo,
		Distancia,
		Cajado,
		Armadura,
		Escudo,
		Capa
	}
	internal static class Reliquia
	{
		internal sealed class Spec
		{
			public string Prefab;

			public Dictionary<string, string> Dados = new Dictionary<string, string>();

			public void Escreve(ZPackage pkg)
			{
				pkg.Write(Prefab ?? "");
				pkg.Write(Dados.Count);
				foreach (KeyValuePair<string, string> dado in Dados)
				{
					pkg.Write(dado.Key);
					pkg.Write(dado.Value);
				}
			}

			public static Spec Le(ZPackage pkg)
			{
				Spec spec = new Spec
				{
					Prefab = pkg.ReadString()
				};
				int num = pkg.ReadInt();
				for (int i = 0; i < num; i++)
				{
					spec.Dados[pkg.ReadString()] = pkg.ReadString();
				}
				return spec;
			}
		}

		public const string KRelic = "myth_relic";

		public const string KNivel = "myth_nivel";

		public const string KBioma = "myth_bioma";

		public const string KMult = "myth_mult";

		public const string KAttr = "myth_attr";

		public const string KElem = "myth_elem";

		public const string KElemDano = "myth_elem_dano";

		public const string KEitr = "myth_eitr";

		private static readonly Elemento[] Elementos = new Elemento[8]
		{
			Elemento.Fogo,
			Elemento.Gelo,
			Elemento.Raio,
			Elemento.Espirito,
			Elemento.Veneno,
			Elemento.Vampirismo,
			Elemento.Lentidao,
			Elemento.Sangramento
		};

		public static bool Eh(ItemData item)
		{
			if (item?.m_customData != null)
			{
				return item.m_customData.ContainsKey("myth_relic");
			}
			return false;
		}

		private static string Get(ItemData item, string k)
		{
			if (item?.m_customData == null || !item.m_customData.TryGetValue(k, out var value))
			{
				return null;
			}
			return value;
		}

		public static int Nivel(ItemData item)
		{
			return Txt.I(Get(item, "myth_nivel"));
		}

		public static Bioma BiomaDe(ItemData item)
		{
			return (Bioma)Mathf.Clamp(Txt.I(Get(item, "myth_bioma")), 0, 3);
		}

		public static float Mult(ItemData item)
		{
			if (!Eh(item))
			{
				return 1f;
			}
			return Mathf.Max(1f, Txt.F(Get(item, "myth_mult"), 1f));
		}

		public static Elemento ElementoDe(ItemData item)
		{
			if (!Eh(item))
			{
				return Elemento.Nenhum;
			}
			return (Elemento)Txt.I(Get(item, "myth_elem"), -1);
		}

		public static float DanoElemental(ItemData item)
		{
			return Txt.F(Get(item, "myth_elem_dano"));
		}

		public static float EconomiaEitr(ItemData item)
		{
			if (!Eh(item))
			{
				return 0f;
			}
			return Mathf.Clamp01(Txt.F(Get(item, "myth_eitr")));
		}

		public static Dictionary<int, int> Atributos(ItemData item)
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			string text = Get(item, "myth_attr");
			if (string.IsNullOrEmpty(text))
			{
				return dictionary;
			}
			string[] array = text.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(':');
				if (array2.Length == 2)
				{
					int num = Txt.I(array2[0], -1);
					int num2 = Txt.I(array2[1]);
					if (num >= 0 && num2 > 0)
					{
						dictionary[num] = (dictionary.TryGetValue(num, out var value) ? value : 0) + num2;
					}
				}
			}
			return dictionary;
		}

		public static string Nome(ItemData item)
		{
			return ((Localization.instance != null) ? Localization.instance.Localize(item.m_shared.m_name) : item.m_shared.m_name) + " " + Biomas.Epiteto(BiomaDe(item));
		}

		public static Spec Sorteia(Bioma b, int nivel, Categoria estilo = Categoria.Nenhuma)
		{
			List<string> list = EscolheItens(b, estilo);
			if (list == null || list.Count == 0)
			{
				Plugin.Log.LogWarning((object)("[Reliquias] lista de reliquias da " + Biomas.Nome(b) + " vazia (config Itens*)."));
				return null;
			}
			return Cria(b, nivel, list[Random.Range(0, list.Count)]);
		}

		internal static List<string> EscolheItens(Bioma b, Categoria estilo)
		{
			List<string> list = Pool.Do(b);
			if (list.Count == 0)
			{
				return list;
			}
			Dictionary<Categoria, List<string>> dictionary = new Dictionary<Categoria, List<string>>();
			foreach (string item in list)
			{
				Categoria categoria = Pool.Categoria(item);
				if (categoria != Categoria.Nenhuma)
				{
					if (!dictionary.TryGetValue(categoria, out var value))
					{
						value = (dictionary[categoria] = new List<string>());
					}
					value.Add(item);
				}
			}
			if (dictionary.Count == 0)
			{
				return list;
			}
			float num = Mathf.Clamp01(Cfg.StyleChance.Value);
			Categoria categoria2 = ((estilo == Categoria.Nenhuma || !dictionary.ContainsKey(estilo) || !(Random.value < num)) ? SorteiaCategoria(dictionary) : estilo);
			if (categoria2 == Categoria.Nenhuma)
			{
				return list;
			}
			List<string> list3 = dictionary[categoria2];
			if (categoria2 == Categoria.Armadura && estilo != Categoria.Nenhuma && Random.value < num)
			{
				bool mago = estilo == Categoria.Cajado;
				List<string> list4 = list3.FindAll((string p) => Pool.EhDeMago(p) == mago);
				if (list4.Count > 0)
				{
					list3 = list4;
				}
			}
			return list3;
		}

		private static Categoria SorteiaCategoria(Dictionary<Categoria, List<string>> porCat)
		{
			Dictionary<Categoria, float> dictionary = Pesos();
			float num = 0f;
			foreach (Categoria key in porCat.Keys)
			{
				num += (dictionary.TryGetValue(key, out var value) ? value : 0f);
			}
			if (num <= 0f)
			{
				List<Categoria> list = new List<Categoria>();
				foreach (KeyValuePair<Categoria, List<string>> item in porCat)
				{
					foreach (string item2 in item.Value)
					{
						_ = item2;
						list.Add(item.Key);
					}
				}
				return list[Random.Range(0, list.Count)];
			}
			float num2 = Random.value * num;
			foreach (Categoria key2 in porCat.Keys)
			{
				float value2;
				float num3 = (dictionary.TryGetValue(key2, out value2) ? value2 : 0f);
				if (!(num3 <= 0f))
				{
					if (num2 < num3)
					{
						return key2;
					}
					num2 -= num3;
				}
			}
			foreach (Categoria key3 in porCat.Keys)
			{
				if (dictionary.TryGetValue(key3, out var value3) && value3 > 0f)
				{
					return key3;
				}
			}
			return Categoria.Nenhuma;
		}

		internal static Dictionary<Categoria, float> Pesos()
		{
			Dictionary<Categoria, float> dictionary = new Dictionary<Categoria, float>();
			string[] array = (Cfg.CategoryWeights.Value ?? "").Split(',');
			f