Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MayheimMiticas v0.1.3
plugins\MayheimMiticas\MayheimMiticas.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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