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