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 ValheimCuisine v2.2.8
ValheimCuisine.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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Timers; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CreatureManager; using HarmonyLib; using ItemManager; using JetBrains.Annotations; using LocalizationManager; using LocationManager; using Microsoft.CodeAnalysis; using PieceManager; using ServerSync; using SoftReferenceableAssets; using StatusEffectManager; using TMPro; using UnityEngine; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ValheimCuisine")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("XutzBR")] [assembly: AssemblyProduct("ValheimCuisine")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("2.2.8")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.8.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 ValheimCuisine { [BepInPlugin("XutzBR.ValheimCuisine", "ValheimCuisine", "2.2.8")] public class ValheimCuisinePlugin : BaseUnityPlugin { private class GrimpyBoxConversionData { public int RequiredAmount { get; set; } public int ProducedAmount { get; set; } public GrimpyBoxConversionData(int requiredAmount, int producedAmount) { RequiredAmount = requiredAmount; ProducedAmount = producedAmount; } } public class ConversionData { public string ToItem { get; set; } public float CookTime { get; set; } public int ProducedItems { get; set; } public ConversionData(string toItem, float cookTime = 0f, int producedItems = 0) { ToItem = toItem; CookTime = cookTime; ProducedItems = producedItems; } } public enum Toggle { On = 1, Off = 0 } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ButcherTableCraftingStationPatch { private static bool hasRun; private static void Postfix(ZNetScene __instance) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown if (hasRun) { return; } hasRun = true; if ((Object)(object)__instance == (Object)null) { return; } GameObject prefab = __instance.GetPrefab("cauldron_ext3_butchertable"); if ((Object)(object)prefab == (Object)null) { ValheimCuisineLogger.LogWarning((object)"Could not find butcher table prefab 'cauldron_ext3_butchertable'"); return; } CraftingStation component = prefab.GetComponent<CraftingStation>(); if ((Object)(object)component != (Object)null) { ValheimCuisineLogger.LogDebug((object)"CraftingStation already exists on butcher table, skipping..."); return; } component = prefab.AddComponent<CraftingStation>(); component.m_name = "$piece_cauldron_ext3_butchertable"; component.m_discoverRange = 4f; component.m_rangeBuild = 20f; component.m_useDistance = 2f; component.m_useAnimation = 1; component.m_craftingSkill = (SkillType)105; component.m_craftRequireRoof = false; component.m_craftRequireFire = false; Piece component2 = prefab.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.m_icon != (Object)null) { component.m_icon = component2.m_icon; } CraftingStation obj = component; EffectList val = new EffectList(); val.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { new EffectData { m_prefab = GetEffectPrefab(__instance, "VC_sfx_ChefTableCraft"), m_enabled = true, m_variant = -1 } }; obj.m_craftItemEffects = val; CraftingStation obj2 = component; val = new EffectList(); val.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { new EffectData { m_prefab = GetEffectPrefab(__instance, "VC_sfx_gui_craftitem_workbench_end"), m_enabled = true, m_variant = -1 } }; obj2.m_craftItemDoneEffects = val; ValheimCuisineLogger.LogInfo((object)"Successfully added CraftingStation component to butcher table"); } private static GameObject GetEffectPrefab(ZNetScene zNetScene, string effectName) { GameObject prefab = zNetScene.GetPrefab(effectName); if ((Object)(object)prefab == (Object)null) { ValheimCuisineLogger.LogWarning((object)("Effect prefab '" + effectName + "' not found in ZNetScene")); } return prefab; } } [HarmonyPatch(typeof(StationExtension), "GetHoverText")] public static class ButcherTableHoverTextPatch { private static void Postfix(StationExtension __instance, ref string __result) { string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject); if (prefabName != "cauldron_ext3_butchertable" || (Object)(object)Player.m_localPlayer == (Object)null) { return; } CraftingStation component = ((Component)__instance).GetComponent<CraftingStation>(); if (!((Object)(object)component == (Object)null)) { if (!component.InUseDistance((Humanoid)(object)Player.m_localPlayer)) { __result = Localization.instance.Localize("<color=#888888>$piece_toofar</color>"); } else { __result = Localization.instance.Localize("$piece_cauldron_ext3_butchertable\n[<color=yellow><b>$KEY_Use</b></color>] $piece_use"); } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ConversionsZNetScene_AwakePost_Patch { private static bool hasRun; private static List<ItemConversion> vanillaCookingStationConversions; private static List<ItemConversion> vanillaCookingStationIronConversions; private static List<ItemConversion> vanillaOvenConversions; private static List<ItemConversion> vanillaFermenterConversions; private static void Postfix(ZNetScene __instance) { if (!hasRun) { hasRun = true; ReapplyConversions(__instance, updateWorldInstances: false); } } public static void ReapplyConversions(ZNetScene scene, bool updateWorldInstances = true) { if ((Object)(object)scene == (Object)null) { return; } List<GameObject> prefabs = scene.m_prefabs; if (prefabs == null || prefabs.Count <= 0) { return; } try { GameObject prefab = scene.GetPrefab("piece_cookingstation"); CookingStation val = ((prefab != null) ? prefab.GetComponent<CookingStation>() : null); GameObject prefab2 = scene.GetPrefab("piece_cookingstation_iron"); CookingStation val2 = ((prefab2 != null) ? prefab2.GetComponent<CookingStation>() : null); GameObject prefab3 = scene.GetPrefab("piece_oven"); CookingStation val3 = ((prefab3 != null) ? prefab3.GetComponent<CookingStation>() : null); GameObject prefab4 = scene.GetPrefab("fermenter"); Fermenter val4 = ((prefab4 != null) ? prefab4.GetComponent<Fermenter>() : null); if (vanillaCookingStationConversions == null && (Object)(object)val != (Object)null && val.m_conversion != null) { vanillaCookingStationConversions = new List<ItemConversion>(val.m_conversion); } if (vanillaCookingStationIronConversions == null && (Object)(object)val2 != (Object)null && val2.m_conversion != null) { vanillaCookingStationIronConversions = new List<ItemConversion>(val2.m_conversion); } if (vanillaOvenConversions == null && (Object)(object)val3 != (Object)null && val3.m_conversion != null) { vanillaOvenConversions = new List<ItemConversion>(val3.m_conversion); } if (vanillaFermenterConversions == null && (Object)(object)val4 != (Object)null && val4.m_conversion != null) { vanillaFermenterConversions = new List<ItemConversion>(val4.m_conversion); } GameObject prefab5 = scene.GetPrefab("VC_SmokehouseWood"); CookingStation val5 = ((prefab5 != null) ? prefab5.GetComponent<CookingStation>() : null); GameObject prefab6 = scene.GetPrefab("VC_SmokehouseStone"); CookingStation val6 = ((prefab6 != null) ? prefab6.GetComponent<CookingStation>() : null); GameObject prefab7 = scene.GetPrefab("VC_DryingHook"); CookingStation val7 = ((prefab7 != null) ? prefab7.GetComponent<CookingStation>() : null); GameObject prefab8 = scene.GetPrefab("VC_DryingRack"); CookingStation val8 = ((prefab8 != null) ? prefab8.GetComponent<CookingStation>() : null); GameObject prefab9 = scene.GetPrefab("VC_FoodBarrel1"); Fermenter val9 = ((prefab9 != null) ? prefab9.GetComponent<Fermenter>() : null); GameObject prefab10 = scene.GetPrefab("VC_FoodBarrel2"); Fermenter val10 = ((prefab10 != null) ? prefab10.GetComponent<Fermenter>() : null); GameObject prefab11 = scene.GetPrefab("VC_LegendFermenter"); Fermenter val11 = ((prefab11 != null) ? prefab11.GetComponent<Fermenter>() : null); GameObject prefab12 = scene.GetPrefab("VC_DvergrCauldron"); Fermenter val12 = ((prefab12 != null) ? prefab12.GetComponent<Fermenter>() : null); ClearAllConversions(val, val2, val3, val4, val5, val6, val7, val8, val9, val10, val11, val12); if ((Object)(object)val != (Object)null) { RestoreVanillaConversions(val, vanillaCookingStationConversions); ApplyCookingStationConversions(scene, val, CookingStationConversions.Value, "Cooking Station"); } if ((Object)(object)val2 != (Object)null) { RestoreVanillaConversions(val2, vanillaCookingStationIronConversions); ApplyCookingStationConversions(scene, val2, CookingStationIronConversions.Value, "Iron Cooking Station"); } if ((Object)(object)val3 != (Object)null) { RestoreVanillaConversions(val3, vanillaOvenConversions); ApplyCookingStationConversions(scene, val3, OvenConversions.Value, "Oven"); } if ((Object)(object)val4 != (Object)null) { RestoreVanillaConversions(val4, vanillaFermenterConversions); ApplyFermenterConversions(scene, val4, FermenterConversions.Value, "Fermenter"); } if ((Object)(object)val5 != (Object)null) { ApplyCookingStationConversions(scene, val5, SmokehouseWoodConversions.Value, "Wooden Smokehouse"); } if ((Object)(object)val6 != (Object)null) { ApplyCookingStationConversions(scene, val6, SmokehouseStoneConversions.Value, "Stone Smokehouse"); } if ((Object)(object)val7 != (Object)null) { ApplyCookingStationConversions(scene, val7, DryingRack1Conversions.Value, "Drying Hook"); } if ((Object)(object)val8 != (Object)null) { ApplyCookingStationConversions(scene, val8, DryingRack2Conversions.Value, "Drying Rack"); } if ((Object)(object)val9 != (Object)null) { ApplyFermenterConversions(scene, val9, FoodBarrel1Conversions.Value, "Food Fermenter"); } if ((Object)(object)val10 != (Object)null) { ApplyFermenterConversions(scene, val10, FoodBarrel2Conversions.Value, "Ashwood Food Fermenter"); } if ((Object)(object)val11 != (Object)null) { ApplyFermenterConversions(scene, val11, LegendFermenterConversions.Value, "Great Fermenter"); } if ((Object)(object)val12 != (Object)null) { ApplyFermenterConversions(scene, val12, DvergrCauldronConversions.Value, "Dvergr Cauldron"); } if (updateWorldInstances) { UpdateAllWorldInstances(scene, val, val2, val3, val4, val5, val6, val7, val8, val9, val10, val11, val12); } ValheimCuisineLogger.LogInfo((object)(updateWorldInstances ? "[Conversions] All conversions applied from config (prefabs and world instances updated)" : "[Conversions] All conversions applied from config (prefabs only, world instances will update on config reload)")); } catch (Exception arg) { ValheimCuisineLogger.LogError((object)$"Error applying conversions: {arg}"); } } private static void RestoreVanillaConversions(CookingStation station, List<ItemConversion> vanillaConversions) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_005e: Expected O, but got Unknown if ((Object)(object)station == (Object)null || vanillaConversions == null) { return; } foreach (ItemConversion vanillaConversion in vanillaConversions) { station.m_conversion.Add(new ItemConversion { m_from = vanillaConversion.m_from, m_to = vanillaConversion.m_to, m_cookTime = vanillaConversion.m_cookTime }); } } private static void RestoreVanillaConversions(Fermenter fermenter, List<ItemConversion> vanillaConversions) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_005e: Expected O, but got Unknown if ((Object)(object)fermenter == (Object)null || vanillaConversions == null) { return; } foreach (ItemConversion vanillaConversion in vanillaConversions) { fermenter.m_conversion.Add(new ItemConversion { m_from = vanillaConversion.m_from, m_to = vanillaConversion.m_to, m_producedItems = vanillaConversion.m_producedItems }); } } private static void UpdateAllWorldInstances(ZNetScene scene, CookingStation cookingStationPrefab, CookingStation cookingStationIronPrefab, CookingStation cookingStationOvenPrefab, Fermenter fermenterPrefab, CookingStation smokehouseWoodPrefab, CookingStation smokehouseStonePrefab, CookingStation dryingRack1Prefab, CookingStation dryingRack2Prefab, Fermenter foodBarrel1Prefab, Fermenter foodBarrel2Prefab, Fermenter legendFermenterPrefab, Fermenter dvergrCauldronPrefab) { if ((Object)(object)Player.m_localPlayer == (Object)null) { ValheimCuisineLogger.LogWarning((object)"[Conversions] Skipping world instance update - player not yet loaded"); return; } int num = 0; CookingStation[] array = Object.FindObjectsByType<CookingStation>((FindObjectsSortMode)0); foreach (CookingStation val in array) { if (!((Object)(object)val == (Object)null)) { string prefabName = Utils.GetPrefabName(((Component)val).gameObject); if (prefabName == "piece_cookingstation" && (Object)(object)cookingStationPrefab != (Object)null) { val.m_conversion = new List<ItemConversion>(cookingStationPrefab.m_conversion); num++; } else if (prefabName == "piece_cookingstation_iron" && (Object)(object)cookingStationIronPrefab != (Object)null) { val.m_conversion = new List<ItemConversion>(cookingStationIronPrefab.m_conversion); num++; } else if (prefabName == "piece_oven" && (Object)(object)cookingStationOvenPrefab != (Object)null) { val.m_conversion = new List<ItemConversion>(cookingStationOvenPrefab.m_conversion); num++; } else if (prefabName == "VC_SmokehouseWood" && (Object)(object)smokehouseWoodPrefab != (Object)null) { val.m_conversion = new List<ItemConversion>(smokehouseWoodPrefab.m_conversion); num++; } else if (prefabName == "VC_SmokehouseStone" && (Object)(object)smokehouseStonePrefab != (Object)null) { val.m_conversion = new List<ItemConversion>(smokehouseStonePrefab.m_conversion); num++; } else if (prefabName == "VC_DryingHook" && (Object)(object)dryingRack1Prefab != (Object)null) { val.m_conversion = new List<ItemConversion>(dryingRack1Prefab.m_conversion); num++; } else if (prefabName == "VC_DryingRack" && (Object)(object)dryingRack2Prefab != (Object)null) { val.m_conversion = new List<ItemConversion>(dryingRack2Prefab.m_conversion); num++; } } } Fermenter[] array2 = Object.FindObjectsByType<Fermenter>((FindObjectsSortMode)0); foreach (Fermenter val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { string prefabName2 = Utils.GetPrefabName(((Component)val2).gameObject); if (prefabName2 == "fermenter" && (Object)(object)fermenterPrefab != (Object)null) { val2.m_conversion = new List<ItemConversion>(fermenterPrefab.m_conversion); num++; } else if (prefabName2 == "VC_FoodBarrel1" && (Object)(object)foodBarrel1Prefab != (Object)null) { val2.m_conversion = new List<ItemConversion>(foodBarrel1Prefab.m_conversion); num++; } else if (prefabName2 == "VC_FoodBarrel2" && (Object)(object)foodBarrel2Prefab != (Object)null) { val2.m_conversion = new List<ItemConversion>(foodBarrel2Prefab.m_conversion); num++; } else if (prefabName2 == "VC_LegendFermenter" && (Object)(object)legendFermenterPrefab != (Object)null) { val2.m_conversion = new List<ItemConversion>(legendFermenterPrefab.m_conversion); num++; } else if (prefabName2 == "VC_DvergrCauldron" && (Object)(object)dvergrCauldronPrefab != (Object)null) { val2.m_conversion = new List<ItemConversion>(dvergrCauldronPrefab.m_conversion); num++; } } } if (num > 0) { ValheimCuisineLogger.LogInfo((object)$"[Conversions] Updated {num} existing station instances in the world"); } } private static void ClearAllConversions(params object[] stations) { foreach (object obj in stations) { if (obj != null) { CookingStation val = (CookingStation)((obj is CookingStation) ? obj : null); if (val != null) { val.m_conversion.Clear(); } else { ((Fermenter)(((obj is Fermenter) ? obj : null)?)).m_conversion.Clear(); } } } } private static void ApplyCookingStationConversions(ZNetScene scene, CookingStation station, string configValue, string stationName) { //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(configValue)) { return; } string[] array = configValue.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); int num = 0; string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { ':' }); if (array3.Length != 3) { ValheimCuisineLogger.LogWarning((object)("[Conversions] Invalid format for " + stationName + ": " + text)); continue; } string text2 = array3[0].Trim(); string text3 = array3[1].Trim(); if (!float.TryParse(array3[2].Trim(), out var result)) { ValheimCuisineLogger.LogWarning((object)("[Conversions] Invalid cook time for " + stationName + ": " + array3[2])); continue; } GameObject prefab = scene.GetPrefab(text2); GameObject prefab2 = scene.GetPrefab(text3); if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab2 == (Object)null)) { ItemDrop component = prefab.GetComponent<ItemDrop>(); ItemDrop component2 = prefab2.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null)) { station.m_conversion.Add(new ItemConversion { m_cookTime = result, m_from = component, m_to = component2 }); num++; } } } if (num > 0) { ValheimCuisineLogger.LogInfo((object)$"[Conversions] Added {num} conversions to {stationName}"); } } private static void ApplyFermenterConversions(ZNetScene scene, Fermenter fermenter, string configValue, string fermenterName) { //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(configValue)) { return; } string[] array = configValue.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); int num = 0; string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { ':' }); if (array3.Length != 3) { ValheimCuisineLogger.LogWarning((object)("[Conversions] Invalid format for " + fermenterName + ": " + text)); continue; } string text2 = array3[0].Trim(); string text3 = array3[1].Trim(); if (!int.TryParse(array3[2].Trim(), out var result)) { ValheimCuisineLogger.LogWarning((object)("[Conversions] Invalid produced items for " + fermenterName + ": " + array3[2])); continue; } GameObject prefab = scene.GetPrefab(text2); GameObject prefab2 = scene.GetPrefab(text3); if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab2 == (Object)null)) { ItemDrop component = prefab.GetComponent<ItemDrop>(); ItemDrop component2 = prefab2.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null)) { fermenter.m_conversion.Add(new ItemConversion { m_from = component, m_to = component2, m_producedItems = result }); num++; } } } if (num > 0) { ValheimCuisineLogger.LogInfo((object)$"[Conversions] Added {num} conversions to {fermenterName}"); } } } [HarmonyPatch(typeof(Fermenter), "GetStatus")] public static class Fermenter_OverrideDuration { [HarmonyPrefix] private static void Prefix(Fermenter __instance) { switch (((Object)((Component)__instance).gameObject).name.Replace("(Clone)", "").Trim()) { case "fermenter": __instance.m_fermentationDuration = VanillaFermenterTime.Value; break; case "VC_LegendFermenter": __instance.m_fermentationDuration = LegendFermenterTime.Value; break; case "VC_FoodBarrel1": __instance.m_fermentationDuration = FoodBarrel1Time.Value; break; case "VC_FoodBarrel2": __instance.m_fermentationDuration = FoodBarrel2Time.Value; break; } } } public class GrimpyBoxConverter : MonoBehaviour { private static readonly List<GrimpyBoxConverter> m_instances = new List<GrimpyBoxConverter>(); private Container m_container; private ZNetView m_nview; private void Awake() { m_container = ((Component)this).GetComponent<Container>(); m_nview = m_container?.m_nview; if (!((Object)(object)m_container == (Object)null) && !((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { ((MonoBehaviour)this).InvokeRepeating("UpdateConversion", 1f, GrimpyBoxConversionTime.Value); m_instances.Add(this); ValheimCuisineLogger.LogInfo((object)("[GrimpyBox] Converter initialized on " + ((Object)((Component)this).gameObject).name)); } } private void OnDestroy() { m_instances.Remove(this); } public static void UpdateConversionRate() { foreach (GrimpyBoxConverter instance in m_instances) { ((MonoBehaviour)instance).CancelInvoke("UpdateConversion"); ((MonoBehaviour)instance).InvokeRepeating("UpdateConversion", 0f, GrimpyBoxConversionTime.Value); } } private void UpdateConversion() { if ((Object)(object)m_container == (Object)null || (Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner()) { return; } Inventory inventory = m_container.GetInventory(); if (inventory == null) { return; } List<ItemData> allItems = inventory.GetAllItems(); if (!GetConversion(allItems, out ItemData itemToConvert, out GrimpyBoxConversionData conversionData) || itemToConvert == null || conversionData == null) { return; } string itemPrefabName = GetItemPrefabName(itemToConvert); int num = allItems.Where((ItemData i) => GetItemPrefabName(i) == itemPrefabName).Sum((ItemData i) => i.m_stack); if (num < conversionData.RequiredAmount) { return; } int num2 = conversionData.RequiredAmount; foreach (ItemData item in allItems.ToList()) { if (!(GetItemPrefabName(item) != itemPrefabName)) { if (item.m_stack >= num2) { inventory.RemoveItem(item, num2); break; } num2 -= item.m_stack; inventory.RemoveItem(item, item.m_stack); } } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Ectoplasm"); if ((Object)(object)itemPrefab == (Object)null) { ValheimCuisineLogger.LogError((object)"[GrimpyBox] Ectoplasm prefab not found in ObjectDB!"); return; } ItemData val = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone(); val.m_stack = conversionData.ProducedAmount; if (inventory.AddItem(val)) { ValheimCuisineLogger.LogInfo((object)$"[GrimpyBox] Converted {conversionData.RequiredAmount}x {itemPrefabName} to {conversionData.ProducedAmount}x Ectoplasm"); } else { ValheimCuisineLogger.LogError((object)"[GrimpyBox] Failed to add Ectoplasm to inventory!"); } m_container.Save(); } private bool GetConversion(List<ItemData> items, out ItemData itemToConvert, out GrimpyBoxConversionData conversionData) { itemToConvert = null; conversionData = null; foreach (ItemData item in items) { string itemPrefabName = GetItemPrefabName(item); if (grimpyBoxConversionDict.TryGetValue(itemPrefabName, out GrimpyBoxConversionData value)) { int num = items.Where((ItemData i) => GetItemPrefabName(i) == itemPrefabName).Sum((ItemData i) => i.m_stack); if (num >= value.RequiredAmount) { itemToConvert = item; conversionData = value; return true; } } } return false; } } [HarmonyPatch(typeof(Container), "Awake")] public static class GrimpyBox_Container_Awake_Patch { [HarmonyPostfix] public static void Postfix(Container __instance) { if (!(__instance.m_name != "$piece_vc_volvacauldron_ext4") && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && (Object)(object)((Component)__instance).GetComponent<GrimpyBoxConverter>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<GrimpyBoxConverter>(); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] public static class GrimpyBox_Inventory_AddItem_Patch { [HarmonyPrefix] public static bool Prefix(Inventory __instance, ItemData item) { if (__instance.m_name != "$piece_vc_volvacauldron_ext4") { return true; } string itemPrefabName = GetItemPrefabName(item); if (itemPrefabName == "Ectoplasm" || item.m_shared.m_name == "$item_ectoplasm") { return true; } if (!IsGrimpyBoxConvertibleItem(itemPrefabName)) { ValheimCuisineLogger.LogWarning((object)("[GrimpyBox] BLOCKED: " + itemPrefabName + " is not convertible!")); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$vc_grimpybox_only_convertible"), 0, (Sprite)null); } return false; } return true; } } [HarmonyPatch(typeof(Container), "OnContainerChanged")] public static class GrimpyBox_Container_OnContainerChanged_Patch { [HarmonyPostfix] public static void Postfix(Container __instance) { if (!(__instance.m_name != "$piece_vc_volvacauldron_ext4") && Object.op_Implicit((Object)(object)__instance.m_nview) && __instance.m_nview.IsValid() && __instance.IsOwner() && !__instance.m_loading) { __instance.Save(); } } } [HarmonyPatch(typeof(Container), "Interact")] public static class GrimpyBox_Container_Interact_Patch { [HarmonyPostfix] public static void Postfix(Container __instance, bool __result) { if (__result && !(__instance.m_name != "$piece_vc_volvacauldron_ext4") && (Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid() && __instance.IsOwner()) { __instance.Save(); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] public static class GrimpyBox_InventoryGui_Hide_Patch { [HarmonyPrefix] public static void Prefix(InventoryGui __instance) { Container currentContainer = __instance.m_currentContainer; if ((Object)(object)currentContainer != (Object)null && currentContainer.m_name == "$piece_vc_volvacauldron_ext4" && (Object)(object)currentContainer.m_nview != (Object)null && currentContainer.m_nview.IsValid() && currentContainer.IsOwner()) { currentContainer.Save(); } } } [HarmonyPatch(typeof(Container), "Save")] public static class GrimpyBox_Container_Save_Patch { [HarmonyPostfix] public static void Postfix(Container __instance) { if (!(__instance.m_name != "$piece_vc_volvacauldron_ext4") && (Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid()) { ZDO zDO = __instance.m_nview.GetZDO(); zDO.IncreaseDataRevision(); } } } [HarmonyPatch(typeof(Container), "GetHoverText")] public static class GrimpyBox_Container_GetHoverText_Patch { [HarmonyPostfix] public static void Postfix(Container __instance, ref string __result) { if (__instance.m_name != "$piece_vc_volvacauldron_ext4") { return; } Inventory inventory = __instance.GetInventory(); if (inventory != null) { int num = (from i in inventory.GetAllItems() where GetItemPrefabName(i) == "Ectoplasm" || i.m_shared.m_name == "$item_ectoplasm" select i).Sum((ItemData i) => i.m_stack); if (num > 0) { __result = __result + "\n\n<color=yellow>" + Localization.instance.Localize("$vc_grimpybox_ectoplasm") + ":</color> " + num; } else if (inventory.GetAllItems().Count == 0) { __result = __result + "\n<color=yellow>" + Localization.instance.Localize("$vc_grimpybox_empty") + "</color>"; } __result = __result + "\n<color=yellow>" + Localization.instance.Localize("$vc_grimpybox_conversion_time") + ":</color> " + GrimpyBoxConversionTime.Value + "s"; } } } [Serializable] public class FreydisResource { public string itemName; public int minAmount = 1; public int maxAmount = 3; public float dropChance = 100f; } public class FreydisCollector : MonoBehaviour, Hoverable, Interactable { public string m_name = "$piece_vc_freydis"; public Transform m_spawnPoint; public GameObject m_visualObject; public GameObject m_ravenSpeak; public GameObject m_workingEffect; public GameObject m_notEmptyEffect; public float m_secPerUnit = 60f; public int m_maxLevel = 5; public List<FreydisResource> m_collectionRewards = new List<FreydisResource>(); public EffectList m_spawnEffect = new EffectList(); public float m_doubleDropChance = 50f; public float m_tripleDropChance = 25f; public string m_extractText = "$piece_vc_freydis_findings"; public string m_collectingText = "$piece_vc_freydis_collecting"; public string m_readyText = "$piece_vc_freydis_ready"; public string m_fullText = "$piece_vc_freydis_full"; private ZNetView m_nview; private bool m_configured = false; public void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)m_nview == (Object)null) { return; } if (!m_configured) { ConfigureFromConfig(); m_configured = true; } if ((Object)(object)m_spawnPoint == (Object)null) { m_spawnPoint = ((Component)this).transform; } if (m_nview.GetZDO() != null) { if (m_nview.IsOwner() && m_nview.GetZDO().GetLong(ZDOVars.s_lastTime, 0L) == 0) { m_nview.GetZDO().Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks); } m_nview.Register("RPC_Extract", (Action<long>)RPC_Extract); m_nview.Register("RPC_UpdateEffects", (Action<long>)RPC_UpdateEffects); ((MonoBehaviour)this).InvokeRepeating("UpdateTick", 2f, 5f); } } private void ConfigureFromConfig() { m_secPerUnit = FreydisCooldownTime?.Value ?? 60f; m_maxLevel = FreydisMaxStoredCollections?.Value ?? 5; m_doubleDropChance = FreydisDoubleDropChance?.Value ?? 50f; m_tripleDropChance = FreydisTripleDropChance?.Value ?? 25f; m_collectionRewards.Clear(); string text = FreydisDropTable?.Value ?? ""; if (string.IsNullOrWhiteSpace(text)) { return; } string[] array = text.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text2 in array2) { string[] array3 = text2.Trim().Split(new char[1] { ':' }); if (array3.Length == 4 && int.TryParse(array3[1], out var result) && int.TryParse(array3[2], out var result2) && float.TryParse(array3[3], out var result3)) { m_collectionRewards.Add(new FreydisResource { itemName = array3[0].Trim(), minAmount = result, maxAmount = result2, dropChance = result3 }); } } } public string GetHoverText() { int level = GetLevel(); string text = Localization.instance.Localize(m_name); if (level > 0) { string text2 = ((level == 1) ? "$piece_vc_freydis_singular" : "$piece_vc_freydis_plural"); string text3 = Localization.instance.Localize(text2); text3 = text3.Replace("{0}", level.ToString()); text = text + " (" + text3 + ")"; text = text + "\n[<color=yellow><b>$KEY_Use</b></color>] " + Localization.instance.Localize(m_extractText); } else { text = text + " ( " + Localization.instance.Localize(GetStatusText()) + " )"; } return Localization.instance.Localize(text); } public string GetHoverName() { return Localization.instance.Localize(m_name); } public bool Interact(Humanoid character, bool repeat, bool alt) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (repeat) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (GetLevel() > 0) { Extract(); return true; } return false; } public string GetStatusText() { int level = GetLevel(); if (level >= m_maxLevel) { return m_fullText; } if (level > 0) { return m_readyText; } return m_collectingText; } public bool UseItem(Humanoid user, ItemData item) { return false; } public void Extract() { m_nview.InvokeRPC("RPC_Extract", Array.Empty<object>()); } public void RPC_Extract(long caller) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) int level = GetLevel(); if (level > 0 && m_collectionRewards.Count > 0) { m_spawnEffect.Create(m_spawnPoint.position, Quaternion.identity, (Transform)null, 1f, -1); for (int i = 0; i < level; i++) { PerformLootRoll(); } ResetLevel(); m_nview.InvokeRPC(ZNetView.Everybody, "RPC_UpdateEffects", Array.Empty<object>()); } } private void PerformLootRoll() { int num = 1; float num2 = Random.Range(0f, 100f); if (num2 <= m_tripleDropChance) { num = 3; } else if (num2 <= m_tripleDropChance + m_doubleDropChance) { num = 2; } List<(int, float)> list = new List<(int, float)>(); for (int i = 0; i < m_collectionRewards.Count; i++) { list.Add((i, m_collectionRewards[i].dropChance)); } for (int j = 0; j < num; j++) { if (list.Count <= 0) { break; } int index = SelectWeightedItem(list); FreydisResource resource = m_collectionRewards[list[index].Item1]; list.RemoveAt(index); SpawnItem(resource); } } private int SelectWeightedItem(List<(int index, float weight)> items) { float num = 0f; foreach (var item in items) { num += item.weight; } float num2 = Random.Range(0f, num); float num3 = 0f; for (int i = 0; i < items.Count; i++) { num3 += items[i].weight; if (num2 <= num3) { return i; } } return items.Count - 1; } private void SpawnItem(FreydisResource resource) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(resource.itemName); if (!((Object)(object)itemPrefab == (Object)null)) { int stack = Random.Range(resource.minAmount, resource.maxAmount + 1); Vector3 val = m_spawnPoint.position + Random.insideUnitSphere * 0.3f; GameObject val2 = Object.Instantiate<GameObject>(itemPrefab, val, Quaternion.identity); ItemDrop component = val2.GetComponent<ItemDrop>(); if (component?.m_itemData != null) { component.m_itemData.m_stack = stack; component.Save(); } } } public float GetTimeSinceLastUpdate() { ZNetView nview = m_nview; if (((nview != null) ? nview.GetZDO() : null) == null) { return 0f; } DateTime dateTime = new DateTime(m_nview.GetZDO().GetLong(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks)); DateTime time = ZNet.instance.GetTime(); TimeSpan timeSpan = time - dateTime; m_nview.GetZDO().Set(ZDOVars.s_lastTime, time.Ticks); return (timeSpan.TotalSeconds < 0.0) ? 0f : ((float)timeSpan.TotalSeconds); } public void ResetLevel() { m_nview.GetZDO().Set(ZDOVars.s_level, 0, false); } public void IncreaseLevel(int amount) { int level = GetLevel(); int num = Mathf.Clamp(level + amount, 0, m_maxLevel); m_nview.GetZDO().Set(ZDOVars.s_level, num, false); } public int GetLevel() { ZNetView nview = m_nview; if (((nview != null) ? nview.GetZDO() : null) == null) { return 0; } return m_nview.GetZDO().GetInt(ZDOVars.s_level, 0); } public void UpdateTick() { ZNetView nview = m_nview; if (((nview != null) ? nview.GetZDO() : null) == null || !m_nview.IsValid()) { return; } if (!m_nview.IsOwner()) { m_nview.ClaimOwnership(); } if (m_nview.IsOwner()) { float timeSinceLastUpdate = GetTimeSinceLastUpdate(); int level = GetLevel(); if (level < m_maxLevel) { float @float = m_nview.GetZDO().GetFloat(ZDOVars.s_product, 0f); @float += timeSinceLastUpdate; if (@float >= m_secPerUnit) { int amount = (int)(@float / m_secPerUnit); IncreaseLevel(amount); @float = 0f; } m_nview.GetZDO().Set(ZDOVars.s_product, @float); } } UpdateEffects(); } public void RPC_UpdateEffects(long caller) { UpdateEffects(); } public void UpdateEffects() { int level = GetLevel(); if ((Object)(object)m_visualObject != (Object)null) { m_visualObject.SetActive(level > 0); } if ((Object)(object)m_ravenSpeak != (Object)null) { m_ravenSpeak.SetActive(level > 0); } if ((Object)(object)m_notEmptyEffect != (Object)null) { m_notEmptyEffect.SetActive(level >= m_maxLevel); } if ((Object)(object)m_workingEffect != (Object)null) { m_workingEffect.SetActive(level == 0); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class FreydisPatch { private static void Postfix(ZNetScene __instance) { //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown if (__instance?.m_prefabs == null) { return; } GameObject prefab = __instance.GetPrefab("VC_Freydis"); if (!((Object)(object)prefab == (Object)null)) { Piece componentInChildren = prefab.GetComponentInChildren<Piece>(); GameObject val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : prefab); Component component = val.GetComponent("RavenInteraction"); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } FreydisCollector freydisCollector = val.GetComponent<FreydisCollector>(); if ((Object)(object)freydisCollector == (Object)null) { freydisCollector = val.AddComponent<FreydisCollector>(); } Transform val2 = FindChildRecursive(val.transform, "SpawnPoint"); freydisCollector.m_spawnPoint = (((Object)(object)val2 != (Object)null) ? val2 : val.transform); Transform val3 = FindChildRecursive(val.transform, "Raven"); if ((Object)(object)val3 != (Object)null) { freydisCollector.m_visualObject = ((Component)val3).gameObject; } Transform val4 = FindChildRecursive(val.transform, "RavenSpeak"); if ((Object)(object)val4 != (Object)null) { freydisCollector.m_ravenSpeak = ((Component)val4).gameObject; } Transform val5 = FindChildRecursive(val.transform, "WorkingEffect"); Transform val6 = FindChildRecursive(val.transform, "NotEmptyEffect"); if ((Object)(object)val5 != (Object)null) { freydisCollector.m_workingEffect = ((Component)val5).gameObject; } if ((Object)(object)val6 != (Object)null) { freydisCollector.m_notEmptyEffect = ((Component)val6).gameObject; } if ((Object)(object)freydisCollector.m_workingEffect == (Object)null) { freydisCollector.m_workingEffect = new GameObject("WorkingEffect"); freydisCollector.m_workingEffect.transform.SetParent(val.transform); freydisCollector.m_workingEffect.SetActive(false); } if ((Object)(object)freydisCollector.m_notEmptyEffect == (Object)null) { freydisCollector.m_notEmptyEffect = new GameObject("NotEmptyEffect"); freydisCollector.m_notEmptyEffect.transform.SetParent(val.transform); freydisCollector.m_notEmptyEffect.SetActive(false); } } } private static Transform FindChildRecursive(Transform parent, string name) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown Transform val = parent.Find(name); if ((Object)(object)val != (Object)null) { return val; } foreach (Transform item in parent) { Transform parent2 = item; val = FindChildRecursive(parent2, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class BirdMeatDropsPatch { private static bool hasRun = false; private static readonly string[] BirdPrefabs = new string[3] { "Crow", "Seagal", "AshCrow" }; [HarmonyPostfix] [HarmonyPriority(0)] public static void Postfix(ZNetScene __instance) { if (!hasRun) { hasRun = true; string[] birdPrefabs = BirdPrefabs; foreach (string creatureName in birdPrefabs) { AddBirdMeatDrop(__instance, creatureName); } } } private static void AddBirdMeatDrop(ZNetScene zNetScene, string creatureName) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = zNetScene.GetPrefab(creatureName); if ((Object)(object)prefab == (Object)null) { ValheimCuisineLogger.LogWarning((object)("[BirdMeatDrops] " + creatureName + " prefab not found.")); return; } DropOnDestroyed component = prefab.GetComponent<DropOnDestroyed>(); if ((Object)(object)component == (Object)null) { ValheimCuisineLogger.LogWarning((object)("[BirdMeatDrops] " + creatureName + " has no DropOnDestroyed component.")); return; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab("VC_BirdMeat") : null); if ((Object)(object)val == (Object)null) { ValheimCuisineLogger.LogWarning((object)"[BirdMeatDrops] VC_BirdMeat prefab not found in ObjectDB."); return; } DropTable dropWhenDestroyed = component.m_dropWhenDestroyed; dropWhenDestroyed.m_drops.RemoveAll((DropData drop) => (Object)(object)drop.m_item != (Object)null && ((Object)drop.m_item).name == "VC_BirdMeat"); for (int i = 0; i < dropWhenDestroyed.m_drops.Count; i++) { DropData val2 = dropWhenDestroyed.m_drops[i]; if ((Object)(object)val2.m_item != (Object)null && ((Object)val2.m_item).name == "Feathers") { val2.m_weight = 10000f; dropWhenDestroyed.m_drops[i] = val2; break; } } dropWhenDestroyed.m_drops.Add(new DropData { m_item = val, m_stackMin = 1, m_stackMax = 1, m_weight = 3f, m_dontScale = false }); dropWhenDestroyed.m_drops.Add(new DropData { m_item = val, m_stackMin = 2, m_stackMax = 2, m_weight = 1f, m_dontScale = false }); dropWhenDestroyed.m_dropMin = 2; dropWhenDestroyed.m_dropMax = 2; dropWhenDestroyed.m_dropChance = 1f; dropWhenDestroyed.m_oneOfEach = true; ValheimCuisineLogger.LogInfo((object)("[BirdMeatDrops] Successfully configured " + creatureName + " to drop Feathers + VC_BirdMeat (75% → 1 meat, 25% → 2 meats)")); } } [HarmonyPatch(typeof(Player), "Update")] public static class LoxMilkingUpdatePatch { private const string BUCKET_PREFAB_NAME = "VC_MilkinBucket"; private const string MILK_PREFAB_NAME = "VC_LoxMilk"; private const string COOLDOWN_SE_NAME = "SE_LoxMilkedCooldown"; private static float m_lastMilkAttempt; private static void Postfix(Player __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (MilkingKey == null || !MilkingKey.Value.IsKeyDown() || Time.time - m_lastMilkAttempt < 0.5f) { return; } m_lastMilkAttempt = Time.time; if (!HasBucketEquipped(__instance)) { return; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Tameable componentInParent = hoverObject.GetComponentInParent<Tameable>(); if ((Object)(object)componentInParent == (Object)null) { return; } Character character = componentInParent.m_character; if (!((Object)(object)character == (Object)null) && ((Object)character).name.StartsWith("Lox") && componentInParent.IsTamed() && !(Vector3.Distance(((Component)__instance).transform.position, ((Component)character).transform.position) > 3f)) { if (RequireBreeding != null && RequireBreeding.Value && !HasLoxBred(componentInParent)) { ((Character)__instance).Message((MessageType)2, Localization.instance.Localize("$lox_milking_nobaby"), 0, (Sprite)null); } else if (HasMilkCooldown(character)) { ((Character)__instance).Message((MessageType)2, Localization.instance.Localize("$lox_milking_cooldown"), 0, (Sprite)null); } else { MilkLox(__instance, character, componentInParent); } } } private static bool HasBucketEquipped(Player player) { ItemData rightItem = ((Humanoid)player).GetRightItem(); if (rightItem == null) { return false; } return (Object)(object)rightItem.m_dropPrefab != (Object)null && ((Object)rightItem.m_dropPrefab).name == "VC_MilkinBucket"; } private static bool HasLoxBred(Tameable tameable) { ZNetView nview = tameable.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return false; } int @int = zDO.GetInt("LoxBirthCount", 0); if (@int > 0) { ValheimCuisineLogger.LogInfo((object)$"Lox has birth count: {@int}"); return true; } float @float = zDO.GetFloat("pregnant", 0f); if (@float > 0f) { ValheimCuisineLogger.LogInfo((object)$"Lox is currently pregnant: {@float}"); return true; } if (zDO.GetBool("LoxHasBeenPregnant", false)) { ValheimCuisineLogger.LogInfo((object)"Lox has been pregnant before"); return true; } ValheimCuisineLogger.LogInfo((object)"Lox has never bred"); return false; } private static bool HasMilkCooldown(Character character) { return character.GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_LoxMilkedCooldown")); } private static void MilkLox(Player player, Character lox, Tameable tameable) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) ApplyCooldown(lox); GiveMilk(player); PlayMilkingEffects(((Component)lox).transform.position); ((Character)player).Message((MessageType)2, Localization.instance.Localize("$lox_milking_success"), 0, (Sprite)null); } private static void ApplyCooldown(Character lox) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_LoxMilkedCooldown")); float ttl = CooldownDuration?.Value ?? 1800f; if ((Object)(object)statusEffect != (Object)null) { statusEffect.m_ttl = ttl; lox.GetSEMan().AddStatusEffect(statusEffect, false, 0, 0f); return; } SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val).name = "SE_LoxMilkedCooldown"; ((StatusEffect)val).m_name = "Recently Milked"; ((StatusEffect)val).m_ttl = ttl; ((StatusEffect)val).m_tooltip = "This Lox was recently milked"; lox.GetSEMan().AddStatusEffect((StatusEffect)(object)val, true, 0, 0f); } private static void GiveMilk(Player player) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("VC_LoxMilk"); if ((Object)(object)itemPrefab == (Object)null) { Debug.LogError((object)"Could not find milk prefab: VC_LoxMilk"); ((Character)player).Message((MessageType)2, Localization.instance.Localize("$lox_milking_error"), 0, (Sprite)null); return; } int num = MilkAmount?.Value ?? 5; ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { Debug.LogError((object)"Milk prefab has no ItemDrop component"); return; } ItemData val = component.m_itemData.Clone(); val.m_stack = num; if (!((Humanoid)player).GetInventory().AddItem(val)) { ItemDrop.DropItem(val, num, ((Component)player).transform.position + ((Component)player).transform.forward * 0.5f + Vector3.up * 0.5f, ((Component)player).transform.rotation); ((Character)player).Message((MessageType)2, Localization.instance.Localize("$lox_milking_inventory_full"), 0, (Sprite)null); } } private static void PlayMilkingEffects(Vector3 position) { //IL_001e: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab("VC_sfx_LoxMilking"); if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, position, Quaternion.identity); } GameObject prefab2 = ZNetScene.instance.GetPrefab("vfx_lootspawn"); if ((Object)(object)prefab2 != (Object)null) { Object.Instantiate<GameObject>(prefab2, position + Vector3.up * 1f, Quaternion.identity); } } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] public static class LoxMilkingHoverTextPatch { private const string BUCKET_PREFAB_NAME = "VC_MilkinBucket"; private const string COOLDOWN_SE_NAME = "SE_LoxMilkedCooldown"; private static void Postfix(Tameable __instance, ref string __result) { //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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (MilkingKey == null) { return; } Character character = __instance.m_character; if ((Object)(object)character == (Object)null || !((Object)character).name.StartsWith("Lox") || !__instance.IsTamed()) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ItemData rightItem = ((Humanoid)localPlayer).GetRightItem(); if (rightItem == null) { return; } GameObject dropPrefab = rightItem.m_dropPrefab; if (((dropPrefab != null) ? ((Object)dropPrefab).name : null) != "VC_MilkinBucket") { return; } KeyboardShortcut value = MilkingKey.Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; string text = ((object)(KeyCode)(ref mainKey)).ToString(); if (RequireBreeding != null && RequireBreeding.Value) { ZNetView nview = __instance.m_nview; if ((Object)(object)nview != (Object)null && nview.IsValid()) { ZDO zDO = nview.GetZDO(); if (zDO != null) { int @int = zDO.GetInt("LoxBirthCount", 0); float @float = zDO.GetFloat("pregnant", 0f); bool @bool = zDO.GetBool("LoxHasBeenPregnant", false); if (@int == 0 && @float == 0f && !@bool) { __result = __result + "\n<color=orange>" + Localization.instance.Localize("$lox_milking_hover_nobaby") + "</color>"; return; } } } } if (character.GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_LoxMilkedCooldown"))) { __result = __result + "\n<color=orange>" + Localization.instance.Localize("$lox_milking_hover_cooldown") + "</color>"; return; } __result = __result + "\n[<color=yellow><b>" + text + "</b></color>] " + Localization.instance.Localize("$lox_milking_hover_action"); } } [HarmonyPatch(typeof(Procreation), "MakePregnant")] public static class ProcreationPregnancyTracker { private static void Postfix(Procreation __instance) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) Character component = ((Component)__instance).GetComponent<Character>(); if ((Object)(object)component == (Object)null || !((Object)component).name.StartsWith("Lox")) { return; } ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component2 == (Object)null) && component2.IsValid()) { ZDO zDO = component2.GetZDO(); if (zDO != null) { zDO.Set("LoxHasBeenPregnant", true); ValheimCuisineLogger.LogInfo((object)$"Lox {component.GetZDOID()} became pregnant"); } } } } [HarmonyPatch(typeof(CookingStation))] public static class CookingStationPatches { private static HashSet<string> noOvercookList = new HashSet<string>(); private static HashSet<string> multiFuelList = new HashSet<string>(); private static HashSet<string> passiveCookingList = new HashSet<string>(); private static Dictionary<string, List<string>> prefabFuelMap = new Dictionary<string, List<string>>(); private const string ZDO_FUEL_TYPE = "VC_CurrentFuelType"; public static void Initialize() { SmokehouseNoOvercookPrefabs.SettingChanged += delegate { RefreshNoOvercookList(); }; SmokehouseMultiFuelPrefabs.SettingChanged += delegate { RefreshMultiFuelList(); }; SmokehouseAllowedFuels.SettingChanged += delegate { RefreshFuelMaps(); }; PassiveCookingPrefabs.SettingChanged += delegate { RefreshPassiveCookingList(); }; RefreshNoOvercookList(); RefreshMultiFuelList(); RefreshFuelMaps(); RefreshPassiveCookingList(); } private static void RefreshNoOvercookList() { noOvercookList.Clear(); string[] array = SmokehouseNoOvercookPrefabs.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2)) { noOvercookList.Add(text2); } } } private static void RefreshMultiFuelList() { multiFuelList.Clear(); string[] array = SmokehouseMultiFuelPrefabs.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2)) { multiFuelList.Add(text2); } } } private static void RefreshFuelMaps() { prefabFuelMap.Clear(); List<string> value = (from f in SmokehouseAllowedFuels.Value.Split(new char[1] { ',' }) select f.Trim() into f where !string.IsNullOrEmpty(f) select f).ToList(); foreach (string multiFuel in multiFuelList) { prefabFuelMap[multiFuel] = value; } } private static void RefreshPassiveCookingList() { passiveCookingList.Clear(); string[] array = PassiveCookingPrefabs.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (!string.IsNullOrEmpty(text2)) { passiveCookingList.Add(text2); } } } private static bool IsNoOvercookStation(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)station).gameObject); return noOvercookList.Contains(prefabName); } private static bool IsMultiFuelStation(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)station).gameObject); return multiFuelList.Contains(prefabName); } private static bool IsPassiveCookingStation(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } string prefabName = Utils.GetPrefabName(((Component)station).gameObject); return passiveCookingList.Contains(prefabName); } private static bool IsModStation(CookingStation station) { return IsNoOvercookStation(station) || IsMultiFuelStation(station) || IsPassiveCookingStation(station); } private static List<string> GetAllowedFuels(CookingStation station) { if ((Object)(object)station == (Object)null) { return null; } string prefabName = Utils.GetPrefabName(((Component)station).gameObject); return prefabFuelMap.ContainsKey(prefabName) ? prefabFuelMap[prefabName] : null; } private static bool IsStationFullyInitialized(CookingStation station) { if ((Object)(object)station == (Object)null) { return false; } if ((Object)(object)station.m_nview == (Object)null) { return false; } if (!station.m_nview.IsValid()) { return false; } if (station.m_slots == null) { return false; } if (station.m_conversion == null) { return false; } return true; } [HarmonyPrefix] [HarmonyPatch("UpdateCooking")] [HarmonyPriority(800)] public static bool UpdateCooking_Complete_Prefix(CookingStation __instance) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Invalid comparison between Unknown and I4 //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) if (!IsModStation(__instance)) { return true; } if (!IsStationFullyInitialized(__instance)) { return false; } bool flag = IsPassiveCookingStation(__instance); bool flag2 = (__instance.m_requireFire && __instance.IsFireLit()) || (__instance.m_useFuel && __instance.GetFuel() > 0f); if (__instance.m_nview.IsOwner()) { float deltaTime = __instance.GetDeltaTime(); if (flag2 || flag) { __instance.UpdateFuel(deltaTime); string text = default(string); float num = default(float); Status val = default(Status); for (int i = 0; i < __instance.m_slots.Length; i++) { __instance.GetSlot(i, ref text, ref num, ref val); if (string.IsNullOrEmpty(text) || (int)val == 2) { continue; } ItemConversion itemConversion = __instance.GetItemConversion(text); if (itemConversion == null) { __instance.SetSlot(i, "", 0f, (Status)0); } else { if ((Object)(object)itemConversion.m_from == (Object)null || (Object)(object)itemConversion.m_to == (Object)null) { continue; } num += deltaTime; if (IsNoOvercookStation(__instance)) { if (num > itemConversion.m_cookTime && text == ((Object)itemConversion.m_from).name) { __instance.m_doneEffect.Create(__instance.m_slots[i].position, Quaternion.identity, (Transform)null, 1f, -1); __instance.SetSlot(i, ((Object)itemConversion.m_to).name, itemConversion.m_cookTime, (Status)1); } else { __instance.SetSlot(i, text, num, (Status)0); } } else if (num > itemConversion.m_cookTime * 2f) { if (__instance.m_overcookedEffect != null && (Object)(object)__instance.m_overCookedItem != (Object)null) { __instance.m_overcookedEffect.Create(__instance.m_slots[i].position, Quaternion.identity, (Transform)null, 1f, -1); __instance.SetSlot(i, ((Object)__instance.m_overCookedItem).name, num, (Status)2); } } else if (num > itemConversion.m_cookTime && text == ((Object)itemConversion.m_from).name) { __instance.m_doneEffect.Create(__instance.m_slots[i].position, Quaternion.identity, (Transform)null, 1f, -1); __instance.SetSlot(i, ((Object)itemConversion.m_to).name, num, (Status)1); } else { __instance.SetSlot(i, text, num, (Status)0); } } } } } __instance.UpdateVisual(flag2); return false; } [HarmonyPrefix] [HarmonyPatch("IsItemDone")] public static bool IsItemDone_Prefix(CookingStation __instance, string itemName, ref bool __result) { if ((Object)(object)__instance == (Object)null || string.IsNullOrEmpty(itemName)) { __result = false; return false; } if (__instance.m_conversion == null) { __result = false; return false; } if ((Object)(object)__instance.m_overCookedItem == (Object)null && IsNoOvercookStation(__instance)) { ItemConversion itemConversion = __instance.GetItemConversion(itemName); if (itemConversion == null) { __result = false; return false; } if ((Object)(object)itemConversion.m_to == (Object)null) { __result = false; return false; } if (itemName == ((Object)itemConversion.m_to).name) { __result = true; return false; } __result = false; return false; } return true; } [HarmonyPrefix] [HarmonyPatch("OnAddFuelSwitch")] public static bool OnAddFuelSwitch_Prefix(CookingStation __instance, Switch sw, Humanoid user, ItemData item, ref bool __result) { if (!IsMultiFuelStation(__instance)) { return true; } List<string> allowedFuels = GetAllowedFuels(__instance); if (allowedFuels == null || allowedFuels.Count == 0) { return true; } if (__instance.GetFuel() > (float)(__instance.m_maxFuel - 1)) { ((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null); __result = false; return false; } if (item == null) { foreach (ItemData allItem in user.GetInventory().GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null) { string name = ((Object)allItem.m_dropPrefab).name; if (allowedFuels.Contains(name)) { item = allItem; break; } } } if (item == null) { ((Character)user).Message((MessageType)2, "$msg_noprocessableitems", 0, (Sprite)null); __result = false; return false; } } string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : ""); if (!allowedFuels.Contains(text)) { ((Character)user).Message((MessageType)2, "$msg_wrongitem", 0, (Sprite)null); __result = false; return false; } if (!user.GetInventory().HaveItem(item.m_shared.m_name, true)) { ((Character)user).Message((MessageType)2, "$msg_donthaveany " + item.m_shared.m_name, 0, (Sprite)null); __result = false; return false; } ((Character)user).Message((MessageType)2, "$msg_added " + item.m_shared.m_name, 0, (Sprite)null); user.GetInventory().RemoveItem(item.m_shared.m_name, 1, -1, true); if ((Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid()) { __instance.m_nview.GetZDO().Set("VC_CurrentFuelType", text); } __instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>()); __result = true; return false; } [HarmonyPostfix] [HarmonyPatch("OnHoverFuelSwitch")] public static void OnHoverFuelSwitch_Postfix(CookingStation __instance, ref string __result) { if (!IsMultiFuelStation(__instance)) { return; } List<string> allowedFuels = GetAllowedFuels(__instance); if (allowedFuels == null || allowedFuels.Count == 0) { return; } float fuel = __instance.GetFuel(); List<string> list = new List<string>(); foreach (string item in allowedFuels) { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(item) : null); if ((Object)(object)val != (Object)null) { ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { list.Add(Localization.instance.Localize(component.m_itemData.m_shared.m_name)); } } } string text = string.Join(", ", list); __result = Localization.instance.Localize($"{__instance.m_name} ($piece_fire_fuel {Mathf.Ceil(fuel)}/{__instance.m_maxFuel})\n" + "[<color=yellow><b>$KEY_Use</b></color>] $piece_smelter_add " + text); } [HarmonyPostfix] [HarmonyPatch("TryGetItems")] public static void TryGetItems_Postfix(CookingStation __instance, Switch switchRef, ref List<string> items, ref bool __result) { if (__result && IsMultiFuelStation(__instance) && (Object)(object)switchRef == (Object)(object)__instance.m_addFuelSwitch) { List<string> allowedFuels = GetAllowedFuels(__instance); if (allowedFuels != null && allowedFuels.Count > 0) { items.Clear(); items.AddRange(allowedFuels); } } } [HarmonyPrefix] [HarmonyPatch(typeof(WearNTear), "Destroy")] public static void WearNTear_Destroy_Prefix(WearNTear __instance) { if ((Object)(object)__instance == (Object)null) { return; } CookingStation component = ((Component)__instance).GetComponent<CookingStation>(); if ((Object)(object)component == (Object)null || !IsMultiFuelStation(component)) { return; } float fuel = component.GetFuel(); if (fuel <= 0f || (Object)(object)component.m_nview == (Object)null || !component.m_nview.IsValid()) { return; } string @string = component.m_nview.GetZDO().GetString("VC_CurrentFuelType", ""); if (string.IsNullOrEmpty(@string)) { return; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(@string) : null); if (!((Object)(object)val == (Object)null)) { ItemDrop component2 = val.GetComponent<ItemDrop>(); if ((Object)(object)component2 != (Object)null) { component.m_fuelItem = component2; } } } } [HarmonyPatch(typeof(Fermenter), "GetHoverText")] public static class Fermenter_GetHoverText_Patch { [HarmonyPostfix] public static void Postfix(Fermenter __instance, ref string __result) { if (IsDvergrCauldron(__instance)) { string oldValue = Localization.instance.Localize("$piece_fermenter_fermenting"); string newValue = Localization.instance.Localize("$piece_vc_dvergrcauldron_processing"); __result = __result.Replace(oldValue, newValue); } } private static bool IsDvergrCauldron(Fermenter fermenter) { if ((Object)(object)((fermenter != null) ? ((Component)fermenter).gameObject : null) == (Object)null) { return false; } string text = ((Object)((Component)fermenter).gameObject).name.Replace("(Clone)", "").Trim(); return text == "VC_DvergrCauldron"; } } [HarmonyPatch(typeof(Projectile), "SpawnOnHit")] public static class Projectile_CreatureBomb_SpawnOnHit_Patch { private enum BombType { None, Niflheimr, Bloodmoon, Horde, Custom } [HarmonyPrefix] public static bool Prefix(Projectile __instance, GameObject go, Collider collider, Vector3 normal) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<bool> enableCreatureBombs = EnableCreatureBombs; if (enableCreatureBombs == null || !enableCreatureBombs.Value) { return true; } BombType bombType = GetBombType(__instance); if (bombType == BombType.None) { return true; } ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Detected {bombType} bomb, spawning creatures..."); if (__instance.m_groundHitOnly && ((Object)(object)go == (Object)null || (Object)(object)go.GetComponent<Heightmap>() == (Object)null)) { ValheimCuisineLogger.LogWarning((object)"[CreatureBomb] Ground hit only restriction failed"); return true; } if (__instance.m_staticHitOnly && (((Object)(object)collider != (Object)null && (Object)(object)collider.attachedRigidbody != (Object)null) || ((Object)(object)go != (Object)null && go.GetComponent<IDestructible>() != null))) { ValheimCuisineLogger.LogWarning((object)"[CreatureBomb] Static hit only restriction failed"); return true; } Vector3 val = ((Component)__instance).transform.position + ((Component)__instance).transform.TransformDirection(__instance.m_spawnOffset); ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Spawn center: {val}"); SpawnCreaturesForBomb(bombType, val); EffectList spawnOnHitEffects = __instance.m_spawnOnHitEffects; if (spawnOnHitEffects != null) { spawnOnHitEffects.Create(val, Quaternion.identity, (Transform)null, 1f, -1); } ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] {bombType} bomb completed!"); return false; } private static BombType GetBombType(Projectile projectile) { if ((Object)(object)projectile == (Object)null) { return BombType.None; } string text = ((Object)((Component)projectile).gameObject).name.Replace("(Clone)", "").Trim(); if (text.Equals("VC_NiflheimrBomb_projectile", StringComparison.OrdinalIgnoreCase)) { return BombType.Niflheimr; } if (text.Equals("VC_BloodmoonBomb_projectile", StringComparison.OrdinalIgnoreCase)) { return BombType.Bloodmoon; } if (text.Equals("VC_HordeBomb_projectile", StringComparison.OrdinalIgnoreCase)) { return BombType.Horde; } if (text.Equals("VC_CustomBomb_projectile", StringComparison.OrdinalIgnoreCase)) { return BombType.Custom; } if ((Object)(object)projectile.m_nview != (Object)null && projectile.m_nview.IsValid()) { ZDO zDO = projectile.m_nview.GetZDO(); if (zDO != null) { int prefab = zDO.GetPrefab(); if (prefab == StringExtensionMethods.GetStableHashCode("VC_NiflheimrBomb_projectile")) { return BombType.Niflheimr; } if (prefab == StringExtensionMethods.GetStableHashCode("VC_BloodmoonBomb_projectile")) { return BombType.Bloodmoon; } if (prefab == StringExtensionMethods.GetStableHashCode("VC_HordeBomb_projectile")) { return BombType.Horde; } if (prefab == StringExtensionMethods.GetStableHashCode("VC_CustomBomb_projectile")) { return BombType.Custom; } } } return BombType.None; } private static void SpawnCreaturesForBomb(BombType bombType, Vector3 center) { //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) if (1 == 0) { } string text = bombType switch { BombType.Niflheimr => NiflheimrBombCreatures?.Value, BombType.Bloodmoon => BloodmoonBombCreatures?.Value, BombType.Horde => HordeBombCreatures?.Value, BombType.Custom => CustomBombCreatures?.Value, _ => null, }; if (1 == 0) { } string text2 = text; if (1 == 0) { } bool flag = bombType switch { BombType.Niflheimr => NiflheimrBombRandomizeLevels?.Value ?? true, BombType.Bloodmoon => BloodmoonBombRandomizeLevels?.Value ?? true, BombType.Horde => HordeBombRandomizeLevels?.Value ?? true, BombType.Custom => CustomBombRandomizeLevels?.Value ?? true, _ => false, }; if (1 == 0) { } bool flag2 = flag; ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Config: '{text2}', Randomize: {flag2}"); if (string.IsNullOrWhiteSpace(text2)) { ValheimCuisineLogger.LogWarning((object)$"[CreatureBomb] No creatures configured for {bombType}!"); return; } if ((Object)(object)ZNetScene.instance == (Object)null) { ValheimCuisineLogger.LogError((object)"[CreatureBomb] ZNetScene.instance is null!"); return; } List<(string, int, int)> list = ParseCreatureList(text2); float radius = Mathf.Clamp(BombSpawnRadius?.Value ?? 2.5f, 0f, 10f); bool flag3 = BombSpawnRandomRotation?.Value ?? true; int num = 0; foreach (var item5 in list) { int item = item5.Item2; num += item; } ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Spawning {num} total creatures at {center}"); int num2 = 0; foreach (var item6 in list) { string item2 = item6.Item1; int item3 = item6.Item2; int item4 = item6.Item3; GameObject prefab = ZNetScene.instance.GetPrefab(item2); if ((Object)(object)prefab == (Object)null) { ValheimCuisineLogger.LogWarning((object)("[CreatureBomb] Prefab not found: " + item2)); continue; } for (int i = 0; i < item3; i++) { Vector3 val = CalculateSpawnPosition(center, radius, num2, num); Quaternion val2 = (flag3 ? Quaternion.Euler(0f, Random.Range(0f, 360f), 0f) : Quaternion.identity); int num3 = item4; if (flag2 && item4 > 1) { num3 = Random.Range(1, item4 + 1); } GameObject val3 = Object.Instantiate<GameObject>(prefab, val, val2); if ((Object)(object)val3 != (Object)null) { ZNetView component = val3.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && num3 > 1) { ZDO zDO = component.GetZDO(); if (zDO != null) { zDO.Set(ZDOVars.s_level, num3, false); } } MonsterAI component2 = val3.GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null) { component2.m_sleeping = false; ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Spawned {item2} AWAKE at {val} (Level {num3})"); } else { ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Spawned {item2} at {val} (Level {num3})"); } } else { ValheimCuisineLogger.LogError((object)("[CreatureBomb] Failed to spawn " + item2 + "!")); } num2++; } } } private static List<(string prefabName, int count, int level)> ParseCreatureList(string configValue) { List<(string, int, int)> list = new List<(string, int, int)>(); if (string.IsNullOrWhiteSpace(configValue)) { ValheimCuisineLogger.LogWarning((object)"[CreatureBomb] Config value is null or empty"); return list; } ValheimCuisineLogger.LogInfo((object)("[CreatureBomb] Parsing creature list: " + configValue)); string[] array = configValue.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Trim().Split(new char[1] { ':' }); if (array2.Length >= 2) { string text2 = array2[0].Trim(); if (!int.TryParse(array2[1].Trim(), out var result) || result <= 0) { ValheimCuisineLogger.LogWarning((object)("[CreatureBomb] Invalid count in entry: '" + text + "'")); continue; } int num = 1; if (array2.Length >= 3 && int.TryParse(array2[2].Trim(), out var result2)) { num = Mathf.Clamp(result2, 1, 3); } list.Add((text2, result, num)); ValheimCuisineLogger.LogInfo((object)$"[CreatureBomb] Parsed: {text2} x {result} (Level {num})"); } else { ValheimCuisineLogger.LogWarning((object)("[CreatureBomb] Invalid entry: '" + text + "'")); } } return list; } private static Vector3 CalculateSpawnPosition(Vector3 center, float radius, int index, int total) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) Vector3 val = center; if (radius > 0f && total > 1) { float num = 360f / (float)total * (float)index; float num2 = num * ((float)Math.PI / 180f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Cos(num2) * radius, 0f, Mathf.Sin(num2) * radius); val += val2; } return val; } } [HarmonyPatch(typeof(Character), "OnDeath")] public static class GroaElixir_Character_OnDeath_Patch { [HarmonyPrefix] private static void Prefix(Character __instance) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if (__instance.IsPlayer() || !__instance.m_localPlayerHasHit) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } StatusEffect statusEffect = ((Character)localPlayer).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("VC_GroaElixirEffect")); if ((Object)(object)statusEffect == (Object)null) { return; } float value = GroaElixirHealthOnKill.Value; if (value > 0f) { float health = Mathf.Min(((Character)localPlayer).GetHealth() + value, ((Character)localPlayer).GetMaxHealth()); ((Character)localPlayer).SetHealth(health); if (value >= 1f) { Vector3 centerPoint = ((Character)localPlayer).GetCenterPoint(); DamageText.instance.ShowText((TextType)4, centerPoint, value, false); } } } } [HarmonyPatch(typeof(Player))] public static class BerserkRoar_ActivePower_Patch { private static readonly Dictionary<long, float> playerCooldowns = new Dictionary<long, float>(); [HarmonyPostfix] [HarmonyPatch("Update")] private static void Update_Postfix(Player __instance) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (((Character)__instance).IsOwner() && Input.GetKeyDown(BerserkRoarActivationKey.Value)) { TryTriggerBerserkRoar(__instance); } } private static void TryTriggerBerserkRoar(Player player) { bool flag = false; foreach (StatusEffect statusEffect in ((Character)player).GetSEMan().GetStatusEffects()) { if (statusEffect.m_name == "$item_vc_fulingberserkerelixir") { flag = true; break; } } if (!flag) { if (((Humanoid)player).GetInventory().HaveItem("$item_vc_fulingberserkerelixir", true)) { ((Character)player).Message((MessageType)2, Localization.instance.Localize("$vc_hamask_needpotion"), 0, (Sprite)null); } return; } long playerID = player.GetPlayerID(); float time = Time.time; if (playerCooldowns.TryGetValue(playerID, out var value)) { float num = time - value; float num2 = BerserkRoarCooldown.Value - num; if (num2 > 0f) { int num3 = Mathf.FloorToInt(num2 / 60f); int num4 = Mathf.FloorToInt(num2 % 60f); string text = Localization.instance.Localize("$vc_hamask_cooldown"); text = ((num3 <= 0) ? (text + $" {num4}s") : (text + $" {num3}m {num4}s")); ((Character)player).Message((MessageType)2, text, 0, (Sprite)null); return; } } playerCooldowns[playerID] = time; TriggerBerserkRoar(player); } private static void TriggerBerserkRoar(Player player) { string text = ((player.GetPlayerModel() == 0) ? "VC_sfx_BerserkergangMale" : "VC_sfx_BerserkergangFemale"); if (player.StartEmote("roar", false)) { ((Character)player).m_nview.InvokeRPC(ZNetView.Everybody, "VC_PlayBerserkRoar", new object[1] { text }); SpawnHamaskVFX(player); ApplyRoarEffects(player); } else { ApplyRoarEffects(player); ((Character)player).Message((MessageType)2, Localization.instance.Localize("$vc_hamask_noanimation"), 0, (Sprite)null); } } private static void SpawnHamaskVFX(Player player) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab("VC_vfx_Hamask"); if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity); } } } private static void ApplyRoarEffects(Player player) { if (!((Object)(object)player == (Object)null)) { ApplyDamageBuff(player); StaggerNearbyEnemies(player); TauntNearbyEnemies(player); } } private static void ApplyDamageBuff(Player player) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) bool flag = false; ObjectDB instance = ObjectDB.instance; StatusEffect val = ((instance != null) ? instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("VC_FulingBerserkerElixirDamageEffect")) : null); if ((Object)(object)val != (Object)null) { SE_Stats val2 = (SE_Stats)(object)((val is SE_Stats) ? val : null); if ((Object)(object)val2 != (Object)null) { ((StatusEffect)val2).m_ttl = BerserkRoarDamageBoostDuration.Value; val2.m_damageModifier = BerserkRoarDamageBoostPercent.Value / 100f; val2.m_modifyAttackSkill = (SkillType)999; ((Character)player).GetSEMan().AddStatusEffect((StatusEffect)(object)val2, false, 0, 0f); return; } } SE_Stats val3 = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val3).name = "VC_FulingBerserkerElixirDamageEffect"; string text = Localization.instance.Localize("$vc_fulinghamask_damage"); ((StatusEffect)val3).m_name = ((!text.Contains("[") && text != "$vc_fulinghamask_damage") ? text : "Hamask"); string text2 = Localization.instance.Localize("$vc_fulinghamask_damage_tooltip"); ((StatusEffect)val3).m_tooltip = ((!text2.Contains("[") && text2 != "$vc_fulinghamask_damage_tooltip") ? text2 : "Damage increased!"); ((StatusEffect)val3).m_ttl = BerserkRoarDamageBoostDuration.Value; val3.m_damageModifier = BerserkRoarDamageBoostPercent.Value / 100f; val3.m_modifyAttackSkill = (SkillType)999; StatusEffect statusEffect = ((Character)player).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("GP_Eikthyr")); if ((Object)(object)statusEffect != (Object)null && (Object)(object)statusEffect.m_icon != (Object)null) { ((StatusEffect)val3).m_icon = statusEffect.m_icon; } else { StatusEffect statusEffect2 = ((Character)player).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("Rested")); if ((Object)(object)statusEffect2 != (Object)null && (Object)(object)statusEffect2.m_icon != (Object)null) { ((StatusEffect)val3).m_icon = statusEffect2.m_icon; } } ((Character)player).GetSEMan().AddStatusEffect((StatusEffect)(object)val3, false, 0, 0f); } private static void StaggerNearbyEnemies(Player player) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) float value = BerserkRoarStaggerRadius.Value; List<Character> list = new List<Character>(); Character.GetCharactersInRange(((Component)player).transform.position, value, list); foreach (Character item in list) { if (!((Object)(object)item == (Object)(object)player) && !item.IsDead() && BaseAI.IsEnemy((Character)(object)player, item)) { item.Stagger(((Component)player).transform.position - ((Component)item).transform.position); SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((StatusEffect)val).m_name = "Berserk Stagger"; ((StatusEffect)val).m_ttl = BerserkRoarStaggerDuration.Value; val.m_staggerModifier = 2f; item.GetSEMan().AddStatusEffect((StatusEffect)(object)val, false, 0, 0f); } } } private static void TauntNearbyEnemies(Player player) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) float value = BerserkRoarTauntRadius.Value; List<Character> list = new List<Character>(); Character.GetCharactersInRange(((Component)player).transform.position, value, list); foreach (Character item in list) { if (!((Object)(object)item == (Object)(object)player) && !item.IsDead() && BaseAI.IsEnemy((Character)(object)player, item)) { MonsterAI component = ((Component)item).GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null) { component.SetTarget((Character)(object)player); ((BaseAI)component).SetAlerted(true); } } } } } [HarmonyPatch(typeof(Player))] public static class BerserkRoar_Player_RPC_Patch { [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Awake_Postfix(Player __instance) { Player __instance2 = __instance; if ((Object)(object)((Character)__instance2).m_nview != (Object)null && ((Character)__instance2).m_nview.IsValid()) { ((Character)__instance2).m_nview.Register<string>("VC_PlayBerserkRoar", (Action<long, string>)delegate(long sender, string sfxName) { RPC_PlayBerserkRoar(__instance2, sender, sfxName); }); } } private static void RPC_PlayBerserkRoar(Player player, long sender, string sfxName) { //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) if (!((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab(sfxName); if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity); } } } } [HarmonyPatch(typeof(Attack), "GetAttackEitr")] public static class StaffEitrReduction_Patch { [HarmonyPostfix] private static void Postfix(Attack __instance, ref float __result) { if ((Object)(object)__instance.m_character == (Object)null || !((Character)__instance.m_character).IsPlayer()) { return; } ItemData weapon = __instance.m_weapon; if (weapon == null || !IsStaff(weapon)) { return; } Humanoid character = __instance.m_character; Player val = (Player)(object)((character is Player) ? character : null); if (!((Object)(object)val == (Object)null)) { float num = 0f; string text = ""; if (((Character)val).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("VC_FreyjaDraughtEffect"))) { num = FreyjaStaffEitrReduction.Value / 100f; text = "Freyja's Draught"; } else if (((Character)val).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("VC_FulingGutfireBrewEffect"))) { num = FulingStaffEitrReduction.Value / 100f; text = "Fuling Gutfire Brew"; } if (num > 0f) { float num2 = __result; __result *= 1f - num; ValheimCuisineLogger.LogDebug((object)$"{text} active: Reducing staff eitr cost by {num * 100f}% (from {num2} to {__result})"); } } } private static bool IsStaff(ItemData weapon) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 return (int)weapon.m_shared.m_skillType == 10 || (int)weapon.m_shared.m_skillType == 9; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] public static class VidarrDraughtBossDamage_Patch { [HarmonyPrefix] private static void ApplyDamage_Prefix(Character __instance, ref HitData hit) { Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null && !((Object)(object)__instance == (Object)null) && __instance.IsBoss() && ((Character)val).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("VC_VidarrDraughtEffect"))) { float value = VidarrBossDamageMultiplier.Value; ((DamageTypes)(ref hit.m_damage)).Modify(value); ValheimCuisineLogger.LogDebug((object)$"Víðarr Draught active: Applying {value}x damage to boss {__instance.m_name}"); } } } public static class SkadiDraughtTracker { public static Player LastKillingPlayer; } [HarmonyPatch(typeof(Character), "OnDeath")] public static class Character_OnDeath_TrackKiller { [HarmonyPrefix] private static void Prefix(Character __instance) { SkadiDraughtTracker.LastKillingPlayer = null; if (__instance.m_lastHit != null) { Character attacker = __instance.m_lastHit.GetAttacker(); if ((Object)(object)attacker != (Object)null && attacker.IsPlayer()) { SkadiDraughtTracker.LastKillingPlayer = (Player)(object)((attacker is Player) ? attacker : null); } } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public static class CharacterDrop