Decompiled source of Hunger Pangs v1.2.2

plugins/HungerPangs.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("HungerPangs")]
[assembly: AssemblyDescription("Valheim HungerPangs Mod by DrummerCraig")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HungerPangs")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ea00b146-e2c4-41cd-8e70-7bbada299b8e")]
[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: AssemblyVersion("1.2.2.0")]
namespace DrummerCraig.HungerPangs;

[BepInPlugin("drummercraig.hungerpangs", "Hunger Pangs", "1.2.2")]
public class HungerPangs : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Player), "UpdateFood")]
	private static class Player_UpdateFood_Patch
	{
		private static void Postfix(Player __instance)
		{
			if ((!_nearWorkbench && !_onBoat) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			float deltaTime = Time.deltaTime;
			foreach (Food food in __instance.GetFoods())
			{
				if (food?.m_item != null)
				{
					food.m_time = Mathf.Min(food.m_time + deltaTime, food.m_item.m_shared.m_foodBurnTime);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	private static class Character_RPC_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				Character attacker = hit.GetAttacker();
				if ((Object)(object)attacker != (Object)null && !attacker.IsPlayer())
				{
					_lastEnemyHitTime = Time.time;
				}
				if (hit.m_damage.m_frost > 0f)
				{
					_frostHitTimes.Enqueue(Time.time);
				}
			}
		}
	}

	private ConfigEntry<bool> modStatus;

	private ConfigEntry<bool> autoEat;

	private ConfigEntry<bool> foodExpiryNotify;

	private ConfigEntry<int> autoEatPercent;

	private ConfigEntry<int> foodExpiryPercent;

	private ConfigEntry<bool> autoEatNotify;

	private ConfigEntry<bool> lowSupplyNotify;

	private ConfigEntry<int> lowSupplyCount;

	private ConfigEntry<bool> autoMead;

	private ConfigEntry<int> autoMeadHealthPercent;

	private ConfigEntry<bool> autoMeadOnlyOnEnemyHit;

	private ConfigEntry<float> autoMeadEnemyHitWindow;

	private ConfigEntry<bool> autoMeadRequireMaxHealth;

	private ConfigEntry<bool> autoMeadNotify;

	private ConfigEntry<bool> autoPoisonMead;

	private ConfigEntry<float> autoPoisonMeadRange;

	private ConfigEntry<bool> autoPoisonMeadNotify;

	private ConfigEntry<bool> autoFireMead;

	private ConfigEntry<float> autoFireMeadRange;

	private ConfigEntry<bool> autoFireMeadNotify;

	private ConfigEntry<bool> autoFrostMead;

	private ConfigEntry<int> autoFrostMeadTickCount;

	private ConfigEntry<float> autoFrostMeadTickWindow;

	private ConfigEntry<bool> autoFrostMeadNotify;

	private ConfigEntry<bool> pauseFoodNearWorkbench;

	private ConfigEntry<bool> pauseFoodOnBoat;

	private static float _lastEnemyHitTime = float.MinValue;

	private static bool _nearWorkbench;

	private static bool _onBoat;

	private static readonly List<Character> _nearbyCharacterBuffer = new List<Character>();

	private static readonly Queue<float> _frostHitTimes = new Queue<float>();

	private static readonly HashSet<string> _poisonEnemyPrefabs = new HashSet<string>();

	private static readonly HashSet<string> _fireEnemyPrefabs = new HashSet<string>();

	private static readonly HashSet<string> _checkedPrefabs = new HashSet<string>();

	private const float MeleeRange = 3f;

	private const float MeleeRangeSq = 9f;

	private readonly HashSet<string> hasShown = new HashSet<string>();

	private readonly HashSet<string> seenThisTick = new HashSet<string>();

	private readonly HashSet<string> lowSupplyShown = new HashSet<string>();

	private Predicate<string> _notSeenThisTick;

	private void Awake()
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Expected O, but got Unknown
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Expected O, but got Unknown
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Expected O, but got Unknown
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Expected O, but got Unknown
		//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bf: Expected O, but got Unknown
		//IL_0335: Unknown result type (might be due to invalid IL or missing references)
		//IL_033f: Expected O, but got Unknown
		//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b4: Expected O, but got Unknown
		//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f2: Expected O, but got Unknown
		//IL_043a: Unknown result type (might be due to invalid IL or missing references)
		modStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "01. Mod Status", true, "Master toggle for the entire mod. When disabled, no auto-eating or notifications occur.");
		autoEat = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "02. Auto-Eat", true, "Automatically re-eat food before it expires. When disabled, the mod will only show notifications if NotificationsEnabled is on, allowing you to eat manually on cue.");
		autoEatPercent = ((BaseUnityPlugin)this).Config.Bind<int>("General", "03. Auto-Eat Percent", 5, new ConfigDescription("Percentage of a food's total duration remaining when it is automatically re-eaten. Food becomes eligible to re-eat at 50% remaining (when it starts blinking), so this is your window. Lower values eat later and waste less food; higher values re-eat sooner after becoming eligible. Example: 5 = eat when 5% remains (e.g. ~1.5 min of a 30-min food). Requires Auto-Eat Enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 49), Array.Empty<object>()));
		autoEatNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "04. Auto-Eat Notify", true, "Show a HUD notification when a food item is automatically eaten. Requires AutomaticallyEat.");
		foodExpiryNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "05. Food Expiry Notify", true, "Show a HUD notification when a food item nears its expiry threshold. Useful on its own when Auto-Eat is Disabled,as a manual reminder to eat.");
		foodExpiryPercent = ((BaseUnityPlugin)this).Config.Bind<int>("General", "06. Food Expiry Percent", 30, new ConfigDescription("Percentage of a food's total duration remaining when the HUD notification appears. Food becomes eligible to re-eat at 50% remaining (when it starts blinking). Set this higher than Auto-Eat Percent so the notification fires before auto-eat. Example: 30 = notify when 30% remains (e.g. ~9 min of a 30-min food). Requires Notifications.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
		lowSupplyNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "07. Low Supply Notify", true, "Show a HUD notification when AutomaticallyEat is enabled, a food item is consumed and the remaining count in your inventory is at or below the LowSupplyThreshold.");
		lowSupplyCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "08. Low Supply Count", 1, "The number of food items in your inventory for the LowSupplyNotification to appear.");
		pauseFoodNearWorkbench = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "09. Pause Near Workbench", true, "Pause food expiry timers when within range of a workbench. Food effects (health and stamina regen) continue normally — only the countdown is paused.");
		pauseFoodOnBoat = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "10. Pause On Boat", true, "Pause food expiry timers while sailing on a boat. Food effects (health and stamina regen) continue normally — only the countdown is paused.");
		autoMead = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Mead", "01. Auto Health Mead", true, "Automatically drink a health mead when your health drops below the configured threshold.");
		autoMeadHealthPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Health Mead", "02. Health Threshold", 30, new ConfigDescription("Health percentage below which a health mead will be automatically consumed. Example: 40 = drink when health drops below 40% of your maximum.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 99), Array.Empty<object>()));
		autoMeadOnlyOnEnemyHit = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Mead", "03. Only On Enemy Hit", true, "Only auto-drink when the health drop was caused by an enemy. Prevents wasting meads on fall damage, lava, or other environmental hazards when not in combat.");
		autoMeadEnemyHitWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Health Mead", "04. Enemy Hit Window", 5f, new ConfigDescription("Seconds after the last enemy hit during which the mead trigger remains active. Requires Only On Enemy Hit. Example: 5 = the mead can fire within 5 seconds of being struck.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
		autoMeadRequireMaxHealth = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Mead", "05. Require Sufficient Max Health", false, "Only drink a mead if your maximum health is at least equal to the mead's total healing value. Prevents drinking a mead that heals more than your health cap, which would waste the excess. Meads that exceed your max health are skipped; the next-strongest eligible mead is tried instead.");
		autoMeadNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Mead", "06. Notify", true, "Show a HUD notification when a health mead is automatically consumed.");
		autoPoisonMead = ((BaseUnityPlugin)this).Config.Bind<bool>("Poison Resist Mead", "01. Auto Poison Mead", true, "Automatically drink a poison resist mead when a nearby enemy can deal poison damage.");
		autoPoisonMeadRange = ((BaseUnityPlugin)this).Config.Bind<float>("Poison Resist Mead", "02. Detection Range", 4f, new ConfigDescription("Radius in meters to scan for poison-capable enemies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
		autoPoisonMeadNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("Poison Resist Mead", "03. Notify", true, "Show a HUD notification when a poison resist mead is automatically consumed.");
		autoFireMead = ((BaseUnityPlugin)this).Config.Bind<bool>("Fire Resist Mead", "01. Auto Fire Mead", true, "Automatically drink a fire resist mead when a nearby enemy can deal fire damage.");
		autoFireMeadRange = ((BaseUnityPlugin)this).Config.Bind<float>("Fire Resist Mead", "02. Detection Range", 15f, new ConfigDescription("Radius in meters to scan for fire-capable enemies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
		autoFireMeadNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("Fire Resist Mead", "03. Notify", true, "Show a HUD notification when a fire resist mead is automatically consumed.");
		autoFrostMead = ((BaseUnityPlugin)this).Config.Bind<bool>("Frost Resist Mead", "01. Auto Frost Mead", true, "Automatically drink a frost resist mead after receiving repeated frost damage hits.");
		autoFrostMeadTickCount = ((BaseUnityPlugin)this).Config.Bind<int>("Frost Resist Mead", "02. Frost Tick Count", 3, new ConfigDescription("Number of frost damage hits within the time window required to trigger auto-consume.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
		autoFrostMeadTickWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Frost Resist Mead", "03. Frost Tick Window", 10f, new ConfigDescription("Seconds over which frost hits are counted toward the trigger threshold.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()));
		autoFrostMeadNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("Frost Resist Mead", "04. Notify", true, "Show a HUD notification when a frost resist mead is automatically consumed.");
		_notSeenThisTick = (string key) => !seenThisTick.Contains(key);
		new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
		((MonoBehaviour)this).StartCoroutine(FoodCheckLoop());
		((MonoBehaviour)this).StartCoroutine(MeadCheckLoop());
	}

	private IEnumerator FoodCheckLoop()
	{
		WaitForSeconds wait = new WaitForSeconds(1f);
		while (true)
		{
			yield return wait;
			CheckFoods();
		}
	}

	private IEnumerator MeadCheckLoop()
	{
		WaitForSeconds wait = new WaitForSeconds(0.5f);
		while (true)
		{
			yield return wait;
			CheckMeads();
			CheckProximityResistMeads();
			CheckFrostResistMeads();
		}
	}

	private void CheckFoods()
	{
		Player localPlayer = Player.m_localPlayer;
		_nearWorkbench = (Object)(object)localPlayer != (Object)null && pauseFoodNearWorkbench.Value && NearWorkbench(localPlayer);
		_onBoat = (Object)(object)localPlayer != (Object)null && pauseFoodOnBoat.Value && IsOnBoat(localPlayer);
		if (!modStatus.Value || (Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		Humanoid val = (Humanoid)(object)localPlayer;
		Inventory inventory = val.GetInventory();
		List<Food> foods = localPlayer.GetFoods();
		seenThisTick.Clear();
		for (int i = 0; i < foods.Count; i++)
		{
			Food val2 = foods[i];
			string name = val2.m_item.m_shared.m_name;
			seenThisTick.Add(name);
			float time = val2.m_time;
			float foodBurnTime = val2.m_item.m_shared.m_foodBurnTime;
			float num = ((foodBurnTime > 0f) ? (time / foodBurnTime * 100f) : 0f);
			if (!val2.CanEatAgain())
			{
				hasShown.Remove(name);
				lowSupplyShown.Remove(name);
				continue;
			}
			if (foodExpiryNotify.Value && !hasShown.Contains(name) && num <= (float)foodExpiryPercent.Value)
			{
				string arg = Localization.instance.Localize(val2.m_item.m_shared.m_name);
				int num2 = Mathf.CeilToInt(time / 60f);
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, $"{arg} expires in {num2} min", 0, (Sprite)null, false);
				}
				hasShown.Add(name);
			}
			if (!autoEat.Value || !(num <= (float)autoEatPercent.Value))
			{
				continue;
			}
			ItemData item = inventory.GetItem(name, -1, false);
			if (item == null || !val.ConsumeItem(inventory, item, false))
			{
				continue;
			}
			hasShown.Remove(name);
			if (autoEatNotify.Value)
			{
				string text = Localization.instance.Localize(val2.m_item.m_shared.m_name);
				MessageHud instance2 = MessageHud.instance;
				if (instance2 != null)
				{
					instance2.ShowMessage((MessageType)2, text + " automatically re-eaten", 0, (Sprite)null, false);
				}
			}
			if (!lowSupplyNotify.Value || lowSupplyCount.Value <= 0 || lowSupplyShown.Contains(name))
			{
				continue;
			}
			int num3 = inventory.CountItems(name, -1, true);
			if (num3 <= lowSupplyCount.Value)
			{
				string arg2 = Localization.instance.Localize(val2.m_item.m_shared.m_name);
				MessageHud instance3 = MessageHud.instance;
				if (instance3 != null)
				{
					instance3.ShowMessage((MessageType)2, $"Low supply: {num3} {arg2} remaining", 0, (Sprite)null, false);
				}
				lowSupplyShown.Add(name);
			}
		}
		hasShown.RemoveWhere(_notSeenThisTick);
		lowSupplyShown.RemoveWhere(_notSeenThisTick);
	}

	private void CheckMeads()
	{
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		if (!modStatus.Value || !autoMead.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).GetHealthPercentage() * 100f >= (float)autoMeadHealthPercent.Value || (autoMeadOnlyOnEnemyHit.Value && Time.time - _lastEnemyHitTime > autoMeadEnemyHitWindow.Value))
		{
			return;
		}
		Humanoid val = (Humanoid)(object)localPlayer;
		Inventory inventory = val.GetInventory();
		List<ItemData> healthMeads = GetHealthMeads(inventory);
		float maxHealth = ((Character)localPlayer).GetMaxHealth();
		SEMan sEMan = ((Character)localPlayer).GetSEMan();
		foreach (ItemData item in healthMeads)
		{
			StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect;
			if ((Object)(object)consumeStatusEffect != (Object)null && sEMan.HaveStatusEffect(consumeStatusEffect.NameHash()))
			{
				continue;
			}
			if (autoMeadRequireMaxHealth.Value)
			{
				float healthOverTime = ((SE_Stats)item.m_shared.m_consumeStatusEffect).m_healthOverTime;
				if (maxHealth < healthOverTime)
				{
					continue;
				}
			}
			if (!val.ConsumeItem(inventory, item, false))
			{
				continue;
			}
			if (autoMeadNotify.Value)
			{
				string text = Localization.instance.Localize(item.m_shared.m_name);
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, text + " automatically consumed", 0, (Sprite)null, false);
				}
			}
			break;
		}
	}

	private static bool NearWorkbench(Player player)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		return (Object)(object)CraftingStation.FindClosestStationInRange("$piece_workbench", ((Component)player).transform.position, 20f) != (Object)null;
	}

	private static bool IsOnBoat(Player player)
	{
		return ((Character)player).IsAttachedToShip();
	}

	private void CheckProximityResistMeads()
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: 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)
		bool flag = modStatus.Value && autoPoisonMead.Value;
		bool flag2 = modStatus.Value && autoFireMead.Value;
		if (!flag && !flag2)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		float num = 0f;
		if (flag)
		{
			num = Mathf.Max(num, autoPoisonMeadRange.Value);
		}
		if (flag2)
		{
			num = Mathf.Max(num, autoFireMeadRange.Value);
		}
		bool flag3 = false;
		bool flag4 = false;
		_nearbyCharacterBuffer.Clear();
		Character.GetCharactersInRange(((Component)localPlayer).transform.position, num, _nearbyCharacterBuffer);
		float num2 = autoPoisonMeadRange.Value * autoPoisonMeadRange.Value;
		float num3 = autoFireMeadRange.Value * autoFireMeadRange.Value;
		foreach (Character item in _nearbyCharacterBuffer)
		{
			if ((Object)(object)item == (Object)null || item.IsPlayer() || item.IsDead())
			{
				continue;
			}
			Vector3 val = ((Component)item).transform.position - ((Component)localPlayer).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (IsThreateningPlayer(item, localPlayer, sqrMagnitude))
			{
				string prefabName = GetPrefabName(item);
				EnsureCached(prefabName, item);
				if (flag && !flag3 && sqrMagnitude <= num2 && _poisonEnemyPrefabs.Contains(prefabName))
				{
					flag3 = true;
				}
				if (flag2 && !flag4 && sqrMagnitude <= num3 && _fireEnemyPrefabs.Contains(prefabName))
				{
					flag4 = true;
				}
				if (flag3 && flag4)
				{
					break;
				}
			}
		}
		if (flag3)
		{
			ConsumeResistMead(localPlayer, autoPoisonMeadNotify, (DamageType)256);
		}
		if (flag4)
		{
			ConsumeResistMead(localPlayer, autoFireMeadNotify, (DamageType)32);
		}
	}

	private static bool IsThreateningPlayer(Character c, Player localPlayer, float distSq)
	{
		if (distSq <= 9f)
		{
			return true;
		}
		MonsterAI component = ((Component)c).GetComponent<MonsterAI>();
		if ((Object)(object)component != (Object)null)
		{
			return ((BaseAI)component).GetTargetCreature() == localPlayer;
		}
		return false;
	}

	private static string GetPrefabName(Character c)
	{
		return ((Object)((Component)c).gameObject).name.Replace("(Clone)", "").Trim();
	}

	private static void EnsureCached(string prefab, Character c)
	{
		if (_checkedPrefabs.Contains(prefab))
		{
			return;
		}
		Humanoid val = (Humanoid)(object)((c is Humanoid) ? c : null);
		if ((Object)(object)val == (Object)null)
		{
			_checkedPrefabs.Add(prefab);
			return;
		}
		foreach (ItemData allItem in val.GetInventory().GetAllItems())
		{
			if (allItem.m_shared.m_damages.m_poison > 0f)
			{
				_poisonEnemyPrefabs.Add(prefab);
			}
			if (allItem.m_shared.m_damages.m_fire > 0f)
			{
				_fireEnemyPrefabs.Add(prefab);
			}
		}
		ItemData currentWeapon = val.GetCurrentWeapon();
		if (currentWeapon != null)
		{
			if (currentWeapon.m_shared.m_damages.m_poison > 0f)
			{
				_poisonEnemyPrefabs.Add(prefab);
			}
			if (currentWeapon.m_shared.m_damages.m_fire > 0f)
			{
				_fireEnemyPrefabs.Add(prefab);
			}
		}
		_checkedPrefabs.Add(prefab);
	}

	private void ConsumeResistMead(Player localPlayer, ConfigEntry<bool> notify, DamageType type)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = ((Humanoid)localPlayer).GetInventory();
		SEMan sEMan = ((Character)localPlayer).GetSEMan();
		foreach (ItemData resistMead in GetResistMeads(inventory, type))
		{
			StatusEffect consumeStatusEffect = resistMead.m_shared.m_consumeStatusEffect;
			if ((Object)(object)consumeStatusEffect != (Object)null && sEMan.HaveStatusEffect(consumeStatusEffect.NameHash()))
			{
				break;
			}
			if (!((Humanoid)localPlayer).ConsumeItem(inventory, resistMead, false))
			{
				continue;
			}
			if (notify.Value)
			{
				string text = Localization.instance.Localize(resistMead.m_shared.m_name);
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, text + " automatically consumed", 0, (Sprite)null, false);
				}
			}
			break;
		}
	}

	private void CheckFrostResistMeads()
	{
		if (!modStatus.Value || !autoFrostMead.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		float num = Time.time - autoFrostMeadTickWindow.Value;
		while (_frostHitTimes.Count > 0 && _frostHitTimes.Peek() < num)
		{
			_frostHitTimes.Dequeue();
		}
		SEMan sEMan = ((Character)localPlayer).GetSEMan();
		bool num2 = sEMan.HaveStatusEffect(StringExtensionMethods.GetStableHashCode("Freezing"));
		bool flag = _frostHitTimes.Count >= autoFrostMeadTickCount.Value;
		if (!num2 && !flag)
		{
			return;
		}
		Humanoid val = (Humanoid)(object)localPlayer;
		Inventory inventory = val.GetInventory();
		foreach (ItemData resistMead in GetResistMeads(inventory, (DamageType)64))
		{
			StatusEffect consumeStatusEffect = resistMead.m_shared.m_consumeStatusEffect;
			if ((Object)(object)consumeStatusEffect != (Object)null && sEMan.HaveStatusEffect(consumeStatusEffect.NameHash()))
			{
				_frostHitTimes.Clear();
				break;
			}
			if (!val.ConsumeItem(inventory, resistMead, false))
			{
				continue;
			}
			_frostHitTimes.Clear();
			if (autoFrostMeadNotify.Value)
			{
				string text = Localization.instance.Localize(resistMead.m_shared.m_name);
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, text + " automatically consumed", 0, (Sprite)null, false);
				}
			}
			break;
		}
	}

	private static List<ItemData> GetResistMeads(Inventory inventory, DamageType type)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Invalid comparison between Unknown and I4
		//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_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)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if ((int)allItem.m_shared.m_itemType != 2)
			{
				continue;
			}
			StatusEffect consumeStatusEffect = allItem.m_shared.m_consumeStatusEffect;
			SE_Stats val = (SE_Stats)(object)((consumeStatusEffect is SE_Stats) ? consumeStatusEffect : null);
			if (val == null)
			{
				continue;
			}
			foreach (DamageModPair mod in val.m_mods)
			{
				if (mod.m_type == type && (int)mod.m_modifier != 0)
				{
					list.Add(allItem);
					break;
				}
			}
		}
		return list;
	}

	private static List<ItemData> GetHealthMeads(Inventory inventory)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Invalid comparison between Unknown and I4
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if ((int)allItem.m_shared.m_itemType == 2)
			{
				StatusEffect consumeStatusEffect = allItem.m_shared.m_consumeStatusEffect;
				SE_Stats val = (SE_Stats)(object)((consumeStatusEffect is SE_Stats) ? consumeStatusEffect : null);
				if (val != null && val.m_healthOverTime > 0f)
				{
					list.Add(allItem);
				}
			}
		}
		list.Sort(delegate(ItemData a, ItemData b)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			float healthOverTime = ((SE_Stats)a.m_shared.m_consumeStatusEffect).m_healthOverTime;
			float healthOverTime2 = ((SE_Stats)b.m_shared.m_consumeStatusEffect).m_healthOverTime;
			return healthOverTime2.CompareTo(healthOverTime);
		});
		return list;
	}
}