using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Managers; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Profesiones")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Profesiones")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("50CF68F9-AA2B-4F41-B995-4C2EB29C4A19")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace EinjarheimProfessions; [BepInPlugin("nazhi.einjarheim.professions", "Einjarheim Professions", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("valheim.exe")] public class EinjarheimProfessionsPlugin : BaseUnityPlugin { public const string PluginGuid = "nazhi.einjarheim.professions"; public const string PluginName = "Einjarheim Professions"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"[Einjarheim Professions] v1.0.0 – iniciando..."); BlacksmithingSystem.RegisterSkill(); AlchemySystem.RegisterSkill(); _harmony = new Harmony("nazhi.einjarheim.professions"); _harmony.PatchAll(); Log.LogInfo((object)"[Einjarheim Professions] Profesiones cargadas:"); Log.LogInfo((object)"[Einjarheim Professions] · Cooking – bonus HP/Stamina/Eitr según nivel de cocina del chef"); Log.LogInfo((object)"[Einjarheim Professions] · Blacksmithing – durabilidad, daño y armadura según nivel de herrería"); Log.LogInfo((object)"[Einjarheim Professions] · Construction – HP de estructuras y descuento de recursos según Crafting"); Log.LogInfo((object)"[Einjarheim Professions] · Alchemy – potencia, duración y fermentación según nivel de alquimia"); } private void OnDestroy() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[Einjarheim Professions] OnDestroy – deshaciendo patches."); } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class AlchemySystem { public const string SkillIdentifier = "nazhi.alchemist"; private static SkillType s_skillType; private const float XP_PotionConsumed = 1f; private const float XP_PotionCrafted = 2f; private const float BasePowerBonus = 0.1f; private const float PowerPerLevel = 0.003f; private const float MaxPowerBonus = 0.4f; private const float BaseDurationBonus = 0.2f; private const float DurationPerLevel = 0.005f; private const float MaxDurationBonus = 0.7f; private const float BaseExtraChance = 0.15f; private const float ExtraChancePerLevel = 0.0015f; private const float MaxExtraChance = 0.3f; private const float BaseCooldownReduction = 0.1f; private const float CooldownReductionPerLevel = 0.002f; private const float MaxCooldownReduction = 0.3f; private const float BaseFermentReduction = 0.2f; private const float FermentReductionPerLevel = 0.004f; private const float MaxFermentReduction = 0.6f; private static bool _minLevelApplied; internal static SkillType SkillType => s_skillType; internal static void ResetMinLevelFlag() { _minLevelApplied = false; } internal static void RegisterSkill() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) SkillConfig val = new SkillConfig { Identifier = "nazhi.alchemist", Name = "Alquimista", Description = "$skill_alchemist_desc", Icon = null, IncreaseStep = 1f }; s_skillType = SkillManager.Instance.AddSkill(val); EinjarheimProfessionsPlugin.Log.LogInfo((object)string.Format("[Alchemy] Skill registrada: {0} ({1})", "nazhi.alchemist", s_skillType)); } internal static void AddExperience(Player player, float amount) { //IL_000a: 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) if (!((Object)(object)player == (Object)null) && (int)s_skillType != 0 && !(amount <= 0f) && !((Object)(object)((Character)player).m_nview == (Object)null) && ((Character)player).m_nview.IsOwner()) { ((Character)player).RaiseSkill(s_skillType, amount); } } internal static void OnPotionConsumed(Player player) { AddExperience(player, 1f); } internal static void OnPotionCrafted(Player player) { AddExperience(player, 2f); } internal static float GetLevel(Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return 0f; } return ((Character)player).GetSkillLevel(s_skillType); } internal static float GetPotionPowerMultiplier(Player player) { float num = 0.1f + 0.003f * GetLevel(player); return 1f + Mathf.Clamp(num, 0.1f, 0.4f); } internal static float GetPotionDurationMultiplier(Player player) { float num = 0.2f + 0.005f * GetLevel(player); return 1f + Mathf.Clamp(num, 0.2f, 0.7f); } internal static float GetExtraPotionChance(Player player) { float num = 0.15f + 0.0015f * GetLevel(player); return Mathf.Clamp(num, 0.15f, 0.3f); } internal static float GetPotionCooldownMultiplier(Player player) { float num = 0.1f + 0.002f * GetLevel(player); return 1f - Mathf.Clamp(num, 0.1f, 0.3f); } internal static float GetFermentationReduction(Player player) { float num = 0.2f + 0.004f * GetLevel(player); return Mathf.Clamp(num, 0f, 0.6f); } internal static float GetFermentationTimeMultiplier(Player player) { return 1f - GetFermentationReduction(player); } internal static bool RollExtraPotion(Player player) { return Random.value <= GetExtraPotionChance(player); } internal static void EnsureMinLevel(Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_0027: 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 (!_minLevelApplied && !((Object)(object)player == (Object)null) && (int)s_skillType != 0) { if (((Character)player).GetSkillLevel(s_skillType) < 1f) { ((Character)player).RaiseSkill(s_skillType, 0.5f); EinjarheimProfessionsPlugin.Log.LogInfo((object)"[Alchemy] Nivel inicial de Alquimia establecido a 1."); } _minLevelApplied = true; } } } internal static class AlchemyPotionUtils { internal static bool IsPotion(ItemData item) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (item?.m_shared == null) { return false; } if ((int)item.m_shared.m_itemType != 2) { return false; } return (Object)(object)item.m_shared.m_consumeStatusEffect != (Object)null; } internal static bool IsMeadBase(ItemData item) { if (item?.m_shared == null) { return false; } string text = item.m_shared.m_name.ToLowerInvariant(); return text.Contains("item_meadbase") || text.Contains("meadbase") || text.Contains("mead_base") || (text.Contains("ketill") && (text.Contains("mead") || text.Contains("base"))); } internal static bool IsFinalMead(ItemData item) { if (item?.m_shared == null) { return false; } string text = item.m_shared.m_name.ToLowerInvariant(); return text.Contains("item_mead_") || (text.Contains("mead") && !text.Contains("meadbase")); } } internal static class AlchemyStatsApplier { internal static void ApplyPowerAndDuration(Player player, SE_Stats stats) { if (!((Object)(object)player == (Object)null) && !((Object)(object)stats == (Object)null)) { float potionDurationMultiplier = AlchemySystem.GetPotionDurationMultiplier(player); float potionPowerMultiplier = AlchemySystem.GetPotionPowerMultiplier(player); if (((StatusEffect)stats).m_ttl > 0f) { ((StatusEffect)stats).m_ttl = ((StatusEffect)stats).m_ttl * potionDurationMultiplier; } if (stats.m_healthOverTimeDuration > 0f) { stats.m_healthOverTimeDuration *= potionDurationMultiplier; } if (stats.m_staminaOverTimeDuration > 0f) { stats.m_staminaOverTimeDuration *= potionDurationMultiplier; } if (stats.m_eitrOverTimeDuration > 0f) { stats.m_eitrOverTimeDuration *= potionDurationMultiplier; } stats.m_healthUpFront *= potionPowerMultiplier; stats.m_staminaUpFront *= potionPowerMultiplier; stats.m_eitrUpFront *= potionPowerMultiplier; stats.m_healthOverTime *= potionPowerMultiplier; stats.m_staminaOverTime *= potionPowerMultiplier; stats.m_eitrOverTime *= potionPowerMultiplier; stats.m_healthRegenMultiplier *= potionPowerMultiplier; stats.m_staminaRegenMultiplier *= potionPowerMultiplier; stats.m_eitrRegenMultiplier *= potionPowerMultiplier; } } } [HarmonyPatch(typeof(Player), "Update")] internal static class Alchemy_Patch_EnsureMinLevel { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { AlchemySystem.EnsureMinLevel(__instance); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Alchemy_Patch_OnSpawned { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { AlchemySystem.ResetMinLevelFlag(); } } } [HarmonyPatch(typeof(Player), "ConsumeItem")] internal static class Alchemy_Patch_ConsumeItem { private static void Prefix(Player __instance, ItemData item) { try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && AlchemyPotionUtils.IsPotion(item)) { AlchemySystem.OnPotionConsumed(__instance); } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en ConsumeItem: {arg}"); } } } [HarmonyPatch(typeof(SE_Stats), "Setup")] internal static class Alchemy_Patch_SE_Stats_Setup { private static void Prefix(SE_Stats __instance, Character character) { try { Player val = (Player)(object)((character is Player) ? character : null); if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer) { AlchemyStatsApplier.ApplyPowerAndDuration(val, __instance); } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en SE_Stats.Setup: {arg}"); } } } [HarmonyPatch(typeof(Fermenter), "AddItem")] internal static class Alchemy_Patch_Fermenter_AddItem { private static void Postfix(Fermenter __instance, Humanoid user, ItemData item, bool __result) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) try { if (__result && item != null && AlchemyPotionUtils.IsMeadBase(item)) { EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Alchemy] Mead base en fermenter {((Component)__instance).transform.position}: {item.m_shared.m_name} x{item.m_stack}"); Player val = (Player)(object)((user is Player) ? user : null); if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer) { AlchemySystem.OnPotionCrafted(val); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en Fermenter.AddItem: {arg}"); } } } [HarmonyPatch(typeof(Fermenter), "RPC_AddItem")] internal static class Alchemy_Patch_Fermenter_RPC_AddItem { private static void Postfix(Fermenter __instance, long sender, string name) { try { if ((Object)(object)__instance?.m_nview == (Object)null || !__instance.m_nview.IsOwner()) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } float fermentationReduction = AlchemySystem.GetFermentationReduction(localPlayer); if (!(fermentationReduction <= 0f)) { ZDO zDO = __instance.m_nview.GetZDO(); long @long = zDO.GetLong(ZDOVars.s_startTime, 0L); if (@long != 0) { double num = __instance.m_fermentationDuration * fermentationReduction; long num2 = (long)(num * 10000000.0); long num3 = Math.Max(0L, @long - num2); zDO.Set(ZDOVars.s_startTime, num3); EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Alchemy] Fermentación acelerada -{fermentationReduction * 100f:0}% (~{num:0}s) para '{name}'."); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en RPC_AddItem: {arg}"); } } } [HarmonyPatch(typeof(Fermenter), "DelayedTap")] internal static class Alchemy_Patch_Fermenter_DelayedTap { private static void Postfix(Fermenter __instance) { try { string delayedTapItem = __instance.m_delayedTapItem; if (string.IsNullOrEmpty(delayedTapItem)) { return; } ItemConversion itemConversion = __instance.GetItemConversion(delayedTapItem); if (!((Object)(object)itemConversion?.m_to == (Object)null)) { EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Alchemy] Fermenter produjo: {itemConversion.m_to.m_itemData?.m_shared?.m_name} x{itemConversion.m_producedItems}"); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { AlchemySystem.OnPotionCrafted(localPlayer); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en DelayedTap: {arg}"); } } } [HarmonyPatch] internal static class Alchemy_Patch_Tooltip { private static IEnumerable TargetMethods() { return from m in typeof(ItemData).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "GetTooltip" && m.ReturnType == typeof(string) select m; } private static void Postfix(ItemData __instance, ref string __result) { try { if (__instance?.m_shared == null) { return; } bool flag = AlchemyPotionUtils.IsPotion(__instance); bool flag2 = AlchemyPotionUtils.IsMeadBase(__instance); bool flag3 = AlchemyPotionUtils.IsFinalMead(__instance); if (flag || flag2 || flag3) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !__result.Contains("=== Alquimia ===")) { int num = Mathf.FloorToInt(AlchemySystem.GetLevel(localPlayer)); float num2 = (AlchemySystem.GetPotionDurationMultiplier(localPlayer) - 1f) * 100f; float num3 = (AlchemySystem.GetPotionPowerMultiplier(localPlayer) - 1f) * 100f; float num4 = AlchemySystem.GetFermentationReduction(localPlayer) * 100f; __result = __result + $"\n\n==== Alquimia Level [{num}] ====" + $"\nPotencia de poción: +{num3:0}%" + $"\nDuración de poción: +{num2:0}%" + $"\nFermentación rápida: -{num4:0}%"; } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogWarning((object)$"[Alchemy] Error en Tooltip: {arg}"); } } } internal static class BlacksmithingSystem { private const string DurabilityKey = "nazhi_blacksmith_durability"; private const string LevelKey = "nazhi_blacksmith_lvl"; private const string CrafterKey = "nazhi_blacksmith_crafter"; private const float MaxDurabilityBonusAt100 = 0.6f; private const float DamageArmorMaxBonusAt100 = 1f; internal static SkillType BlacksmithingSkillType; private static bool _minLevelApplied; internal static void ResetMinLevelFlag() { _minLevelApplied = false; } internal static void RegisterSkill() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) SkillConfig val = new SkillConfig { Identifier = "nazhi.blacksmithing.skill", Name = "Herreria", Description = "Mejora la durabilidad y calidad del equipo forjado en fragua, fragua negra y mesa de trabajo.", Icon = null, IncreaseStep = 1f }; BlacksmithingSkillType = SkillManager.Instance.AddSkill(val); } internal static float GetLevel(Player player) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (int)BlacksmithingSkillType == 0) { return 0f; } return Mathf.Clamp(((Character)player).GetSkillLevel(BlacksmithingSkillType), 0f, 100f); } internal static float GetDurabilityFactor(float level) { if (level <= 0f) { return 1f; } return 1f + 0.6f * Mathf.Clamp01(level / 100f); } internal static float GetDamageArmorFactor(int level) { if (level <= 0) { return 1f; } return 1f + 1f * Mathf.Clamp01((float)level / 100f); } internal static float GetDamageArmorPercent(int level) { return (GetDamageArmorFactor(level) - 1f) * 100f; } internal static void OnItemForged(Player player, ItemData item) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && item != null && item.m_shared != null) { float level = GetLevel(player); float durabilityFactor = GetDurabilityFactor(level); int num = Mathf.RoundToInt(level); string playerName = player.GetPlayerName(); if (item.m_customData == null) { item.m_customData = new Dictionary(); } item.m_customData["nazhi_blacksmith_durability"] = durabilityFactor.ToString(CultureInfo.InvariantCulture); item.m_customData["nazhi_blacksmith_lvl"] = num.ToString(CultureInfo.InvariantCulture); item.m_customData["nazhi_blacksmith_crafter"] = playerName; ((Character)player).RaiseSkill(BlacksmithingSkillType, 1f); } } internal static float GetSavedDurabilityFactor(ItemData item) { if (item?.m_customData == null) { return 1f; } if (!item.m_customData.TryGetValue("nazhi_blacksmith_durability", out var value)) { return 1f; } if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return 1f; } return (result > 1f) ? result : 1f; } internal static int GetSavedLevel(ItemData item) { if (item?.m_customData == null) { return 0; } if (!item.m_customData.TryGetValue("nazhi_blacksmith_lvl", out var value)) { return 0; } int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result); return result; } internal static string GetSavedCrafter(ItemData item) { if (item?.m_customData == null) { return null; } item.m_customData.TryGetValue("nazhi_blacksmith_crafter", out var value); return value; } internal static bool HasSignature(ItemData item) { if (item?.m_customData == null) { return false; } return item.m_customData.ContainsKey("nazhi_blacksmith_durability") || item.m_customData.ContainsKey("nazhi_blacksmith_lvl") || item.m_customData.ContainsKey("nazhi_blacksmith_crafter"); } internal static bool IsExcludedUtility(ItemData item) { if (item == null) { return false; } string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : (item.m_shared?.m_name ?? "")); return text == "Cultivator" || text == "Hoe" || text == "Hammer"; } internal static void EnsureMinLevel(Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!_minLevelApplied && !((Object)(object)player == (Object)null) && (int)BlacksmithingSkillType != 0) { float skillLevel = ((Character)player).GetSkillLevel(BlacksmithingSkillType); if (skillLevel < 1f) { ((Character)player).RaiseSkill(BlacksmithingSkillType, 0.5f); } _minLevelApplied = true; } } } internal static class BlacksmithingCraftContext { internal static bool Active; internal static CraftingStation Station; internal static Player Crafter; internal static bool IsForgeStation(CraftingStation station) { if ((Object)(object)station == (Object)null) { return false; } return station.m_name == "$piece_forge" || station.m_name == "$piece_blackforge" || station.m_name == "$piece_workbench"; } internal static void Begin(Player player) { Active = true; Crafter = player; Station = ((player != null) ? player.GetCurrentCraftingStation() : null); } internal static void End() { Active = false; Station = null; Crafter = null; } } [HarmonyPatch(typeof(Player), "Update")] internal static class Blacksmithing_Patch_EnsureMinLevel { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { BlacksmithingSystem.EnsureMinLevel(__instance); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Blacksmithing_Patch_OnSpawned { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { BlacksmithingSystem.ResetMinLevelFlag(); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class Blacksmithing_Patch_DoCrafting { private static void Prefix(Player player) { BlacksmithingCraftContext.Begin(player); } private static void Postfix() { BlacksmithingCraftContext.End(); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Vector2i), typeof(bool) })] internal static class Blacksmithing_Patch_AddItem { private static void Postfix(ref ItemData __result) { if (BlacksmithingCraftContext.Active && __result != null) { CraftingStation station = BlacksmithingCraftContext.Station; Player crafter = BlacksmithingCraftContext.Crafter; bool flag = BlacksmithingCraftContext.IsForgeStation(station); if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && !((Object)(object)crafter == (Object)null) && flag) { BlacksmithingSystem.OnItemForged(crafter, __result); } } } } [HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { })] internal static class Blacksmithing_Patch_MaxDurability { private static void Postfix(ItemData __instance, ref float __result) { if (__instance != null) { float savedDurabilityFactor = BlacksmithingSystem.GetSavedDurabilityFactor(__instance); if (savedDurabilityFactor > 1f) { __result *= savedDurabilityFactor; } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) })] internal static class Blacksmithing_Patch_Tooltip { private static void Postfix([HarmonyArgument(0)] ItemData item, ref string __result) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 if (item != null && BlacksmithingSystem.HasSignature(item)) { float savedDurabilityFactor = BlacksmithingSystem.GetSavedDurabilityFactor(item); int savedLevel = BlacksmithingSystem.GetSavedLevel(item); string text = BlacksmithingSystem.GetSavedCrafter(item) ?? item.m_crafterName; SharedData shared = item.m_shared; ItemType val = (ItemType)((shared != null) ? ((int)shared.m_itemType) : 0); bool flag = (int)val == 3 || (int)val == 14 || (int)val == 4 || (int)val == 19; bool flag2 = (int)val == 6 || (int)val == 7 || (int)val == 11 || (int)val == 17; if (flag && BlacksmithingSystem.IsExcludedUtility(item)) { flag = false; } float damageArmorPercent = BlacksmithingSystem.GetDamageArmorPercent(savedLevel); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine(); if (savedDurabilityFactor > 1f) { stringBuilder.AppendLine($"Durabilidad extra +{(savedDurabilityFactor - 1f) * 100f:0.#}%"); } if (flag && damageArmorPercent > 0.01f) { stringBuilder.AppendLine($"Daño aumentado +{damageArmorPercent:0.#}%"); } else if (flag2 && damageArmorPercent > 0.01f) { stringBuilder.AppendLine($"Armadura aumentada +{damageArmorPercent:0.#}%"); } string text2 = ((!string.IsNullOrEmpty(text)) ? text : "Desconocido"); string text3 = ((savedLevel > 0) ? savedLevel.ToString() : "?"); stringBuilder.AppendLine("Forjado por " + text2 + " · Herrero nivel " + text3 + ""); __result += stringBuilder.ToString(); } } } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] internal static class Blacksmithing_Patch_Damage { private static void Postfix(ItemData __instance, ref DamageTypes __result) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 if (__instance == null || !BlacksmithingSystem.HasSignature(__instance)) { return; } SharedData shared = __instance.m_shared; ItemType val = (ItemType)((shared != null) ? ((int)shared.m_itemType) : 0); if (((int)val == 3 || (int)val == 14 || (int)val == 4 || (int)val == 19 || (int)val == 5) && !BlacksmithingSystem.IsExcludedUtility(__instance)) { int savedLevel = BlacksmithingSystem.GetSavedLevel(__instance); float damageArmorFactor = BlacksmithingSystem.GetDamageArmorFactor(savedLevel); if (!(damageArmorFactor <= 1f)) { __result.m_blunt *= damageArmorFactor; __result.m_slash *= damageArmorFactor; __result.m_pierce *= damageArmorFactor; __result.m_chop *= damageArmorFactor; __result.m_pickaxe *= damageArmorFactor; __result.m_fire *= damageArmorFactor; __result.m_frost *= damageArmorFactor; __result.m_lightning *= damageArmorFactor; __result.m_poison *= damageArmorFactor; __result.m_spirit *= damageArmorFactor; } } } } [HarmonyPatch(typeof(ItemData), "GetArmor", new Type[] { typeof(int), typeof(float) })] internal static class Blacksmithing_Patch_Armor { private static void Postfix(ItemData __instance, ref float __result) { //IL_0025: 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) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 if (__instance == null || !BlacksmithingSystem.HasSignature(__instance)) { return; } SharedData shared = __instance.m_shared; ItemType val = (ItemType)((shared != null) ? ((int)shared.m_itemType) : 0); if ((int)val == 6 || (int)val == 7 || (int)val == 11 || (int)val == 17) { int savedLevel = BlacksmithingSystem.GetSavedLevel(__instance); float damageArmorFactor = BlacksmithingSystem.GetDamageArmorFactor(savedLevel); if (!(damageArmorFactor <= 1f)) { __result *= damageArmorFactor; } } } } internal static class ConstructionSystem { internal const string ZdoKeyMaxHealth = "nazhi_construction_maxhp"; internal static float GetCraftingLevel(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } return ((Character)player).GetSkillLevel((SkillType)107); } internal static float GetHealthMultiplier(Player player) { return 1f + GetCraftingLevel(player) * 0.005f; } internal static float GetCostDiscount(Player player) { return Mathf.Clamp(GetCraftingLevel(player) * 0.005f, 0f, 0.5f); } internal static int GetRequiredAmount(int baseAmount, float discount) { if (baseAmount <= 0) { return 0; } return Mathf.Max(1, Mathf.CeilToInt((float)baseAmount * (1f - discount))); } internal static int GetConsumedAmount(int baseAmount, float discount) { if (baseAmount <= 0) { return 0; } return Mathf.Max(1, Mathf.FloorToInt((float)baseAmount * (1f - discount))); } } [HarmonyPatch(typeof(Player), "SetPlaceMode", new Type[] { typeof(PieceTable) })] internal static class Construction_Patch_SetPlaceMode { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null)) { float craftingLevel = ConstructionSystem.GetCraftingLevel(__instance); float healthMultiplier = ConstructionSystem.GetHealthMultiplier(__instance); float num = ConstructionSystem.GetCostDiscount(__instance) * 100f; EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] Modo construcción – Crafting={craftingLevel:0} HPmult={healthMultiplier:0.000} CostReduction={num:0.0}%"); } } } [HarmonyPatch(typeof(Player), "SetSelectedPiece", new Type[] { typeof(Vector2Int) })] internal static class Construction_Patch_SetSelectedPiece { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null)) { Piece selectedPiece = __instance.GetSelectedPiece(); if (!((Object)(object)selectedPiece == (Object)null)) { WearNTear component = ((Component)selectedPiece).GetComponent(); float num = (((Object)(object)component != (Object)null) ? component.m_health : (-1f)); float healthMultiplier = ConstructionSystem.GetHealthMultiplier(__instance); float craftingLevel = ConstructionSystem.GetCraftingLevel(__instance); string text = ((num >= 0f) ? (num * healthMultiplier).ToString("0.0") : "N/A"); string text2 = ((num >= 0f) ? num.ToString("0.0") : "N/A"); EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] Pieza={((Object)selectedPiece).name} BaseHP={text2} BuffedHP={text} Crafting={craftingLevel:0}"); } } } } [HarmonyPatch(typeof(Player), "PlacePiece", new Type[] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool) })] internal static class Construction_Patch_PlacePiece { private static void Postfix(Player __instance, Piece piece) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)piece == (Object)null)) { float craftingLevel = ConstructionSystem.GetCraftingLevel(__instance); float num = ConstructionSystem.GetCostDiscount(__instance) * 100f; EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] PlacePiece '{((Object)piece).name}' lvl={craftingLevel:0} CostReduction={num:0.0}%"); } } } [HarmonyPatch(typeof(Piece), "SetCreator", new Type[] { typeof(long) })] internal static class Construction_Patch_SetCreator { private static void Postfix(Piece __instance, long uid) { try { if ((Object)(object)__instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } WearNTear component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component.m_nview == (Object)null || !component.m_nview.IsValid()) { return; } ZDO zDO = component.m_nview.GetZDO(); if (zDO == null || zDO.GetFloat("nazhi_construction_maxhp", 0f) > 0f) { return; } Player player = Player.GetPlayer(uid); if ((Object)(object)player == (Object)null) { return; } float healthMultiplier = ConstructionSystem.GetHealthMultiplier(player); if (!(healthMultiplier <= 1f)) { float health = component.m_health; if (!(health <= 0f)) { float num = (component.m_health = health * healthMultiplier); zDO.Set("nazhi_construction_maxhp", num); EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] SetCreator HP buff '{((Object)__instance).name}' {health:0} → {num:0} (x{healthMultiplier:0.000})"); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogError((object)$"[Construction] Error en Piece.SetCreator: {arg}"); } } } [HarmonyPatch(typeof(WearNTear), "Awake")] internal static class Construction_Patch_WearNTear_Awake { private static void Postfix(WearNTear __instance) { try { if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid()) { return; } ZDO zDO = __instance.m_nview.GetZDO(); if (zDO != null) { float @float = zDO.GetFloat("nazhi_construction_maxhp", 0f); if (!(@float <= 0f)) { float health = __instance.m_health; __instance.m_health = @float; EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] WearNTear.Awake restore '{((Object)__instance).name}' {health:0} → {@float:0}"); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogError((object)$"[Construction] Error en WearNTear.Awake: {arg}"); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class Construction_Patch_HaveRequirements { private static bool Prefix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)piece == (Object)null) { return true; } if ((int)mode > 0) { return true; } float costDiscount = ConstructionSystem.GetCostDiscount(__instance); if (costDiscount <= 0f) { return true; } if (Object.op_Implicit((Object)(object)piece.m_craftingStation) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position)) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)22)) { __result = false; return false; } if (piece.m_dlc.Length > 0 && !DLCMan.instance.IsDLCInstalled(piece.m_dlc)) { __result = false; return false; } if (ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { __result = true; return false; } Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (Object.op_Implicit((Object)(object)val.m_resItem) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; int requiredAmount = ConstructionSystem.GetRequiredAmount(val.m_amount, costDiscount); int num = ((Humanoid)__instance).m_inventory.CountItems(name, -1, true); if (num < requiredAmount) { EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] HaveReq falta '{name}': have={num} need={requiredAmount}"); __result = false; return false; } } } __result = true; return false; } } [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] internal static class Construction_Patch_ConsumeResources { private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { if ((Object)(object)__instance == (Object)null || requirements == null) { return true; } float costDiscount = ConstructionSystem.GetCostDiscount(__instance); if (costDiscount <= 0f) { return true; } foreach (Requirement val in requirements) { if (Object.op_Implicit((Object)(object)val?.m_resItem)) { int num = val.GetAmount(qualityLevel) * multiplier; if (num > 0) { int consumedAmount = ConstructionSystem.GetConsumedAmount(num, costDiscount); string name = val.m_resItem.m_itemData.m_shared.m_name; ((Humanoid)__instance).m_inventory.RemoveItem(name, consumedAmount, itemQuality, true); EinjarheimProfessionsPlugin.Log.LogInfo((object)$"[Construction] Consume '{name}' original={num} gastado={consumedAmount} ({costDiscount * 100f:0.0}% desc)"); } } } return false; } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] internal static class Construction_Patch_HudPieceInfo { private static void Postfix(Hud __instance, Piece piece) { try { if ((Object)(object)piece == (Object)null || (Object)(object)__instance == (Object)null) { return; } TMP_Text pieceDescription = __instance.m_pieceDescription; if (!((Object)(object)pieceDescription == (Object)null)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float craftingLevel = ConstructionSystem.GetCraftingLevel(localPlayer); float healthMultiplier = ConstructionSystem.GetHealthMultiplier(localPlayer); float num = ConstructionSystem.GetCostDiscount(localPlayer) * 100f; WearNTear component = ((Component)piece).GetComponent(); float num2 = (((Object)(object)component != (Object)null) ? component.m_health : 0f); float num3 = num2 * healthMultiplier - num2; string text = Localization.instance.Localize(piece.m_description); pieceDescription.text = text + $"\nCrafting: Level {craftingLevel:0}" + $"\nHealth: {num2:0} (+{num3:0})" + $"\nRecursos: -{num:0.0}%"; } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogError((object)$"[Construction] Error en HUD SetupPieceInfo: {arg}"); } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement", new Type[] { typeof(Transform), typeof(Requirement), typeof(Player), typeof(bool), typeof(int), typeof(int) })] internal static class Construction_Patch_SetupRequirement { private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier) { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)player == (Object)null || (Object)(object)req?.m_resItem == (Object)null || craft || quality != 0) { return; } float costDiscount = ConstructionSystem.GetCostDiscount(player); if (costDiscount <= 0f) { return; } int num = req.GetAmount(quality) * craftMultiplier; if (num > 0) { int requiredAmount = ConstructionSystem.GetRequiredAmount(num, costDiscount); Transform obj = elementRoot.Find("res_amount"); TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent() : null); if (!((Object)(object)val == (Object)null)) { val.text = requiredAmount.ToString(); int num2 = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); bool flag = (!craft && ZoneSystem.instance.GetGlobalKey((GlobalKeys)19)) || (craft && ZoneSystem.instance.GetGlobalKey((GlobalKeys)20)); ((Graphic)val).color = ((requiredAmount <= 0 || num2 >= requiredAmount || flag) ? Color.white : ((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : Color.white)); } } } catch (Exception arg) { EinjarheimProfessionsPlugin.Log.LogError((object)$"[Construction] Error en SetupRequirement: {arg}"); } } } internal static class CookingSystem { internal struct ChefInfo { public long ChefId; public string ChefName; public int ChefLv; public int Count; } internal const string CD_CHEF_NAME = "nazhi_chef_name"; internal const string CD_CHEF_ID = "nazhi_chef_id"; internal const string CD_CHEF_LV = "nazhi_chef_cooking_lv"; internal const string ZDO_FOOD0_NAME = "nazhi_food0_name"; internal const string ZDO_FOOD0_LV = "nazhi_food0_chef_lv"; internal const string ZDO_FOOD0_CHEF = "nazhi_food0_chef_name"; internal const string ZDO_FOOD1_NAME = "nazhi_food1_name"; internal const string ZDO_FOOD1_LV = "nazhi_food1_chef_lv"; internal const string ZDO_FOOD1_CHEF = "nazhi_food1_chef_name"; internal const string ZDO_FOOD2_NAME = "nazhi_food2_name"; internal const string ZDO_FOOD2_LV = "nazhi_food2_chef_lv"; internal const string ZDO_FOOD2_CHEF = "nazhi_food2_chef_name"; internal static readonly Dictionary> PendingByPlayer = new Dictionary>(); internal static bool IsFood(ItemData item) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 SharedData val = item?.m_shared; if (val == null) { return false; } if ((int)val.m_itemType != 2) { return false; } return val.m_food > 0f || val.m_foodStamina > 0f || val.m_foodEitr > 0f; } internal static int GetVanillaCookingLevel(Player p) { if ((Object)(object)p == (Object)null) { return 1; } return Mathf.Max(1, Mathf.FloorToInt(((Character)p).GetSkillLevel((SkillType)105))); } internal static int BonusFromChefLevel(int chefLv) { return Mathf.Max(1, chefLv); } internal static void CalculateBonus(ItemData item, int chefLv, out int bonusHp, out int bonusSt, out int bonusEi) { bonusHp = 0; bonusSt = 0; bonusEi = 0; if (item?.m_shared == null) { return; } int num = BonusFromChefLevel(chefLv); float food = item.m_shared.m_food; float foodStamina = item.m_shared.m_foodStamina; float foodEitr = item.m_shared.m_foodEitr; if (foodEitr > 0f) { if (food > 0f) { bonusHp = Mathf.RoundToInt((float)num * 0.2f); } if (foodStamina > 0f) { bonusSt = Mathf.RoundToInt((float)num * 0.2f); } bonusEi = Mathf.RoundToInt((float)num * 0.5f); } else if (food > 0f && foodStamina > 0f) { if (food >= foodStamina) { bonusHp = Mathf.RoundToInt((float)num * 0.8f); bonusSt = Mathf.RoundToInt((float)num * 0.2f); } else { bonusSt = Mathf.RoundToInt((float)num * 0.8f); bonusHp = Mathf.RoundToInt((float)num * 0.2f); } } else if (food > 0f) { bonusHp = num; } else if (foodStamina > 0f) { bonusSt = num; } } internal static void StampChef(ItemData item, ChefInfo chef) { if (item != null) { if (item.m_customData == null) { item.m_customData = new Dictionary(); } item.m_customData["nazhi_chef_name"] = chef.ChefName; item.m_customData["nazhi_chef_id"] = chef.ChefId.ToString(); item.m_customData["nazhi_chef_cooking_lv"] = chef.ChefLv.ToString(); } } internal static ChefInfo BuildChef(Player chef) { ChefInfo result = default(ChefInfo); result.ChefId = chef.GetPlayerID(); result.ChefName = chef.GetPlayerName(); result.ChefLv = GetVanillaCookingLevel(chef); result.Count = 1; return result; } internal static void SetPending(Player chef, string itemSharedName) { if (!((Object)(object)chef == (Object)null) && !string.IsNullOrEmpty(itemSharedName)) { long playerID = chef.GetPlayerID(); if (!PendingByPlayer.TryGetValue(playerID, out var value) || value == null) { value = new Dictionary(); PendingByPlayer[playerID] = value; } if (value.TryGetValue(itemSharedName, out var value2)) { value2.Count++; value[itemSharedName] = value2; } else { ChefInfo value3 = BuildChef(chef); value3.Count = 1; value[itemSharedName] = value3; } } } internal static bool TryConsumePending(Player receiver, string itemSharedName, out ChefInfo chef) { chef = default(ChefInfo); if ((Object)(object)receiver == (Object)null || string.IsNullOrEmpty(itemSharedName)) { return false; } long playerID = receiver.GetPlayerID(); if (!PendingByPlayer.TryGetValue(playerID, out var value) || value == null) { return false; } if (!value.TryGetValue(itemSharedName, out chef)) { return false; } if (chef.Count <= 1) { value.Remove(itemSharedName); } else { ChefInfo value2 = chef; value2.Count--; value[itemSharedName] = value2; } return true; } internal static int GetChefLevelFromItem(ItemData item) { if (item?.m_customData == null) { return 1; } if (item.m_customData.TryGetValue("nazhi_chef_cooking_lv", out var value) && int.TryParse(value, out var result)) { return Mathf.Max(1, result); } return 1; } internal static string GetChefNameFromItem(ItemData item) { if (item?.m_customData == null) { return "Desconocido"; } if (item.m_customData.TryGetValue("nazhi_chef_name", out var value) && !string.IsNullOrEmpty(value)) { return value; } return "Desconocido"; } internal static void SaveFoodSlotToProfile(Player p, int slot, string foodName, int chefLv, string chefName) { if ((Object)(object)p == (Object)null) { return; } string text = $"naz_food{slot}_name"; string text2 = $"naz_food{slot}_lv"; string text3 = $"naz_food{slot}_chef"; try { MethodInfo method = typeof(Player).GetMethod("SetCustomData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { method.Invoke(p, new object[2] { text, foodName ?? "" }); method.Invoke(p, new object[2] { text2, Mathf.Max(1, chefLv).ToString() }); method.Invoke(p, new object[2] { text3, chefName ?? "" }); } else if (typeof(Player).GetField("m_customData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(p) is Dictionary dictionary) { dictionary[text] = foodName ?? ""; dictionary[text2] = Mathf.Max(1, chefLv).ToString(); dictionary[text3] = chefName ?? ""; } TryInvokeGameSaveProfile(); } catch (Exception ex) { EinjarheimProfessionsPlugin.Log.LogWarning((object)("[Cooking] SaveFoodSlotToProfile error: " + ex.Message)); } } internal static bool LoadFoodSlotFromProfile(Player p, int slot, out string foodName, out int chefLv, out string chefName) { foodName = ""; chefLv = 1; chefName = "Desconocido"; if ((Object)(object)p == (Object)null) { return false; } string text = $"naz_food{slot}_name"; string text2 = $"naz_food{slot}_lv"; string text3 = $"naz_food{slot}_chef"; try { MethodInfo method = typeof(Player).GetMethod("GetCustomData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { foodName = (method.Invoke(p, new object[1] { text }) as string) ?? ""; string s = (method.Invoke(p, new object[1] { text2 }) as string) ?? "1"; chefName = (method.Invoke(p, new object[1] { text3 }) as string) ?? "Desconocido"; int.TryParse(s, out chefLv); } else if (typeof(Player).GetField("m_customData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(p) is Dictionary dictionary) { dictionary.TryGetValue(text, out foodName); dictionary.TryGetValue(text3, out chefName); if (dictionary.TryGetValue(text2, out var value)) { int.TryParse(value, out chefLv); } } } catch (Exception ex) { EinjarheimProfessionsPlugin.Log.LogWarning((object)("[Cooking] LoadFoodSlotFromProfile error: " + ex.Message)); } chefLv = Mathf.Max(1, chefLv); if (string.IsNullOrEmpty(foodName)) { return false; } if (string.IsNullOrEmpty(chefName)) { chefName = "Desconocido"; } return true; } private static bool TryInvokeGameSaveProfile() { try { Game instance = Game.instance; if ((Object)(object)instance == (Object)null) { return false; } Type typeFromHandle = typeof(Game); MethodInfo methodInfo = typeFromHandle.GetMethod("SavePlayerProfile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeFromHandle.GetMethod("SavePlayerProfileThreadsafe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (methodInfo != null) { methodInfo.Invoke(instance, null); return true; } } catch { } return false; } internal static bool TryGetChefFromZDO(Player p, int slot, out string foodName, out int chefLv, out string chefName) { foodName = ""; chefLv = 1; chefName = "Desconocido"; if ((Object)(object)p == (Object)null) { return false; } ZNetView nview = ((Character)p).m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val == null) { return false; } switch (slot) { case 0: foodName = val.GetString("nazhi_food0_name", ""); chefLv = Mathf.Max(1, val.GetInt("nazhi_food0_chef_lv", 1)); chefName = val.GetString("nazhi_food0_chef_name", "Desconocido"); break; case 1: foodName = val.GetString("nazhi_food1_name", ""); chefLv = Mathf.Max(1, val.GetInt("nazhi_food1_chef_lv", 1)); chefName = val.GetString("nazhi_food1_chef_name", "Desconocido"); break; case 2: foodName = val.GetString("nazhi_food2_name", ""); chefLv = Mathf.Max(1, val.GetInt("nazhi_food2_chef_lv", 1)); chefName = val.GetString("nazhi_food2_chef_name", "Desconocido"); break; } if (string.IsNullOrEmpty(foodName)) { return false; } if (string.IsNullOrEmpty(chefName)) { chefName = "Desconocido"; } return true; } internal static void EnsureStampedFromFallback(ItemData item, int chefLv, string chefName) { if (item != null) { if (item.m_customData == null) { item.m_customData = new Dictionary(); } item.m_customData["nazhi_chef_cooking_lv"] = Mathf.Max(1, chefLv).ToString(); item.m_customData["nazhi_chef_name"] = (string.IsNullOrEmpty(chefName) ? "Desconocido" : chefName); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class Cooking_Patch_Caldero_Pending { private static void Prefix(InventoryGui __instance, Player player) { if ((Object)(object)player == (Object)null) { return; } Recipe craftRecipe = __instance.m_craftRecipe; if (craftRecipe?.m_item?.m_itemData != null) { ItemData itemData = craftRecipe.m_item.m_itemData; if (CookingSystem.IsFood(itemData)) { CookingSystem.SetPending(player, itemData.m_shared.m_name); } } } } [HarmonyPatch(typeof(CookingStation), "SpawnItem")] internal static class Cooking_Patch_Station_SpawnItem { private static void Prefix(CookingStation __instance, string name) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(name)) { return; } Player val = Player.GetClosestPlayer(((Component)__instance).transform.position, 10f) ?? Player.m_localPlayer; if (!((Object)(object)val == (Object)null)) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); ItemData val2 = ((itemPrefab == null) ? null : itemPrefab.GetComponent()?.m_itemData); if (val2 != null && CookingSystem.IsFood(val2)) { CookingSystem.SetPending(val, val2.m_shared.m_name); } } } } [HarmonyPatch] internal static class Cooking_Patch_Inventory_AddItem_Stamp { private static IEnumerable TargetMethods() { return from m in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "AddItem" select m; } private static void Prefix(Inventory __instance, ref object __state, params object[] __args) { __state = null; if (__instance == null || __args == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).GetInventory() != __instance) { return; } foreach (object obj in __args) { ItemData val = (ItemData)((obj is ItemData) ? obj : null); if (val != null && CookingSystem.IsFood(val)) { string name = val.m_shared.m_name; if (!CookingSystem.TryConsumePending(localPlayer, name, out var chef)) { break; } CookingSystem.StampChef(val, chef); return; } } foreach (object obj2 in __args) { if (obj2 is string text && !string.IsNullOrEmpty(text)) { __state = text; break; } } } private static void Postfix(Inventory __instance, object __state) { if (__instance == null || __state == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).GetInventory() != __instance) { return; } string text = __state as string; if (string.IsNullOrEmpty(text)) { return; } string sharedName = text; if (!sharedName.StartsWith("$")) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(sharedName); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent() : null); if (val?.m_itemData?.m_shared != null) { sharedName = val.m_itemData.m_shared.m_name; } } if (CookingSystem.TryConsumePending(localPlayer, sharedName, out var chef)) { ItemData val2 = ((IEnumerable)__instance.GetAllItems()).LastOrDefault((Func)((ItemData i) => i?.m_shared?.m_name == sharedName)); if (val2 != null) { CookingSystem.StampChef(val2, chef); } } } } [HarmonyPatch] internal static class Cooking_Patch_EatFood_Save { private static IEnumerable TargetMethods() { return from m in typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "EatFood" select m; } private static void Prefix(Player __instance, ref object __state, params object[] __args) { __state = null; if ((Object)(object)__instance == (Object)null || __args == null) { return; } foreach (object obj in __args) { ItemData val = (ItemData)((obj is ItemData) ? obj : null); if (val != null && CookingSystem.IsFood(val)) { __state = val; break; } } } private static void Postfix(Player __instance, object __state) { if ((Object)(object)__instance == (Object)null) { return; } ItemData val = (ItemData)((__state is ItemData) ? __state : null); if (val == null || !CookingSystem.IsFood(val)) { return; } ZNetView nview = ((Character)__instance).m_nview; ZDO val2 = ((nview != null) ? nview.GetZDO() : null); if (val2 == null) { return; } int chefLevelFromItem = CookingSystem.GetChefLevelFromItem(val); string chefNameFromItem = CookingSystem.GetChefNameFromItem(val); string name = val.m_shared.m_name; IList list = (IList)AccessTools.Field(typeof(Player), "m_foods").GetValue(__instance); if (list == null) { return; } for (int i = 0; i < Mathf.Min(3, list.Count); i++) { if (!((list[i]?.m_item)?.m_shared?.m_name != name)) { GetZdoKeys(i, out var name2, out var lv, out var chef); val2.Set(name2, name); val2.Set(lv, chefLevelFromItem); val2.Set(chef, chefNameFromItem); CookingSystem.SaveFoodSlotToProfile(__instance, i, name, chefLevelFromItem, chefNameFromItem); break; } } } private static void GetZdoKeys(int slot, out string name, out string lv, out string chef) { switch (slot) { case 0: name = "nazhi_food0_name"; lv = "nazhi_food0_chef_lv"; chef = "nazhi_food0_chef_name"; break; case 1: name = "nazhi_food1_name"; lv = "nazhi_food1_chef_lv"; chef = "nazhi_food1_chef_name"; break; default: name = "nazhi_food2_name"; lv = "nazhi_food2_chef_lv"; chef = "nazhi_food2_chef_name"; break; } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Cooking_Patch_OnSpawned_Restore { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } ZNetView nview = ((Character)__instance).m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); IList list = (IList)AccessTools.Field(typeof(Player), "m_foods").GetValue(__instance); for (int i = 0; i < 3; i++) { if (!CookingSystem.LoadFoodSlotFromProfile(__instance, i, out var foodName, out var chefLv, out var chefName)) { continue; } if (val != null) { switch (i) { case 0: val.Set("nazhi_food0_name", foodName); val.Set("nazhi_food0_chef_lv", chefLv); val.Set("nazhi_food0_chef_name", chefName); break; case 1: val.Set("nazhi_food1_name", foodName); val.Set("nazhi_food1_chef_lv", chefLv); val.Set("nazhi_food1_chef_name", chefName); break; default: val.Set("nazhi_food2_name", foodName); val.Set("nazhi_food2_chef_lv", chefLv); val.Set("nazhi_food2_chef_name", chefName); break; } } if (list != null && i < list.Count) { ItemData val2 = list[i]?.m_item; if (val2?.m_shared?.m_name == foodName) { CookingSystem.EnsureStampedFromFallback(val2, chefLv, chefName); } } } if (((Character)__instance).GetSkillLevel((SkillType)105) < 1f) { ((Character)__instance).RaiseSkill((SkillType)105, 0.5f); } } } [HarmonyPatch] internal static class Cooking_Patch_Tooltip { private static IEnumerable TargetMethods() { return from m in typeof(ItemData).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "GetTooltip" && m.ReturnType == typeof(string) select m; } private static void Postfix(ItemData __instance, ref string __result) { if (__instance?.m_shared != null && CookingSystem.IsFood(__instance)) { int chefLevelFromItem = CookingSystem.GetChefLevelFromItem(__instance); string chefNameFromItem = CookingSystem.GetChefNameFromItem(__instance); CookingSystem.CalculateBonus(__instance, chefLevelFromItem, out var bonusHp, out var bonusSt, out var bonusEi); List list = new List(); if (bonusHp > 0) { list.Add($"HP +{bonusHp}"); } if (bonusSt > 0) { list.Add($"Stamina +{bonusSt}"); } if (bonusEi > 0) { list.Add($"Eitr +{bonusEi}"); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); if (list.Count > 0) { stringBuilder.AppendLine("Bonus al comer: " + string.Join(", ", list)); } stringBuilder.AppendLine("Cocinado por: " + chefNameFromItem + " " + $"(Cooking Lv {chefLevelFromItem})"); if (!__result.Contains("Bonus al comer:") && !__result.Contains("Cocinado por:")) { __result += stringBuilder.ToString(); } } } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] internal static class Cooking_Patch_TotalFoodValue { private static readonly Dictionary _lastSig = new Dictionary(); private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } IList list = (IList)AccessTools.Field(typeof(Player), "m_foods").GetValue(__instance); if (list == null || list.Count == 0) { return; } int num = 0; int num2 = 0; int num3 = 0; List list2 = new List(); for (int i = 0; i < list.Count; i++) { ItemData val = list[i]?.m_item; if (val?.m_shared != null) { string name = val.m_shared.m_name; int num4 = CookingSystem.GetChefLevelFromItem(val); string text = CookingSystem.GetChefNameFromItem(val); if (num4 <= 1 && text == "Desconocido" && CookingSystem.TryGetChefFromZDO(__instance, i, out var foodName, out var chefLv, out var chefName) && foodName == name) { num4 = chefLv; text = chefName; CookingSystem.EnsureStampedFromFallback(val, num4, text); } if (num4 <= 1 && text == "Desconocido" && CookingSystem.LoadFoodSlotFromProfile(__instance, i, out var foodName2, out var chefLv2, out var chefName2) && foodName2 == name) { num4 = chefLv2; text = chefName2; CookingSystem.EnsureStampedFromFallback(val, num4, text); } CookingSystem.CalculateBonus(val, num4, out var bonusHp, out var bonusSt, out var bonusEi); num += bonusHp; num2 += bonusSt; num3 += bonusEi; list2.Add($"{name}|{text}|Lv{num4}"); } } hp += num; stamina += num2; eitr += num3; long playerID = __instance.GetPlayerID(); string text2 = string.Join("##", list2); if (!_lastSig.TryGetValue(playerID, out var value) || value != text2) { _lastSig[playerID] = text2; } } } [HarmonyPatch] internal static class Cooking_Patch_AddItem_Context { [ThreadStatic] private static ItemData _incoming; internal static ItemData Incoming => _incoming; private static IEnumerable TargetMethods() { return from m in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "AddItem" && m.GetParameters().Length != 0 && m.GetParameters()[0].ParameterType == typeof(ItemData) select m; } private static void Prefix(ItemData item) { _incoming = item; } private static void Finalizer() { _incoming = null; } } [HarmonyPatch(typeof(Inventory), "FindFreeStackItem")] internal static class Cooking_Patch_FindFreeStackItem { private static bool Prefix(Inventory __instance, string name, int quality, float worldLevel, ref ItemData __result) { ItemData incoming = Cooking_Patch_AddItem_Context.Incoming; if (incoming == null || !CookingSystem.IsFood(incoming)) { return true; } int chefLevelFromItem = CookingSystem.GetChefLevelFromItem(incoming); foreach (ItemData item in __instance.m_inventory) { if (item?.m_shared?.m_name != name || item.m_quality != quality || item.m_stack >= item.m_shared.m_maxStackSize || (double)item.m_worldLevel != (double)worldLevel || CookingSystem.GetChefLevelFromItem(item) != chefLevelFromItem) { continue; } __result = item; return false; } __result = null; return false; } } [HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class Cooking_Patch_CanAddItem { private static bool Prefix(Inventory __instance, ItemData item, int stack, ref bool __result) { if (item == null || !CookingSystem.IsFood(item)) { return true; } if (stack <= 0) { stack = item.m_stack; } int chefLevelFromItem = CookingSystem.GetChefLevelFromItem(item); int num = 0; foreach (ItemData item2 in __instance.m_inventory) { if (!(item2?.m_shared?.m_name != item.m_shared.m_name) && (double)item2.m_worldLevel == (double)item.m_worldLevel && (item2.m_shared.m_maxQuality <= 1 || item2.m_quality == item.m_quality) && item2.m_stack < item2.m_shared.m_maxStackSize && CookingSystem.GetChefLevelFromItem(item2) == chefLevelFromItem) { num += item2.m_shared.m_maxStackSize - item2.m_stack; } } int num2 = __instance.m_width * __instance.m_height - __instance.m_inventory.Count; int num3 = num2 * item.m_shared.m_maxStackSize; __result = num + num3 >= stack; return false; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int) })] internal static class Cooking_Patch_AddItemXY { private static bool Prefix(Inventory __instance, ItemData item, int amount, int x, int y, ref bool __result) { if (item == null || !CookingSystem.IsFood(item)) { return true; } ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt == null) { return true; } if (CookingSystem.IsFood(itemAt) && itemAt.m_shared?.m_name == item.m_shared?.m_name && CookingSystem.GetChefLevelFromItem(itemAt) != CookingSystem.GetChefLevelFromItem(item)) { __result = false; return false; } return true; } }