Decompiled source of Troll Toll v0.20.4

TrollToll.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BeardyMike")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Stamina mod for Valheim that turns off stamina drain when no enemies are nearby, with granular biome, creature, and boss relief progression control.")]
[assembly: AssemblyFileVersion("0.20.4")]
[assembly: AssemblyInformationalVersion("0.20.4+17bc48ff1bed24fb97f0e8342682a777b573321a")]
[assembly: AssemblyProduct("Troll-Toll")]
[assembly: AssemblyTitle("TrollToll")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.20.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TrollToll
{
	public static class BiomeManager
	{
		public class BiomeSetting
		{
			public ConfigEntry<bool> Enabled;

			public ConfigEntry<float> DetectionRadius;
		}

		private static readonly Dictionary<Biome, BiomeSetting> _biomeSettings = new Dictionary<Biome, BiomeSetting>();

		public static void Initialize(ConfigFile config)
		{
			_biomeSettings.Clear();
			RegisterBiome(config, (Biome)1, "Meadows", 30f);
			RegisterBiome(config, (Biome)8, "BlackForest", 30f);
			RegisterBiome(config, (Biome)2, "Swamp", 30f);
			RegisterBiome(config, (Biome)4, "Mountain", 30f);
			RegisterBiome(config, (Biome)16, "Plains", 30f);
			RegisterBiome(config, (Biome)512, "Mistlands", 30f);
			RegisterBiome(config, (Biome)32, "Ashlands", 30f);
			RegisterBiome(config, (Biome)64, "DeepNorth", 30f);
			RegisterBiome(config, (Biome)256, "Ocean", 30f);
		}

		private static void RegisterBiome(ConfigFile config, Biome biome, string displayName, float defaultRadius)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			BiomeSetting value = new BiomeSetting
			{
				Enabled = config.Bind<bool>("5 - Biome Controls", displayName + "_Enabled", true, "Enable Troll-Toll stamina mechanics in the " + displayName + " biome."),
				DetectionRadius = config.Bind<float>("5 - Biome Controls", displayName + "_DetectionRadius", defaultRadius, "Threat detection radius in meters for the " + displayName + " biome. Set to -1 to use global DetectionRadius.")
			};
			_biomeSettings[biome] = value;
		}

		public static bool IsBiomeModEnabled(Biome biome)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			biome = GetPrimaryBiome(biome);
			if (_biomeSettings.TryGetValue(biome, out var value))
			{
				return value.Enabled.Value;
			}
			return true;
		}

		public static float GetBiomeDetectionRadius(Biome biome)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			biome = GetPrimaryBiome(biome);
			if (_biomeSettings.TryGetValue(biome, out var value))
			{
				float value2 = value.DetectionRadius.Value;
				if (value2 > 0f)
				{
					return value2;
				}
			}
			return TrollTollPlugin.DetectionRadius.Value;
		}

		public static Biome GetPrimaryBiome(Biome biome)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_005a: Invalid comparison between Unknown and I4
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Invalid comparison between Unknown and I4
			//IL_0094: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (_biomeSettings.ContainsKey(biome))
			{
				return biome;
			}
			if ((biome & 0x20) > 0)
			{
				return (Biome)32;
			}
			if ((biome & 0x200) > 0)
			{
				return (Biome)512;
			}
			if ((biome & 0x40) > 0)
			{
				return (Biome)64;
			}
			if ((biome & 0x10) > 0)
			{
				return (Biome)16;
			}
			if ((biome & 4) > 0)
			{
				return (Biome)4;
			}
			if ((biome & 2) > 0)
			{
				return (Biome)2;
			}
			if ((biome & 8) > 0)
			{
				return (Biome)8;
			}
			if ((biome & 1) > 0)
			{
				return (Biome)1;
			}
			if ((biome & 0x100) > 0)
			{
				return (Biome)256;
			}
			return (Biome)0;
		}
	}
	public class BossInfo
	{
		public Biome Biome { get; }

		public string BossName { get; }

		public string GlobalKey { get; }

		public int Tier { get; }

		public BossInfo(Biome biome, string bossName, string globalKey, int tier)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Biome = biome;
			BossName = bossName;
			GlobalKey = globalKey;
			Tier = tier;
		}
	}
	public static class BossReliefManager
	{
		public static readonly List<BossInfo> Bosses;

		private static readonly Dictionary<Biome, BossInfo> _biomeBossLookup;

		static BossReliefManager()
		{
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			Bosses = new List<BossInfo>
			{
				new BossInfo((Biome)1, "Eikthyr", "defeated_eikthyr", 1),
				new BossInfo((Biome)8, "The Elder", "defeated_gdking", 2),
				new BossInfo((Biome)2, "Bonemass", "defeated_bonemass", 3),
				new BossInfo((Biome)4, "Moder", "defeated_dragon", 4),
				new BossInfo((Biome)16, "Yagluth", "defeated_goblinking", 5),
				new BossInfo((Biome)512, "The Queen", "defeated_queen", 6),
				new BossInfo((Biome)32, "Fader", "defeated_fader", 7)
			};
			_biomeBossLookup = new Dictionary<Biome, BossInfo>();
			foreach (BossInfo boss in Bosses)
			{
				_biomeBossLookup[boss.Biome] = boss;
			}
		}

		public static BossInfo GetBossForBiome(Biome biome)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			biome = BiomeManager.GetPrimaryBiome(biome);
			if (_biomeBossLookup.TryGetValue(biome, out var value))
			{
				return value;
			}
			return null;
		}

		public static bool IsBossDefeated(string globalKey)
		{
			if (string.IsNullOrEmpty(globalKey) || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			return ZoneSystem.instance.GetGlobalKey(globalKey);
		}

		public static int GetTotalDefeatedBossCount()
		{
			int num = 0;
			for (int i = 0; i < Bosses.Count; i++)
			{
				if (IsBossDefeated(Bosses[i].GlobalKey))
				{
					num++;
				}
			}
			return num;
		}

		public static float GetReliefFraction(Biome biome)
		{
			//IL_0020: 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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (!TrollTollPlugin.BossReliefEnabled.Value)
			{
				return 0f;
			}
			biome = BiomeManager.GetPrimaryBiome(biome);
			if ((int)biome == 256)
			{
				if (!TrollTollPlugin.OceanBossRelief.Value)
				{
					return 0f;
				}
				int totalDefeatedBossCount = GetTotalDefeatedBossCount();
				if (totalDefeatedBossCount <= 0)
				{
					return 0f;
				}
				float value = TrollTollPlugin.BossReliefBasePercent.Value;
				float value2 = TrollTollPlugin.BossReliefPerAdditionalBossPercent.Value;
				float value3 = TrollTollPlugin.BossReliefCapPercent.Value;
				float num = value + (float)(totalDefeatedBossCount - 1) * value2;
				return Mathf.Clamp(num, 0f, value3) / 100f;
			}
			BossInfo bossForBiome = GetBossForBiome(biome);
			if (bossForBiome == null)
			{
				return 0f;
			}
			if (!IsBossDefeated(bossForBiome.GlobalKey))
			{
				return 0f;
			}
			float value4 = TrollTollPlugin.BossReliefBasePercent.Value;
			float value5 = TrollTollPlugin.BossReliefPerAdditionalBossPercent.Value;
			float value6 = TrollTollPlugin.BossReliefCapPercent.Value;
			int num2 = 0;
			string value7 = TrollTollPlugin.BossReliefCalculationMode.Value;
			if (value7 == "AllDefeatedBosses")
			{
				for (int i = 0; i < Bosses.Count; i++)
				{
					if (Bosses[i] != bossForBiome && IsBossDefeated(Bosses[i].GlobalKey))
					{
						num2++;
					}
				}
			}
			else
			{
				for (int j = 0; j < Bosses.Count; j++)
				{
					if (Bosses[j].Tier > bossForBiome.Tier && IsBossDefeated(Bosses[j].GlobalKey))
					{
						num2++;
					}
				}
			}
			float num3 = value4 + (float)num2 * value5;
			float num4 = Mathf.Clamp(num3, 0f, value6);
			return num4 / 100f;
		}

		public static string GetStatusSummary(Biome biome)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			biome = BiomeManager.GetPrimaryBiome(biome);
			BossInfo bossForBiome = GetBossForBiome(biome);
			float num = GetReliefFraction(biome) * 100f;
			int totalDefeatedBossCount = GetTotalDefeatedBossCount();
			if (bossForBiome == null)
			{
				return $"Biome: {biome} | Relief: {num:0}% | World Bosses Defeated: {totalDefeatedBossCount}";
			}
			bool flag = IsBossDefeated(bossForBiome.GlobalKey);
			return $"Biome: {biome} | Boss: {bossForBiome.BossName} (Defeated: {flag}) | Relief: {num:0}% | World Bosses Defeated: {totalDefeatedBossCount}";
		}
	}
	public static class CreatureManager
	{
		public static ConfigEntry<string> IgnoredCreatures;

		public static ConfigEntry<string> EnforcedThreatCreatures;

		public static ConfigEntry<string> CustomCreatureRadii;

		public static ConfigEntry<bool> BossesAlwaysThreat;

		public static ConfigEntry<bool> IgnoreBoars;

		public static ConfigEntry<bool> IgnoreNecks;

		public static ConfigEntry<bool> IgnoreGreylings;

		public static ConfigEntry<bool> IgnoreBats;

		public static ConfigEntry<bool> IgnoreSkeletons;

		private static readonly HashSet<string> _parsedIgnored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> _parsedEnforced = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _parsedCustomRadii = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		public static float MaxCustomRadius { get; private set; } = 30f;

		public static void Initialize(ConfigFile config)
		{
			IgnoredCreatures = config.Bind<string>("6 - Creature Controls", "IgnoredCreatures", "Deer, Seagull, Crow", "Comma-separated list of creature names or prefabs that NEVER trigger threat or consume combat stamina (e.g. 'Greyling, Neck, Boar, Skeleton'). Matches display name or prefab name.");
			EnforcedThreatCreatures = config.Bind<string>("6 - Creature Controls", "EnforcedThreatCreatures", "Troll, Abomination, StoneGolem, Gjall, SeekerSoldier", "Comma-separated list of creature names or prefabs that ALWAYS trigger threat when within range, regardless of alert status (e.g. 'Troll, Abomination, Gjall').");
			CustomCreatureRadii = config.Bind<string>("6 - Creature Controls", "CustomCreatureRadii", "Troll:50, Abomination:40, Gjall:50", "Creature-specific threat detection radius in 'CreatureName:Distance' format (e.g. 'Troll:50, Greyling:10'). Overrides biome and global detection radius.");
			BossesAlwaysThreat = config.Bind<bool>("6 - Creature Controls", "BossesAlwaysThreat", true, "If true, any active boss in detection range is always treated as an active threat.");
			IgnoreBoars = config.Bind<bool>("6 - Creature Controls", "IgnoreBoars", false, "Quick toggle: If true, wild Boars never trigger threat or interrupt free stamina.");
			IgnoreNecks = config.Bind<bool>("6 - Creature Controls", "IgnoreNecks", false, "Quick toggle: If true, Necks never trigger threat or interrupt free stamina.");
			IgnoreGreylings = config.Bind<bool>("6 - Creature Controls", "IgnoreGreylings", false, "Quick toggle: If true, Greylings never trigger threat or interrupt free stamina.");
			IgnoreBats = config.Bind<bool>("6 - Creature Controls", "IgnoreBats", false, "Quick toggle: If true, Bats never trigger threat or interrupt free stamina.");
			IgnoreSkeletons = config.Bind<bool>("6 - Creature Controls", "IgnoreSkeletons", false, "Quick toggle: If true, Skeletons never trigger threat or interrupt free stamina.");
			IgnoredCreatures.SettingChanged += delegate
			{
				RefreshCache();
			};
			EnforcedThreatCreatures.SettingChanged += delegate
			{
				RefreshCache();
			};
			CustomCreatureRadii.SettingChanged += delegate
			{
				RefreshCache();
			};
			RefreshCache();
		}

		public static void RefreshCache()
		{
			_parsedIgnored.Clear();
			if (!string.IsNullOrWhiteSpace(IgnoredCreatures.Value))
			{
				string[] array = IgnoredCreatures.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array2 = array;
				foreach (string input in array2)
				{
					string text = CleanName(input);
					if (!string.IsNullOrEmpty(text))
					{
						_parsedIgnored.Add(text);
					}
				}
			}
			_parsedEnforced.Clear();
			if (!string.IsNullOrWhiteSpace(EnforcedThreatCreatures.Value))
			{
				string[] array3 = EnforcedThreatCreatures.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array4 = array3;
				foreach (string input2 in array4)
				{
					string text2 = CleanName(input2);
					if (!string.IsNullOrEmpty(text2))
					{
						_parsedEnforced.Add(text2);
					}
				}
			}
			_parsedCustomRadii.Clear();
			float num = 30f;
			if (!string.IsNullOrWhiteSpace(CustomCreatureRadii.Value))
			{
				string[] array5 = CustomCreatureRadii.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array6 = array5;
				foreach (string text3 in array6)
				{
					string[] array7 = text3.Split(':');
					if (array7.Length != 2 || !float.TryParse(array7[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						continue;
					}
					string text4 = CleanName(array7[0]);
					if (!string.IsNullOrEmpty(text4))
					{
						_parsedCustomRadii[text4] = result;
						if (result > num)
						{
							num = result;
						}
					}
				}
			}
			MaxCustomRadius = num;
		}

		public static string CleanName(string input)
		{
			if (string.IsNullOrEmpty(input))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(input.Length);
			foreach (char c in input)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		public static List<string> GetCandidateNames(Character character)
		{
			List<string> list = new List<string>(4);
			if ((Object)(object)character == (Object)null)
			{
				return list;
			}
			if ((Object)(object)((Component)character).gameObject != (Object)null)
			{
				string prefabName = Utils.GetPrefabName(((Component)character).gameObject);
				if (!string.IsNullOrEmpty(prefabName))
				{
					list.Add(CleanName(prefabName));
				}
			}
			try
			{
				string hoverName = character.GetHoverName();
				if (!string.IsNullOrEmpty(hoverName))
				{
					list.Add(CleanName(hoverName));
				}
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(character.m_name))
			{
				string text = CleanName(character.m_name);
				list.Add(text);
				if (text.StartsWith("enemy"))
				{
					list.Add(text.Substring(5));
				}
			}
			if ((Object)(object)((Component)character).gameObject != (Object)null)
			{
				string input = ((Object)((Component)character).gameObject).name.Replace("(Clone)", "");
				list.Add(CleanName(input));
			}
			return list;
		}

		public static bool IsCreatureIgnored(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			List<string> candidateNames = GetCandidateNames(character);
			if (IgnoreBoars.Value && candidateNames.Contains("boar"))
			{
				return true;
			}
			if (IgnoreNecks.Value && candidateNames.Contains("neck"))
			{
				return true;
			}
			if (IgnoreGreylings.Value && candidateNames.Contains("greyling"))
			{
				return true;
			}
			if (IgnoreBats.Value && candidateNames.Contains("bat"))
			{
				return true;
			}
			if (IgnoreSkeletons.Value && candidateNames.Contains("skeleton"))
			{
				return true;
			}
			for (int i = 0; i < candidateNames.Count; i++)
			{
				if (_parsedIgnored.Contains(candidateNames[i]))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsCreatureEnforcedThreat(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			if (BossesAlwaysThreat.Value && character.IsBoss())
			{
				return true;
			}
			List<string> candidateNames = GetCandidateNames(character);
			for (int i = 0; i < candidateNames.Count; i++)
			{
				if (_parsedEnforced.Contains(candidateNames[i]))
				{
					return true;
				}
			}
			return false;
		}

		public static float GetCustomRadius(Character character, float defaultRadius)
		{
			if ((Object)(object)character == (Object)null)
			{
				return defaultRadius;
			}
			List<string> candidateNames = GetCandidateNames(character);
			for (int i = 0; i < candidateNames.Count; i++)
			{
				if (_parsedCustomRadii.TryGetValue(candidateNames[i], out var value))
				{
					return value;
				}
			}
			return defaultRadius;
		}
	}
	public static class EnemyDetector
	{
		private static float _lastScanTime = -10f;

		private static bool _cachedHasThreat = false;

		private static Vector3 _lastPlayerPosition = Vector3.zero;

		public static float GetStaminaDiscount(Player player)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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 ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return 0f;
			}
			if (!TrollTollPlugin.ModEnabled.Value)
			{
				return 0f;
			}
			if (!TrollTollPlugin.AllowSwimmingStaminaDiscount.Value && ((Character)player).IsSwimming())
			{
				return 0f;
			}
			if (!TrollTollPlugin.AllowEncumberedStaminaDiscount.Value && ((Character)player).IsEncumbered())
			{
				return 0f;
			}
			Biome currentBiome = player.GetCurrentBiome();
			if (!HasThreatNearby(player))
			{
				if (BiomeManager.IsBiomeModEnabled(currentBiome))
				{
					return 1f;
				}
				return BossReliefManager.GetReliefFraction(currentBiome);
			}
			return BossReliefManager.GetReliefFraction(currentBiome);
		}

		public static bool IsStaminaDiscountActive(Player player)
		{
			return GetStaminaDiscount(player) >= 1f;
		}

		public static bool HasThreatNearby(Player player)
		{
			//IL_001c: 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)
			//IL_0035: 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)
			//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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			float time = Time.time;
			Vector3 position = ((Component)player).transform.position;
			if (time - _lastScanTime < TrollTollPlugin.UpdateInterval.Value)
			{
				Vector3 val = position - _lastPlayerPosition;
				if (((Vector3)(ref val)).sqrMagnitude < 9f)
				{
					return _cachedHasThreat;
				}
			}
			_lastScanTime = time;
			_lastPlayerPosition = position;
			_cachedHasThreat = ScanForThreats(player, position);
			return _cachedHasThreat;
		}

		private static bool ScanForThreats(Player player, Vector3 playerPosition)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if (TrollTollPlugin.EnforceDuringRaids.Value && RandEventSystem.HaveActiveEvent())
			{
				return true;
			}
			Biome currentBiome = player.GetCurrentBiome();
			if (!BiomeManager.IsBiomeModEnabled(currentBiome))
			{
				return true;
			}
			List<Character> allCharacters = Character.GetAllCharacters();
			if (allCharacters == null)
			{
				return false;
			}
			float biomeDetectionRadius = BiomeManager.GetBiomeDetectionRadius(currentBiome);
			float num = Mathf.Max(biomeDetectionRadius, CreatureManager.MaxCustomRadius);
			float num2 = num * num;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)player || val.IsDead())
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - playerPosition;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (sqrMagnitude > num2)
				{
					continue;
				}
				if (val.IsPlayer())
				{
					if (TrollTollPlugin.EnableInPVP.Value)
					{
						Player val3 = (Player)(object)((val is Player) ? val : null);
						if ((Object)(object)val3 != (Object)null && ((Character)player).IsPVPEnabled() && ((Character)val3).IsPVPEnabled() && sqrMagnitude <= biomeDetectionRadius * biomeDetectionRadius)
						{
							return true;
						}
					}
				}
				else
				{
					if (CreatureManager.IsCreatureIgnored(val))
					{
						continue;
					}
					float customRadius = CreatureManager.GetCustomRadius(val, biomeDetectionRadius);
					if (sqrMagnitude > customRadius * customRadius)
					{
						continue;
					}
					if (CreatureManager.IsCreatureEnforcedThreat(val))
					{
						return true;
					}
					if (TrollTollPlugin.IncludePassiveCreatures.Value)
					{
						return true;
					}
					if (BaseAI.IsEnemy((Character)(object)player, val))
					{
						if (!TrollTollPlugin.RequireAlertedOnly.Value)
						{
							return true;
						}
						BaseAI baseAI = val.GetBaseAI();
						if ((Object)(object)baseAI != (Object)null && (baseAI.IsAlerted() || baseAI.HaveTarget()))
						{
							return true;
						}
					}
					else
					{
						BaseAI baseAI2 = val.GetBaseAI();
						if ((Object)(object)baseAI2 != (Object)null && (baseAI2.IsAlerted() || baseAI2.HaveTarget()) && !val.IsTamed())
						{
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	[BepInPlugin("com.beardymike.trolltoll", "Troll-Toll", "0.20.4")]
	public class TrollTollPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.beardymike.trolltoll";

		public const string PluginName = "Troll-Toll";

		public const string PluginVersion = "0.20.4";

		public const string PluginAuthor = "BeardyMike";

		public static ConfigEntry<bool> ModEnabled;

		public static ConfigEntry<float> DetectionRadius;

		public static ConfigEntry<bool> IncludePassiveCreatures;

		public static ConfigEntry<bool> RequireAlertedOnly;

		public static ConfigEntry<bool> EnforceDuringRaids;

		public static ConfigEntry<bool> EnableInPVP;

		public static ConfigEntry<bool> AllowSwimmingStaminaDiscount;

		public static ConfigEntry<bool> AllowEncumberedStaminaDiscount;

		public static ConfigEntry<float> UpdateInterval;

		public static ConfigEntry<bool> BossReliefEnabled;

		public static ConfigEntry<float> BossReliefBasePercent;

		public static ConfigEntry<float> BossReliefPerAdditionalBossPercent;

		public static ConfigEntry<float> BossReliefCapPercent;

		public static ConfigEntry<string> BossReliefCalculationMode;

		public static ConfigEntry<bool> OceanBossRelief;

		public static ConfigEntry<bool> ShowBiomeEntryMessage;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Expected O, but got Unknown
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Master switch to enable or disable Troll-Toll.");
			DetectionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "DetectionRadius", 30f, "Default distance in meters to search for nearby threats. Inside this radius, stamina costs apply normally unless reduced by Boss Relief.");
			IncludePassiveCreatures = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Detection", "IncludePassiveCreatures", false, "If true, peaceful wildlife (like deer and birds) also triggers normal stamina usage.");
			RequireAlertedOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Detection", "RequireAlertedOnly", false, "If true, nearby enemies only trigger stamina consumption once they are actively alerted (spotted you) or targeting someone.");
			EnforceDuringRaids = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Detection", "EnforceDuringRaids", true, "If true, stamina is always consumed normally whenever a base raid / random event is in progress.");
			EnableInPVP = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Detection", "EnableInPVP", true, "If true, other players with PvP enabled in range will trigger normal stamina costs.");
			AllowSwimmingStaminaDiscount = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Restrictions", "AllowSwimmingStaminaDiscount", false, "If true, swimming out of combat will consume zero stamina. Keep false for vanilla ocean balance.");
			AllowEncumberedStaminaDiscount = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Restrictions", "AllowEncumberedStaminaDiscount", false, "If true, walking while encumbered out of combat will consume zero stamina.");
			UpdateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Performance", "UpdateInterval", 0.2f, "How often (in seconds) the mod scans for nearby creatures. Caching scans prevents frame rate drops.");
			BiomeManager.Initialize(((BaseUnityPlugin)this).Config);
			CreatureManager.Initialize(((BaseUnityPlugin)this).Config);
			BossReliefEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Boss Relief System", "BossReliefEnabled", true, "Defeating the boss of a biome grants permanent stamina cost relief in that biome, scaling stronger as additional bosses are defeated.");
			BossReliefBasePercent = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Boss Relief System", "BossReliefBasePercent", 25f, new ConfigDescription("Base stamina relief percentage (stamina cost discount) granted in a biome immediately upon defeating its boss. (Recommended: 25% - 75%).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			BossReliefPerAdditionalBossPercent = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Boss Relief System", "BossReliefPerAdditionalBossPercent", 25f, new ConfigDescription("Additional stamina relief percentage granted in a conquered biome for each additional boss defeated beyond that biome. E.g. at 25% base + 25% per additional, 4 bosses total grants 100% relief in Meadows.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			BossReliefCapPercent = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Boss Relief System", "BossReliefCapPercent", 100f, new ConfigDescription("Maximum stamina relief percentage attainable in any biome (100% = zero stamina consumed even during combat).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			BossReliefCalculationMode = ((BaseUnityPlugin)this).Config.Bind<string>("7 - Boss Relief System", "BossReliefCalculationMode", "ProgressionTier", "ProgressionTier: Only bosses defeated in higher-tier biomes grant additional relief (e.g. Elder/Bonemass/Moder increase Meadows relief). AllDefeatedBosses: Any other defeated boss in the world grants additional relief.");
			OceanBossRelief = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Boss Relief System", "OceanBossRelief", true, "If true, Ocean biome receives stamina relief scaling with total world bosses defeated.");
			ShowBiomeEntryMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Boss Relief System", "ShowBiomeEntryMessage", false, "If true, displays a brief top-left notification showing your current biome's Boss Relief stamina discount upon entering a new biome.");
			_harmony = new Harmony("com.beardymike.trolltoll");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Troll-Toll v0.20.4 by BeardyMike loaded successfully.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace TrollToll.Patches
{
	[HarmonyPatch(typeof(Player), "UseStamina")]
	public static class Player_UseStamina_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(Player __instance, ref float v)
		{
			if (v <= 0f)
			{
				return true;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			float staminaDiscount = EnemyDetector.GetStaminaDiscount(__instance);
			if (staminaDiscount >= 1f)
			{
				return false;
			}
			if (staminaDiscount > 0f)
			{
				v *= 1f - staminaDiscount;
				return true;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "HaveStamina")]
	public static class Player_HaveStamina_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(Player __instance, ref bool __result, float amount)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			float staminaDiscount = EnemyDetector.GetStaminaDiscount(__instance);
			if (staminaDiscount >= 1f)
			{
				__result = true;
				return false;
			}
			if (staminaDiscount > 0f)
			{
				float num = amount * (1f - staminaDiscount);
				if (__instance.GetStamina() >= num)
				{
					__result = true;
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Chat), "SendText")]
	public static class Chat_SendText_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(Chat __instance, Type type, string text)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(text))
			{
				return true;
			}
			string text2 = text.Trim();
			if (text2.Equals("/trolltoll", StringComparison.OrdinalIgnoreCase) || text2.Equals("/tt", StringComparison.OrdinalIgnoreCase))
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					Biome currentBiome = Player.m_localPlayer.GetCurrentBiome();
					string statusSummary = BossReliefManager.GetStatusSummary(currentBiome);
					float num = EnemyDetector.GetStaminaDiscount(Player.m_localPlayer) * 100f;
					bool flag = EnemyDetector.HasThreatNearby(Player.m_localPlayer);
					string text3 = $"<color=orange>[Troll-Toll]</color> {statusSummary}\nThreat Nearby: {flag} | Active Stamina Discount: {num:0}%";
					((Terminal)Chat.instance).AddString(text3);
				}
				else
				{
					((Terminal)Chat.instance).AddString("<color=orange>[Troll-Toll]</color> Local player not active.");
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateBiome")]
	public static class Player_UpdateBiome_Patch
	{
		private static Biome _previousBiome;

		[HarmonyPostfix]
		public static void Postfix(Player __instance, float dt)
		{
			//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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !TrollTollPlugin.ShowBiomeEntryMessage.Value || !TrollTollPlugin.ModEnabled.Value)
			{
				return;
			}
			Biome currentBiome = __instance.GetCurrentBiome();
			if (currentBiome != _previousBiome)
			{
				_previousBiome = currentBiome;
				if ((int)currentBiome != 0 && (Object)(object)MessageHud.instance != (Object)null)
				{
					float num = BossReliefManager.GetReliefFraction(currentBiome) * 100f;
					string text = ((num > 0f) ? $"{currentBiome}: {num:0}% Boss Stamina Relief" : $"{currentBiome}: 0% Boss Relief");
					MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
				}
			}
		}
	}
}