Decompiled source of Tame Guild Wars v1.0.0

TameGuildWars.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Guilds;
using HarmonyLib;
using ItemManager;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using TameGuildWars.Compatibility;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TameGuildWars")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("TameGuildWars")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1327040b-77e8-48df-918a-542534b5ec0f")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyCompany("WackyMole")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<54445620-f45c-49a6-9f02-d5bbf8177ed1>Embedded]
	internal sealed class <54445620-f45c-49a6-9f02-d5bbf8177ed1>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	[<54445620-f45c-49a6-9f02-d5bbf8177ed1>Embedded]
	internal sealed class <01a73d35-473a-4adb-86fb-c7fd269b4cb1>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <01a73d35-473a-4adb-86fb-c7fd269b4cb1>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <01a73d35-473a-4adb-86fb-c7fd269b4cb1>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<54445620-f45c-49a6-9f02-d5bbf8177ed1>Embedded]
	[CompilerGenerated]
	internal sealed class <3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace TameGuildWars
{
	[BepInPlugin("WackyMole.TameGuildWars", "TameGuildWars", "1.0.0")]
	[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(0)]
	[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(1)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class TameGuildWarsPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ZNet), "Awake")]
		[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)]
		private static class ZNetAwakePatch
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Instance?.TryRegisterAllyRpc();
			}
		}

		[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)]
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(2)]
			[UsedImplicitly]
			public string Category;

			[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(new byte[] { 2, 1 })]
			[UsedImplicitly]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(0)]
		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		private static string _pendingAllyRequesterGuild = string.Empty;

		private static string _pendingAllyRequestedTarget = string.Empty;

		private static bool _showAllyRequestPopup;

		private static GUIStyle _allyPopupTitleStyle;

		private static GUIStyle _allyPopupLabelStyle;

		private bool _allyRpcRegistered;

		private bool _allyRpcRegistrationStarted;

		internal static TameGuildWarsPlugin Instance;

		internal const string ModName = "TameGuildWars";

		internal const string ModVersion = "1.0.0";

		internal const string Author = "WackyMole";

		private const string ModGUID = "WackyMole.TameGuildWars";

		private static string ConfigFileName = "WackyMole.TameGuildWars.cfg";

		private static string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("WackyMole.TameGuildWars");

		public static readonly ManualLogSource TameGuildWarsLogger;

		private static readonly ConfigSync ConfigSync;

		public static ConfigEntry<float> ConfigObedienceDecayRate;

		public static ConfigEntry<float> ConfigNonGuildMemberDecayMultiplier;

		public static ConfigEntry<float> ConfigNoGuildDecayMultiplier;

		public static ConfigEntry<Toggle> ConfigHostileToNeutrals;

		public static ConfigEntry<float> ConfigConfusionDurationSeconds;

		public static ConfigEntry<float> ConfigCommandHornRadius;

		public static ConfigEntry<string> ConfigCommandHornSound;

		public static ConfigEntry<float> ConfigConfusionResistanceMinHealth;

		public static ConfigEntry<float> ConfigConfusionResistanceMaxHealth;

		public static ConfigEntry<float> ConfigConfusionResistanceMaxValue;

		public static ConfigEntry<float> ConfigConfusionResistanceLowHealthMultiplier;

		public static ConfigEntry<float> ConfigConfusionBomb1Min;

		public static ConfigEntry<float> ConfigConfusionBomb1Max;

		public static ConfigEntry<float> ConfigConfusionBomb2Min;

		public static ConfigEntry<float> ConfigConfusionBomb2Max;

		public static ConfigEntry<float> ConfigConfusionBomb3Min;

		public static ConfigEntry<float> ConfigConfusionBomb3Max;

		public static ConfigEntry<Toggle> ConfigAllowBossConfusion;

		public static ConfigEntry<Toggle> ConfigDeathNotifications;

		public static ConfigEntry<Toggle> ConfigShowGuildIcon;

		public static ConfigEntry<float> ConfigGuildIconOffsetX;

		public static ConfigEntry<float> ConfigGuildIconOffsetY;

		public static ConfigEntry<float> ConfigAlarmDurationSeconds;

		public static ConfigEntry<float> ConfigAlarmLeashDistance;

		public static ConfigEntry<float> ConfigAllyAddCooldownSeconds;

		public static ConfigEntry<float> ConfigGuardLeashDistance;

		public static ConfigEntry<float> ConfigSwarmRadius;

		public static ConfigEntry<float> ConfigSwarmCheckInterval;

		public static ConfigEntry<Toggle> ConfigMobActionLogging;

		public static readonly CustomSyncedValue<string> SyncedAllies;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		private const string SharedChatInputRpc = "TGW_SendSharedChatInput";

		private static readonly FieldInfo ChatInputField;

		private void OnGUI()
		{
			//IL_006d: 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)
			//IL_0084: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (_showAllyRequestPopup && !string.IsNullOrEmpty(_pendingAllyRequesterGuild) && !string.IsNullOrEmpty(_pendingAllyRequestedTarget) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				EnsureAllyPopupStyles();
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((float)Screen.width - 520f) * 0.5f, ((float)Screen.height - 200f) * 0.5f, 520f, 200f);
				GUI.ModalWindow(938412, val, new WindowFunction(DrawAllyRequestPopupWindow), "Guild Ally Request");
			}
		}

		private static void EnsureAllyPopupStyles()
		{
			//IL_0011: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0038: Expected O, but got Unknown
			//IL_0049: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (_allyPopupTitleStyle == null)
			{
				_allyPopupTitleStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 18,
					fontStyle = (FontStyle)1,
					wordWrap = true
				};
			}
			if (_allyPopupLabelStyle == null)
			{
				_allyPopupLabelStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 14,
					wordWrap = true
				};
			}
		}

		private static void DrawAllyRequestPopupWindow(int windowId)
		{
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Space(12f);
			GUILayout.Label("Guild '" + _pendingAllyRequesterGuild + "' is requesting an alliance with '" + _pendingAllyRequestedTarget + "'.", _allyPopupTitleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(54f) });
			GUILayout.Space(10f);
			GUILayout.Label("Accepting will make both sides allied. Denying will reject the request.", _allyPopupLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) });
			GUILayout.Space(14f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			GUI.enabled = ZRoutedRpc.instance != null;
			if (GUILayout.Button("Accept", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(170f),
				GUILayout.Height(40f)
			}))
			{
				RespondToPendingAllyRequest(accept: true);
			}
			GUILayout.Space(16f);
			if (GUILayout.Button("Deny", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(170f),
				GUILayout.Height(40f)
			}))
			{
				RespondToPendingAllyRequest(accept: false);
			}
			GUI.enabled = true;
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			GUILayout.EndVertical();
			GUI.DragWindow();
		}

		private static void RespondToPendingAllyRequest(bool accept)
		{
			if (string.IsNullOrEmpty(_pendingAllyRequesterGuild) || string.IsNullOrEmpty(_pendingAllyRequestedTarget))
			{
				_showAllyRequestPopup = false;
				return;
			}
			if (ZRoutedRpc.instance == null)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "Unable to respond right now (network not ready).", 0, (Sprite)null);
				}
				return;
			}
			string pendingAllyRequesterGuild = _pendingAllyRequesterGuild;
			string pendingAllyRequestedTarget = _pendingAllyRequestedTarget;
			TameGuildWarsLogger.LogInfo((object)("Popup ally response: action='" + (accept ? "accept" : "deny") + "', requester='" + pendingAllyRequesterGuild + "', target='" + pendingAllyRequestedTarget + "'."));
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TGW_RespondAllyRequest", new object[3] { pendingAllyRequesterGuild, pendingAllyRequestedTarget, accept });
			_showAllyRequestPopup = false;
			_pendingAllyRequesterGuild = string.Empty;
			_pendingAllyRequestedTarget = string.Empty;
		}

		private static void ShowAllyRequestPopup(string requesterGuild, string requestedTarget)
		{
			_pendingAllyRequesterGuild = requesterGuild ?? string.Empty;
			_pendingAllyRequestedTarget = requestedTarget ?? string.Empty;
			_showAllyRequestPopup = !string.IsNullOrEmpty(_pendingAllyRequesterGuild) && !string.IsNullOrEmpty(_pendingAllyRequestedTarget);
		}

		private void TryRegisterAllyRpc()
		{
			if (!_allyRpcRegistered && ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<string, string, bool>("TGW_SetAlly", (Action<long, string, string, bool>)RPC_TGW_SetAlly);
				ZRoutedRpc.instance.Register<string, string>("TGW_RequestAlly", (Action<long, string, string>)RPC_TGW_RequestAlly);
				ZRoutedRpc.instance.Register<string, string>("TGW_NotifyAllyRequest", (Action<long, string, string>)RPC_TGW_NotifyAllyRequest);
				ZRoutedRpc.instance.Register<string, string, bool>("TGW_RespondAllyRequest", (Action<long, string, string, bool>)RPC_TGW_RespondAllyRequest);
				ZRoutedRpc.instance.Register<string, string, bool>("TGW_NotifyAllyResponse", (Action<long, string, string, bool>)RPC_TGW_NotifyAllyResponse);
				ZRoutedRpc.instance.Register<string, string>("TGW_BroadcastAllyRemoved", (Action<long, string, string>)RPC_TGW_BroadcastAllyRemoved);
				ZRoutedRpc.instance.Register<string, string>("TGW_NotifyAllyRemoved", (Action<long, string, string>)RPC_TGW_NotifyAllyRemoved);
				ZRoutedRpc.instance.Register<string>("TGW_SendSharedChatInput", (Action<long, string>)RPC_TGW_SendSharedChatInput);
				_allyRpcRegistered = true;
				((MonoBehaviour)this).CancelInvoke("TryRegisterAllyRpc");
			}
		}

		private static void RPC_TGW_SetAlly(long sender, string myGuild, string targetNameOrGuild, bool ally)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				TameGuildWarsLogger.LogInfo((object)string.Format("Received TGW_SetAlly RPC from sender {0}: guild='{1}', target='{2}', action='{3}'.", sender, myGuild, targetNameOrGuild, ally ? "add" : "remove"));
				if (!GuildUtils.TryGetSenderGuild(sender, out var guildName) || string.IsNullOrEmpty(guildName))
				{
					TameGuildWarsLogger.LogWarning((object)$"Unable to resolve guild for ally update sender {sender}; accepting claimed guild '{myGuild}'.");
				}
				else if (!string.Equals(guildName, myGuild, StringComparison.Ordinal))
				{
					TameGuildWarsLogger.LogWarning((object)$"Rejected ally update from sender {sender}: claimed guild '{myGuild}' but actual guild was '{guildName}'.");
					return;
				}
				if (GuildUtils.SetAlly(myGuild, targetNameOrGuild, ally))
				{
					TameGuildWarsLogger.LogInfo((object)("Guild '" + myGuild + "' " + (ally ? "added" : "removed") + " ally '" + targetNameOrGuild + "'."));
				}
				else
				{
					TameGuildWarsLogger.LogWarning((object)("Guild '" + myGuild + "' failed to " + (ally ? "add" : "remove") + " ally '" + targetNameOrGuild + "' (cooldown or invalid state)."));
				}
			}
		}

		private static void RPC_TGW_RequestAlly(long sender, string requesterGuild, string requestedTarget)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				TameGuildWarsLogger.LogInfo((object)$"Received TGW_RequestAlly RPC from sender {sender}: requester='{requesterGuild}', target='{requestedTarget}'.");
				if (string.IsNullOrWhiteSpace(requesterGuild) || string.IsNullOrWhiteSpace(requestedTarget))
				{
					TameGuildWarsLogger.LogWarning((object)"Rejected TGW_RequestAlly because requester guild or target was blank.");
					return;
				}
				if (GuildUtils.TryGetSenderGuild(sender, out var guildName) && !string.IsNullOrEmpty(guildName) && !string.Equals(guildName, requesterGuild, StringComparison.Ordinal))
				{
					TameGuildWarsLogger.LogWarning((object)$"Rejected TGW_RequestAlly from sender {sender}: claimed guild '{requesterGuild}' but actual guild was '{guildName}'.");
					return;
				}
				GuildUtils.CreatePendingAllyRequest(requesterGuild, requestedTarget, sender);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TGW_NotifyAllyRequest", new object[2] { requesterGuild, requestedTarget });
			}
		}

		private static void RPC_TGW_NotifyAllyRequest(long sender, string requesterGuild, string requestedTarget)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			foreach (string localPlayerAllyRequestTarget in GuildUtils.GetLocalPlayerAllyRequestTargets(localPlayer))
			{
				if (string.Equals(localPlayerAllyRequestTarget, requestedTarget, StringComparison.OrdinalIgnoreCase))
				{
					GuildUtils.CreatePendingAllyRequest(requesterGuild, requestedTarget, sender);
					TameGuildWarsLogger.LogInfo((object)("Received ally request prompt for local target '" + requestedTarget + "' from guild '" + requesterGuild + "'."));
					((Character)localPlayer).Message((MessageType)2, "Ally request from " + requesterGuild + ". Use guild_ally accept " + requesterGuild + " " + requestedTarget + " or guild_ally deny " + requesterGuild + " " + requestedTarget, 0, (Sprite)null);
					ShowAllyRequestPopup(requesterGuild, requestedTarget);
					break;
				}
			}
		}

		private static void RPC_TGW_RespondAllyRequest(long sender, string requesterGuild, string requestedTarget, bool accepted)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			TameGuildWarsLogger.LogInfo((object)$"Received TGW_RespondAllyRequest RPC from sender {sender}: requester='{requesterGuild}', target='{requestedTarget}', accepted={accepted}.");
			if (!GuildUtils.TryGetPendingAllyRequest(requesterGuild, requestedTarget, out var _))
			{
				TameGuildWarsLogger.LogWarning((object)("No pending ally request found for requester='" + requesterGuild + "', target='" + requestedTarget + "'."));
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "TGW_NotifyAllyResponse", new object[3] { requesterGuild, requestedTarget, false });
				return;
			}
			GuildUtils.RemovePendingAllyRequest(requesterGuild, requestedTarget);
			if (accepted)
			{
				bool flag = GuildUtils.SetAlly(requesterGuild, requestedTarget, ally: true);
				bool flag2 = GuildUtils.SetAlly(requestedTarget, requesterGuild, ally: true);
				string text = BuildAllianceFormedMessage(requesterGuild, requestedTarget);
				TameGuildWarsLogger.LogInfo((object)((flag && flag2) ? text : ("Alliance acceptance partially failed between " + requesterGuild + " and " + requestedTarget + ".")));
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TGW_NotifyAllyResponse", new object[3]
				{
					requesterGuild,
					requestedTarget,
					flag && flag2
				});
				if (flag && flag2)
				{
					SendSharedChatInput(sender, "/s " + text);
				}
			}
			else
			{
				string text2 = "Alliance request from " + requesterGuild + " to " + requestedTarget + " was denied.";
				TameGuildWarsLogger.LogInfo((object)text2);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TGW_NotifyAllyResponse", new object[3] { requesterGuild, requestedTarget, false });
			}
		}

		private static void RPC_TGW_NotifyAllyResponse(long sender, string requesterGuild, string requestedTarget, bool accepted)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				bool num = GuildUtils.GetLocalPlayerAllyRequestTargets(localPlayer).Any([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string target) => string.Equals(target, requestedTarget, StringComparison.OrdinalIgnoreCase) || string.Equals(target, requesterGuild, StringComparison.OrdinalIgnoreCase));
				string playerGuildName = GuildUtils.GetPlayerGuildName(localPlayer);
				if (num || string.Equals(playerGuildName, requesterGuild, StringComparison.OrdinalIgnoreCase))
				{
					string text = (accepted ? ("Alliance formed between " + requesterGuild + " and " + requestedTarget + ".") : ("Alliance request between " + requesterGuild + " and " + requestedTarget + " was denied or failed."));
					TameGuildWarsLogger.LogInfo((object)$"Ally response notification: requester='{requesterGuild}', target='{requestedTarget}', accepted={accepted}. Message='{text}'");
					((Character)localPlayer).Message((MessageType)(accepted ? 1 : 2), text, 0, (Sprite)null);
				}
			}
		}

		private static void RPC_TGW_BroadcastAllyRemoved(long sender, string removerGuild, string removedTarget)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !string.IsNullOrWhiteSpace(removerGuild) && !string.IsNullOrWhiteSpace(removedTarget))
			{
				if (GuildUtils.TryGetSenderGuild(sender, out var guildName) && !string.IsNullOrEmpty(guildName) && !string.Equals(guildName, removerGuild, StringComparison.Ordinal))
				{
					TameGuildWarsLogger.LogWarning((object)$"Rejected TGW_BroadcastAllyRemoved from sender {sender}: claimed guild '{removerGuild}' but actual guild was '{guildName}'.");
					return;
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TGW_NotifyAllyRemoved", new object[2] { removerGuild, removedTarget });
				SendSharedChatInput(sender, "/s " + BuildAllianceRemovedMessage(removerGuild, removedTarget));
			}
		}

		private static void RPC_TGW_NotifyAllyRemoved(long sender, string removerGuild, string removedTarget)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				string playerGuildName = GuildUtils.GetPlayerGuildName(localPlayer);
				if (string.Equals(playerGuildName, removerGuild, StringComparison.OrdinalIgnoreCase) || string.Equals(playerGuildName, removedTarget, StringComparison.OrdinalIgnoreCase) || string.Equals(localPlayer.GetPlayerName(), removedTarget, StringComparison.OrdinalIgnoreCase))
				{
					string text = BuildAllianceRemovedMessage(removerGuild, removedTarget);
					((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null);
					TameGuildWarsLogger.LogInfo((object)("Ally removal notification: remover='" + removerGuild + "', target='" + removedTarget + "'."));
				}
			}
		}

		private static string BuildAllianceFormedMessage(string requesterGuild, string requestedTarget)
		{
			return "Alliance formed between " + requesterGuild + " and " + requestedTarget + ".";
		}

		private static string BuildAllianceRemovedMessage(string removerGuild, string removedTarget)
		{
			return "Alliance between " + removerGuild + " and " + removedTarget + " has been removed.";
		}

		public void Awake()
		{
			Instance = this;
			ConfigObedienceDecayRate = config("1 - General", "Obedience Decay Rate", 0.1f, "Base Obedience Loss per update tick");
			ConfigNonGuildMemberDecayMultiplier = config("1 - General", "Non-Guild Member Decay Multiplier", 3f, "Multiplier applied to obedience decay when near non-guild members");
			ConfigNoGuildDecayMultiplier = config("1 - General", "No Guild Decay Multiplier", 5f, "Multiplier applied to obedience decay when the owner has no guild");
			ConfigConfusionDurationSeconds = config("1 - General", "Confusion Duration", 120f, "Duration in seconds for maximum (100) confusion to wear off.");
			ConfigCommandHornRadius = config("1 - General", "Command Horn Radius", 30f, "Radius in meters for tamed guild mobs affected by the command horn.");
			ConfigCommandHornSound = config("1 - General", "Command Horn Sound", "sfx_viking-horn", "Sound effect played when using the command horn.");
			ConfigDeathNotifications = config("1 - General", "Death Notifications", Toggle.On, "If On, global notifications will be sent when high-value guild mobs (2+ stars) are killed by a player from another guild.");
			ConfigShowGuildIcon = config("1 - General", "Show Guild Icon", Toggle.On, "If On, shows the guild's icon image next to the mob's name plate.");
			ConfigGuildIconOffsetX = config("1 - General", "Guild Icon Offset X", -85f, "Horizontal offset for the guild icon relative to the mob nameplate.");
			ConfigGuildIconOffsetY = config("1 - General", "Guild Icon Offset Y", 0f, "Vertical offset for the guild icon relative to the mob nameplate.");
			ConfigHostileToNeutrals = config("3 - Combat", "Hostile To Neutral Players", Toggle.On, "If On, guild mobs will attack players who are not in any guild.");
			ConfigAlarmDurationSeconds = config("3 - Combat", "Alarm Duration", 30f, "How long a mob remembers the last hostile player before calming down.");
			ConfigAlarmLeashDistance = config("3 - Combat", "Alarm Leash Distance", 75f, "How far the alarmed player can get from the mob before the alarm is cleared.");
			ConfigAllyAddCooldownSeconds = config("3 - Combat", "Ally Add Cooldown Seconds", 10f, "Cooldown before adding the same ally target again with guild_ally add.");
			ConfigGuardLeashDistance = config("3 - Combat", "Guard Leash Distance", 125f, "Maximum distance a mob in Guard stance can move from its stance anchor before returning.");
			ConfigSwarmRadius = config("3 - Combat", "Swarm Radius", 50f, "Radius in meters for nearby same-guild mobs to join a swarm response.");
			ConfigSwarmCheckInterval = config("3 - Combat", "Swarm Check Interval", 2f, "How often idle guild mobs scan nearby same-guild mobs for a swarm target. Lower is more responsive; higher is cheaper.");
			ConfigMobActionLogging = config("4 - Debug", "Mob Action Logging", Toggle.Off, "If On, logs major guild mob actions such as stance changes, alarms, and target swaps.", synchronizedSetting: false);
			ConfigConfusionResistanceMinHealth = config("2 - Confusion", "Resistance Min Health", 25f, "Max health value where confusion resistance starts scaling.");
			ConfigConfusionResistanceMaxHealth = config("2 - Confusion", "Resistance Max Health", 1600f, "Max health value where confusion resistance reaches full configured strength (before multiplayer scaling).");
			ConfigConfusionResistanceMaxValue = config("2 - Confusion", "Resistance Max Value", 0.9f, "Maximum confusion resistance at or above Resistance Max Health. 0 = none, 1 = full immunity.");
			ConfigConfusionResistanceLowHealthMultiplier = config("2 - Confusion", "Resistance At 0% Health Multiplier", 0.7f, "How much of baseline resistance remains when the mob is near 0 health. 0 = no resistance when low, 1 = full baseline.");
			ConfigConfusionBomb1Min = config("2 - Confusion", "Bomb Tier 1 Min", 12f, "Minimum confusion added by tgw_confusionbomb1 before resistance.");
			ConfigConfusionBomb1Max = config("2 - Confusion", "Bomb Tier 1 Max", 32f, "Maximum confusion added by tgw_confusionbomb1 before resistance.");
			ConfigConfusionBomb2Min = config("2 - Confusion", "Bomb Tier 2 Min", 24f, "Minimum confusion added by tgw_confusionbomb2 before resistance.");
			ConfigConfusionBomb2Max = config("2 - Confusion", "Bomb Tier 2 Max", 55f, "Maximum confusion added by tgw_confusionbomb2 before resistance.");
			ConfigConfusionBomb3Min = config("2 - Confusion", "Bomb Tier 3 Min", 40f, "Minimum confusion added by tgw_confusionbomb3 before resistance.");
			ConfigConfusionBomb3Max = config("2 - Confusion", "Bomb Tier 3 Max", 85f, "Maximum confusion added by tgw_confusionbomb3 before resistance.");
			ConfigAllowBossConfusion = config("2 - Confusion", "Allow Boss Confusion", Toggle.Off, "If On, boss-class enemies can be affected by Confusion Bombs. Default: Off (bosses immune). [Synced with Server]");
			Item item = new Item("tamebundle", "tgw_confusionbomb1");
			item.Name.English("Confusion Bomb I");
			item.Description.English("Applies a low confusion amount to tamed mobs in an area.");
			item.RequiredItems.Add("Resin", 8);
			item.RequiredItems.Add("Coal", 4);
			item.RequiredItems.Add("LeatherScraps", 3);
			item.RequiredItems.Add("Ooze", 2);
			item.Crafting.Add(CraftingTable.Workbench, 2);
			item.Configurable = Configurability.Recipe | Configurability.Drop | Configurability.Trader;
			Item item2 = new Item("tamebundle", "tgw_confusionbomb2");
			item2.Name.English("Confusion Bomb II");
			item2.Description.English("Applies a medium confusion amount to tamed mobs in an area.");
			item2.RequiredItems.Add("Resin", 10);
			item2.RequiredItems.Add("Ooze", 4);
			item2.RequiredItems.Add("Obsidian", 3);
			item2.RequiredItems.Add("Crystal", 6);
			item2.Crafting.Add(CraftingTable.Workbench, 5);
			item2.Configurable = Configurability.Recipe | Configurability.Drop | Configurability.Trader;
			Item item3 = new Item("tamebundle", "tgw_confusionbomb3");
			item3.Name.English("Confusion Bomb III");
			item3.Description.English("Applies a high confusion amount to tamed mobs in an area.");
			item3.RequiredItems.Add("Resin", 12);
			item3.RequiredItems.Add("Ooze", 6);
			item3.RequiredItems.Add("Bilebag", 2);
			item3.RequiredItems.Add("BlackCore", 1);
			item3.Crafting.Add(CraftingTable.MageTable, 1);
			item3.Configurable = Configurability.Recipe | Configurability.Drop | Configurability.Trader;
			Item item4 = new Item("tamebundle", "tgw_command");
			item4.Name.English("Command Horn");
			item4.Description.English("Blow to cycle nearby guild tamed mob orders.");
			item4.RequiredItems.Add("FineWood", 10);
			item4.RequiredItems.Add("LeatherScraps", 4);
			item4.RequiredItems.Add("Bronze", 2);
			item4.Crafting.Add(CraftingTable.Workbench, 3);
			PrefabManager.RegisterPrefab("tamebundle", "sfx_viking-horn");
			item4.Configurable = Configurability.Recipe | Configurability.Drop | Configurability.Trader;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			PortablePalsPatches.TryPatch(_harmony);
			SetupWatcher();
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			TryRegisterAllyRpc();
			if (!_allyRpcRegistered && !_allyRpcRegistrationStarted)
			{
				((MonoBehaviour)this).InvokeRepeating("TryRegisterAllyRpc", 1f, 1f);
				_allyRpcRegistrationStarted = true;
			}
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			FileSystemWatcher fileSystemWatcher2 = new FileSystemWatcher(Paths.ConfigPath, "TameGuildWarsAllies.txt");
			fileSystemWatcher2.Changed += ReadAlliesValues;
			fileSystemWatcher2.Created += ReadAlliesValues;
			fileSystemWatcher2.Renamed += ReadAlliesValues;
			fileSystemWatcher2.IncludeSubdirectories = true;
			fileSystemWatcher2.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher2.EnableRaisingEvents = true;
			ReadAlliesValues(null, null);
		}

		private void ReadAlliesValues(object sender, FileSystemEventArgs e)
		{
			string path = Path.Combine(Paths.ConfigPath, "TameGuildWarsAllies.txt");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, "");
			}
			try
			{
				TameGuildWarsLogger.LogDebug((object)"ReadAlliesValues called");
				string value = File.ReadAllText(path);
				SyncedAllies.Value = value;
			}
			catch (Exception arg)
			{
				TameGuildWarsLogger.LogError((object)$"There was an issue loading your TameGuildWarsAllies.txt\n{arg}");
			}
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				TameGuildWarsLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				TameGuildWarsLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				TameGuildWarsLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		internal static void SendGuildChatInput(string message)
		{
			SendChatInput("/g", message);
		}

		internal static void SendShoutChatInput(string message)
		{
			SendChatInput("/s", message);
		}

		private static void SendSharedChatInput(long targetPeerId, string inputText)
		{
			if (!string.IsNullOrWhiteSpace(inputText) && ZRoutedRpc.instance != null)
			{
				long serverPeerID = ZRoutedRpc.instance.GetServerPeerID();
				if (targetPeerId == serverPeerID && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					SendRawChatInput(inputText);
					return;
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(targetPeerId, "TGW_SendSharedChatInput", new object[1] { inputText });
			}
		}

		private static void RPC_TGW_SendSharedChatInput(long sender, string inputText)
		{
			SendRawChatInput(inputText);
		}

		private static void SendChatInput(string command, string message)
		{
			if (!string.IsNullOrWhiteSpace(command) && !string.IsNullOrWhiteSpace(message))
			{
				SendRawChatInput(command + " " + NormalizeChatMessage(message));
			}
		}

		private static void SendRawChatInput(string inputText)
		{
			if ((Object)(object)Chat.instance == (Object)null || string.IsNullOrWhiteSpace(inputText))
			{
				return;
			}
			object obj = ChatInputField?.GetValue(Chat.instance);
			PropertyInfo propertyInfo = obj?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			string value = (propertyInfo?.GetValue(obj, null) as string) ?? string.Empty;
			try
			{
				if (obj == null || propertyInfo == null || !propertyInfo.CanWrite)
				{
					TameGuildWarsLogger.LogWarning((object)"Failed to send shared chat input: Chat.m_input.text was not available.");
					return;
				}
				propertyInfo.SetValue(obj, NormalizeChatMessage(inputText), null);
				((Terminal)Chat.instance).InputText();
			}
			catch (Exception ex)
			{
				TameGuildWarsLogger.LogWarning((object)("Failed to send shared chat input '" + inputText + "': " + ex.Message));
			}
			finally
			{
				if (obj != null && propertyInfo != null && propertyInfo.CanWrite && !string.IsNullOrEmpty(value))
				{
					propertyInfo.SetValue(obj, value, null);
				}
			}
		}

		private static string NormalizeChatMessage(string message)
		{
			return message.Replace('\r', ' ').Replace('\n', ' ').Trim();
		}

		static TameGuildWarsPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			TameGuildWarsLogger = Logger.CreateLogSource("TameGuildWars");
			ConfigSync = new ConfigSync("WackyMole.TameGuildWars")
			{
				DisplayName = "TameGuildWars",
				CurrentVersion = "1.0.0",
				MinimumRequiredVersion = "1.0.0"
			};
			ConfigObedienceDecayRate = null;
			ConfigNonGuildMemberDecayMultiplier = null;
			ConfigNoGuildDecayMultiplier = null;
			ConfigHostileToNeutrals = null;
			ConfigConfusionDurationSeconds = null;
			ConfigCommandHornRadius = null;
			ConfigCommandHornSound = null;
			ConfigConfusionResistanceMinHealth = null;
			ConfigConfusionResistanceMaxHealth = null;
			ConfigConfusionResistanceMaxValue = null;
			ConfigConfusionResistanceLowHealthMultiplier = null;
			ConfigConfusionBomb1Min = null;
			ConfigConfusionBomb1Max = null;
			ConfigConfusionBomb2Min = null;
			ConfigConfusionBomb2Max = null;
			ConfigConfusionBomb3Min = null;
			ConfigConfusionBomb3Max = null;
			ConfigAllowBossConfusion = null;
			ConfigDeathNotifications = null;
			ConfigShowGuildIcon = null;
			ConfigGuildIconOffsetX = null;
			ConfigGuildIconOffsetY = null;
			ConfigAlarmDurationSeconds = null;
			ConfigAlarmLeashDistance = null;
			ConfigAllyAddCooldownSeconds = null;
			ConfigGuardLeashDistance = null;
			ConfigSwarmRadius = null;
			ConfigSwarmCheckInterval = null;
			ConfigMobActionLogging = null;
			SyncedAllies = new CustomSyncedValue<string>(ConfigSync, "TameGuildWarsAllies", "");
			_serverConfigLocked = null;
			ChatInputField = typeof(Chat).GetField("m_input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}
	}
	[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(0)]
	[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(1)]
	public static class GuildUtils
	{
		[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)]
		private struct CachedGuildName
		{
			[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(1)]
			public string GuildName;

			public long CachedAtTicks;
		}

		[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(0)]
		public struct PendingAllyRequest
		{
			public string RequesterGuild;

			public string RequestedTarget;

			public long SenderPeerId;

			public long ExpiresAtTicks;
		}

		private const double PlayerGuildCacheSeconds = 1.0;

		private const double AllianceBreakGraceSeconds = 10.0;

		private const double AllyRequestLifetimeSeconds = 60.0;

		private static readonly Dictionary<string, long> AllianceGraceUntilTicks = new Dictionary<string, long>();

		private static readonly Dictionary<string, long> AllyAddCooldownUntilTicks = new Dictionary<string, long>();

		private static readonly Dictionary<string, PendingAllyRequest> PendingIncomingAllyRequests = new Dictionary<string, PendingAllyRequest>();

		private static readonly Dictionary<long, CachedGuildName> PlayerGuildCache = new Dictionary<long, CachedGuildName>();

		public static string GetPlayerGuildName(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return string.Empty;
			}
			long playerID = player.GetPlayerID();
			long ticks = DateTime.UtcNow.Ticks;
			if (playerID != 0L && PlayerGuildCache.TryGetValue(playerID, out var value) && new TimeSpan(ticks - value.CachedAtTicks).TotalSeconds <= 1.0)
			{
				return value.GuildName ?? string.Empty;
			}
			string text = string.Empty;
			if (API.IsLoaded())
			{
				Guild playerGuild = API.GetPlayerGuild(player);
				if (playerGuild != null)
				{
					text = playerGuild.Name;
				}
			}
			if (playerID != 0L)
			{
				PlayerGuildCache[playerID] = new CachedGuildName
				{
					GuildName = text,
					CachedAtTicks = ticks
				};
			}
			return text ?? string.Empty;
		}

		public static void InvalidatePlayerGuildCache(long playerId = 0L)
		{
			if (playerId == 0L)
			{
				PlayerGuildCache.Clear();
			}
			else
			{
				PlayerGuildCache.Remove(playerId);
			}
		}

		public static bool IsAlly(string myGuild, string targetNameOrGuild)
		{
			if (string.IsNullOrEmpty(myGuild) || string.IsNullOrEmpty(targetNameOrGuild))
			{
				return false;
			}
			string key = BuildAllyKey(myGuild, targetNameOrGuild);
			if (TameGuildWarsPlugin.SyncedAllies.Value == null)
			{
				return false;
			}
			return TameGuildWarsPlugin.SyncedAllies.Value.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).Any([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string ally) => string.Equals(ally.Trim(), key, StringComparison.OrdinalIgnoreCase));
		}

		public static bool IsAllianceBreakGraceActive(string myGuild, string targetNameOrGuild)
		{
			if (string.IsNullOrEmpty(myGuild) || string.IsNullOrEmpty(targetNameOrGuild))
			{
				return false;
			}
			string key = BuildAllyKey(myGuild, targetNameOrGuild);
			if (!AllianceGraceUntilTicks.TryGetValue(key, out var value))
			{
				return false;
			}
			if (DateTime.UtcNow.Ticks <= value)
			{
				return true;
			}
			AllianceGraceUntilTicks.Remove(key);
			return false;
		}

		public static string BuildPendingAllyRequestKey(string requesterGuild, string requestedTarget)
		{
			return requesterGuild.Trim().ToLowerInvariant() + "::" + requestedTarget.Trim().ToLowerInvariant();
		}

		public static PendingAllyRequest CreatePendingAllyRequest(string requesterGuild, string requestedTarget, long senderPeerId)
		{
			PendingAllyRequest pendingAllyRequest = new PendingAllyRequest
			{
				RequesterGuild = requesterGuild.Trim(),
				RequestedTarget = requestedTarget.Trim(),
				SenderPeerId = senderPeerId,
				ExpiresAtTicks = DateTime.UtcNow.AddSeconds(60.0).Ticks
			};
			PendingIncomingAllyRequests[BuildPendingAllyRequestKey(pendingAllyRequest.RequesterGuild, pendingAllyRequest.RequestedTarget)] = pendingAllyRequest;
			TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)$"Stored pending ally request: requester='{pendingAllyRequest.RequesterGuild}', target='{pendingAllyRequest.RequestedTarget}', sender={pendingAllyRequest.SenderPeerId}.");
			return pendingAllyRequest;
		}

		public static bool TryGetPendingAllyRequest(string requesterGuild, string requestedTarget, out PendingAllyRequest request)
		{
			string key = BuildPendingAllyRequestKey(requesterGuild, requestedTarget);
			if (!PendingIncomingAllyRequests.TryGetValue(key, out request))
			{
				return false;
			}
			if (DateTime.UtcNow.Ticks <= request.ExpiresAtTicks)
			{
				return true;
			}
			PendingIncomingAllyRequests.Remove(key);
			request = default(PendingAllyRequest);
			return false;
		}

		public static bool RemovePendingAllyRequest(string requesterGuild, string requestedTarget)
		{
			string key = BuildPendingAllyRequestKey(requesterGuild, requestedTarget);
			bool flag = PendingIncomingAllyRequests.Remove(key);
			if (flag)
			{
				TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)("Removed pending ally request: requester='" + requesterGuild + "', target='" + requestedTarget + "'."));
			}
			return flag;
		}

		public static string BuildAllyKey(string myGuild, string targetNameOrGuild)
		{
			return ("TGW_Ally_" + myGuild.Trim() + "_" + targetNameOrGuild.Trim()).ToLowerInvariant();
		}

		public static bool TryGetAllyAddCooldownRemaining(string myGuild, string targetNameOrGuild, out double remainingSeconds)
		{
			remainingSeconds = 0.0;
			if (string.IsNullOrEmpty(myGuild) || string.IsNullOrEmpty(targetNameOrGuild))
			{
				return false;
			}
			string key = BuildAllyKey(myGuild, targetNameOrGuild);
			if (!AllyAddCooldownUntilTicks.TryGetValue(key, out var value))
			{
				return false;
			}
			remainingSeconds = new TimeSpan(value - DateTime.UtcNow.Ticks).TotalSeconds;
			if (remainingSeconds > 0.0)
			{
				return true;
			}
			AllyAddCooldownUntilTicks.Remove(key);
			remainingSeconds = 0.0;
			return false;
		}

		public static bool SetAlly(string myGuild, string targetNameOrGuild, bool ally)
		{
			if (string.IsNullOrEmpty(myGuild) || string.IsNullOrEmpty(targetNameOrGuild))
			{
				return false;
			}
			string text = BuildAllyKey(myGuild, targetNameOrGuild);
			if (ally && TryGetAllyAddCooldownRemaining(myGuild, targetNameOrGuild, out var remainingSeconds))
			{
				TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)$"Rejected ally add for '{text}' due to cooldown ({remainingSeconds:0.0}s remaining).");
				return false;
			}
			if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
			{
				if (ZRoutedRpc.instance == null)
				{
					TameGuildWarsPlugin.TameGuildWarsLogger.LogWarning((object)("Unable to " + (ally ? "add" : "remove") + " ally '" + targetNameOrGuild + "' for guild '" + myGuild + "': ZRoutedRpc is not ready."));
					return false;
				}
				TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)("Dispatching ally " + (ally ? "add" : "remove") + " RPC: guild='" + myGuild + "', target='" + targetNameOrGuild + "', key='" + text + "'."));
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TGW_SetAlly", new object[3] { myGuild, targetNameOrGuild, ally });
				if (ally)
				{
					float num = ((TameGuildWarsPlugin.ConfigAllyAddCooldownSeconds != null) ? Mathf.Max(0f, TameGuildWarsPlugin.ConfigAllyAddCooldownSeconds.Value) : 0f);
					if (num > 0f)
					{
						AllyAddCooldownUntilTicks[text] = DateTime.UtcNow.AddSeconds(num).Ticks;
					}
				}
				return true;
			}
			TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)("Applying ally " + (ally ? "add" : "remove") + " locally on server: key='" + text + "'."));
			InternalSetAlly(text, ally);
			return true;
		}

		public static List<string> ResolveAllyTargets(string targetNameOrGuild)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(targetNameOrGuild))
			{
				return list;
			}
			string trimmedTarget = targetNameOrGuild.Trim();
			list.Add(trimmedTarget);
			Player val = Player.GetAllPlayers().Find([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (Player player) => (Object)(object)player != (Object)null && string.Equals(player.GetPlayerName(), trimmedTarget, StringComparison.OrdinalIgnoreCase));
			if ((Object)(object)val == (Object)null)
			{
				return list;
			}
			string matchedGuild = GetPlayerGuildName(val);
			if (!string.IsNullOrWhiteSpace(matchedGuild) && !list.Any([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string target) => string.Equals(target, matchedGuild, StringComparison.OrdinalIgnoreCase)))
			{
				list.Add(matchedGuild);
			}
			return list;
		}

		public static List<string> GetLocalPlayerAllyRequestTargets(Player player)
		{
			List<string> list = new List<string>();
			if ((Object)(object)player == (Object)null)
			{
				return list;
			}
			string playerGuildName = GetPlayerGuildName(player);
			if (!string.IsNullOrWhiteSpace(playerGuildName))
			{
				list.Add(playerGuildName.Trim());
			}
			string playerName = player.GetPlayerName();
			if (!string.IsNullOrWhiteSpace(playerName) && !list.Any([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string target) => string.Equals(target, playerName, StringComparison.OrdinalIgnoreCase)))
			{
				list.Add(playerName.Trim());
			}
			return list;
		}

		public static bool TryGetSenderGuild(long sender, out string guildName)
		{
			//IL_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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)
			guildName = string.Empty;
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			foreach (PlayerInfo player in ZNet.instance.m_players)
			{
				if (TryGetPlayerInfoPeerId(player, out var peerId) && peerId == sender)
				{
					guildName = API.GetPlayerGuild(PlayerReference.fromPlayerInfo(player))?.Name ?? string.Empty;
					return true;
				}
			}
			return false;
		}

		private static bool TryGetPlayerInfoPeerId(PlayerInfo playerInfo, out long peerId)
		{
			//IL_003a: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			peerId = 0L;
			string[] obj = new string[6] { "m_host", "m_hostID", "m_peerID", "m_sender", "m_userID", "m_characterID" };
			Type type = ((object)playerInfo).GetType();
			string[] array = obj;
			foreach (string name in array)
			{
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && TryConvertToLong(field.GetValue(playerInfo), out peerId))
				{
					return true;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanRead && TryConvertToLong(property.GetValue(playerInfo, null), out peerId))
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryConvertToLong(object value, out long result)
		{
			result = 0L;
			if (value == null)
			{
				return false;
			}
			if (value is long num)
			{
				result = num;
				return true;
			}
			if (value is int num2)
			{
				result = num2;
				return true;
			}
			if (value is uint num3)
			{
				result = num3;
				return true;
			}
			if (value is ulong num4 && num4 <= long.MaxValue)
			{
				result = (long)num4;
				return true;
			}
			return long.TryParse(value.ToString(), out result);
		}

		public static void InternalSetAlly(string key, bool ally)
		{
			string path = Path.Combine(Paths.ConfigPath, "TameGuildWarsAllies.txt");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, "");
			}
			List<string> list = (from line in File.ReadAllLines(path)
				select line.Trim() into line
				where line.Length > 0
				select line).ToList();
			int count = list.Count;
			if (ally)
			{
				if (!list.Any([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string line) => string.Equals(line, key, StringComparison.OrdinalIgnoreCase)))
				{
					list.Add(key);
				}
				AllianceGraceUntilTicks[key] = DateTime.UtcNow.AddSeconds(10.0).Ticks;
				float num = ((TameGuildWarsPlugin.ConfigAllyAddCooldownSeconds != null) ? Mathf.Max(0f, TameGuildWarsPlugin.ConfigAllyAddCooldownSeconds.Value) : 0f);
				if (num > 0f)
				{
					AllyAddCooldownUntilTicks[key] = DateTime.UtcNow.AddSeconds(num).Ticks;
				}
				else
				{
					AllyAddCooldownUntilTicks.Remove(key);
				}
			}
			else
			{
				list.RemoveAll([<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(0)] (string line) => string.Equals(line, key, StringComparison.OrdinalIgnoreCase));
				AllianceGraceUntilTicks.Remove(key);
				AllyAddCooldownUntilTicks.Remove(key);
			}
			File.WriteAllLines(path, list);
			TameGuildWarsPlugin.SyncedAllies.Value = string.Join("\n", list);
			TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)string.Format("InternalSetAlly {0}: key='{1}', before={2}, after={3}.", ally ? "add" : "remove", key, count, list.Count));
		}

		public static List<string> GetAlliesForGuild(string myGuild)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrEmpty(myGuild))
			{
				return list;
			}
			if (TameGuildWarsPlugin.SyncedAllies.Value == null)
			{
				return list;
			}
			string text = "tgw_ally_" + myGuild.Trim().ToLowerInvariant() + "_";
			string[] array = TameGuildWarsPlugin.SyncedAllies.Value.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.StartsWith(text, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(text2.Substring(text.Length));
				}
			}
			return list;
		}

		public static Sprite GetGuildIcon(string guildName)
		{
			if (string.IsNullOrEmpty(guildName))
			{
				return null;
			}
			if (API.IsLoaded())
			{
				Guild guild = API.GetGuild(guildName);
				if (guild != null)
				{
					return API.GetGuildIcon(guild);
				}
			}
			return null;
		}

		public static bool API_SetTamedGuildMobData(string payload, Character character)
		{
			TamedGuildMob tamedGuildMob = default(TamedGuildMob);
			if (!((Component)character).TryGetComponent<TamedGuildMob>(ref tamedGuildMob))
			{
				return false;
			}
			tamedGuildMob.RestoreMobdata(payload);
			return true;
		}

		public static bool API_CanCaptureCreature(Player player, Character character)
		{
			return true;
		}
	}
	public static class KeyboardExtensions
	{
		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
	public enum GuildMobStance
	{
		Guard,
		Stay,
		GuardWard,
		Follow,
		FollowAttack,
		Static
	}
	[<3caa0b4f-4b82-489f-b8ce-dd36932aef56>NullableContext(1)]
	[<01a73d35-473a-4adb-86fb-c7fd269b4cb1>Nullable(0)]
	public class TamedGuildMob : MonoBehaviour, Interactable
	{
		private static readonly HashSet<TamedGuildMob> ActiveGuildMobs = new HashSet<TamedGuildMob>();

		private ZNetView m_nview;

		private BaseAI m_baseAI;

		public HitData m_lastHit;

		private const string ZdoGuildName = "TGW_GuildName";

		private const string ZdoTamerId = "TGW_TamerID";

		private const string ZdoTamerName = "TGW_TamerName";

		private const string ZdoObedience = "TGW_Obedience";

		private const string ZdoStance = "TGW_Stance";

		private const string ZdoConfusion = "TGW_Confusion";

		private const string ZdoAlarmPlayerId = "TGW_AlarmPlayerId";

		private const string ZdoAlarmRaisedTicks = "TGW_AlarmRaisedTicks";

		private const string ZdoFollowTargetPlayerId = "TGW_FollowTargetPlayerId";

		private const string ZdoCommandLock = "TGW_CommandLock";

		private const string ZdoSkipDecay = "TGW_SkipDecay";

		private readonly float ObedienceRecoverRate = 1f;

		private readonly float MaxObedience = 100f;

		private readonly float UpdateInterval = 10f;

		private readonly float TamerProximityRange = 50f;

		private readonly float ObedienceDrop = 10f;

		private readonly float childStartingObedience = 20f;

		private float _swarmCheckTimer;

		private Character _rememberedSwarmTarget;

		private Vector3 _rememberedSwarmTargetLastKnownPos = Vector3.zero;

		private float _rememberedSwarmTargetUntil;

		private float _swarmTargetReassertTimer;

		private float _wardPatrolAngle;

		private Vector3 _currentWardPatrolPoint = Vector3.zero;

		private float _wardPatrolStuckTimer;

		private Vector3 _stanceAnchorPoint = Vector3.zero;

		private bool _ordersRefreshedForCurrentLoad;

		private float _stanceUpdateTimer;

		public MonsterAI MonsterAi { get; private set; }

		public Character Character { get; private set; }

		private float GuardMaxDistance => Mathf.Max(0f, TameGuildWarsPlugin.ConfigGuardLeashDistance.Value);

		private float ObedienceDecayRate => TameGuildWarsPlugin.ConfigObedienceDecayRate.Value;

		private float SwarmCheckInterval => Mathf.Max(0.1f, TameGuildWarsPlugin.ConfigSwarmCheckInterval.Value);

		private float SwarmRadius => Mathf.Max(0f, TameGuildWarsPlugin.ConfigSwarmRadius.Value);

		private bool MobActionLoggingEnabled
		{
			get
			{
				if (TameGuildWarsPlugin.ConfigMobActionLogging != null)
				{
					return TameGuildWarsPlugin.ConfigMobActionLogging.Value == TameGuildWarsPlugin.Toggle.On;
				}
				return false;
			}
		}

		public string GuildName
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return "";
				}
				return m_nview.GetZDO().GetString("TGW_GuildName", "");
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_GuildName", value ?? "");
				}
			}
		}

		public long TamerID
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0L;
				}
				return m_nview.GetZDO().GetLong("TGW_TamerID", 0L);
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_TamerID", value);
				}
			}
		}

		public string TamerName
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return "";
				}
				return m_nview.GetZDO().GetString("TGW_TamerName", "");
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_TamerName", value ?? "");
				}
			}
		}

		public float Obedience
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0f;
				}
				return m_nview.GetZDO().GetFloat("TGW_Obedience", 0f);
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_Obedience", Mathf.Clamp(value, 0f, MaxObedience));
				}
			}
		}

		public GuildMobStance Stance
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return GuildMobStance.Guard;
				}
				return (GuildMobStance)m_nview.GetZDO().GetInt("TGW_Stance", 0);
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_Stance", (int)value);
				}
			}
		}

		public float Confusion
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0f;
				}
				return m_nview.GetZDO().GetFloat("TGW_Confusion", 0f);
			}
			set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_Confusion", Mathf.Clamp(value, 0f, 100f));
				}
			}
		}

		public long AlarmPlayerId
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0L;
				}
				return m_nview.GetZDO().GetLong("TGW_AlarmPlayerId", 0L);
			}
			set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner())
				{
					m_nview.GetZDO().Set("TGW_AlarmPlayerId", value);
				}
			}
		}

		public long AlarmRaisedTicks
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0L;
				}
				return m_nview.GetZDO().GetLong("TGW_AlarmRaisedTicks", 0L);
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner())
				{
					m_nview.GetZDO().Set("TGW_AlarmRaisedTicks", value);
				}
			}
		}

		public bool CommandLocked
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return false;
				}
				return m_nview.GetZDO().GetBool("TGW_CommandLock", false);
			}
			set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_CommandLock", value);
				}
			}
		}

		public long FollowTargetPlayerId
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0L;
				}
				return m_nview.GetZDO().GetLong("TGW_FollowTargetPlayerId", 0L);
			}
			private set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_FollowTargetPlayerId", value);
				}
			}
		}

		public bool SkipDecay
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return false;
				}
				return m_nview.GetZDO().GetBool("TGW_SkipDecay", false);
			}
			set
			{
				if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
				{
					m_nview.GetZDO().Set("TGW_SkipDecay", value);
				}
			}
		}

		private void Awake()
		{
			MonsterAi = ((Component)this).GetComponent<MonsterAI>();
			m_baseAI = ((Component)this).GetComponent<BaseAI>();
			Character = ((Component)this).GetComponent<Character>();
			m_nview = ((Component)this).GetComponent<ZNetView>();
			_wardPatrolAngle = Random.Range(0f, 360f);
			m_nview.Register("RPC_ObedienceDrop", (Action<long>)RPC_ObedienceDrop);
			m_nview.Register<float>("RPC_TGW_AddConfusion", (Action<long, float>)RPC_AddConfusion);
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
			{
				((MonoBehaviour)this).InvokeRepeating("UpdateObedience", Random.Range(1f, 5f), UpdateInterval);
				((MonoBehaviour)this).InvokeRepeating("UpdateConfusion", Random.Range(1f, 5f), 2f);
			}
		}

		private void OnEnable()
		{
			ActiveGuildMobs.Add(this);
			_ordersRefreshedForCurrentLoad = false;
			((MonoBehaviour)this).Invoke("RefreshOrdersForLoadedArea", 0.25f);
		}

		private void OnDisable()
		{
			ActiveGuildMobs.Remove(this);
			((MonoBehaviour)this).CancelInvoke("RefreshOrdersForLoadedArea");
		}

		public void RaiseAlarm(Character attacker)
		{
			if (!(Obedience <= 0f) && !((Object)(object)attacker == (Object)null) && !((Object)(object)attacker == (Object)(object)Character) && !((Object)(object)m_nview == (Object)null) && m_nview.IsValid() && m_nview.IsOwner())
			{
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				bool num = (Object)(object)val != (Object)null;
				long num2 = (num ? val.GetPlayerID() : 0);
				long alarmPlayerId = AlarmPlayerId;
				long alarmRaisedTicks = AlarmRaisedTicks;
				long ticks = DateTime.UtcNow.Ticks;
				if (num)
				{
					AlarmPlayerId = num2;
					AlarmRaisedTicks = ticks;
				}
				LogMobAction("alarm raised on " + DescribeCharacter(attacker));
				TryApplySwarmTarget(attacker, num2, ticks, "alarm");
				if (!num || alarmPlayerId != num2 || alarmRaisedTicks == 0L || new TimeSpan(ticks - alarmRaisedTicks).TotalSeconds >= 1.0)
				{
					BroadcastSwarmAlarm(attacker, num2, ticks);
				}
			}
		}

		public void ClearAlarm()
		{
			if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid() && m_nview.IsOwner())
			{
				bool num = AlarmPlayerId != 0L || AlarmRaisedTicks != 0;
				AlarmPlayerId = 0L;
				AlarmRaisedTicks = 0L;
				if (num)
				{
					LogMobAction("alarm cleared");
				}
			}
		}

		private void BroadcastSwarmAlarm(Character attacker, long attackerPlayerId, long alarmTicks)
		{
			//IL_0033: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)attacker == (Object)null || attacker.IsDead() || string.IsNullOrEmpty(GuildName))
			{
				return;
			}
			float num = SwarmRadius * SwarmRadius;
			Vector3 position = ((Component)this).transform.position;
			foreach (TamedGuildMob activeGuildMob in ActiveGuildMobs)
			{
				if (!((Object)(object)activeGuildMob == (Object)null) && !((Object)(object)activeGuildMob == (Object)(object)this) && !((Object)(object)activeGuildMob.Character == (Object)null) && activeGuildMob.IsSameGuild(GuildName))
				{
					Vector3 val = ((Component)activeGuildMob).transform.position - position;
					if (!(((Vector3)(ref val)).sqrMagnitude > num))
					{
						activeGuildMob.TryApplySwarmTarget(attacker, attackerPlayerId, alarmTicks, "broadcast swarm");
					}
				}
			}
		}

		private bool TryApplySwarmTarget(Character target, long alarmPlayerId, long alarmTicks, string source)
		{
			if ((Object)(object)target == (Object)null || target.IsDead())
			{
				return false;
			}
			if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner())
			{
				return false;
			}
			if ((Object)(object)MonsterAi == (Object)null || (Object)(object)Character == (Object)null || Character.IsDead())
			{
				return false;
			}
			if (string.IsNullOrEmpty(GuildName) || Obedience <= 0f)
			{
				return false;
			}
			if (Stance == GuildMobStance.Stay || Stance == GuildMobStance.Follow)
			{
				return false;
			}
			if (target.IsPlayer())
			{
				Player val = (Player)(object)((target is Player) ? target : null);
				if ((Object)(object)val == (Object)null || val.GetPlayerID() != alarmPlayerId || TargetingPatches.IsPlayerGhost(val))
				{
					return false;
				}
				AlarmPlayerId = alarmPlayerId;
				AlarmRaisedTicks = alarmTicks;
			}
			Character targetCreature = ((BaseAI)MonsterAi).GetTargetCreature();
			if (!ShouldPrioritizeSwarmTarget(targetCreature, target, alarmPlayerId))
			{
				return false;
			}
			ForceCombatTarget(target);
			Character targetCreature2 = ((BaseAI)MonsterAi).GetTargetCreature();
			if ((Object)(object)targetCreature2 == (Object)(object)target && (Object)(object)targetCreature != (Object)(object)target)
			{
				RememberSwarmTarget(target);
				LogMobAction(source + ": targeting " + DescribeCharacter(target) + (((Object)(object)targetCreature != (Object)null) ? (" instead of " + DescribeCharacter(targetCreature)) : string.Empty));
			}
			else if ((Object)(object)targetCreature2 != (Object)(object)target)
			{
				LogMobAction(source + ": failed to hold target " + DescribeCharacter(target));
			}
			return (Object)(object)targetCreature2 == (Object)(object)target;
		}

		private void RememberSwarmTarget(Character target)
		{
			//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)
			if ((Object)(object)target == (Object)null || target.IsDead())
			{
				ClearRememberedSwarmTarget();
				return;
			}
			_rememberedSwarmTarget = target;
			_rememberedSwarmTargetLastKnownPos = ((Component)target).transform.position;
			_rememberedSwarmTargetUntil = Time.time + Mathf.Max(5f, TameGuildWarsPlugin.ConfigAlarmDurationSeconds.Value);
		}

		private void ClearTargetAndAlert(bool alerted)
		{
			if (!((Object)(object)MonsterAi == (Object)null))
			{
				Traverse.Create((object)MonsterAi).Field("m_targetCreature").SetValue((object)null);
				((BaseAI)MonsterAi).SetAlerted(alerted);
				ClearRememberedSwarmTarget();
			}
		}

		private void ClearRememberedSwarmTarget()
		{
			//IL_0008: 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)
			_rememberedSwarmTarget = null;
			_rememberedSwarmTargetLastKnownPos = Vector3.zero;
			_rememberedSwarmTargetUntil = 0f;
			_swarmTargetReassertTimer = 0f;
		}

		public void ClearGhostAggro()
		{
			ClearAlarm();
			ClearTargetAndAlert(alerted: false);
		}

		private bool HasRememberedSwarmTarget()
		{
			if ((Object)(object)_rememberedSwarmTarget != (Object)null)
			{
				return Time.time <= _rememberedSwarmTargetUntil;
			}
			return false;
		}

		private void RefreshRememberedSwarmTargetPosition()
		{
			//IL_0027: 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)
			if ((Object)(object)_rememberedSwarmTarget != (Object)null && !_rememberedSwarmTarget.IsDead())
			{
				_rememberedSwarmTargetLastKnownPos = ((Component)_rememberedSwarmTarget).transform.position;
			}
		}

		private void ApplyRememberedSwarmChaseState()
		{
			//IL_0037: 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)
			if (!((Object)(object)MonsterAi == (Object)null))
			{
				RefreshRememberedSwarmTargetPosition();
				((BaseAI)MonsterAi).SetAlerted(true);
				Traverse.Create((object)MonsterAi).Field("m_lastKnownTargetPos").SetValue((object)_rememberedSwarmTargetLastKnownPos);
				((BaseAI)MonsterAi).SetPatrolPoint(_rememberedSwarmTargetLastKnownPos);
			}
		}

		private void MaintainRememberedSwarmTarget(float dt)
		{
			if ((Object)(object)_rememberedSwarmTarget == (Object)null)
			{
				return;
			}
			if (_rememberedSwarmTarget.IsPlayer() && TargetingPatches.IsPlayerGhost((Player)/*isinst with value type is only supported in some contexts*/))
			{
				ClearRememberedSwarmTarget();
				return;
			}
			if (_rememberedSwarmTarget.IsDead() || Time.time > _rememberedSwarmTargetUntil)
			{
				LogMobAction("forgot swarm target " + DescribeCharacter(_rememberedSwarmTarget));
				ClearRememberedSwarmTarget();
				return;
			}
			if ((Object)(object)MonsterAi == (Object)null || (Object)(object)Character == (Object)null || Character.IsDead() || Obedience <= 0f || Stance == GuildMobStance.Stay || Stance == GuildMobStance.Follow)
			{
				ClearRememberedSwarmTarget();
				return;
			}
			ApplyRememberedSwarmChaseState();
			if (!((Object)(object)((BaseAI)MonsterAi).GetTargetCreature() == (Object)(object)_rememberedSwarmTarget))
			{
				_swarmTargetReassertTimer += dt;
				if (!(_swarmTargetReassertTimer < 0.5f))
				{
					_swarmTargetReassertTimer = 0f;
					LogMobAction("reasserting swarm target " + DescribeCharacter(_rememberedSwarmTarget) + " after AI cleared target");
					ForceCombatTarget(_rememberedSwarmTarget);
					ApplyRememberedSwarmChaseState();
				}
			}
		}

		private void ForceCombatTarget(Character target)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			Traverse obj = Traverse.Create((object)MonsterAi);
			((BaseAI)MonsterAi).SetAlerted(true);
			MonsterAi.SetTarget(target);
			obj.Field("m_targetCreature").SetValue((object)target);
			obj.Field("m_lastKnownTargetPos").SetValue((object)((Component)target).transform.position);
		}

		private void LogMobAction(string action)
		{
			if (MobActionLoggingEnabled)
			{
				TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)("[GuildMob:" + (Character?.m_name ?? ((Object)this).name) + "] " + action));
			}
		}

		public string GetDebugHoverText()
		{
			if (!MobActionLoggingEnabled)
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			Character val = (((Object)(object)MonsterAi != (Object)null) ? ((BaseAI)MonsterAi).GetTargetCreature() : null);
			if ((Object)(object)val != (Object)null && !val.IsDead())
			{
				list.Add("Target: " + DescribeCharacter(val));
			}
			else
			{
				list.Add("Target: none");
			}
			if (AlarmPlayerId != 0L)
			{
				Player player = Player.GetPlayer(AlarmPlayerId);
				list.Add("Alarm: " + (((Object)(object)player != (Object)null) ? player.GetPlayerName() : AlarmPlayerId.ToString()));
			}
			list.Add($"Stance: {Stance}");
			if (HasRememberedSwarmTarget())
			{
				list.Add("Remembered: " + DescribeCharacter(_rememberedSwarmTarget));
			}
			GameObject val2 = (((Object)(object)MonsterAi != (Object)null) ? MonsterAi.GetFollowTarget() : null);
			string text = ((Stance == GuildMobStance.Follow || Stance == GuildMobStance.FollowAttack) ? string.Empty : " (non-follow)");
			list.Add("Follow: " + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "none") + text);
			return "\n<color=orange>Debug:</color> " + string.Join(" | ", list);
		}

		private static string DescribeCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return "none";
			}
			string text = ((!string.IsNullOrEmpty(character.m_name)) ? character.m_name : ((Object)character).name);
			if (!character.IsPlayer())
			{
				return text;
			}
			return "player " + text;
		}

		private bool ShouldPrioritizeSwarmTarget(Character currentTarget, Character swarmTarget, long swarmAlarmPlayerId)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_0074: 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)
			if ((Object)(object)swarmTarget == (Object)null || swarmTarget.IsDead())
			{
				return false;
			}
			if ((Object)(object)currentTarget == (Object)null || currentTarget.IsDead() || (Object)(object)currentTarget == (Object)(object)swarmTarget)
			{
				return true;
			}
			bool flag = IsAlarmedPlayerTarget(swarmTarget, swarmAlarmPlayerId);
			bool flag2 = IsAlarmedPlayerTarget(currentTarget, AlarmPlayerId);
			if (flag != flag2)
			{
				return flag;
			}
			Vector3 val = ((Component)currentTarget).transform.position - ((Component)this).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			val = ((Component)swarmTarget).transform.position - ((Component)this).transform.position;
			return ((Vector3)(ref val)).sqrMagnitude + 16f < sqrMagnitude;
		}

		private static bool IsAlarmedPlayerTarget(Character target, long alarmPlayerId)
		{
			if (alarmPlayerId == 0L || (Object)(object)target == (Object)null || !target.IsPlayer())
			{
				return false;
			}
			Player val = (Player)(object)((target is Player) ? target : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.GetPlayerID() == alarmPlayerId;
			}
			return false;
		}

		public void CycleStance(Player player)
		{
			int newStance = (int)(Stance + 1) % 6;
			SetStance((GuildMobStance)newStance, player);
		}

		public void ToggleCommandLock(Player player)
		{
			CommandLocked = !CommandLocked;
			((Character)player).Message((MessageType)2, Character.m_name + " command lock: " + (CommandLocked ? "On" : "Off"), 0, (Sprite)null);
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && !m_nview.IsOwner())
			{
				m_nview.ClaimOwnership();
			}
		}

		public void ToggleSkipDecay(Player player)
		{
			SkipDecay = !SkipDecay;
			((Character)player).Message((MessageType)2, Character.m_name + " skip obedience decay: " + (SkipDecay ? "On" : "Off"), 0, (Sprite)null);
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && !m_nview.IsOwner())
			{
				m_nview.ClaimOwnership();
			}
		}

		public bool SetStance(GuildMobStance newStance, Player player = null, bool notifyPlayer = true)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player != (Object)null)
			{
				if (Obedience <= 0f)
				{
					if (notifyPlayer)
					{
						((Character)player).Message((MessageType)2, Character.m_name + " will not obey new orders.", 0, (Sprite)null);
					}
					return false;
				}
				if (CommandLocked)
				{
					if (notifyPlayer)
					{
						((Character)player).Message((MessageType)2, Character.m_name + " command is locked!", 0, (Sprite)null);
					}
					return false;
				}
			}
			Stance = newStance;
			if ((Object)(object)player != (Object)null && notifyPlayer)
			{
				((Character)player).Message((MessageType)2, $"{Character.m_name} order: {newStance}", 0, (Sprite)null);
			}
			string arg = (((Object)(object)player != (Object)null) ? player.GetPlayerName() : "system");
			LogMobAction($"stance changed to {newStance} by {arg}");
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && !m_nview.IsOwner())
			{
				m_nview.ClaimOwnership();
			}
			switch (newStance)
			{
			case GuildMobStance.Guard:
			case GuildMobStance.Stay:
			case GuildMobStance.Static:
				_stanceAnchorPoint = ((Component)this).transform.position;
				FollowTargetPlayerId = 0L;
				ClearNonFollowOrders(_stanceAnchorPoint, newStance == GuildMobStance.Stay || newStance == GuildMobStance.Static);
				((BaseAI)MonsterAi).SetPatrolPoint(_stanceAnchorPoint);
				break;
			case GuildMobStance.GuardWard:
				FollowTargetPlayerId = 0L;
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: false);
				break;
			case GuildMobStance.Follow:
			case GuildMobStance.FollowAttack:
			{
				Player val = player ?? Player.m_localPlayer;
				FollowTargetPlayerId = (((Object)(object)val != (Object)null) ? val.GetPlayerID() : TamerID);
				SetVanillaTameableFollowState(val);
				if ((Object)(object)player != (Object)null)
				{
					MonsterAi.SetFollowTarget(((Component)player).gameObject);
					((BaseAI)MonsterAi).ResetPatrolPoint();
					break;
				}
				MonsterAI monsterAi = MonsterAi;
				Player localPlayer = Player.m_localPlayer;
				monsterAi.SetFollowTarget((localPlayer != null) ? ((Component)localPlayer).gameObject : null);
				((BaseAI)MonsterAi).ResetPatrolPoint();
				break;
			}
			}
			return true;
		}

		private void EnsureStanceAnchor()
		{
			//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_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)
			if (_stanceAnchorPoint == Vector3.zero)
			{
				_stanceAnchorPoint = ((Component)this).transform.position;
			}
		}

		private void EnforceStanceLeash(float maxDistance, bool clearCombatTarget)
		{
			//IL_000c: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			EnsureStanceAnchor();
			if (!(Vector3.Distance(((Component)this).transform.position, _stanceAnchorPoint) <= maxDistance))
			{
				ClearNonFollowOrders(_stanceAnchorPoint, clearCombatState: false);
				if (clearCombatTarget && !((Object)(object)((BaseAI)MonsterAi).GetTargetCreature() == (Object)null))
				{
					Traverse.Create((object)MonsterAi).Field("m_targetCreature").SetValue((object)null);
					Traverse.Create((object)MonsterAi).Method("SetAlerted", new object[1] { false }).GetValue();
				}
			}
		}

		private void RefreshFollowTarget()
		{
			long num = FollowTargetPlayerId;
			if (num == 0L)
			{
				num = TamerID;
				if (num != 0L)
				{
					FollowTargetPlayerId = num;
				}
			}
			if (num == 0L)
			{
				ClearVanillaTameableFollowState();
				MonsterAi.SetFollowTarget((GameObject)null);
				return;
			}
			Player player = Player.GetPlayer(num);
			if ((Object)(object)player == (Object)null)
			{
				MonsterAi.SetFollowTarget((GameObject)null);
				return;
			}
			SetVanillaTameableFollowState(player);
			if ((Object)(object)MonsterAi.GetFollowTarget() != (Object)(object)((Component)player).gameObject)
			{
				MonsterAi.SetFollowTarget(((Component)player).gameObject);
				((BaseAI)MonsterAi).ResetPatrolPoint();
			}
		}

		private void ClearNonFollowOrders(Vector3 patrolPoint, bool clearCombatState)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)MonsterAi == (Object)null))
			{
				GameObject followTarget = MonsterAi.GetFollowTarget();
				if ((Object)(object)followTarget != (Object)null)
				{
					LogMobAction($"clearing stale follow target {((Object)followTarget).name} for stance {Stance}");
				}
				ClearVanillaTameableFollowState();
				MonsterAi.SetFollowTarget((GameObject)null);
				((BaseAI)MonsterAi).ResetPatrolPoint();
				((BaseAI)MonsterAi).SetPatrolPoint(patrolPoint);
				if (clearCombatState)
				{
					ClearAlarm();
					ClearRememberedSwarmTarget();
					ClearTargetAndAlert(alerted: false);
				}
			}
		}

		private void ClearVanillaTameableFollowState()
		{
			SetVanillaTameableFollowState(null);
		}

		private void SetVanillaTameableFollowState(Player followPlayer)
		{
			if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid())
			{
				ZDO zDO = m_nview.GetZDO();
				if (zDO != null)
				{
					zDO.Set(ZDOVars.s_follow, ((Object)(object)followPlayer != (Object)null) ? followPlayer.GetPlayerName() : string.Empty);
				}
			}
		}

		private void RefreshOrdersForLoadedArea()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if (_ordersRefreshedForCurrentLoad || (Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner() || (Object)(object)MonsterAi == (Object)null || (Object)(object)Character == (Object)null || !Character.IsTamed())
			{
				return;
			}
			_ordersRefreshedForCurrentLoad = true;
			if (Obedience <= 0f)
			{
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: true);
				LogMobAction("refreshed loaded orders: no obedience");
				return;
			}
			switch (Stance)
			{
			case GuildMobStance.Guard:
				EnsureStanceAnchor();
				ClearRememberedSwarmTarget();
				ClearNonFollowOrders(_stanceAnchorPoint, clearCombatState: false);
				break;
			case GuildMobStance.Stay:
			case GuildMobStance.Static:
				_stanceAnchorPoint = ((Component)this).transform.position;
				ClearNonFollowOrders(_stanceAnchorPoint, clearCombatState: true);
				break;
			case GuildMobStance.GuardWard:
				ClearRememberedSwarmTarget();
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: false);
				break;
			case GuildMobStance.Follow:
			case GuildMobStance.FollowAttack:
				RefreshFollowTarget();
				break;
			}
			LogMobAction($"refreshed loaded orders for stance {Stance}");
		}

		public bool TryClaim(Player player, string guildName)
		{
			long playerID = player.GetPlayerID();
			if ((TamerID == 0L || Obedience <= 0f || TamerID == playerID) && guildName != "No Guild")
			{
				TamerID = playerID;
				TamerName = player.GetPlayerName();
				GuildName = guildName;
				Obedience = MaxObedience;
				ClearAlarm();
				ClearTargetAndAlert(alerted: false);
				if (!Object.op_Implicit((Object)(object)((Component)this).gameObject.GetComponent<MonsterAI>()))
				{
					return true;
				}
				SetStance(GuildMobStance.Guard);
				return true;
			}
			return false;
		}

		public bool TryChangeTamer(Player player)
		{
			long playerID = player.GetPlayerID();
			if (Obedience <= 0f && TamerID != playerID)
			{
				TamerID = playerID;
				TamerName = player.GetPlayerName();
				ClearAlarm();
				ClearTargetAndAlert(alerted: false);
				return true;
			}
			return false;
		}

		public bool TryChangeGuild(Player player, string newGuildName)
		{
			if (TamerID == player.GetPlayerID() && Obedience > 0f)
			{
				GuildName = newGuildName;
				ClearAlarm();
				ClearTargetAndAlert(alerted: false);
				return true;
			}
			return false;
		}

		public bool IsSameGuild(string otherGuildName)
		{
			string guildName = GuildName;
			if (string.IsNullOrEmpty(guildName) || string.IsNullOrEmpty(otherGuildName))
			{
				return false;
			}
			return guildName == otherGuildName;
		}

		private void UpdateObedience()
		{
			//IL_0082: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner() || SkipDecay)
			{
				return;
			}
			long tamerID = TamerID;
			bool flag = tamerID == 0;
			float obedience = Obedience;
			if (flag && obedience <= 0f)
			{
				return;
			}
			bool flag2 = false;
			Player val = null;
			string text = string.Empty;
			if (!flag)
			{
				val = Player.GetPlayer(tamerID);
				if ((Object)(object)val != (Object)null)
				{
					text = GuildUtils.GetPlayerGuildName(val);
					if (Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) <= TamerProximityRange)
					{
						flag2 = true;
					}
				}
			}
			if (flag2)
			{
				if (obedience < MaxObedience)
				{
					Obedience = obedience + ObedienceRecoverRate;
				}
				return;
			}
			float num = ObedienceDecayRate;
			bool flag3 = false;
			bool flag4 = false;
			if (!flag)
			{
				foreach (Player allPlayer in Player.GetAllPlayers())
				{
					if (Vector3.Distance(((Component)this).transform.position, ((Component)allPlayer).transform.position) <= TamerProximityRange)
					{
						string playerGuildName = GuildUtils.GetPlayerGuildName(allPlayer);
						if (!string.IsNullOrEmpty(playerGuildName) && playerGuildName == GuildName && playerGuildName != "No Guild")
						{
							flag3 = true;
						}
						else
						{
							flag4 = true;
						}
					}
				}
			}
			if (flag4 && !flag3)
			{
				num *= TameGuildWarsPlugin.ConfigNonGuildMemberDecayMultiplier.Value;
			}
			int num2;
			int num3;
			if (!string.IsNullOrEmpty(text))
			{
				num2 = ((text == "No Guild") ? 1 : 0);
				if (num2 == 0 && !string.IsNullOrEmpty(GuildName))
				{
					num3 = ((text != GuildName) ? 1 : 0);
					goto IL_01ae;
				}
			}
			else
			{
				num2 = 1;
			}
			num3 = 0;
			goto IL_01ae;
			IL_01ae:
			bool flag5 = (byte)num3 != 0;
			if (((uint)num2 | (flag5 ? 1u : 0u)) != 0)
			{
				num *= TameGuildWarsPlugin.ConfigNoGuildDecayMultiplier.Value;
			}
			float num4 = obedience - num;
			if (num4 <= 0f)
			{
				Obedience = 0f;
				ClearAlarm();
				TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)$"Mob {Character.m_name} lost obedience to tamer {tamerID} and reverted to neutral.");
			}
			else
			{
				Obedience = num4;
			}
		}

		private void RPC_ObedienceDrop(long uid)
		{
			if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid() && m_nview.IsOwner() && !string.IsNullOrEmpty(GuildName) && !(Obedience <= 0f))
			{
				if (Obedience <= ObedienceDrop)
				{
					Obedience = 0f;
				}
				Obedience -= ObedienceDrop;
			}
		}

		private void RPC_AddConfusion(long uid, float amount)
		{
			if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid() && m_nview.IsOwner() && !(amount <= 0f))
			{
				Confusion = Mathf.Clamp(Confusion + amount, 0f, 100f);
			}
		}

		private void UpdateConfusion()
		{
			if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid() || !m_nview.IsOwner())
			{
				return;
			}
			float confusion = Confusion;
			if (!(confusion > 0f))
			{
				return;
			}
			float num = TameGuildWarsPlugin.ConfigConfusionDurationSeconds.Value;
			if (num <= 0f)
			{
				num = 1f;
			}
			Confusion = Mathf.Max(0f, confusion - 100f / num * 2f);
			if (Confusion > 50f)
			{
				ClearAlarm();
				if (Random.value < 0.3f)
				{
					List<Character> list = Character.GetAllCharacters().FindAll(IsValidConfusionTarget);
					if (list.Count > 0)
					{
						Character val = list[Random.Range(0, list.Count)];
						ForceCombatTarget(val);
						LogMobAction("confused: targeting " + DescribeCharacter(val));
					}
					else if (Random.value < 0.5f)
					{
						ClearTargetAndAlert(alerted: true);
					}
				}
			}
			else if ((Object)(object)MonsterAi != (Object)null && (Object)(object)((BaseAI)MonsterAi).GetTargetCreature() != (Object)null && AlarmPlayerId != 0L)
			{
				ClearAlarm();
			}
		}

		private bool IsValidConfusionTarget(Character candidate)
		{
			//IL_0027: 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)
			//IL_0037: 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)
			if ((Object)(object)candidate == (Object)null || (Object)(object)candidate == (Object)(object)Character || candidate.IsDead())
			{
				return false;
			}
			Vector3 val = ((Component)candidate).transform.position - ((Component)this).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 900f)
			{
				return false;
			}
			if (candidate.IsPlayer() && TargetingPatches.IsPlayerGhost((Player)(object)((candidate is Player) ? candidate : null)))
			{
				return false;
			}
			return true;
		}

		public void UpdateSwarmAggro(float dt)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			MaintainRememberedSwarmTarget(dt);
			if (string.IsNullOrEmpty(GuildName) || Obedience <= 0f || Stance == GuildMobStance.Stay || Stance == GuildMobStance.Follow)
			{
				return;
			}
			_swarmCheckTimer += dt;
			if (_swarmCheckTimer < SwarmCheckInterval)
			{
				return;
			}
			_swarmCheckTimer = 0f;
			float num = SwarmRadius * SwarmRadius;
			Vector3 position = ((Component)this).transform.position;
			foreach (TamedGuildMob activeGuildMob in ActiveGuildMobs)
			{
				if ((Object)(object)activeGuildMob == (Object)null || (Object)(object)activeGuildMob == (Object)(object)this || (Object)(object)activeGuildMob.Character == (Object)null || (Object)(object)activeGuildMob.MonsterAi == (Object)null || !activeGuildMob.IsSameGuild(GuildName))
				{
					continue;
				}
				Vector3 val = ((Component)activeGuildMob).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude > num)
				{
					continue;
				}
				Character targetCreature = ((BaseAI)activeGuildMob.MonsterAi).GetTargetCreature();
				if (!((Object)(object)targetCreature != (Object)null) || targetCreature.IsDead())
				{
					continue;
				}
				bool flag = false;
				if (targetCreature.IsPlayer())
				{
					Player val2 = (Player)(object)((targetCreature is Player) ? targetCreature : null);
					if ((Object)(object)val2 != (Object)null && activeGuildMob.AlarmPlayerId == val2.GetPlayerID())
					{
						flag = true;
					}
				}
				else
				{
					flag = true;
				}
				if (flag)
				{
					TryApplySwarmTarget(targetCreature, activeGuildMob.AlarmPlayerId, activeGuildMob.AlarmRaisedTicks, "fallback swarm");
					break;
				}
			}
		}

		public void UpdateStanceBehavior(float dt)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			RefreshOrdersForLoadedArea();
			_stanceUpdateTimer += dt;
			if (_stanceUpdateTimer < 2f)
			{
				return;
			}
			_stanceUpdateTimer = 0f;
			UpdateAlarmState();
			Character targetCreature = ((BaseAI)MonsterAi).GetTargetCreature();
			if ((Object)(object)targetCreature != (Object)null && !((BaseAI)MonsterAi).IsEnemy(targetCreature))
			{
				ClearAlarm();
				ClearTargetAndAlert(alerted: false);
			}
			if (Obedience <= 0f)
			{
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: true);
				if ((Object)(object)((BaseAI)MonsterAi).GetTargetCreature() != (Object)null)
				{
					Traverse.Create((object)MonsterAi).Field("m_targetCreature").SetValue((object)null);
					Traverse.Create((object)MonsterAi).Method("SetAlerted", new object[1] { false }).GetValue();
				}
			}
			else if (HasRememberedSwarmTarget())
			{
				ApplyRememberedSwarmChaseState();
			}
			else if (Stance == GuildMobStance.GuardWard)
			{
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: false);
				if ((Object)(object)((BaseAI)MonsterAi).GetTargetCreature() != (Object)null)
				{
					return;
				}
				PrivateArea val = null;
				float num = float.MaxValue;
				foreach (PrivateArea allArea in PrivateArea.m_allAreas)
				{
					if (allArea.IsEnabled())
					{
						float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)allArea).transform.position);
						if (num2 < num)
						{
							num = num2;
							val = allArea;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					float radius = val.m_radius;
					float num3 = Vector3.Distance(((Component)this).transform.position, _currentWardPatrolPoint);
					_wardPatrolStuckTimer += dt;
					if (_currentWardPatrolPoint == Vector3.zero || num3 < 6f || _wardPatrolStuckTimer > 20f)
					{
						_wardPatrolStuckTimer = 0f;
						_wardPatrolAngle += Random.Range(30f, 60f);
						if (_wardPatrolAngle >= 360f)
						{
							_wardPatrolAngle -= 360f;
						}
						float num4 = _wardPatrolAngle * ((float)Math.PI / 180f);
						_currentWardPatrolPoint = ((Component)val).transform.position + new Vector3(Mathf.Cos(num4) * radius, 0f, Mathf.Sin(num4) * radius);
						float y = default(float);
						if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(_currentWardPatrolPoint, ref y, 1000))
						{
							_currentWardPatrolPoint.y = y;
						}
					}
					((BaseAI)MonsterAi).SetPatrolPoint(_currentWardPatrolPoint);
				}
				else
				{
					((BaseAI)MonsterAi).SetPatrolPoint(((Component)this).transform.position);
				}
			}
			else if (Stance == GuildMobStance.Stay)
			{
				ClearNonFollowOrders(((Component)this).transform.position, clearCombatState: true);
				if ((Object)(object)((BaseAI)MonsterAi).GetTargetCreature() != (Object)null)
				{
					Traverse.Create((object)MonsterAi).Field("m_targetCreature").SetValue((object)null);
					Traverse.Create((object)MonsterAi).Method("SetAlerted", new object[1] { false }).GetValue();
				}
			}
			else if (Stance == GuildMobStance.Guard)
			{
				EnforceStanceLeash(GuardMaxDistance, clearCombatTarget: true);
				ClearNonFollowOrders((_stanceAnchorPoint == Vector3.zero) ? ((Component)this).transform.position : _stanceAnchorPoint, clearCombatState: false);
			}
			else if (Stance == GuildMobStance.Follow || Stance == GuildMobStance.FollowAttack)
			{
				RefreshFollowTarget();
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			Tameable component = ((Component)this).GetComponent<Tameable>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return component.Interact(user, hold, alt);
			}
			if (!m_nview.IsValid() || hold || (Object)(object)Character == (Object)null)
			{
				return false;
			}
			if (!Character.IsTamed())
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || !Character.IsTamed())
			{
				return true;
			}
			TamedGuildMob component2 = ((Component)this).GetComponent<TamedGuildMob>();
			if ((Object)(object)component2 != (Object)null)
			{
				long playerID = val.GetPlayerID();
				long tamerID = component2.TamerID;
				float obedience = component2.Obedience;
				string text = GuildUtils.GetPlayerGuildName(val);
				if (string.IsNullOrEmpty(text))
				{
					text = "No Guild";
				}
				if (tamerID == 0L || obedience <= 0f)
				{
					if (tamerID != 0L && tamerID != playerID)
					{
						if (!hold)
						{
							((Character)val).Message((MessageType)2, "This beast is wild, but belongs to another.", 0, (Sprite)null);
						}
						return false;
					}
					if ((Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && text != "No Guild" && component2.TryClaim(val, text))
					{
						((Character)val).Message((MessageType)2, "Mob claimed for guild: " + text, 0, (Sprite)null);
						return false;
					}
				}
				else if (tamerID == playerID && text != component2.GuildName && text != "No Guild")
				{
					if (alt)
					{
						return true;
					}
					if (component2.TryChangeGuild(val, text))
					{
						((Character)val).Message((MessageType)2, "Mob updated to guild: " + text, 0, (Sprite)null);
						return false;
					}
				}
			}
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		private void UpdateAlarmState()
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (AlarmPlayerId == 0L)
			{
				return;
			}
			float num = Mathf.Max(0f, TameGuildWarsPlugin.ConfigAlarmDurationSeconds.Value);
			if (num == 0f)
			{
				ClearAlarm();
				return;
			}
			long alarmRaisedTicks = AlarmRaisedTicks;
			if (alarmRaisedTicks > 0)
			{
				TimeSpan timeSpan = new TimeSpan(DateTime.UtcNow.Ticks - alarmRaisedTicks);
				if (timeSpan.TotalSeconds >= (double)num)
				{
					ClearAlarm();
					return;
				}
			}
			Player player = Player.GetPlayer(AlarmPlayerId);
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (TargetingPatches.IsPlayerGhost(player))
			{
				ClearAlarm();
				return;
			}
			float num2 = Mathf.Max(0f, TameGuildWarsPlugin.ConfigAlarmLeashDistance.Value);
			if (num2 > 0f && Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position) > num2)
			{
				ClearAlarm();
			}
		}

		public void inheritGuild(TamedGuildMob fromTGM, float obedience = -1f, bool newTamer = true)
		{
			if (!((Object)(object)fromTGM == (Object)null) && fromTGM.GuildName != null)
			{
				GuildName = fromTGM.GuildName;
				if (obedience >= 0f)
				{
					Obedience = obedience;
				}
				else
				{
					Obedience = childStartingObedience;
				}
				if (newTamer)
				{
					FindNearestTamer();
					return;
				}
				TamerID = fromTGM.TamerID;
				TamerName = fromTGM.TamerName;
			}
		}

		public void EggStart(EggGrow growup)
		{
			if (!((Object)(object)growup == (Object)null))
			{
				Obedience = childStartingObedience;
				FindNearestTamer();
			}
		}

		private bool FindNearestTamer()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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)
			//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)
			if (TamerID != 0L)
			{
				return true;
			}
			TameGuildWarsPlugin.TameGuildWarsLogger.LogInfo((object)$"Creature:{((Object)this).name}, Guild:{GuildName}, loc:{((Component)this).transform.position}, obedience:{Obedience}");