Decompiled source of DvergrRedux v1.0.6

DvergrRedux.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("DvergrRedux")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("DvergrRedux")]
[assembly: AssemblyTitle("DvergrRedux")]
[assembly: AssemblyVersion("0.1.0.0")]
[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 DvergrRedux
{
	internal static class BossHud
	{
		public static int Depth;

		public static bool Applies(Character character)
		{
			if (Depth > 0 && BossQuestSettings.BossHudEnabled.Value && !(character is Player))
			{
				return DvergrBossQuest.IsBoss((Component)(object)character);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(EnemyHud), "UpdateHuds")]
	internal static class EnemyHudUpdatePatch
	{
		private static void Prefix()
		{
			BossHud.Depth++;
		}

		private static void Finalizer()
		{
			BossHud.Depth--;
		}
	}
	[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
	internal static class EnemyHudShowPatch
	{
		private static void Prefix()
		{
			BossHud.Depth++;
		}

		private static void Finalizer()
		{
			BossHud.Depth--;
		}
	}
	[HarmonyPatch(typeof(EnemyHud), "TestShow")]
	internal static class EnemyHudTestShowPatch
	{
		private static void Prefix()
		{
			BossHud.Depth++;
		}

		private static void Finalizer()
		{
			BossHud.Depth--;
		}
	}
	[HarmonyPatch(typeof(Character), "IsBoss")]
	internal static class CharacterIsBossPatch
	{
		private static void Postfix(Character __instance, ref bool __result)
		{
			if (!__result && BossHud.Applies(__instance))
			{
				__result = true;
			}
		}
	}
	internal static class SpareBuildings
	{
		public static bool Applies(BaseAI ai)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			if (!BossQuestSettings.SpareBuildings.Value || (Object)(object)ai == (Object)null)
			{
				return false;
			}
			Character component = ((Component)ai).GetComponent<Character>();
			if ((Object)(object)component != (Object)null)
			{
				return (int)component.m_faction == 10;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "FindClosestStaticPriorityTarget")]
	internal static class BaseAIStaticPriorityPatch
	{
		private static bool Prefix(BaseAI __instance, ref StaticTarget __result)
		{
			if (!SpareBuildings.Applies(__instance))
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "FindRandomStaticTarget")]
	internal static class BaseAIRandomStaticPatch
	{
		private static bool Prefix(BaseAI __instance, ref StaticTarget __result)
		{
			if (!SpareBuildings.Applies(__instance))
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	internal static class BossQuestSettings
	{
		public const string Section = "Boss Quest";

		private const string GiverSection = "Quest Giver";

		private const string FriendshipSection = "Friendship";

		private const string RewardSection = "Rewards";

		private const string TextHelp = " Use \\n for a new line.";

		private const string TitleHelp = " {title} is replaced with the quest title.";

		public static ConfigEntry<string> Title;

		public static ConfigEntry<string> OfferText;

		public static ConfigEntry<string> ObjectiveText;

		public static ConfigEntry<string> ReadyObjectiveText;

		public static ConfigEntry<string> TurnInText;

		public static ConfigEntry<string> ReadyMessage;

		public static ConfigEntry<string> CompletedText;

		public static ConfigEntry<string> AcceptedMessage;

		public static ConfigEntry<string> CompletedMessage;

		public static ConfigEntry<string> SpawnFailedMessage;

		public static ConfigEntry<string> BossPrefab;

		public static ConfigEntry<int> Stars;

		public static ConfigEntry<bool> RandomFromBiomes;

		public static ConfigEntry<string> RandomBiomes;

		public static ConfigEntry<string> BossPrefabAshlands;

		public static ConfigEntry<string> ExcludedEnemies;

		public static ConfigEntry<float> MinSpawnDistance;

		public static ConfigEntry<float> MaxSpawnDistance;

		public static ConfigEntry<bool> SameBiomeOnly;

		public static ConfigEntry<int> SpawnAttempts;

		public static ConfigEntry<bool> SitePinEnabled;

		public static ConfigEntry<bool> BossHudEnabled;

		public static ConfigEntry<bool> PinEnabled;

		public static ConfigEntry<bool> RemovePinOnKill;

		public static ConfigEntry<string> PinName;

		public static ConfigEntry<PinType> PinType;

		public static ConfigEntry<string> TalkPrompt;

		public static ConfigEntry<bool> PacifyQuestGiver;

		public static ConfigEntry<bool> FriendshipEnabled;

		public static ConfigEntry<float> FriendlyRadius;

		public static ConfigEntry<bool> GrantBuildPermission;

		public static ConfigEntry<bool> IgnoreWardDamage;

		public static ConfigEntry<bool> SpareBuildings;

		public static ConfigEntry<bool> MistBonusEnabled;

		public static ConfigEntry<float> MistBonusPercent;

		public static ConfigEntry<string> MistBonusLogText;

		public static ConfigEntry<bool> HealEnabled;

		public static ConfigEntry<bool> HealPlayers;

		public static ConfigEntry<float> HealPercentPerSecond;

		public static ConfigEntry<string> FriendlyMessage;

		public static ConfigEntry<string> FriendlyLogText;

		public static ConfigEntry<string> RegionLogText;

		public static ConfigEntry<float> WardRadius;

		public static void Bind(ConfigFile config)
		{
			Title = config.Bind<string>("Boss Quest", "Title", "Slay the {boss}", "Quest title, shown in the dialog and the Compendium.");
			OfferText = config.Bind<string>("Boss Quest", "OfferText", "The Dvergr studies you for a long moment, then speaks low.\n\n\"A hulking {boss} has crawled out of the mist and stalks the land near our tower. Hunt it down and kill it, outlander, and the Dvergr will remember your deed.\"", "Text of the quest offer shown in the dialog. Use \\n for a new line.");
			ObjectiveText = config.Bind<string>("Boss Quest", "ObjectiveText", "A {boss} stalks the land near the Dvergr tower. Hunt it down and slay it.", "Objective shown in the Compendium while the quest is active. Use \\n for a new line.");
			ReadyObjectiveText = config.Bind<string>("Boss Quest", "ReadyObjectiveText", "The {boss} is dead. Return to the Dvergr marked with an exclamation mark.", "Objective shown in the Compendium once the creature is slain and the quest can be turned in. Use \\n for a new line.");
			TurnInText = config.Bind<string>("Boss Quest", "TurnInText", "The Dvergr looks past you, then back, and something in his shoulders loosens.\n\n\"The beast is dead. The Dvergr of this tower owe you a debt, outlander. Our ward will no longer turn you away.\"", "Text shown in the dialog when you turn the quest in. Use \\n for a new line.");
			ReadyMessage = config.Bind<string>("Boss Quest", "ReadyMessage", "The {boss} is dead. Return to the Dvergr.", "Message shown when the creature is slain.");
			CompletedText = config.Bind<string>("Boss Quest", "CompletedText", "You slew the {boss}, and the Dvergr of the tower now count you a friend. You may build within their ward.", "Text shown in the Compendium once the quest is turned in. Use \\n for a new line.");
			AcceptedMessage = config.Bind<string>("Boss Quest", "AcceptedMessage", "Quest accepted: {title}", "Message shown when the quest is accepted. {title} is replaced with the quest title.");
			CompletedMessage = config.Bind<string>("Boss Quest", "CompletedMessage", "Quest complete: {title}", "Message shown when you turn the quest in. {title} is replaced with the quest title.");
			SpawnFailedMessage = config.Bind<string>("Boss Quest", "SpawnFailedMessage", "The Dvergr cannot say where the beast lurks. Try again.", "Message shown when no place to spawn the creature could be found.");
			BossPrefab = config.Bind<string>("Boss Quest", "BossPrefab", "SeekerBrute", "Prefab names of the creatures that can spawn, separated by commas. One is picked at random each time the quest is offered. Add :stars after a name to give it its own star level, for example SeekerBrute,Gjall:2. Names that can't be found are skipped and the log says so. The creature's name replaces {boss} in all the texts here.");
			BossPrefabAshlands = config.Bind<string>("Boss Quest", "BossPrefabAshlands", "Morgen", "Same as BossPrefab, but used at Dvergr sites in the Ashlands. If none of these can be found, BossPrefab is used instead. With RandomFromBiomes on, Ashlands sites always draw from the Ashlands, whatever RandomBiomes says.");
			Stars = config.Bind<int>("Boss Quest", "Stars", 1, UiSettings.Range(0, 4, "Star level for random creatures and for creatures in the list that have no :stars of their own. 0 is a normal creature, 1 is one star, and so on."));
			RandomFromBiomes = config.Bind<bool>("Boss Quest", "RandomFromBiomes", false, "Pick a random creature that spawns in the biomes listed in RandomBiomes instead of using BossPrefab.");
			RandomBiomes = config.Bind<string>("Boss Quest", "RandomBiomes", "Mistlands", "Comma separated biomes to draw a random creature from: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth. Only hostile creatures that the game spawns in those biomes are used, and bosses are never picked.");
			ExcludedEnemies = config.Bind<string>("Boss Quest", "ExcludedEnemies", "Dverger,DvergerMage,DvergerMageFire,DvergerMageIce,DvergerMageSupport,DvergerAshlands", "Comma separated prefab names that are never picked, whether from BossPrefab or from RandomBiomes.");
			MinSpawnDistance = config.Bind<float>("Boss Quest", "MinSpawnDistance", 100f, UiSettings.Range(10f, 500f, "The creature spawns at least this many metres from the Dvergr you talked to."));
			MaxSpawnDistance = config.Bind<float>("Boss Quest", "MaxSpawnDistance", 200f, UiSettings.Range(10f, 500f, "The creature spawns at most this many metres from the Dvergr you talked to."));
			SameBiomeOnly = config.Bind<bool>("Boss Quest", "SameBiomeOnly", true, "Only spawn the creature in the same biome as the Dvergr.");
			SpawnAttempts = config.Bind<int>("Boss Quest", "SpawnAttempts", 40, UiSettings.Range(1, 200, "How many random spots to try before giving up. Spots in water or in the wrong biome are skipped."));
			SitePinEnabled = config.Bind<bool>("Boss Quest", "SitePinEnabled", true, "Put the Dvergr site pin (named and styled by Quest.PinName and Quest.PinType) on the map when you accept or receive a boss quest.");
			BossHudEnabled = config.Bind<bool>("Boss Quest", "BossHudEnabled", true, "Show the boss health bar at the top of the screen while you fight the quest creature.");
			PinEnabled = config.Bind<bool>("Boss Quest", "PinEnabled", true, "Drop a map pin where the creature was spawned. It is removed when the creature is killed (see RemovePinOnKill) or the quest is turned in.");
			RemovePinOnKill = config.Bind<bool>("Boss Quest", "RemovePinOnKill", true, "Remove the creature's map pin for every player with the quest as soon as it is killed. When off, the pin stays until the quest is turned in.");
			PinName = config.Bind<string>("Boss Quest", "PinName", "{boss}", "Text shown next to the creature's map pin.");
			PinType = config.Bind<PinType>("Boss Quest", "PinType", (PinType)9, "Map icon used for the creature's pin.");
			TalkPrompt = config.Bind<string>("Quest Giver", "TalkPrompt", "Talk", "Prompt shown when you look at the marked Dvergr.");
			PacifyQuestGiver = config.Bind<bool>("Quest Giver", "PacifyQuestGiver", true, "Stop the marked Dvergr from treating players as enemies, so you can talk to it. It can still be attacked.");
			FriendshipEnabled = config.Bind<bool>("Friendship", "Enabled", true, "Once the quest is turned in, the Dvergr near that tower stop treating every player on the world as an enemy.");
			FriendlyRadius = config.Bind<float>("Friendship", "FriendlyRadius", 100f, UiSettings.Range(20f, 500f, "Dvergr within this many metres of a tower you turned the quest in at are friendly."));
			FriendlyMessage = config.Bind<string>("Friendship", "FriendlyMessage", "The Dvergr of this tower are now friendly.", "Message shown when you turn the quest in and the Dvergr become friendly.");
			FriendlyLogText = config.Bind<string>("Friendship", "FriendlyLogSummary", "Dvergr sites helped: {count}", "First line of the Dvergr entry in the Compendium, shown once you have helped or found a site. {count} is the number of sites you have helped.");
			RegionLogText = config.Bind<string>("Friendship", "RegionLogText", "{region} Dvergr: {helped} site(s) helped", "Line for each region (Mistlands, Ashlands) where you have found a Dvergr site. {region} is the region and {helped} the number of sites you have helped there.");
			IgnoreWardDamage = config.Bind<bool>("Friendship", "IgnoreWardDamage", true, "The Dvergr do not turn hostile when something is broken inside the ward of a friendly tower.");
			GrantBuildPermission = config.Bind<bool>("Friendship", "GrantBuildPermission", true, "Grant every player access to the world-generated ward at towers you turned the quest in at. Wards built by players are never affected.");
			MistBonusEnabled = config.Bind<bool>("Rewards", "MistBonusEnabled", true, "At Dvergr sites you have made friendly, the blue light that clears mist reaches further.");
			MistBonusPercent = config.Bind<float>("Rewards", "MistBonusPercent", 20f, UiSettings.Range(0f, 200f, "How much larger, in percent, the area those lights clear becomes."));
			HealEnabled = config.Bind<bool>("Rewards", "HealEnabled", true, "Dvergr standing inside the ward at a friendly Dvergr site slowly recover health.");
			HealPlayers = config.Bind<bool>("Rewards", "HealPlayers", true, "Players standing inside the ward at a friendly Dvergr site also slowly recover health.");
			HealPercentPerSecond = config.Bind<float>("Rewards", "HealPercentPerSecond", 1f, UiSettings.Range(0.1f, 20f, "Percent of maximum health restored each second while inside the ward, for both Dvergr and players."));
			MistBonusLogText = config.Bind<string>("Rewards", "MistBonusLogText", "The blue lights at the Dvergr sites that count you a friend now clear {percent}% more mist.", "Line added to the Compendium once the bonus is unlocked. {percent} is the bonus.");
			SpareBuildings = config.Bind<bool>("Friendship", "SpareBuildings", true, "Dvergr never pick your buildings (workbenches, walls and the like) as targets. Some Dvergr, such as the ones in the Ashlands, attack them otherwise.");
			WardRadius = config.Bind<float>("Friendship", "WardRadius", 60f, UiSettings.Range(10f, 300f, "A world-generated ward within this many metres of the tower you turned the quest in at counts as the site's ward."));
		}

		public static string Format(string template)
		{
			return (template ?? string.Empty).Replace("{title}", Title.Value).Replace("{boss}", DvergrBossQuest.CurrentBossName());
		}
	}
	internal static class DialogSettings
	{
		public const string SectionPrefix = "Dialog - ";

		private const string WindowSection = "Dialog - Window";

		private const string TextSection = "Dialog - Buttons";

		public static ConfigEntry<UiAnchor> Anchor;

		public static ConfigEntry<float> OffsetX;

		public static ConfigEntry<float> OffsetY;

		public static ConfigEntry<float> Width;

		public static ConfigEntry<float> Height;

		public static ConfigEntry<bool> Draggable;

		public static ConfigEntry<bool> MatchGameScale;

		public static ConfigEntry<float> Scale;

		public static ConfigEntry<float> CloseDistance;

		public static ConfigEntry<string> AcceptLabel;

		public static ConfigEntry<string> TurnInLabel;

		public static ConfigEntry<string> DeclineLabel;

		public static ConfigEntry<string> CloseLabel;

		public static void Bind(ConfigFile config)
		{
			Anchor = config.Bind<UiAnchor>("Dialog - Window", "Anchor", UiAnchor.Center, "Which point of the screen the dialog is positioned relative to.");
			OffsetX = config.Bind<float>("Dialog - Window", "OffsetX", 0f, UiSettings.Range(-2000f, 2000f, "Horizontal offset in pixels from the anchor. Positive moves right."));
			OffsetY = config.Bind<float>("Dialog - Window", "OffsetY", 0f, UiSettings.Range(-2000f, 2000f, "Vertical offset in pixels from the anchor. Positive moves up."));
			Width = config.Bind<float>("Dialog - Window", "Width", 460f, UiSettings.Range(300f, 1200f, "Dialog width in pixels."));
			Height = config.Bind<float>("Dialog - Window", "Height", 420f, UiSettings.Range(250f, 1000f, "Dialog height in pixels."));
			MatchGameScale = config.Bind<bool>("Dialog - Window", "MatchGameScale", true, "Scale the dialog by the same amount as the game's own interface, so it follows the GUI scale setting and your resolution.");
			Scale = config.Bind<float>("Dialog - Window", "Scale", 1f, UiSettings.Range(0.5f, 4f, "Extra size multiplier applied on top of the game's scale."));
			Draggable = config.Bind<bool>("Dialog - Window", "Draggable", false, "Allow dragging the dialog with the mouse. The position resets every time the dialog opens.");
			CloseDistance = config.Bind<float>("Dialog - Window", "CloseDistance", 10f, UiSettings.Range(2f, 50f, "The dialog closes by itself if you walk this many metres away from the Dvergr."));
			AcceptLabel = config.Bind<string>("Dialog - Buttons", "AcceptLabel", "Accept", "Text on the accept button.");
			TurnInLabel = config.Bind<string>("Dialog - Buttons", "TurnInLabel", "Turn in", "Text on the button that hands in the finished quest.");
			DeclineLabel = config.Bind<string>("Dialog - Buttons", "DeclineLabel", "Not now", "Text on the button that closes the dialog while a quest is being offered.");
			CloseLabel = config.Bind<string>("Dialog - Buttons", "CloseLabel", "Close", "Text on the close button when there is nothing to accept.");
		}
	}
	internal static class DvergrBossQuest
	{
		private struct BossChoice
		{
			public string Prefab;

			public int Stars;
		}

		private const string Prefix = "DvergrRedux.Quest.dvergr_boss.";

		private const string IdsKey = "DvergrRedux.Quest.dvergr_boss.Ids";

		private const string NextKey = "DvergrRedux.Quest.dvergr_boss.Next";

		private const string KnownKey = "DvergrRedux.Quest.dvergr_boss.Known";

		private const string OfferPrefabKey = "DvergrRedux.Quest.dvergr_boss.Prefab";

		private const string OfferNameKey = "DvergrRedux.Quest.dvergr_boss.Name";

		private const string BossTag = "DvergrRedux_BossFor";

		private const string SiteTag = "DvergrRedux_BossSite";

		private const string FieldStatus = "Status";

		private const string FieldTarget = "Target";

		private const string FieldSite = "Site";

		private const string FieldSiteKey = "SiteKey";

		private const string FieldSpawned = "Spawned";

		private const string FieldBossId = "BossId";

		private const string FieldGiver = "GiverId";

		private const string FieldPrefab = "Prefab";

		private const string FieldName = "Name";

		private const string FieldOwner = "Owner";

		private static readonly string[] AllFields = new string[10] { "Status", "Target", "Site", "SiteKey", "Spawned", "BossId", "GiverId", "Prefab", "Name", "Owner" };

		private const float SpawnHeightAboveGround = 1f;

		private const float WaterMargin = 0.5f;

		private const float SameSiteRadius = 15f;

		private static bool missingPrefabLogged;

		private static bool existenceChecked;

		private static string nameOverride;

		private const string ClaimPrefix = "dvergrredux_boss_";

		private const float ClearSearchRadius = 12f;

		private const int ClearSearchAttempts = 30;

		private static readonly Dictionary<string, int> spawnRetries = new Dictionary<string, int>();

		private const int MaxSpawnRetries = 15;

		private const float MaxRiseAboveGround = 2.5f;

		private static string Field(string id, string name)
		{
			return "DvergrRedux.Quest.dvergr_boss." + id + "." + name;
		}

		private static string Read(Player player, string id, string name)
		{
			if (!player.m_customData.TryGetValue(Field(id, name), out var value))
			{
				return null;
			}
			return value;
		}

		private static void Write(Player player, string id, string name, string value)
		{
			player.m_customData[Field(id, name)] = value;
		}

		private static QuestStatus StatusOf(Player player, string id)
		{
			string text = Read(player, id, "Status");
			if (text == null || !Enum.TryParse<QuestStatus>(text, out var result))
			{
				return QuestStatus.Available;
			}
			return result;
		}

		private static bool TryReadPosition(Player player, string id, string name, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			string text = Read(player, id, name);
			if (text != null)
			{
				return DvergrTowerQuest.TryParsePosition(text, out position);
			}
			return false;
		}

		private static string SiteKeyOf(Vector3 site)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.RoundToInt(site.x).ToString(CultureInfo.InvariantCulture) + "_" + Mathf.RoundToInt(site.z).ToString(CultureInfo.InvariantCulture);
		}

		private static List<string> ReadIds(Player player)
		{
			MigrateLegacy(player);
			List<string> list = new List<string>();
			if (player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Ids", out var value))
			{
				string[] array = value.Split(new char[1] { ',' });
				foreach (string text in array)
				{
					if (text.Length > 0)
					{
						list.Add(text);
					}
				}
			}
			return list;
		}

		private static void WriteIds(Player player, List<string> ids)
		{
			if (ids.Count == 0)
			{
				player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Ids");
			}
			else
			{
				player.m_customData["DvergrRedux.Quest.dvergr_boss.Ids"] = string.Join(",", ids.ToArray());
			}
		}

		private static string NewId(Player player)
		{
			int result = 1;
			if (player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Next", out var value))
			{
				int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
			}
			if (result < 1)
			{
				result = 1;
			}
			player.m_customData["DvergrRedux.Quest.dvergr_boss.Next"] = (result + 1).ToString(CultureInfo.InvariantCulture);
			return result.ToString(CultureInfo.InvariantCulture);
		}

		private static string TakeLegacy(Player player, string name)
		{
			string key = "DvergrRedux.Quest.dvergr_boss." + name;
			if (!player.m_customData.TryGetValue(key, out var value))
			{
				return null;
			}
			player.m_customData.Remove(key);
			return value;
		}

		private static void MigrateLegacy(Player player)
		{
			//IL_005d: 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)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			string text = TakeLegacy(player, "Status");
			if (text == null)
			{
				return;
			}
			string text2 = TakeLegacy(player, "Target");
			string text3 = TakeLegacy(player, "Spawned");
			string text4 = TakeLegacy(player, "BossId");
			string text5 = TakeLegacy(player, "GiverId");
			string text6 = TakeLegacy(player, "SharedOwner");
			if (Enum.TryParse<QuestStatus>(text, out var result) && result != QuestStatus.Available)
			{
				Vector3 position = Vector3.zero;
				if (text2 != null)
				{
					DvergrTowerQuest.TryParsePosition(text2, out position);
				}
				if (!DvergrTowerQuest.TryGetTarget(player, out var position2))
				{
					position2 = position;
				}
				player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Prefab", out var value);
				player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Name", out var value2);
				string text7 = NewId(player);
				Write(player, text7, "Status", result.ToString());
				Write(player, text7, "Target", DvergrTowerQuest.FormatPosition(position));
				Write(player, text7, "Site", DvergrTowerQuest.FormatPosition(position2));
				Write(player, text7, "SiteKey", SiteKeyOf(position2));
				Write(player, text7, "Spawned", text3 ?? "false");
				if (text4 != null)
				{
					Write(player, text7, "BossId", text4);
				}
				Write(player, text7, "GiverId", text5 ?? string.Empty);
				Write(player, text7, "Prefab", value ?? string.Empty);
				Write(player, text7, "Name", value2 ?? string.Empty);
				Write(player, text7, "Owner", text6 ?? player.GetPlayerID().ToString(CultureInfo.InvariantCulture));
				player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Ids", out var value3);
				player.m_customData["DvergrRedux.Quest.dvergr_boss.Ids"] = (string.IsNullOrEmpty(value3) ? text7 : (value3 + "," + text7));
			}
		}

		private static string CreateRecord(Player player, QuestStatus status, Vector3 point, Vector3 site, long owner, string giverId, string prefab, string name, bool spawned)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			string text = NewId(player);
			Write(player, text, "Status", status.ToString());
			Write(player, text, "Target", DvergrTowerQuest.FormatPosition(point));
			Write(player, text, "Site", DvergrTowerQuest.FormatPosition(site));
			Write(player, text, "SiteKey", SiteKeyOf(site));
			Write(player, text, "Spawned", spawned ? "true" : "false");
			Write(player, text, "GiverId", giverId ?? string.Empty);
			Write(player, text, "Prefab", prefab ?? string.Empty);
			Write(player, text, "Name", name ?? string.Empty);
			Write(player, text, "Owner", owner.ToString(CultureInfo.InvariantCulture));
			List<string> list = ReadIds(player);
			list.Add(text);
			WriteIds(player, list);
			return text;
		}

		private static void RemoveRecord(Player player, string id, bool removeBoss)
		{
			//IL_0022: 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)
			if ((Object)(object)Minimap.instance != (Object)null)
			{
				if (TryReadPosition(player, id, "Target", out var position))
				{
					Minimap.instance.RemovePin(position, 5f);
				}
				if (TryReadPosition(player, id, "Site", out var position2))
				{
					Minimap.instance.RemovePin(position2, 5f);
				}
			}
			string text = Read(player, id, "BossId");
			if (removeBoss && text != null)
			{
				DvergrNetwork.SendBossRemove(text);
			}
			if (removeBoss && Read(player, id, "Owner") == player.GetPlayerID().ToString(CultureInfo.InvariantCulture))
			{
				ReleaseClaims(Read(player, id, "SiteKey"));
			}
			string[] allFields = AllFields;
			foreach (string name in allFields)
			{
				player.m_customData.Remove(Field(id, name));
			}
		}

		private static string FindFor(Player player, Character giver)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)giver == (Object)null)
			{
				return null;
			}
			string result = null;
			int num = -1;
			ZDOID zDOID = giver.GetZDOID();
			foreach (string item in ReadIds(player))
			{
				bool flag = false;
				string text = Read(player, item, "GiverId");
				if (!string.IsNullOrEmpty(text) && TryParseZdoId(text, out var id) && ((ZDOID)(ref id)).UserID == ((ZDOID)(ref zDOID)).UserID && ((ZDOID)(ref id)).ID == ((ZDOID)(ref zDOID)).ID)
				{
					flag = true;
				}
				if (!flag && TryReadPosition(player, item, "Site", out var position) && DvergrTowerQuest.PlanarDistance(position, ((Component)giver).transform.position) <= DvergrRedux.SiteRadius.Value)
				{
					flag = true;
				}
				if (flag)
				{
					int num2 = Rank(StatusOf(player, item));
					if (num2 > num)
					{
						result = item;
						num = num2;
					}
				}
			}
			return result;
		}

		private static int Rank(QuestStatus status)
		{
			return status switch
			{
				QuestStatus.ReadyToTurnIn => 3, 
				QuestStatus.Active => 2, 
				QuestStatus.Completed => 1, 
				_ => 0, 
			};
		}

		private static string FindNear(Player player, Vector3 site)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			foreach (string item in ReadIds(player))
			{
				if (TryReadPosition(player, item, "Site", out var position) && DvergrTowerQuest.PlanarDistance(position, site) < 15f)
				{
					return item;
				}
			}
			return null;
		}

		private static List<Vector3> ReadKnown(Player player)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			if (player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Known", out var value))
			{
				string[] array = value.Split(new char[1] { '|' });
				for (int i = 0; i < array.Length; i++)
				{
					if (DvergrTowerQuest.TryParsePosition(array[i], out var position))
					{
						list.Add(position);
					}
				}
			}
			return list;
		}

		private static void WriteKnown(Player player, List<Vector3> sites)
		{
			//IL_002b: 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: Unknown result type (might be due to invalid IL or missing references)
			if (sites.Count == 0)
			{
				player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Known");
				return;
			}
			List<string> list = new List<string>();
			foreach (Vector3 site in sites)
			{
				list.Add(DvergrTowerQuest.FormatPosition(site));
			}
			player.m_customData["DvergrRedux.Quest.dvergr_boss.Known"] = string.Join("|", list.ToArray());
		}

		private static bool RememberSite(Player player, Vector3 site)
		{
			//IL_0012: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = ReadKnown(player);
			foreach (Vector3 item in list)
			{
				if (DvergrTowerQuest.PlanarDistance(item, site) < 15f)
				{
					return false;
				}
			}
			list.Add(site);
			WriteKnown(player, list);
			return true;
		}

		internal unsafe static void OnSiteShared(Player player, Vector3 site, string fromName)
		{
			//IL_0000: 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_0012: 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)
			if (!IsSiteFriendly(site) && RememberSite(player, site))
			{
				DvergrTowerQuest.PlacePin(site);
				((Character)player).Message((MessageType)1, DvergrRedux.SiteSharedMessage.Value.Replace("{player}", fromName), 0, (Sprite)null, false);
				QuestTracker.InvalidateMarker();
				ManualLogSource log = DvergrRedux.Log;
				Vector3 val = site;
				log.LogInfo((object)(fromName + " found a Dvergr site at " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + "."));
			}
		}

		private static bool TryFindKnownSiteNear(Player player, out Vector3 site)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_002c: 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)
			//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)
			site = Vector3.zero;
			float value = DvergrRedux.AbandonArrivalRadius.Value;
			foreach (Vector3 item in ReadKnown(player))
			{
				if (DvergrTowerQuest.PlanarDistance(item, ((Component)player).transform.position) <= value)
				{
					site = item;
					return true;
				}
			}
			return false;
		}

		internal static bool TryFindBossOnlySite(Player player, out Vector3 site)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			site = Vector3.zero;
			Vector3 sitePosition;
			bool flag = TryFindSiteNear(((Component)player).transform.position, out sitePosition);
			if (!flag)
			{
				flag = TryFindKnownSiteNear(player, out sitePosition);
			}
			if (!flag)
			{
				return false;
			}
			if (DvergrFriendship.IsNearFriendlySite(sitePosition, 15f))
			{
				return false;
			}
			if (FindNear(player, sitePosition) != null || IsClaimedNear(sitePosition))
			{
				return false;
			}
			if (!DvergrTowerQuest.AnyDvergrNear(sitePosition, DvergrRedux.SiteRadius.Value))
			{
				return false;
			}
			if (RememberSite(player, sitePosition))
			{
				DvergrTowerQuest.PlacePin(sitePosition);
				DvergrNetwork.SendSiteFound(player, sitePosition);
			}
			site = sitePosition;
			return true;
		}

		private static bool TryFindSiteNear(Vector3 position, out Vector3 sitePosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			sitePosition = Vector3.zero;
			string[] array = (DvergrRedux.DvergrLocationNames.Value + "," + DvergrRedux.BossOnlyLocationNames.Value).Split(new char[1] { ',' });
			float value = DvergrRedux.AbandonArrivalRadius.Value;
			Vector3[] array2 = (Vector3[])(object)new Vector3[5]
			{
				position,
				position + new Vector3(value, 0f, 0f),
				position + new Vector3(0f - value, 0f, 0f),
				position + new Vector3(0f, 0f, value),
				position + new Vector3(0f, 0f, 0f - value)
			};
			for (int i = 0; i < array2.Length; i++)
			{
				Location zoneLocation = Location.GetZoneLocation(array2[i]);
				if ((Object)(object)zoneLocation == (Object)null)
				{
					continue;
				}
				string b = ((Object)((Component)zoneLocation).gameObject).name.Replace("(Clone)", string.Empty).Trim();
				bool flag = false;
				string[] array3 = array;
				for (int j = 0; j < array3.Length; j++)
				{
					if (string.Equals(array3[j].Trim(), b, StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
						break;
					}
				}
				if (flag && !(DvergrTowerQuest.PlanarDistance(((Component)zoneLocation).transform.position, position) > value))
				{
					sitePosition = ((Component)zoneLocation).transform.position;
					return true;
				}
			}
			return false;
		}

		internal static List<Vector3> FoundSites(Player player)
		{
			//IL_0040: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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)
			List<Vector3> list = new List<Vector3>(DvergrFriendship.Sites);
			list.AddRange(ReadKnown(player));
			foreach (string item in ReadIds(player))
			{
				if (TryReadPosition(player, item, "Site", out var position))
				{
					list.Add(position);
				}
			}
			if (DvergrTowerQuest.GetStatus(player) != QuestStatus.Available && DvergrTowerQuest.TryGetTarget(player, out var position2))
			{
				list.Add(position2);
			}
			List<Vector3> list2 = new List<Vector3>();
			foreach (Vector3 item2 in list)
			{
				bool flag = false;
				foreach (Vector3 item3 in list2)
				{
					if (DvergrTowerQuest.PlanarDistance(item3, item2) < 15f)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list2.Add(item2);
				}
			}
			return list2;
		}

		internal static bool HasQuestNear(Player player, Vector3 site)
		{
			//IL_0001: 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)
			if (FindNear(player, site) == null)
			{
				return IsClaimedNear(site);
			}
			return true;
		}

		internal static bool TryGetTurnInSite(Player player, out Vector3 site)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			site = Vector3.zero;
			foreach (string item in ReadIds(player))
			{
				if (StatusOf(player, item) == QuestStatus.ReadyToTurnIn && TryReadPosition(player, item, "Site", out site))
				{
					return true;
				}
			}
			return false;
		}

		public static QuestStatus GetStatus(Player player, Character giver)
		{
			//IL_0022: 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)
			string text = FindFor(player, giver);
			if (text != null)
			{
				return StatusOf(player, text);
			}
			if ((Object)(object)giver != (Object)null && DvergrFriendship.IsNearFriendlySite(((Component)giver).transform.position, DvergrRedux.SiteRadius.Value))
			{
				return QuestStatus.Completed;
			}
			if (!((Object)(object)giver != (Object)null) || !IsClaimedNear(((Component)giver).transform.position))
			{
				return QuestStatus.Available;
			}
			return QuestStatus.Active;
		}

		internal static bool IsSiteFriendly(Vector3 site)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return DvergrFriendship.IsNearFriendlySite(site, 15f);
		}

		private unsafe static void SyncWithWorld(Player player)
		{
			//IL_0091: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = ReadKnown(player);
			if (list.Count > 0)
			{
				int count = list.Count;
				list.RemoveAll(delegate(Vector3 site)
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					if (!IsSiteFriendly(site))
					{
						return false;
					}
					if ((Object)(object)Minimap.instance != (Object)null)
					{
						Minimap.instance.RemovePin(site, 5f);
					}
					return true;
				});
				if (list.Count != count)
				{
					WriteKnown(player, list);
				}
			}
			foreach (string item in ReadIds(player))
			{
				QuestStatus questStatus = StatusOf(player, item);
				if (questStatus == QuestStatus.Completed || questStatus == QuestStatus.Available || !TryReadPosition(player, item, "Site", out var position) || !IsSiteFriendly(position))
				{
					continue;
				}
				if ((Object)(object)Minimap.instance != (Object)null)
				{
					if (TryReadPosition(player, item, "Target", out var position2))
					{
						Minimap.instance.RemovePin(position2, 5f);
					}
					Minimap.instance.RemovePin(position, 5f);
				}
				string text = Read(player, item, "BossId");
				if (questStatus == QuestStatus.Active && text != null)
				{
					DvergrNetwork.SendBossRemove(text);
				}
				Write(player, item, "Status", QuestStatus.Completed.ToString());
				QuestTracker.InvalidateMarker();
				HaldorQuestPanel.RefreshIfOpen();
				ManualLogSource log = DvergrRedux.Log;
				Vector3 val = position;
				log.LogInfo((object)("The Dvergr at " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + " were made friendly by someone else; the quest there is complete."));
			}
		}

		internal static string CurrentBossName()
		{
			if (!string.IsNullOrEmpty(nameOverride))
			{
				return nameOverride;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && localPlayer.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Name", out var value) && value.Length > 0)
			{
				return value;
			}
			return "creature";
		}

		private static string Format(string template, string bossName)
		{
			nameOverride = bossName;
			try
			{
				return BossQuestSettings.Format(template);
			}
			finally
			{
				nameOverride = null;
			}
		}

		internal static string FormatFor(Player player, Character giver, string template)
		{
			string text = FindFor(player, giver);
			return Format(template, (text != null) ? Read(player, text, "Name") : null);
		}

		private static HashSet<string> ParseExcluded()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] array = BossQuestSettings.ExcludedEnemies.Value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private static List<BossChoice> GetChoices(Vector3 origin)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			bool flag = WorldGenerator.instance != null && (int)WorldGenerator.instance.GetBiome(origin) == 32;
			if (BossQuestSettings.RandomFromBiomes.Value)
			{
				return BuildBiomeChoices(flag ? "AshLands" : BossQuestSettings.RandomBiomes.Value);
			}
			string value = BossQuestSettings.BossPrefab.Value;
			if (flag && BossQuestSettings.BossPrefabAshlands.Value.Trim().Length > 0)
			{
				List<BossChoice> list = ParseChoices(BossQuestSettings.BossPrefabAshlands.Value, validOnly: true);
				if (list.Count > 0)
				{
					return list;
				}
			}
			return ParseChoices(value, validOnly: true);
		}

		private unsafe static List<BossChoice> BuildBiomeChoices(string biomeList)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			List<BossChoice> list = new List<BossChoice>();
			Biome val = (Biome)0;
			string[] array = biomeList.Split(new char[1] { ',' });
			foreach (string text in array)
			{
				if (Enum.TryParse<Biome>(text.Trim(), ignoreCase: true, out Biome result) && (int)result != 0)
				{
					val |= result;
				}
				else if (text.Trim().Length > 0)
				{
					DvergrRedux.Log.LogWarning((object)("Unknown biome '" + text.Trim() + "' in Boss Quest.RandomBiomes."));
				}
			}
			if ((int)val == 0 || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return list;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(SpawnSystem), "m_instances");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(SpawnSystem), "m_spawnLists");
			List<SpawnSystem> list2 = ((fieldInfo != null) ? (fieldInfo.GetValue(null) as List<SpawnSystem>) : null);
			if (list2 == null || fieldInfo2 == null)
			{
				return list;
			}
			HashSet<string> hashSet = ParseExcluded();
			HashSet<string> hashSet2 = new HashSet<string>();
			foreach (SpawnSystem item in list2)
			{
				List<SpawnSystemList> list3 = (((Object)(object)item != (Object)null) ? (fieldInfo2.GetValue(item) as List<SpawnSystemList>) : null);
				if (list3 == null)
				{
					continue;
				}
				foreach (SpawnSystemList item2 in list3)
				{
					foreach (SpawnData spawner in item2.m_spawners)
					{
						if (!spawner.m_enabled || (Object)(object)spawner.m_prefab == (Object)null || (spawner.m_biome & val) == 0)
						{
							continue;
						}
						string name = ((Object)spawner.m_prefab).name;
						if (!hashSet.Contains(name) && hashSet2.Add(name))
						{
							Character component = spawner.m_prefab.GetComponent<Character>();
							if (!((Object)(object)component == (Object)null) && !component.m_boss && !((Object)(object)spawner.m_prefab.GetComponent<MonsterAI>() == (Object)null))
							{
								list.Add(new BossChoice
								{
									Prefab = name,
									Stars = BossQuestSettings.Stars.Value
								});
							}
						}
					}
				}
			}
			DvergrRedux.Log.LogInfo((object)("Random enemy pool for " + ((object)(*(Biome*)(&val))/*cast due to .constrained prefix*/).ToString() + ": " + list.Count + " creatures."));
			return list;
		}

		private static List<BossChoice> ParseChoices(string list, bool validOnly)
		{
			List<BossChoice> list2 = new List<BossChoice>();
			HashSet<string> hashSet = ParseExcluded();
			string[] array = list.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				int stars = BossQuestSettings.Stars.Value;
				int num = text.IndexOf(':');
				if (num >= 0)
				{
					if (int.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
					{
						stars = Mathf.Clamp(result, 0, 4);
					}
					text = text.Substring(0, num).Trim();
				}
				if (!hashSet.Contains(text))
				{
					if (validOnly && ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNetScene.instance.GetPrefab(text) == (Object)null))
					{
						DvergrRedux.Log.LogWarning((object)("Boss prefab '" + text + "' was not found and will be skipped. Check Boss Quest.BossPrefab."));
						continue;
					}
					list2.Add(new BossChoice
					{
						Prefab = text,
						Stars = stars
					});
				}
			}
			return list2;
		}

		private static bool TryParseChoice(string raw, out BossChoice choice)
		{
			choice = default(BossChoice);
			if (string.IsNullOrEmpty(raw))
			{
				return false;
			}
			string[] array = raw.Split(new char[1] { ';' });
			if (array.Length != 2 || array[0].Length == 0 || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			choice = new BossChoice
			{
				Prefab = array[0],
				Stars = result
			};
			return true;
		}

		private static bool TryReadOffer(Player player, out BossChoice choice)
		{
			choice = default(BossChoice);
			if (player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Prefab", out var value))
			{
				return TryParseChoice(value, out choice);
			}
			return false;
		}

		private static bool PickAndStoreChoice(Player player, Vector3 origin)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			List<BossChoice> choices = GetChoices(origin);
			if (choices.Count == 0)
			{
				return false;
			}
			BossChoice bossChoice = choices[Random.Range(0, choices.Count)];
			GameObject prefab = ZNetScene.instance.GetPrefab(bossChoice.Prefab);
			Character val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Character>() : null);
			string value = (((Object)(object)val != (Object)null && Localization.instance != null) ? Localization.instance.Localize(val.m_name) : bossChoice.Prefab);
			player.m_customData["DvergrRedux.Quest.dvergr_boss.Prefab"] = bossChoice.Prefab + ";" + bossChoice.Stars.ToString(CultureInfo.InvariantCulture);
			player.m_customData["DvergrRedux.Quest.dvergr_boss.Name"] = value;
			return true;
		}

		public static void PrepareOffer(Player player, Character giver)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (FindFor(player, giver) == null && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				PickAndStoreChoice(player, ((Component)giver).transform.position);
			}
		}

		public unsafe static bool TryAccept(Player player, Character giver, out string failureMessage)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			failureMessage = null;
			if ((Object)(object)ZNetScene.instance == (Object)null || WorldGenerator.instance == null || (Object)(object)giver == (Object)null)
			{
				failureMessage = "The world is not ready yet.";
				return false;
			}
			if (FindFor(player, giver) != null || IsClaimedNear(((Component)giver).transform.position))
			{
				failureMessage = BossQuestSettings.SpawnFailedMessage.Value;
				return false;
			}
			if ((!TryReadOffer(player, out var choice) || (Object)(object)ZNetScene.instance.GetPrefab(choice.Prefab) == (Object)null) && (!PickAndStoreChoice(player, ((Component)giver).transform.position) || !TryReadOffer(player, out choice)))
			{
				failureMessage = BossQuestSettings.SpawnFailedMessage.Value;
				return false;
			}
			string prefab = choice.Prefab;
			if (!TryPickSpawnPoint(((Component)giver).transform.position, out var point))
			{
				DvergrRedux.Log.LogWarning((object)("No valid spawn point found near the Dvergr after " + BossQuestSettings.SpawnAttempts.Value + " attempts."));
				failureMessage = BossQuestSettings.SpawnFailedMessage.Value;
				return false;
			}
			Vector3 val = ((Component)giver).transform.position;
			Vector3 sitePosition;
			if (DvergrTowerQuest.TryGetTarget(player, out var position) && DvergrTowerQuest.PlanarDistance(position, val) <= DvergrRedux.SiteRadius.Value)
			{
				val = position;
			}
			else if (TryFindSiteNear(((Component)giver).transform.position, out sitePosition))
			{
				val = sitePosition;
			}
			player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Prefab", out var value);
			player.m_customData.TryGetValue("DvergrRedux.Quest.dvergr_boss.Name", out var value2);
			missingPrefabLogged = false;
			string questId = CreateRecord(player, QuestStatus.Active, point, val, player.GetPlayerID(), FormatZdoId(giver.GetZDOID()), value, value2, spawned: false);
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				ZoneSystem.instance.SetGlobalKey(ClaimKey(SiteKeyOf(val), player.GetPlayerID()));
			}
			if (BossQuestSettings.SitePinEnabled.Value)
			{
				if ((Object)(object)Minimap.instance != (Object)null)
				{
					Minimap.instance.RemovePin(val, 5f);
				}
				DvergrTowerQuest.PlacePin(val);
			}
			if (BossQuestSettings.PinEnabled.Value)
			{
				DvergrTowerQuest.PlacePin(point, BossQuestSettings.PinType.Value, Format(BossQuestSettings.PinName.Value, value2));
			}
			((Character)player).Message((MessageType)2, Format(BossQuestSettings.AcceptedMessage.Value, value2), 0, (Sprite)null, false);
			float num = Vector3.Distance(((Component)giver).transform.position, point);
			ManualLogSource log = DvergrRedux.Log;
			string[] obj = new string[7]
			{
				"Boss quest accepted. '",
				prefab,
				"' will spawn ",
				Mathf.RoundToInt(num).ToString(),
				" m from the Dvergr at ",
				null,
				null
			};
			Vector3 val2 = point;
			obj[5] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
			obj[6] = " once that area is loaded.";
			log.LogInfo((object)string.Concat(obj));
			DvergrNetwork.SendBossShare(player, giver, val, point, value ?? string.Empty, value2 ?? string.Empty);
			TrySpawnPending(player, questId);
			return true;
		}

		internal static void OnBossShared(Player player, long ownerId, Vector3 site, Vector3 point, string giverId, string prefabKey, string bossName, string fromName)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0062: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (FindNear(player, site) != null || !DvergrTowerQuest.AcceptSharedSite(player, site))
			{
				return;
			}
			CreateRecord(player, QuestStatus.Active, point, site, ownerId, giverId, prefabKey, bossName, spawned: true);
			if (BossQuestSettings.SitePinEnabled.Value)
			{
				if ((Object)(object)Minimap.instance != (Object)null)
				{
					Minimap.instance.RemovePin(site, 5f);
				}
				DvergrTowerQuest.PlacePin(site);
			}
			if (BossQuestSettings.PinEnabled.Value)
			{
				DvergrTowerQuest.PlacePin(point, BossQuestSettings.PinType.Value, Format(BossQuestSettings.PinName.Value, bossName));
			}
			((Character)player).Message((MessageType)2, Format(BossQuestSettings.AcceptedMessage.Value, bossName), 0, (Sprite)null, false);
			((Character)player).Message((MessageType)1, DvergrRedux.SharedMessage.Value.Replace("{player}", fromName).Replace("{title}", BossQuestSettings.Title.Value), 0, (Sprite)null, false);
			QuestTracker.InvalidateMarker();
			HaldorQuestPanel.RefreshIfOpen();
			DvergrRedux.Log.LogInfo((object)(fromName + " shared the boss quest with you."));
		}

		public static void Tick(Player player)
		{
			SyncWithWorld(player);
			List<string> list = new List<string>();
			foreach (string item in ReadIds(player))
			{
				switch (StatusOf(player, item))
				{
				case QuestStatus.Active:
					list.Add(item);
					break;
				case QuestStatus.ReadyToTurnIn:
					RemoveBossPin(player, item);
					break;
				}
			}
			if (list.Count == 0)
			{
				return;
			}
			bool flag = !existenceChecked;
			existenceChecked = true;
			foreach (string item2 in list)
			{
				if (flag)
				{
					RequestBossCheck(player, item2);
				}
				if (!(Read(player, item2, "Spawned") == "true"))
				{
					TrySpawnPending(player, item2);
				}
			}
		}

		internal static void Reset(Player player)
		{
			foreach (string item in ReadIds(player))
			{
				RemoveRecord(player, item, removeBoss: true);
			}
			player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Ids");
			player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Next");
			player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Known");
			player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Prefab");
			player.m_customData.Remove("DvergrRedux.Quest.dvergr_boss.Name");
		}

		public static void OnPlayerGone()
		{
			existenceChecked = false;
		}

		private static void RequestBossCheck(Player player, string id)
		{
			if (!(Read(player, id, "Spawned") != "true"))
			{
				string text = Read(player, id, "BossId");
				if (text == null || !TryParseZdoId(text, out var _))
				{
					DvergrRedux.Log.LogInfo((object)"The boss was spawned before its id was recorded, so it can't be checked for.");
				}
				else
				{
					DvergrNetwork.SendBossCheck(text);
				}
			}
		}

		public static void HandleBossCheck(string bossId, bool exists)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || exists)
			{
				return;
			}
			foreach (string item in ReadIds(localPlayer))
			{
				if (StatusOf(localPlayer, item) == QuestStatus.Active && !(Read(localPlayer, item, "BossId") != bossId))
				{
					Write(localPlayer, item, "Spawned", "false");
					localPlayer.m_customData.Remove(Field(item, "BossId"));
					DvergrRedux.Log.LogInfo((object)"The boss no longer exists in this world; it will be spawned again.");
				}
			}
		}

		public static void HandleBossDied(long ownerId, string siteKey)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			string text = ownerId.ToString(CultureInfo.InvariantCulture);
			bool flag = !string.IsNullOrEmpty(siteKey);
			foreach (string item in ReadIds(localPlayer))
			{
				if (Read(localPlayer, item, "Owner") != text || (flag && Read(localPlayer, item, "SiteKey") != siteKey))
				{
					continue;
				}
				if (StatusOf(localPlayer, item) != QuestStatus.Active)
				{
					RemoveBossPin(localPlayer, item);
					continue;
				}
				ReleaseClaims(Read(localPlayer, item, "SiteKey"));
				OnBossKilled(localPlayer, item);
				if (!flag)
				{
					continue;
				}
				break;
			}
		}

		internal static string FormatZdoId(ZDOID id)
		{
			return ((ZDOID)(ref id)).UserID.ToString(CultureInfo.InvariantCulture) + ";" + ((ZDOID)(ref id)).ID.ToString(CultureInfo.InvariantCulture);
		}

		internal static bool TryParseZdoId(string raw, out ZDOID id)
		{
			//IL_0001: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			id = default(ZDOID);
			string[] array = raw.Split(new char[1] { ';' });
			if (array.Length != 2 || !long.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !uint.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
			{
				return false;
			}
			id = new ZDOID(result, result2);
			return true;
		}

		private static string ClaimKey(string siteKey, long owner)
		{
			return "dvergrredux_boss_" + siteKey + "_" + owner.ToString(CultureInfo.InvariantCulture);
		}

		private static bool TryFindClaim(string siteKey, out long owner)
		{
			owner = 0L;
			if (string.IsNullOrEmpty(siteKey) || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			string text = "dvergrredux_boss_" + siteKey + "_";
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				if (globalKey.StartsWith(text, StringComparison.Ordinal) && long.TryParse(globalKey.Substring(text.Length), NumberStyles.Integer, CultureInfo.InvariantCulture, out owner))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool IsClaimedNear(Vector3 position)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			float num = Mathf.Max(DvergrRedux.SiteRadius.Value, 15f);
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				if (globalKey.StartsWith("dvergrredux_boss_", StringComparison.Ordinal))
				{
					string[] array = globalKey.Substring("dvergrredux_boss_".Length).Split(new char[1] { '_' });
					if (array.Length == 3 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && DvergrTowerQuest.PlanarDistance(new Vector3(result, 0f, result2), position) <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void ReleaseClaims(string siteKey)
		{
			if (string.IsNullOrEmpty(siteKey) || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return;
			}
			string value = "dvergrredux_boss_" + siteKey + "_";
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				if (globalKey.StartsWith(value, StringComparison.Ordinal))
				{
					ZoneSystem.instance.RemoveGlobalKey(globalKey);
				}
			}
		}

		private unsafe static void TrySpawnPending(Player player, string questId)
		{
			//IL_0031: 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)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			if ((Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || !TryReadPosition(player, questId, "Target", out var position) || !ZoneSystem.instance.GetGroundHeight(position, ref num))
			{
				return;
			}
			if (!TryParseChoice(Read(player, questId, "Prefab"), out var choice))
			{
				List<BossChoice> list = ParseChoices(BossQuestSettings.BossPrefab.Value, validOnly: false);
				if (list.Count == 0)
				{
					return;
				}
				choice = list[0];
			}
			string text = Read(player, questId, "SiteKey");
			if (TryFindClaim(text, out var owner) && owner != player.GetPlayerID())
			{
				Write(player, questId, "Owner", owner.ToString(CultureInfo.InvariantCulture));
				Write(player, questId, "Spawned", "true");
				player.m_customData.Remove(Field(questId, "BossId"));
				DvergrRedux.Log.LogInfo((object)"Another player already has a creature at this site; joining their quest instead of spawning a second one.");
				return;
			}
			string prefab = choice.Prefab;
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				if (!missingPrefabLogged)
				{
					DvergrRedux.Log.LogWarning((object)("Boss prefab '" + prefab + "' was not found. Check Boss Quest.BossPrefab."));
					missingPrefabLogged = true;
				}
				return;
			}
			Vector3 val;
			if (!TryFindClearSpawn(position, num, prefab2, out var spawn))
			{
				spawnRetries.TryGetValue(questId, out var value);
				spawnRetries[questId] = value + 1;
				if (value + 1 < 15)
				{
					return;
				}
				((Vector3)(ref spawn))..ctor(position.x, num + 1f + 3f, position.z);
				ManualLogSource log = DvergrRedux.Log;
				val = position;
				log.LogWarning((object)("No clear ground found near " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + "; spawning above the ground there."));
			}
			spawnRetries.Remove(questId);
			Quaternion val2 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			GameObject obj = Object.Instantiate<GameObject>(prefab2, spawn, val2);
			Character component = obj.GetComponent<Character>();
			if ((Object)(object)component != (Object)null)
			{
				component.SetLevel(choice.Stars + 1);
			}
			ZNetView component2 = obj.GetComponent<ZNetView>();
			ZDO val3 = (((Object)(object)component2 != (Object)null) ? component2.GetZDO() : null);
			if (val3 != null)
			{
				val3.Persistent = true;
				val3.Set("DvergrRedux_BossFor", player.GetPlayerID());
				val3.Set("DvergrRedux_BossSite", Read(player, questId, "SiteKey") ?? string.Empty);
				Write(player, questId, "BossId", FormatZdoId(val3.m_uid));
			}
			else
			{
				player.m_customData.Remove(Field(questId, "BossId"));
				DvergrRedux.Log.LogWarning((object)"Spawned boss has no ZDO; completing the quest will not be detected.");
			}
			MonsterAI component3 = obj.GetComponent<MonsterAI>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.SetDespawnInDay(false);
				Traverse.Create((object)component3).Field("m_eventCreature").SetValue((object)false);
			}
			if (val3 != null)
			{
				val3.Set(ZDOVars.s_eventCreature, false);
			}
			if ((Object)(object)ZoneSystem.instance != (Object)null && !string.IsNullOrEmpty(text))
			{
				ZoneSystem.instance.SetGlobalKey(ClaimKey(text, player.GetPlayerID()));
			}
			Write(player, questId, "Spawned", "true");
			ManualLogSource log2 = DvergrRedux.Log;
			string[] obj2 = new string[7]
			{
				"Spawned '",
				prefab,
				"' (",
				choice.Stars.ToString(),
				" star) at ",
				null,
				null
			};
			val = spawn;
			obj2[5] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString();
			obj2[6] = ".";
			log2.LogInfo((object)string.Concat(obj2));
		}

		private static bool TryFindClearSpawn(Vector3 target, float groundHeight, GameObject prefab, out Vector3 spawn)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: 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_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			spawn = Vector3.zero;
			float num = 0.8f;
			float num2 = 2.5f;
			CapsuleCollider componentInChildren = prefab.GetComponentInChildren<CapsuleCollider>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				float num3 = Mathf.Max(prefab.transform.lossyScale.x, prefab.transform.lossyScale.z);
				num = Mathf.Max(num, componentInChildren.radius * num3);
				num2 = Mathf.Max(num2, componentInChildren.height * prefab.transform.lossyScale.y);
			}
			int mask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vegetation", "terrain" });
			int mask2 = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vegetation" });
			RaycastHit val = default(RaycastHit);
			Vector3 val3 = default(Vector3);
			for (int i = 0; i < 30; i++)
			{
				float num4 = target.x;
				float num5 = target.z;
				if (i > 0)
				{
					float num6 = Random.Range(0f, (float)Math.PI * 2f);
					float num7 = Mathf.Lerp(1f, 12f, (float)i / 30f);
					num4 += Mathf.Cos(num6) * num7;
					num5 += Mathf.Sin(num6) * num7;
				}
				float num8 = groundHeight;
				if (i > 0 && !ZoneSystem.instance.GetGroundHeight(new Vector3(num4, groundHeight, num5), ref num8))
				{
					continue;
				}
				float num9 = num8;
				if (Physics.Raycast(new Vector3(num4, num8 + 60f, num5), Vector3.down, ref val, 120f, mask, (QueryTriggerInteraction)1))
				{
					num9 = ((RaycastHit)(ref val)).point.y;
				}
				if (!(num9 - num8 > 2.5f))
				{
					num9 = Mathf.Max(num9, num8);
					Vector3 val2 = new Vector3(num4, num9 + num + 0.5f, num5);
					((Vector3)(ref val3))..ctor(num4, num9 + Mathf.Max(num2, num * 2f + 0.5f), num5);
					if (!Physics.CheckCapsule(val2, val3, num + 0.4f, mask2, (QueryTriggerInteraction)1))
					{
						spawn = new Vector3(num4, num9 + 1f, num5);
						return true;
					}
				}
			}
			return false;
		}

		public static bool IsBoss(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			ZNetView component2 = component.GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component2 != (Object)null) ? component2.GetZDO() : null);
			if (val != null)
			{
				return val.GetLong("DvergrRedux_BossFor", 0L) != 0;
			}
			return false;
		}

		public static void OnCharacterDeath(Character character)
		{
			if ((Object)(object)character == (Object)null || character is Player)
			{
				return;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
			if (val != null)
			{
				long num = val.GetLong("DvergrRedux_BossFor", 0L);
				if (num != 0L)
				{
					DvergrNetwork.SendBossDied(num, val.GetString("DvergrRedux_BossSite", string.Empty));
				}
			}
		}

		public static string Describe(Player player)
		{
			List<string> list = new List<string>();
			string text = null;
			foreach (string item in ReadIds(player))
			{
				switch (StatusOf(player, item))
				{
				case QuestStatus.Completed:
					text = item;
					break;
				default:
					list.Add(item);
					break;
				case QuestStatus.Available:
					break;
				}
			}
			if (list.Count == 0 && text != null)
			{
				list.Add(text);
			}
			if (list.Count == 0)
			{
				return null;
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append("\n\n");
				}
				string id = list[i];
				QuestStatus questStatus = StatusOf(player, id);
				string bossName = Read(player, id, "Name");
				stringBuilder.Append(DvergrTowerQuest.Highlight(Format(BossQuestSettings.Title.Value, bossName), bold: true)).Append("\n");
				stringBuilder.Append(DvergrTowerQuest.Highlight("Status: " + DvergrTowerQuest.StatusLabel(questStatus), bold: false)).Append("\n\n");
				stringBuilder.Append(Format(questStatus switch
				{
					QuestStatus.Active => BossQuestSettings.ObjectiveText.Value, 
					QuestStatus.ReadyToTurnIn => BossQuestSettings.ReadyObjectiveText.Value, 
					_ => BossQuestSettings.CompletedText.Value, 
				}, bossName));
			}
			return stringBuilder.ToString();
		}

		private static void RemoveBossPin(Player player, string id)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (BossQuestSettings.RemovePinOnKill.Value && (Object)(object)Minimap.instance != (Object)null && TryReadPosition(player, id, "Target", out var position))
			{
				Minimap.instance.RemovePin(position, 5f);
			}
		}

		private static void OnBossKilled(Player player, string id)
		{
			RemoveBossPin(player, id);
			Write(player, id, "Status", QuestStatus.ReadyToTurnIn.ToString());
			((Character)player).Message((MessageType)2, Format(BossQuestSettings.ReadyMessage.Value, Read(player, id, "Name")), 0, (Sprite)null, false);
			QuestTracker.InvalidateMarker();
			DvergrRedux.Log.LogInfo((object)"The boss is dead; the quest is ready to turn in.");
		}

		public static bool TurnIn(Player player, Character giver)
		{
			//IL_004f: 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_0054: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			string text = FindFor(player, giver);
			if (text == null || StatusOf(player, text) != QuestStatus.ReadyToTurnIn)
			{
				return false;
			}
			Write(player, text, "Status", QuestStatus.Completed.ToString());
			Vector3 towerPosition = (((Object)(object)giver != (Object)null) ? ((Component)giver).transform.position : ((Component)player).transform.position);
			if (TryReadPosition(player, text, "Site", out var position))
			{
				towerPosition = position;
			}
			DvergrFriendship.Grant(player, towerPosition);
			string bossName = Read(player, text, "Name");
			((Character)player).Message((MessageType)2, Format(BossQuestSettings.CompletedMessage.Value, bossName), 0, (Sprite)null, false);
			if (BossQuestSettings.FriendshipEnabled.Value)
			{
				((Character)player).Message((MessageType)1, BossQuestSettings.FriendlyMessage.Value, 0, (Sprite)null, false);
			}
			DvergrRedux.Log.LogInfo((object)"Boss quest turned in.");
			return true;
		}

		public static void RememberGiver(Player player, Character giver)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			string text = FindFor(player, giver);
			if (text != null)
			{
				Write(player, text, "GiverId", FormatZdoId(giver.GetZDOID()));
			}
		}

		public static bool IsRememberedGiver(Player player, Character character)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			ZDOID zDOID = character.GetZDOID();
			foreach (string item in ReadIds(player))
			{
				QuestStatus questStatus = StatusOf(player, item);
				if (questStatus == QuestStatus.Active || questStatus == QuestStatus.ReadyToTurnIn)
				{
					string text = Read(player, item, "GiverId");
					if (!string.IsNullOrEmpty(text) && TryParseZdoId(text, out var id) && ((ZDOID)(ref zDOID)).UserID == ((ZDOID)(ref id)).UserID && ((ZDOID)(ref zDOID)).ID == ((ZDOID)(ref id)).ID)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryPickSpawnPoint(Vector3 origin, out Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			WorldGenerator instance = WorldGenerator.instance;
			float num = Mathf.Min(BossQuestSettings.MinSpawnDistance.Value, BossQuestSettings.MaxSpawnDistance.Value);
			float num2 = Mathf.Max(BossQuestSettings.MinSpawnDistance.Value, BossQuestSettings.MaxSpawnDistance.Value);
			Biome biome = instance.GetBiome(origin);
			bool value = BossQuestSettings.SameBiomeOnly.Value;
			for (int i = 0; i < BossQuestSettings.SpawnAttempts.Value; i++)
			{
				float num3 = Random.Range(0f, (float)Math.PI * 2f);
				float num4 = Random.Range(num, num2);
				float num5 = origin.x + Mathf.Cos(num3) * num4;
				float num6 = origin.z + Mathf.Sin(num3) * num4;
				float height = instance.GetHeight(num5, num6);
				if (!(height <= 30.5f) && (!value || instance.GetBiome(new Vector3(num5, height, num6)) == biome))
				{
					point = new Vector3(num5, height + 1f, num6);
					return true;
				}
			}
			return false;
		}
	}
	internal static class DvergrDialog
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnAcceptClicked;

			public static UnityAction <1>__OnTurnInClicked;

			public static UnityAction <2>__Close;
		}

		private const float SideMargin = 35f;

		private const float TopMargin = 30f;

		private const float TitleHeight = 40f;

		private const float GapBelowTitle = 10f;

		private const float AcceptCenterFromBottom = 90f;

		private const float CloseCenterFromBottom = 40f;

		private const float BottomReserved = 120f;

		private const float MinimumBodyHeight = 40f;

		private static GameObject panel;

		private static Character giver;

		private static bool inputBlocked;

		public static bool IsOpen => (Object)(object)panel != (Object)null;

		public static void Open(Character character)
		{
			if (!((Object)(object)panel != (Object)null) && !((Object)(object)character == (Object)null))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null))
				{
					giver = character;
					DvergrTowerQuest.CompleteTalk(localPlayer);
					DvergrBossQuest.RememberGiver(localPlayer, character);
					DvergrBossQuest.PrepareOffer(localPlayer, character);
					Build();
					SetInputBlocked(blocked: true);
				}
			}
		}

		public static void Close()
		{
			if ((Object)(object)panel != (Object)null)
			{
				Object.Destroy((Object)(object)panel);
			}
			panel = null;
			giver = null;
			SetInputBlocked(blocked: false);
		}

		public static void RebuildIfOpen()
		{
			if (!((Object)(object)panel == (Object)null))
			{
				Object.Destroy((Object)(object)panel);
				panel = null;
				Build();
			}
		}

		public static void Tick()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)panel == (Object)null))
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || (Object)(object)giver == (Object)null || giver.IsDead() || ZInput.GetKeyDown((KeyCode)27, true))
				{
					Close();
				}
				else if (Vector3.Distance(((Component)localPlayer).transform.position, ((Component)giver).transform.position) > DialogSettings.CloseDistance.Value)
				{
					Close();
				}
			}
		}

		private static void SetInputBlocked(bool blocked)
		{
			if (blocked)
			{
				GUIManager.BlockInput(true);
				inputBlocked = true;
			}
			else if (inputBlocked)
			{
				GUIManager.BlockInput(false);
				inputBlocked = false;
			}
		}

		private static void Build()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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)
			//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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Expected O, but got Unknown
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Expected O, but got Unknown
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Expected O, but got Unknown
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Expected O, but got Unknown
			GUIManager instance = GUIManager.Instance;
			Player localPlayer = Player.m_localPlayer;
			QuestStatus questStatus = (((Object)(object)localPlayer != (Object)null) ? DvergrBossQuest.GetStatus(localPlayer, giver) : QuestStatus.Available);
			string template = questStatus switch
			{
				QuestStatus.Active => BossQuestSettings.ObjectiveText.Value, 
				QuestStatus.ReadyToTurnIn => BossQuestSettings.TurnInText.Value, 
				QuestStatus.Completed => BossQuestSettings.CompletedText.Value, 
				_ => BossQuestSettings.OfferText.Value, 
			};
			template = (((Object)(object)localPlayer != (Object)null) ? DvergrBossQuest.FormatFor(localPlayer, giver, template) : BossQuestSettings.Format(template));
			bool flag = questStatus == QuestStatus.Available;
			bool flag2 = questStatus == QuestStatus.ReadyToTurnIn;
			float value = DialogSettings.Width.Value;
			float value2 = DialogSettings.Height.Value;
			float num = Mathf.Max(100f, value - 70f);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 1f);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0f);
			Vector2 val3 = UiSettings.AnchorVector(DialogSettings.Anchor.Value);
			Color val4 = UiSettings.ResolveColor(UiSettings.TitleColor, instance.ValheimOrange);
			Color val5 = UiSettings.ResolveColor(UiSettings.BodyColor, instance.ValheimBeige);
			panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, val3, val3, new Vector2(DialogSettings.OffsetX.Value, DialogSettings.OffsetY.Value), value, value2, DialogSettings.Draggable.Value);
			UiScale.Apply(panel, DialogSettings.Scale.Value, DialogSettings.MatchGameScale.Value);
			instance.CreateText(((Object)(object)localPlayer != (Object)null) ? DvergrBossQuest.FormatFor(localPlayer, giver, BossQuestSettings.Title.Value) : BossQuestSettings.Format(BossQuestSettings.Title.Value), panel.transform, val, val, new Vector2(0f, -50f), UiSettings.ResolveFont(UiSettings.TitleFont.Value), UiSettings.TitleFontSize.Value, val4, true, Color.black, num, 40f, false);
			float num2 = 80f;
			float num3 = Mathf.Max(40f, value2 - num2 - 120f);
			Text component = instance.CreateText(template, panel.transform, val, val, new Vector2(0f, 0f - (num2 + num3 / 2f)), UiSettings.ResolveFont(UiSettings.BodyFont.Value), UiSettings.BodyFontSize.Value, val5, true, Color.black, num, num3, false).GetComponent<Text>();
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			component.alignment = (TextAnchor)0;
			if (flag || flag2)
			{
				string text = (flag ? DialogSettings.AcceptLabel.Value : DialogSettings.TurnInLabel.Value);
				GameObject val6 = instance.CreateButton(text, panel.transform, val2, val2, new Vector2(0f, 90f), 220f, 45f);
				if (flag)
				{
					ButtonClickedEvent onClick = val6.GetComponent<Button>().onClick;
					object obj = <>O.<0>__OnAcceptClicked;
					if (obj == null)
					{
						UnityAction val7 = OnAcceptClicked;
						<>O.<0>__OnAcceptClicked = val7;
						obj = (object)val7;
					}
					((UnityEvent)onClick).AddListener((UnityAction)obj);
				}
				else
				{
					ButtonClickedEvent onClick2 = val6.GetComponent<Button>().onClick;
					object obj2 = <>O.<1>__OnTurnInClicked;
					if (obj2 == null)
					{
						UnityAction val8 = OnTurnInClicked;
						<>O.<1>__OnTurnInClicked = val8;
						obj2 = (object)val8;
					}
					((UnityEvent)onClick2).AddListener((UnityAction)obj2);
				}
				ButtonClickedEvent onClick3 = instance.CreateButton(DialogSettings.DeclineLabel.Value, panel.transform, val2, val2, new Vector2(0f, 40f), 160f, 35f).GetComponent<Button>().onClick;
				object obj3 = <>O.<2>__Close;
				if (obj3 == null)
				{
					UnityAction val9 = Close;
					<>O.<2>__Close = val9;
					obj3 = (object)val9;
				}
				((UnityEvent)onClick3).AddListener((UnityAction)obj3);
			}
			else
			{
				ButtonClickedEvent onClick4 = instance.CreateButton(DialogSettings.CloseLabel.Value, panel.transform, val2, val2, new Vector2(0f, 65f), 160f, 40f).GetComponent<Button>().onClick;
				object obj4 = <>O.<2>__Close;
				if (obj4 == null)
				{
					UnityAction val10 = Close;
					<>O.<2>__Close = val10;
					obj4 = (object)val10;
				}
				((UnityEvent)onClick4).AddListener((UnityAction)obj4);
			}
		}

		private static void OnTurnInClicked()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)giver != (Object)null)
			{
				DvergrBossQuest.TurnIn(localPlayer, giver);
			}
			QuestTracker.InvalidateMarker();
			Close();
		}

		private static void OnAcceptClicked()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)giver == (Object)null)
			{
				Close();
				return;
			}
			if (!DvergrBossQuest.TryAccept(localPlayer, giver, out var failureMessage))
			{
				((Character)localPlayer).Message((MessageType)2, failureMessage, 0, (Sprite)null, false);
				return;
			}
			QuestTracker.InvalidateMarker();
			Close();
		}
	}
	internal static class DvergrFriendship
	{
		private const string KeyPrefix = "dvergrredux_friendly_";

		private const string SyncGiverKey = "DvergrRedux_Giver";

		private const float DuplicateRadius = 5f;

		private static readonly List<Vector3> towers = new List<Vector3>();

		public static List<Vector3> Sites => new List<Vector3>(towers);

		public static int Count => towers.Count;

		public static bool HasFriendlySites => towers.Count > 0;

		public unsafe static void Grant(Player player, Vector3 towerPosition)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			Refresh();
			foreach (Vector3 tower in towers)
			{
				if (DvergrTowerQuest.PlanarDistance(tower, towerPosition) < 5f)
				{
					return;
				}
			}
			if (!((Object)(object)ZoneSystem.instance == (Object)null))
			{
				string globalKey = "dvergrredux_friendly_" + Mathf.RoundToInt(towerPosition.x).ToString(CultureInfo.InvariantCulture) + "_" + Mathf.RoundToInt(towerPosition.z).ToString(CultureInfo.InvariantCulture);
				ZoneSystem.instance.SetGlobalKey(globalKey);
				towers.Add(towerPosition);
				ManualLogSource log = DvergrRedux.Log;
				Vector3 val = towerPosition;
				log.LogInfo((object)("The Dvergr near " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + " are now friendly to everyone on this world."));
			}
		}

		public static void Refresh()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				towers.Clear();
				return;
			}
			towers.Clear();
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				if (globalKey != null && globalKey.StartsWith("dvergrredux_friendly_", StringComparison.OrdinalIgnoreCase))
				{
					string[] array = globalKey.Substring("dvergrredux_friendly_".Length).Split(new char[1] { '_' });
					if (array.Length == 2 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						towers.Add(new Vector3(result, 0f, result2));
					}
				}
			}
		}

		public static int ClearAll()
		{
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return 0;
			}
			List<string> list = new List<string>();
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				if (globalKey != null && globalKey.StartsWith("dvergrredux_friendly_", StringComparison.OrdinalIgnoreCase))
				{
					list.Add(globalKey);
				}
			}
			foreach (string item in list)
			{
				ZoneSystem.instance.RemoveGlobalKey(item);
			}
			towers.Clear();
			return list.Count;
		}

		public static bool IsNearFriendlySite(Vector3 point, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return IsNearTower(point, radius);
		}

		public static bool IsInsideFriendlyWard(Vector3 point)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (BossQuestSettings.IgnoreWardDamage.Value && towers.Count > 0)
			{
				return IsNearTower(point, BossQuestSettings.WardRadius.Value);
			}
			return false;
		}

		public static void PublishGiver(Character giver)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			ZDO zdo = GetZdo(Player.m_localPlayer);
			if (zdo != null)
			{
				string text = (((Object)(object)giver != (Object)null) ? DvergrBossQuest.FormatZdoId(giver.GetZDOID()) : string.Empty);
				if (zdo.GetString("DvergrRedux_Giver", string.Empty) != text)
				{
					zdo.Set("DvergrRedux_Giver", text);
				}
			}
		}

		public static bool IsPacified(Character dvergr, Character playerCharacter)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Player val = (Player)(object)((playerCharacter is Player) ? playerCharacter : null);
			if ((Object)(object)val == (Object)null || (Object)(object)dvergr == (Object)null || (int)dvergr.m_faction != 10)
			{
				return false;
			}
			if (BossQuestSettings.PacifyQuestGiver.Value)
			{
				if ((Object)(object)val == (Object)(object)Player.m_localPlayer && QuestTracker.IsQuestGiver(dvergr))
				{
					return true;
				}
				ZDO zdo = GetZdo(val);
				if (zdo != null)
				{
					string text = zdo.GetString("DvergrRedux_Giver", string.Empty);
					if (text.Length > 0 && text == DvergrBossQuest.FormatZdoId(dvergr.GetZDOID()))
					{
						return true;
					}
				}
			}
			if (BossQuestSettings.FriendshipEnabled.Value)
			{
				return IsNearTower(((Component)dvergr).transform.position, BossQuestSettings.FriendlyRadius.Value);
			}
			return false;
		}

		public static bool AllowsWard(PrivateArea area)
		{
			if (BossQuestSettings.GrantBuildPermission.Value)
			{
				return IsSiteWard(area);
			}
			return false;
		}

		public static bool IsSiteWard(PrivateArea area)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)area == (Object)null || towers.Count == 0)
			{
				return false;
			}
			Piece component = ((Component)area).GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && component.GetCreator() != 0L)
			{
				return false;
			}
			return IsNearTower(((Component)area).transform.position, BossQuestSettings.WardRadius.Value);
		}

		private static ZDO GetZdo(Player player)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || ZDOMan.instance == null)
			{
				return null;
			}
			return ZDOMan.instance.GetZDO(((Character)player).GetZDOID());
		}

		private static bool IsNearTower(Vector3 point, float radius)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < towers.Count; i++)
			{
				if (DvergrTowerQuest.PlanarDistance(towers[i], point) <= radius)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class DvergrLocationSearch
	{
		public const string RequestTagPrefix = "DvergrRedux|";

		private const float SearchAreaRadius = 9000f;

		private const float SamePlaceRadius = 10f;

		private static readonly MethodInfo isExploredMethod = AccessTools.Method(typeof(Minimap), "IsExplored", new Type[1] { typeof(Vector3) }, (Type[])null);

		private static readonly List<Vector3> triedPositions = new List<Vector3>();

		private static int lastRequestId;

		private static int pendingRequestId;

		private static string pendingLocationName;

		private static float pendingDeadline;

		private static int attemptsMade;

		private static bool hasFallback;

		private static Vector3 fallbackPosition;

		public static bool IsSearching => pendingRequestId != 0;

		public static bool TryBegin(Player player, out string failureMessage)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			failureMessage = null;
			if (IsSearching)
			{
				failureMessage = "Haldor is still searching his maps.";
				return false;
			}
			if ((Object)(object)Game.instance == (Obje