Decompiled source of Instinct v1.0.0

Instinct.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Instinct
{
	[BepInPlugin("com.razaotium.instinct", "Instinct", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public sealed class Fixed<T>
		{
			public readonly T Value;

			public Fixed(T v)
			{
				Value = v;
			}
		}

		public const string Guid = "com.razaotium.instinct";

		public const string Version = "1.0.0";

		private static ConfigEntry<bool> serverEnabled;

		private static bool localEnabled = true;

		public static Fixed<int> Tokens;

		public static Fixed<float> RingGap;

		public static Fixed<float> Spacing;

		public static Fixed<string> UseGameIn;

		public static Fixed<bool> ReadBlock;

		public static Fixed<bool> PunishTired;

		public static Fixed<bool> Flyers;

		public static Fixed<float> Recovery;

		public static Fixed<bool> Band;

		public static Fixed<bool> Audience;

		public static Fixed<bool> SideTeam;

		public static Fixed<bool> AfterDraw;

		public static Fixed<bool> CurveIn;

		public static Fixed<bool> RearWatch;

		public static Fixed<bool> Pincer;

		public static Fixed<bool> TurnWalk;

		public static Fixed<bool> NoCrossFront;

		public static Fixed<bool> PressOnMove;

		public static Fixed<bool> HitNow;

		public static Fixed<bool> Intercept;

		public static Fixed<bool> ChaseRunner;

		public static Fixed<bool> PassStrike;

		public static Fixed<bool> SpinWindup;

		public static Fixed<bool> KeepPressure;

		public static Fixed<bool> FreeArchers;

		public static Fixed<bool> Suppress;

		public static Fixed<bool> Dodge;

		public static Fixed<bool> Bubble;

		public static Fixed<bool> FlushOut;

		public static Fixed<bool> Shout;

		public static Fixed<float> DodgeChance;

		public static Fixed<float> RetreatChance;

		public static Fixed<bool> PredictReach;

		public static Fixed<float> Stagger;

		public static Fixed<bool> SteadyTarget;

		public static Fixed<float> Split;

		public static Fixed<string> NoClimb;

		public static Fixed<bool> Bridges;

		public static Fixed<float> StrikeDepth;

		public static Fixed<string> BridgePieces;

		public static Fixed<string> Styles;

		public static Fixed<float> NearGap;

		public static Fixed<float> FarGap;

		public static Fixed<float> DefendRadius;

		public static Fixed<float> Patience;

		public static Fixed<bool> FlankBehind;

		public static Fixed<float> AllyDown;

		public static Fixed<bool> StarSkill;

		private Harmony harmony;

		private float switchWarn;

		public static bool EnabledNow
		{
			get
			{
				if (serverEnabled == null)
				{
					return localEnabled;
				}
				return serverEnabled.Value;
			}
		}

		public static bool Active
		{
			get
			{
				if (EnabledNow)
				{
					return !ServerSwitch.ServerOff;
				}
				return false;
			}
		}

		private static Fixed<T> Opt<T>(T v)
		{
			return new Fixed<T>(v);
		}

		private void Awake()
		{
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Expected O, but got Unknown
			if (Application.isBatchMode)
			{
				serverEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "false turns Instinct off for every connected player; true turns it on. Re-read every 10 seconds.");
			}
			Tokens = Opt(2);
			RingGap = Opt(2.5f);
			Spacing = Opt(2.2f);
			UseGameIn = Opt("Draugr:pass,Skeleton:still,Skeleton:back_off,Skeleton:pass,Wolf:still,Wolf:strafe");
			ReadBlock = Opt(v: true);
			PunishTired = Opt(v: true);
			Flyers = Opt(v: true);
			Suppress = Opt(v: true);
			Dodge = Opt(v: true);
			DodgeChance = Opt(0.5f);
			Bubble = Opt(v: true);
			RetreatChance = Opt(0.5f);
			FlushOut = Opt(v: true);
			Shout = Opt(v: true);
			Band = Opt(v: true);
			Audience = Opt(v: true);
			SideTeam = Opt(v: true);
			AfterDraw = Opt(v: true);
			TurnWalk = Opt(v: true);
			NoCrossFront = Opt(v: true);
			PressOnMove = Opt(v: true);
			PassStrike = Opt(v: true);
			FreeArchers = Opt(v: true);
			KeepPressure = Opt(v: true);
			SpinWindup = Opt(v: true);
			StrikeDepth = Opt(0.55f);
			ChaseRunner = Opt(v: true);
			HitNow = Opt(v: true);
			Intercept = Opt(v: true);
			Pincer = Opt(v: true);
			CurveIn = Opt(v: true);
			RearWatch = Opt(v: true);
			Recovery = Opt(0.5f);
			Stagger = Opt(0.45f);
			Bridges = Opt(v: true);
			BridgePieces = Opt("log,beam,pole,floor_1x1");
			NoClimb = Opt("stair");
			Split = Opt(0.5f);
			SteadyTarget = Opt(v: true);
			PredictReach = Opt(v: true);
			Styles = Opt("Wolf=close,Ulv=close,Fenring=close,Draugr_Ranged=far,GoblinArcher=far");
			NearGap = Opt(0.8f);
			FarGap = Opt(4.5f);
			DefendRadius = Opt(12f);
			Patience = Opt(6f);
			FlankBehind = Opt(v: true);
			AllyDown = Opt(1.5f);
			StarSkill = Opt(v: true);
			harmony = new Harmony("com.razaotium.instinct");
			harmony.PatchAll(typeof(Patches));
		}

		private void Update()
		{
			try
			{
				ServerSwitch.Tick(this);
			}
			catch (Exception ex)
			{
				if (Time.time > switchWarn)
				{
					switchWarn = Time.time + 30f;
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Instinct: server switch " + ex.Message));
				}
			}
		}

		private void OnDestroy()
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Director.Fights.Clear();
			Brain.States.Clear();
		}
	}
	internal static class Acc
	{
		public static readonly FieldRef<BaseAI, Character> Char = AccessTools.FieldRefAccess<BaseAI, Character>("m_character");

		public static readonly FieldRef<MonsterAI, Character> Target = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature");

		public static readonly FieldRef<MonsterAI, float> SinceSensed = AccessTools.FieldRefAccess<MonsterAI, float>("m_timeSinceSensedTargetCreature");

		public static readonly FieldRef<MonsterAI, float> MinAttackInterval = AccessTools.FieldRefAccess<MonsterAI, float>("m_minAttackInterval");
	}
	internal static class Reach
	{
		public class Info
		{
			public float Reach;

			public float Windup = 0.7f;

			public int N;
		}

		private class Pending
		{
			public float T;

			public Vector3 Pos;

			public Vector3 Fwd;

			public string Key;

			public Attack A;
		}

		private static readonly Dictionary<string, Info> Learned = new Dictionary<string, Info>();

		private static readonly Dictionary<Humanoid, Pending> Open = new Dictionary<Humanoid, Pending>();

		private static readonly FieldRef<Humanoid, Attack> CurAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack");

		private static readonly FieldRef<Attack, Humanoid> AttChar = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		public static string Key(Character me, ItemData w)
		{
			return Utils.GetPrefabName(((Component)me).gameObject) + "|" + w.m_shared.m_name;
		}

		public static bool Melee(Attack a)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			if (a != null)
			{
				if ((int)a.m_attackType != 0 && (int)a.m_attackType != 1)
				{
					return (int)a.m_attackType == 4;
				}
				return true;
			}
			return false;
		}

		private static Transform Origin(Humanoid h, Attack a)
		{
			if (!string.IsNullOrEmpty(a.m_attackOriginJoint))
			{
				Transform val = Utils.FindChild(((Character)h).GetVisual().transform, a.m_attackOriginJoint, (IterativeSearchType)0);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return ((Component)h).transform;
		}

		private static float Sweep(Attack a)
		{
			return a.m_attackRange + a.m_attackRayWidth + Mathf.Max(0f, a.m_attackRayWidthCharExtra);
		}

		public static Info Get(Humanoid h, ItemData w)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			string key = Key((Character)(object)h, w);
			if (Learned.TryGetValue(key, out var value))
			{
				return value;
			}
			Attack attack = w.m_shared.m_attack;
			value = new Info();
			if (Melee(attack))
			{
				Vector3 val = Origin(h, attack).position - ((Component)h).transform.position;
				value.Reach = Mathf.Max(0.5f, Vector3.Dot(new Vector3(val.x, 0f, val.z), ((Component)h).transform.forward)) + Sweep(attack);
			}
			else
			{
				value.Reach = w.m_shared.m_aiAttackRange;
			}
			Learned[key] = value;
			return value;
		}

		public static void Started(Humanoid h)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)h == (Object)null) && !((Character)h).IsPlayer())
			{
				Attack a = CurAttack.Invoke(h);
				ItemData currentWeapon = h.GetCurrentWeapon();
				if (Melee(a) && currentWeapon != null)
				{
					Vector3 forward = ((Component)h).transform.forward;
					forward.y = 0f;
					Open[h] = new Pending
					{
						T = Time.time,
						Pos = ((Component)h).transform.position,
						Fwd = ((Vector3)(ref forward)).normalized,
						Key = Key((Character)(object)h, currentWeapon),
						A = a
					};
				}
			}
		}

		public static void Triggered(Attack a)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			Humanoid val = AttChar.Invoke(a);
			if ((Object)(object)val == (Object)null || !Open.TryGetValue(val, out var value) || value.A != a)
			{
				return;
			}
			Open.Remove(val);
			MonsterAI component = ((Component)val).GetComponent<MonsterAI>();
			if ((Object)(object)component != (Object)null)
			{
				Director.Landed(component);
			}
			float num = Time.time - value.T;
			if (!(num <= 0.02f) && !(num > 3f))
			{
				Vector3 val2 = Origin(val, a).position - value.Pos;
				val2.y = 0f;
				float num2 = Mathf.Max(0.3f, Vector3.Dot(val2, value.Fwd)) + Sweep(a);
				if (!Learned.TryGetValue(value.Key, out var value2))
				{
					value2 = new Info();
					Learned[value.Key] = value2;
				}
				if (value2.N == 0)
				{
					value2.Reach = num2;
					value2.Windup = num;
				}
				else
				{
					value2.Reach = Mathf.Lerp(value2.Reach, num2, 0.25f);
					value2.Windup = Mathf.Lerp(value2.Windup, num, 0.25f);
				}
				value2.N++;
			}
		}

		public static void Gaps(Character me, Character t, Info i, out float now, out float then)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)t).transform.position - ((Component)me).transform.position;
			val.y = 0f;
			now = ((Vector3)(ref val)).magnitude - t.GetRadius();
			Vector3 velocity = t.GetVelocity();
			velocity.y = 0f;
			Vector3 val2 = val + velocity * i.Windup;
			then = ((Vector3)(ref val2)).magnitude - t.GetRadius();
		}

		public static void Prune()
		{
			List<Humanoid> list = null;
			foreach (KeyValuePair<Humanoid, Pending> item in Open)
			{
				if ((Object)(object)item.Key == (Object)null || Time.time - item.Value.T > 4f)
				{
					(list ?? (list = new List<Humanoid>())).Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Humanoid item2 in list)
			{
				Open.Remove(item2);
			}
		}
	}
	internal static class Targeting
	{
		private class Mem
		{
			public Character Cur;

			public float Since = -99f;

			public Character Rival;

			public float RivalSince = -99f;

			public readonly Dictionary<Character, float> Dmg = new Dictionary<Character, float>();

			public float DmgAt;

			public Character LastHitter;

			public float LastHitAt = -99f;
		}

		private static readonly Dictionary<BaseAI, Mem> Mems = new Dictionary<BaseAI, Mem>();

		private static readonly FieldRef<MonsterAI, float> UpdateTimer = AccessTools.FieldRefAccess<MonsterAI, float>("m_updateTargetTimer");

		private const float MinCommit = 3f;

		private const float Dwell = 0.75f;

		private const float Margin = 1.3f;

		private const float MarginClose = 1.1f;

		private const float HalfLife = 8f;

		private static Mem Get(BaseAI ai)
		{
			if (!Mems.TryGetValue(ai, out var value))
			{
				value = new Mem();
				Mems[ai] = value;
			}
			return value;
		}

		public static bool Applies(BaseAI ai)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			if (!Plugin.Active || !Plugin.SteadyTarget.Value || !(ai is MonsterAI))
			{
				return false;
			}
			Character val = Acc.Char.Invoke(ai);
			if ((Object)(object)val == (Object)null || val.IsTamed() || val.IsBoss() || (int)val.GetFaction() == 8)
			{
				return false;
			}
			return true;
		}

		private static void Decay(Mem m)
		{
			float num = Time.time - m.DmgAt;
			m.DmgAt = Time.time;
			if (num <= 0f || m.Dmg.Count == 0)
			{
				return;
			}
			float num2 = Mathf.Pow(0.5f, num / 8f);
			foreach (Character item in new List<Character>(m.Dmg.Keys))
			{
				float num3 = m.Dmg[item] * num2;
				if ((Object)(object)item == (Object)null || num3 < 0.05f)
				{
					m.Dmg.Remove(item);
				}
				else
				{
					m.Dmg[item] = num3;
				}
			}
		}

		public static void Damaged(BaseAI ai, float damage, Character attacker)
		{
			if (!((Object)(object)attacker == (Object)null) && Applies(ai))
			{
				Character val = Acc.Char.Invoke(ai);
				Mem mem = Get(ai);
				Decay(mem);
				float num = Mathf.Clamp(damage / Mathf.Max(1f, val.GetMaxHealth()), 0.02f, 1f) * 60f;
				mem.Dmg.TryGetValue(attacker, out var value);
				mem.Dmg[attacker] = value + num;
				mem.LastHitter = attacker;
				mem.LastHitAt = Time.time;
				MonsterAI val2 = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)attacker != (Object)(object)Acc.Target.Invoke(val2))
				{
					UpdateTimer.Invoke(val2) = Mathf.Min(UpdateTimer.Invoke(val2), 0.1f);
				}
			}
		}

		private static float Threat(MonsterAI ai, Character me, Character c, Mem m)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)c).transform.position - ((Component)me).transform.position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float num = 10f / (1f + magnitude / 4f) / (1f + Plugin.Split.Value * (float)Director.CountOn(c, ai));
			if (m.Dmg.TryGetValue(c, out var value))
			{
				num += value;
			}
			return num;
		}

		public static Character Choose(MonsterAI ai, Character vanilla)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)vanilla == (Object)null)
			{
				return null;
			}
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			Character val2 = Acc.Target.Invoke(ai);
			Mem mem = Get((BaseAI)(object)ai);
			float time = Time.time;
			Decay(mem);
			if ((Object)(object)mem.Cur != (Object)(object)val2)
			{
				mem.Cur = val2;
				mem.Since = time;
			}
			bool flag = (Object)(object)val2 != (Object)null && !val2.IsDead() && BaseAI.IsEnemy(val, val2) && ((BaseAI)ai).CanSenseTarget(val2);
			Character val3 = null;
			float num = -1f;
			float num2 = -1f;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || allCharacter.IsDead() || allCharacter.m_aiSkipTarget || !BaseAI.IsEnemy(val, allCharacter) || ((Object)(object)allCharacter == (Object)(object)Player.m_localPlayer && CinematicsManager.IsPlaying()))
				{
					continue;
				}
				BaseAI baseAI = allCharacter.GetBaseAI();
				if ((!((Object)(object)baseAI != (Object)null) || !baseAI.IsSleeping()) && ((BaseAI)ai).CanSenseTarget(allCharacter))
				{
					float num3 = Threat(ai, val, allCharacter, mem);
					if ((Object)(object)allCharacter == (Object)(object)val2)
					{
						num2 = num3;
					}
					if (num3 > num)
					{
						num = num3;
						val3 = allCharacter;
					}
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				return vanilla;
			}
			Character val4 = val3;
			if (flag && (Object)(object)val3 != (Object)(object)val2 && num2 > 0f)
			{
				float num4 = Vector3.Distance(((Component)val3).transform.position, ((Component)val).transform.position);
				bool flag2 = (Object)(object)val3 == (Object)(object)mem.LastHitter && time - mem.LastHitAt < 1.5f;
				bool flag3 = num > num2 * ((num4 < 3f) ? 1.1f : 1.3f);
				if ((Object)(object)mem.Rival != (Object)(object)val3)
				{
					mem.Rival = val3;
					mem.RivalSince = time;
				}
				bool flag4 = time - mem.RivalSince >= 0.75f || flag2;
				bool flag5 = time - mem.Since < 3f && !flag2;
				if (!flag3 || !flag4 || flag5)
				{
					val4 = val2;
					if (flag3)
					{
						UpdateTimer.Invoke(ai) = Mathf.Min(UpdateTimer.Invoke(ai), 0.3f);
					}
				}
			}
			else
			{
				mem.Rival = null;
			}
			if ((Object)(object)val4 != (Object)(object)val2)
			{
				Director.Leave(ai);
				mem.Cur = val4;
				mem.Since = time;
				mem.Rival = null;
			}
			return val4;
		}

		public static void Prune()
		{
			List<BaseAI> list = null;
			foreach (BaseAI key in Mems.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					(list ?? (list = new List<BaseAI>())).Add(key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (BaseAI item in list)
			{
				Mems.Remove(item);
			}
		}
	}
	internal static class NavPieces
	{
		public static bool Building;

		private static bool Blocked(Component c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			Piece componentInParent = c.GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return false;
			}
			string prefabName = Utils.GetPrefabName(((Component)componentInParent).gameObject);
			string[] array = Plugin.NoClimb.Value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && prefabName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		public static void Filter(List<NavMeshBuildSource> results)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!Building || results == null || string.IsNullOrEmpty(Plugin.NoClimb.Value) || !Plugin.Active)
			{
				return;
			}
			for (int i = 0; i < results.Count; i++)
			{
				NavMeshBuildSource value = results[i];
				if (((NavMeshBuildSource)(ref value)).area != 1 && Blocked(((NavMeshBuildSource)(ref value)).component))
				{
					((NavMeshBuildSource)(ref value)).area = 1;
					results[i] = value;
				}
			}
		}
	}
	internal static class NavLinks
	{
		private class Link
		{
			public NavMeshLinkInstance Inst;

			public int Agent;
		}

		public struct Beam
		{
			public Vector3 A;

			public Vector3 B;
		}

		private class Seg
		{
			public int Id;

			public Vector3 A;

			public Vector3 B;

			public int Root;
		}

		private static readonly Dictionary<int, List<Link>> byPiece = new Dictionary<int, List<Link>>();

		private static readonly Dictionary<int, HashSet<int>> doneAgents = new Dictionary<int, HashSet<int>>();

		private static readonly List<Piece> tmp = new List<Piece>();

		private static float next;

		public static int Count;

		public static readonly Dictionary<int, Beam> Beams = new Dictionary<int, Beam>();

		public static readonly HashSet<int> BeamPieces = new HashSet<int>();

		public static bool Candidate(Piece p, out Vector3 a, out Vector3 b)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: 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_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			a = (b = Vector3.zero);
			string prefabName = Utils.GetPrefabName(((Component)p).gameObject);
			bool flag = false;
			string[] array = Plugin.BridgePieces.Value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && prefabName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return false;
			}
			BoxCollider[] componentsInChildren = ((Component)p).GetComponentsInChildren<BoxCollider>();
			foreach (BoxCollider val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || ((Collider)val).isTrigger || !((Collider)val).enabled)
				{
					continue;
				}
				Transform transform = ((Component)val).transform;
				Vector3 val2 = Vector3.Scale(val.size, transform.lossyScale);
				Vector3 val3 = ((val2.x >= val2.z) ? transform.right : transform.forward);
				float num = Mathf.Max(val2.x, val2.z);
				float num2 = Mathf.Min(val2.x, val2.z);
				if (!(Mathf.Abs(val3.y) > 0.5f))
				{
					if (num < 2f || num2 > 1.2f)
					{
						return false;
					}
					Vector3 val4 = transform.TransformPoint(val.center);
					Vector3 val5 = val3;
					val5.y = 0f;
					((Vector3)(ref val5)).Normalize();
					float y = val4.y + Mathf.Abs(val2.y) * 0.5f;
					a = val4 - val5 * num * 0.5f;
					a.y = y;
					b = val4 + val5 * num * 0.5f;
					b.y = y;
					return true;
				}
			}
			List<Vector3> list = new List<Vector3>();
			float num3 = float.MinValue;
			MeshRenderer[] componentsInChildren2 = ((Component)p).GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val6 in componentsInChildren2)
			{
				if (!((Object)(object)val6 == (Object)null) && ((Renderer)val6).enabled)
				{
					Bounds localBounds = ((Renderer)val6).localBounds;
					for (int j = 0; j < 8; j++)
					{
						Vector3 val7 = ((Bounds)(ref localBounds)).center + Vector3.Scale(((Bounds)(ref localBounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
						Vector3 val8 = ((Component)val6).transform.TransformPoint(val7);
						list.Add(val8);
						num3 = Mathf.Max(num3, val8.y);
					}
				}
			}
			if (list.Count < 2)
			{
				return false;
			}
			float num4 = 0f;
			for (int k = 0; k < list.Count; k++)
			{
				for (int l = k + 1; l < list.Count; l++)
				{
					float num5 = Utils.DistanceXZ(list[k], list[l]);
					if (num5 > num4)
					{
						num4 = num5;
						a = list[k];
						b = list[l];
					}
				}
			}
			if (num4 < 2f)
			{
				return false;
			}
			Vector3 val9 = b - a;
			val9.y = 0f;
			((Vector3)(ref val9)).Normalize();
			Vector3 val10 = Vector3.Cross(Vector3.up, val9);
			float num6 = float.MaxValue;
			float num7 = float.MinValue;
			foreach (Vector3 item in list)
			{
				float num8 = Vector3.Dot(item, val10);
				num6 = Mathf.Min(num6, num8);
				num7 = Mathf.Max(num7, num8);
			}
			if (num7 - num6 > 1.2f)
			{
				return false;
			}
			float num9 = (num6 + num7) * 0.5f;
			a += val10 * (num9 - Vector3.Dot(a, val10));
			a.y = num3;
			b += val10 * (num9 - Vector3.Dot(b, val10));
			b.y = num3;
			return true;
		}

		private static float PathLen(NavMeshPath path)
		{
			//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)
			float num = 0f;
			Vector3[] corners = path.corners;
			for (int i = 1; i < corners.Length; i++)
			{
				num += Vector3.Distance(corners[i - 1], corners[i]);
			}
			return num;
		}

		private static float SegDist(Vector3 p, Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = b - a;
			Vector3 val2 = p - a;
			val.y = 0f;
			val2.y = 0f;
			float num = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? Mathf.Clamp01(Vector3.Dot(val2, val) / ((Vector3)(ref val)).sqrMagnitude) : 0f);
			Vector3 val3 = val2 - val * num;
			return ((Vector3)(ref val3)).magnitude;
		}

		private static int Find(List<Seg> segs, int i)
		{
			while (segs[i].Root != i)
			{
				segs[i].Root = segs[segs[i].Root].Root;
				i = segs[i].Root;
			}
			return i;
		}

		public static void Tick()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_0546: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Unknown result type (might be due to invalid IL or missing references)
			//IL_056a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_05af: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Expected O, but got Unknown
			//IL_060c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0613: Unknown result type (might be due to invalid IL or missing references)
			//IL_0621: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_062d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Unknown result type (might be due to invalid IL or missing references)
			//IL_066f: Unknown result type (might be due to invalid IL or missing references)
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_063a: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0700: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active || !Plugin.Bridges.Value || Time.time < next || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Pathfinding.instance == (Object)null)
			{
				return;
			}
			HashSet<AgentType> hashSet = Brain.AgentTypesInUse();
			if (hashSet.Count == 0)
			{
				return;
			}
			next = Time.time + 5f;
			tmp.Clear();
			Piece.GetAllPiecesInRadius(((Component)Player.m_localPlayer).transform.position, 60f, tmp);
			List<Seg> list = new List<Seg>();
			foreach (Piece item in tmp)
			{
				if (!((Object)(object)item == (Object)null) && Candidate(item, out var a, out var b))
				{
					list.Add(new Seg
					{
						Id = ((Object)item).GetInstanceID(),
						A = a,
						B = b,
						Root = list.Count
					});
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				for (int j = i + 1; j < list.Count; j++)
				{
					Vector3 val = list[i].B - list[i].A;
					Vector3 val2 = list[j].B - list[j].A;
					val.y = 0f;
					val2.y = 0f;
					if (!(Mathf.Abs(Vector3.Dot(((Vector3)(ref val)).normalized, ((Vector3)(ref val2)).normalized)) < 0.95f) && !(Mathf.Abs(list[i].A.y - list[j].A.y) > 0.3f) && (SegDist(list[i].A, list[j].A, list[j].B) < 0.7f || SegDist(list[i].B, list[j].A, list[j].B) < 0.7f || SegDist(list[j].A, list[i].A, list[i].B) < 0.7f || SegDist(list[j].B, list[i].A, list[i].B) < 0.7f))
					{
						int num = Find(list, i);
						int num2 = Find(list, j);
						if (num != num2)
						{
							list[num2].Root = num;
						}
					}
				}
			}
			Dictionary<int, List<Seg>> dictionary = new Dictionary<int, List<Seg>>();
			for (int k = 0; k < list.Count; k++)
			{
				int key = Find(list, k);
				if (!dictionary.TryGetValue(key, out var value))
				{
					value = (dictionary[key] = new List<Seg>());
				}
				value.Add(list[k]);
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			BeamPieces.Clear();
			NavMeshHit val8 = default(NavMeshHit);
			NavMeshHit val9 = default(NavMeshHit);
			foreach (List<Seg> value3 in dictionary.Values)
			{
				List<Vector3> list3 = new List<Vector3>();
				int num3 = 17;
				List<int> list4 = new List<int>();
				foreach (Seg item2 in value3)
				{
					list3.Add(item2.A);
					list3.Add(item2.B);
					list4.Add(item2.Id);
				}
				list4.Sort();
				foreach (int item3 in list4)
				{
					num3 = num3 * 31 + item3;
				}
				Vector3 val3 = list3[0];
				Vector3 val4 = list3[1];
				float num4 = -1f;
				for (int l = 0; l < list3.Count; l++)
				{
					for (int m = l + 1; m < list3.Count; m++)
					{
						float num5 = Utils.DistanceXZ(list3[l], list3[m]);
						if (num5 > num4)
						{
							num4 = num5;
							val3 = list3[l];
							val4 = list3[m];
						}
					}
				}
				hashSet2.Add(num3);
				if (num4 >= 3f)
				{
					Beams[num3] = new Beam
					{
						A = val3,
						B = val4
					};
					foreach (Seg item4 in value3)
					{
						BeamPieces.Add(item4.Id);
					}
				}
				if (!byPiece.TryGetValue(num3, out var value2))
				{
					value2 = new List<Link>();
					byPiece[num3] = value2;
					doneAgents[num3] = new HashSet<int>();
				}
				Vector3 val5 = val4 - val3;
				val5.y = 0f;
				((Vector3)(ref val5)).Normalize();
				foreach (AgentType item5 in hashSet)
				{
					int num6 = Brain.AgentIdOf(item5);
					if (num6 < 0 || !doneAgents[num3].Add(num6))
					{
						continue;
					}
					NavMeshQueryFilter val6 = default(NavMeshQueryFilter);
					((NavMeshQueryFilter)(ref val6)).agentTypeID = num6;
					((NavMeshQueryFilter)(ref val6)).areaMask = -1;
					NavMeshQueryFilter val7 = val6;
					bool num7 = NavMesh.SamplePosition(val3 - val5 * 0.8f, ref val8, 2f, val7);
					bool flag = NavMesh.SamplePosition(val4 + val5 * 0.8f, ref val9, 2f, val7);
					if (!num7 || !flag)
					{
						continue;
					}
					NavMeshPath val10 = new NavMeshPath();
					float num8 = Vector3.Distance(((NavMeshHit)(ref val8)).position, ((NavMeshHit)(ref val9)).position);
					if (!NavMesh.CalculatePath(((NavMeshHit)(ref val8)).position, ((NavMeshHit)(ref val9)).position, val7, val10) || (int)val10.status != 0 || !(PathLen(val10) < num8 * 1.6f))
					{
						NavMeshLinkData val11 = default(NavMeshLinkData);
						((NavMeshLinkData)(ref val11)).startPosition = ((NavMeshHit)(ref val8)).position;
						((NavMeshLinkData)(ref val11)).endPosition = ((NavMeshHit)(ref val9)).position;
						((NavMeshLinkData)(ref val11)).width = 0f;
						((NavMeshLinkData)(ref val11)).costModifier = -1f;
						((NavMeshLinkData)(ref val11)).bidirectional = true;
						((NavMeshLinkData)(ref val11)).area = 0;
						((NavMeshLinkData)(ref val11)).agentTypeID = num6;
						NavMeshLinkInstance inst = NavMesh.AddLink(val11);
						if (((NavMeshLinkInstance)(ref inst)).valid)
						{
							value2.Add(new Link
							{
								Inst = inst,
								Agent = num6
							});
							Count++;
							Beams[num3] = new Beam
							{
								A = val3,
								B = val4
							};
						}
					}
				}
			}
			List<int> list5 = null;
			foreach (int key2 in byPiece.Keys)
			{
				if (!hashSet2.Contains(key2))
				{
					(list5 ?? (list5 = new List<int>())).Add(key2);
				}
			}
			if (list5 == null)
			{
				return;
			}
			foreach (int item6 in list5)
			{
				foreach (Link item7 in byPiece[item6])
				{
					NavMesh.RemoveLink(item7.Inst);
					Count--;
				}
				byPiece.Remove(item6);
				doneAgents.Remove(item6);
				Beams.Remove(item6);
			}
		}
	}
	public static class ServerSwitch
	{
		private const string Rpc = "Instinct_State";

		public static bool ServerOff;

		private static ZRoutedRpc regOn;

		private static float nextCheck;

		private static bool lastSent = true;

		private static DateTime cfgTime;

		public static void Tick(Plugin p)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				ServerOff = false;
				regOn = null;
				return;
			}
			if (regOn != ZRoutedRpc.instance)
			{
				ZRoutedRpc.instance.Register<ZPackage>("Instinct_State", (Action<long, ZPackage>)OnState);
				regOn = ZRoutedRpc.instance;
				ServerOff = false;
				lastSent = Plugin.EnabledNow;
			}
			if (!ZNet.instance.IsServer() || Time.time < nextCheck)
			{
				return;
			}
			nextCheck = Time.time + 10f;
			string configFilePath = ((BaseUnityPlugin)p).Config.ConfigFilePath;
			if (File.Exists(configFilePath))
			{
				DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(configFilePath);
				if (cfgTime != default(DateTime) && lastWriteTimeUtc != cfgTime)
				{
					((BaseUnityPlugin)p).Config.Reload();
				}
				cfgTime = lastWriteTimeUtc;
			}
			bool enabledNow = Plugin.EnabledNow;
			if (enabledNow == lastSent)
			{
				return;
			}
			lastSent = enabledNow;
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				SendTo(peer.m_uid);
			}
		}

		public static void SendTo(long uid)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if (ZRoutedRpc.instance != null && uid != 0L)
			{
				ZPackage val = new ZPackage();
				val.Write(Plugin.EnabledNow);
				val.Write("1.0.0");
				ZRoutedRpc.instance.InvokeRoutedRPC(uid, "Instinct_State", new object[1] { val });
			}
		}

		private static void OnState(long sender, ZPackage pkg)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer != null && sender == serverPeer.m_uid)
				{
					bool num = pkg.ReadBool();
					pkg.ReadString();
					_ = ServerOff;
					ServerOff = !num;
				}
			}
		}
	}
	internal static class Frame
	{
		public static MonsterAI Ai;

		public static bool Other;

		public static bool Combat;

		public static bool Eligible;

		public static bool Flyer;
	}
	internal static class Patches
	{
		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		[HarmonyPrefix]
		private static void UpdatePre(MonsterAI __instance)
		{
			Frame.Ai = __instance;
			Frame.Other = false;
			Frame.Combat = false;
			Frame.Eligible = Plugin.Active && Brain.Eligible(__instance);
			Frame.Flyer = Plugin.Active && Plugin.Flyers.Value && Brain.FlyerEligible(__instance);
		}

		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		[HarmonyPostfix]
		private static void UpdatePost(MonsterAI __instance, bool __result, float dt)
		{
			try
			{
				if (!__result || !((Object)(object)Frame.Ai == (Object)(object)__instance) || !Plugin.Active || !Brain.TryBeam(__instance, dt))
				{
					if (__result && (Object)(object)Frame.Ai == (Object)(object)__instance && Frame.Flyer && Frame.Combat && !Frame.Other)
					{
						Brain.FlyTick(__instance, dt);
					}
					else if (__result && (Object)(object)Frame.Ai == (Object)(object)__instance && Frame.Eligible && Frame.Combat && !Frame.Other)
					{
						Brain.Tick(__instance, dt);
					}
					else
					{
						_ = Brain.Debug;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex));
				Frame.Eligible = false;
			}
			Frame.Ai = null;
		}

		private static void MarkOther(BaseAI ai)
		{
			if ((Object)(object)Frame.Ai == (Object)(object)ai)
			{
				Frame.Other = true;
			}
		}

		[HarmonyPatch(typeof(BaseAI), "Flee")]
		[HarmonyPrefix]
		private static void P1(BaseAI __instance)
		{
			MarkOther(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "MoveAwayAndDespawn")]
		[HarmonyPrefix]
		private static void P2(BaseAI __instance)
		{
			MarkOther(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "Follow")]
		[HarmonyPrefix]
		private static void P3(BaseAI __instance)
		{
			MarkOther(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "IdleMovement")]
		[HarmonyPrefix]
		private static void P4(BaseAI __instance)
		{
			MarkOther(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "MoveToWater")]
		[HarmonyPrefix]
		private static void P5(BaseAI __instance)
		{
			MarkOther(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "AvoidFire")]
		[HarmonyPostfix]
		private static void P6(BaseAI __instance, bool __result)
		{
			if (__result)
			{
				MarkOther(__instance);
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "SelectBestAttack")]
		[HarmonyPostfix]
		private static void SelectPost(MonsterAI __instance, ItemData __result)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Frame.Ai != (Object)(object)__instance))
			{
				if (__result == null || (int)__result.m_shared.m_aiTargetType != 0)
				{
					Frame.Eligible = false;
				}
				else
				{
					Frame.Combat = true;
				}
			}
		}

		[HarmonyPatch(typeof(BaseAI), "RandomMovementArroundPoint")]
		[HarmonyPrefix]
		private static bool CirclePre(BaseAI __instance, Vector3 point)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null);
			if ((Object)(object)val == (Object)null || (Object)(object)Frame.Ai != (Object)(object)val || !Frame.Eligible)
			{
				return true;
			}
			Character val2 = Acc.Target.Invoke(val);
			if ((Object)(object)val2 == (Object)null || Utils.DistanceXZ(((Component)val2).transform.position, point) > 1f)
			{
				return true;
			}
			Frame.Combat = true;
			return false;
		}

		[HarmonyPatch(typeof(MonsterAI), "DoAttack")]
		[HarmonyPrefix]
		private static bool AttackPre(MonsterAI __instance, Character target, bool isFriend, ref bool __result)
		{
			//IL_007a: 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)
			if (isFriend || (Object)(object)Frame.Ai != (Object)(object)__instance || !Frame.Eligible || (Object)(object)target == (Object)null)
			{
				return true;
			}
			if (!Brain.RangedAllowed(__instance, target))
			{
				__result = false;
				return false;
			}
			Director.Member member = Director.Join(__instance, target);
			if (Plugin.FreeArchers.Value && Brain.HoldsRanged(__instance))
			{
				return true;
			}
			if (!member.Token && Brain.RangedRole(__instance, target))
			{
				return true;
			}
			if (member.Token)
			{
				if (!Brain.InReach(__instance, target, out var _))
				{
					__result = false;
					return false;
				}
				Vector3 velocity = target.GetVelocity();
				velocity.y = 0f;
				if ((!Plugin.HitNow.Value || !(((Vector3)(ref velocity)).magnitude > 1f)) && !Director.OffBeat(__instance, target, Brain.WindupOf(__instance), out var _))
				{
					__result = false;
					return false;
				}
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		[HarmonyPostfix]
		private static void PeerInfoPost(ZNet __instance, ZRpc rpc)
		{
			try
			{
				if (!__instance.IsServer())
				{
					return;
				}
				foreach (ZNetPeer peer in __instance.GetPeers())
				{
					if (peer.m_rpc == rpc)
					{
						ServerSwitch.SendTo(peer.m_uid);
						break;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: server switch on join " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(BaseAI), "FindEnemy")]
		[HarmonyPostfix]
		private static void FindEnemyPost(BaseAI __instance, ref Character __result)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if ((Object)(object)Frame.Ai != (Object)(object)__instance || !Targeting.Applies(__instance))
			{
				return;
			}
			try
			{
				__result = Targeting.Choose((MonsterAI)__instance, __result);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "OnDamaged")]
		[HarmonyPostfix]
		private static void DamagedPost(MonsterAI __instance, float damage, Character attacker)
		{
			try
			{
				Targeting.Damaged((BaseAI)(object)__instance, damage, attacker);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
			try
			{
				Brain.Hurt(__instance, damage);
			}
			catch (Exception ex2)
			{
				Debug.LogWarning((object)("Instinct: " + ex2.Message));
			}
		}

		[HarmonyPatch(typeof(Pathfinding), "BuildTile")]
		[HarmonyPrefix]
		private static void BuildTilePre()
		{
			NavPieces.Building = true;
		}

		[HarmonyPatch(typeof(Pathfinding), "BuildTile")]
		[HarmonyFinalizer]
		private static Exception BuildTileFin(Exception __exception)
		{
			NavPieces.Building = false;
			return __exception;
		}

		[HarmonyPatch(typeof(NavMeshBuilder), "CollectSources", new Type[]
		{
			typeof(Bounds),
			typeof(int),
			typeof(NavMeshCollectGeometry),
			typeof(int),
			typeof(List<NavMeshBuildMarkup>),
			typeof(List<NavMeshBuildSource>)
		})]
		[HarmonyPostfix]
		private static void CollectPost(List<NavMeshBuildSource> results)
		{
			try
			{
				NavPieces.Filter(results);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(Humanoid), "StartAttack")]
		[HarmonyPostfix]
		private static void StartAttackPost(Humanoid __instance, bool __result)
		{
			if (!__result)
			{
				return;
			}
			try
			{
				Reach.Started(__instance);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
		[HarmonyPrefix]
		private static void AttackTriggerPre(Attack __instance)
		{
			try
			{
				Reach.Triggered(__instance);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(Humanoid), "EquipBestWeapon")]
		[HarmonyPostfix]
		private static void EquipBestPost(Humanoid __instance)
		{
			try
			{
				Brain.AfterEquipBest(__instance);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Instinct: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "DoAttack")]
		[HarmonyPostfix]
		private static void AttackPost(MonsterAI __instance, Character target, bool __result)
		{
			if (__result && (Object)(object)target != (Object)null)
			{
				Director.Attacked(__instance, target);
			}
		}
	}
	internal static class Director
	{
		public class Member
		{
			public MonsterAI Ai;

			public float LastSeen;

			public bool Token;

			public float TokenSince;

			public float AttackedAt = -99f;

			public float CooldownUntil;

			public float SwingStart = -99f;

			public float HitEta = -99f;

			public bool OnDeck;

			public float Slot;

			public bool HasSlot;

			public float WaitSince = -1f;

			public bool Charging;
		}

		public class Fight
		{
			public Character Target;

			public readonly List<Member> Members = new List<Member>();

			public float LastUpdate;

			public float NextSlots;

			public float SlotCost = float.MaxValue;

			public int SlotCount;

			public float ShockUntil = -99f;

			public MonsterAI Sup;

			public Vector3 Spot;

			public bool HasSpot;

			public float PressUntil;
		}

		public static readonly Dictionary<Character, Fight> Fights = new Dictionary<Character, Fight>();

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

		private static float Quick(Member m)
		{
			if (!Plugin.StarSkill.Value)
			{
				return 1f;
			}
			Character val = Acc.Char.Invoke((BaseAI)(object)m.Ai);
			int num = ((!((Object)(object)val != (Object)null)) ? 1 : val.GetLevel());
			return 1f / (1f + 0.35f * (float)Mathf.Max(0, num - 1));
		}

		private static void PickSuppressor(Fight f)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (!Plugin.Suppress.Value)
			{
				f.Sup = null;
				return;
			}
			bool flag = false;
			foreach (Member member in f.Members)
			{
				if ((Object)(object)member.Ai == (Object)(object)f.Sup && !member.Token && Brain.HasRanged(member.Ai))
				{
					flag = true;
				}
			}
			if (flag)
			{
				return;
			}
			MonsterAI val = null;
			float num = float.MaxValue;
			Vector3 position = ((Component)f.Target).transform.position;
			foreach (Member member2 in f.Members)
			{
				if (!member2.Token && !((Object)(object)member2.Ai == (Object)null) && Brain.HasRanged(member2.Ai))
				{
					float num2 = Utils.DistanceXZ(((Component)Acc.Char.Invoke((BaseAI)(object)member2.Ai)).transform.position, position);
					if (num2 < num)
					{
						num = num2;
						val = member2.Ai;
					}
				}
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)f.Sup)
			{
				Brain.ShoutOf(val);
			}
			f.Sup = val;
		}

		public static bool IsSup(MonsterAI ai, Character t)
		{
			if (Fights.TryGetValue(t, out var value))
			{
				return (Object)(object)value.Sup == (Object)(object)ai;
			}
			return false;
		}

		public static bool SomeoneEngaged(Character t, MonsterAI except)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!Fights.TryGetValue(t, out var value))
			{
				return false;
			}
			foreach (Member member in value.Members)
			{
				if (!((Object)(object)member.Ai == (Object)(object)except) && !((Object)(object)member.Ai == (Object)null))
				{
					Character obj = Acc.Char.Invoke((BaseAI)(object)member.Ai);
					Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
					ItemData val2 = (((Object)(object)val != (Object)null) ? val.GetCurrentWeapon() : null);
					if (val2 != null && !Brain.IsRanged(val2) && Utils.DistanceXZ(((Component)val).transform.position, ((Component)t).transform.position) - t.GetRadius() < val2.m_shared.m_aiAttackRange + 0.3f)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static void GrantNow(MonsterAI ai, Character t)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				return;
			}
			foreach (Member member in value.Members)
			{
				if ((Object)(object)member.Ai == (Object)(object)ai && !member.Token)
				{
					Grant(member, Time.time, charge: false);
				}
			}
		}

		public static void Release(MonsterAI ai, float cooldown)
		{
			foreach (Fight value in Fights.Values)
			{
				foreach (Member member in value.Members)
				{
					if ((Object)(object)member.Ai == (Object)(object)ai && member.Token)
					{
						member.Token = false;
						member.Charging = false;
						member.CooldownUntil = Time.time + cooldown;
					}
				}
			}
		}

		private static void Grant(Member m, float now, bool charge)
		{
			if (charge && (Object)(object)m.Ai != (Object)null)
			{
				Brain.ShoutOf(m.Ai);
			}
			m.Token = true;
			m.TokenSince = now;
			m.OnDeck = false;
			m.Charging = charge;
			m.WaitSince = -1f;
		}

		public static bool Pressing(Character t)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.PressOnMove.Value)
			{
				return false;
			}
			if (!Fights.TryGetValue(t, out var value))
			{
				return false;
			}
			Vector3 position = ((Component)t).transform.position;
			if (!value.HasSpot)
			{
				value.Spot = position;
				value.HasSpot = true;
			}
			if (Utils.DistanceXZ(position, value.Spot) > 5f)
			{
				value.Spot = position;
				value.PressUntil = Time.time + 3f;
			}
			return Time.time < value.PressUntil;
		}

		public static bool Shaken(Character t)
		{
			if (Fights.TryGetValue(t, out var value))
			{
				return Time.time < value.ShockUntil;
			}
			return false;
		}

		private static void AssignSlots(Fight f)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			int count = f.Members.Count;
			if (count == 0)
			{
				return;
			}
			Vector3 position = ((Component)f.Target).transform.position;
			if (count == 1)
			{
				Member member = f.Members[0];
				member.Slot = Brain.AngleAround(position, ((Component)Acc.Char.Invoke((BaseAI)(object)member.Ai)).transform.position);
				member.HasSlot = true;
				f.SlotCount = 1;
				return;
			}
			Vector3 forward = ((Component)f.Target).transform.forward;
			float facing = Mathf.Atan2(forward.x, forward.z) * 57.29578f;
			List<KeyValuePair<float, Member>> list = new List<KeyValuePair<float, Member>>();
			foreach (Member member2 in f.Members)
			{
				list.Add(new KeyValuePair<float, Member>(Brain.AngleAround(position, ((Component)Acc.Char.Invoke((BaseAI)(object)member2.Ai)).transform.position), member2));
			}
			list.Sort((KeyValuePair<float, Member> a, KeyValuePair<float, Member> b) => a.Key.CompareTo(b.Key));
			float num = 360f / (float)count;
			float num2 = 0f;
			bool flag = f.SlotCount == count;
			if (flag)
			{
				foreach (KeyValuePair<float, Member> item in list)
				{
					num2 += Mathf.Abs(Mathf.DeltaAngle(item.Key, item.Value.Slot)) + FrontCost(item.Value.Slot, facing);
				}
			}
			float num3 = float.MaxValue;
			float num4 = 0f;
			int num5 = 0;
			for (float num6 = 0f; num6 < num; num6 += 5f)
			{
				for (int num7 = 0; num7 < count; num7++)
				{
					float num8 = 0f;
					for (int num9 = 0; num9 < count; num9++)
					{
						float num10 = list[0].Key + num6 + (float)((num9 + num7) % count) * num;
						float num11 = Mathf.Abs(Mathf.DeltaAngle(list[num9].Key, num10));
						num8 += num11 + FrontCost(num10, facing);
					}
					if (num8 < num3)
					{
						num3 = num8;
						num4 = num6;
						num5 = num7;
					}
				}
			}
			if (!flag || !(num3 > num2 * 0.8f - 10f))
			{
				for (int num12 = 0; num12 < count; num12++)
				{
					list[num12].Value.Slot = list[0].Key + num4 + (float)((num12 + num5) % count) * num;
					list[num12].Value.HasSlot = true;
				}
				f.SlotCount = count;
			}
		}

		private static float FrontCost(float slot, float facing)
		{
			float num = Mathf.Abs(Mathf.DeltaAngle(slot, facing));
			if (!(num < 30f))
			{
				return 0f;
			}
			return (30f - num) * 2f;
		}

		private static Fight Get(Character t)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				value = new Fight
				{
					Target = t
				};
				Fights[t] = value;
			}
			return value;
		}

		public static Member Join(MonsterAI ai, Character t)
		{
			Fight fight = Get(t);
			Member member = null;
			foreach (Member member2 in fight.Members)
			{
				if ((Object)(object)member2.Ai == (Object)(object)ai)
				{
					member = member2;
					break;
				}
			}
			if (member == null)
			{
				member = new Member
				{
					Ai = ai
				};
				fight.Members.Add(member);
			}
			member.LastSeen = Time.time;
			if (Time.time - fight.LastUpdate > 0.1f)
			{
				Update(fight);
			}
			return member;
		}

		public static bool HolderNear(Character t, MonsterAI me, float angle, float deg)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!Fights.TryGetValue(t, out var value))
			{
				return false;
			}
			Vector3 position = ((Component)t).transform.position;
			foreach (Member member in value.Members)
			{
				if (!((Object)(object)member.Ai == (Object)(object)me) && member.Token && !((Object)(object)member.Ai == (Object)null))
				{
					Character val = Acc.Char.Invoke((BaseAI)(object)member.Ai);
					if ((Object)(object)val != (Object)null && Mathf.Abs(Mathf.DeltaAngle(Brain.AngleAround(position, ((Component)val).transform.position), angle)) < deg)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static int CountOn(Character t, MonsterAI except)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				return 0;
			}
			int num = 0;
			foreach (Member member in value.Members)
			{
				if ((Object)(object)member.Ai != (Object)(object)except && (Object)(object)member.Ai != (Object)null && Time.time - member.LastSeen < 1f)
				{
					num++;
				}
			}
			return num;
		}

		public static void Leave(MonsterAI ai)
		{
			foreach (Fight value in Fights.Values)
			{
				value.Members.RemoveAll((Member m) => (Object)(object)m.Ai == (Object)(object)ai);
			}
		}

		private static void Update(Fight f)
		{
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0635: Unknown result type (might be due to invalid IL or missing references)
			//IL_063a: Unknown result type (might be due to invalid IL or missing references)
			float now = Time.time;
			f.LastUpdate = now;
			int num = f.Members.RemoveAll((Member m) => now - m.LastSeen < 0.6f && ((Object)(object)m.Ai == (Object)null || (Object)(object)Acc.Char.Invoke((BaseAI)(object)m.Ai) == (Object)null || Acc.Char.Invoke((BaseAI)(object)m.Ai).IsDead()));
			f.Members.RemoveAll((Member m) => (Object)(object)m.Ai == (Object)null || now - m.LastSeen > 1f || (Object)(object)Acc.Char.Invoke((BaseAI)(object)m.Ai) == (Object)null || Acc.Char.Invoke((BaseAI)(object)m.Ai).IsDead());
			if (num > 0 && f.Members.Count > 0 && Plugin.AllyDown.Value > 0f)
			{
				f.ShockUntil = now + Plugin.AllyDown.Value;
			}
			if (f.Members.Count == 0)
			{
				return;
			}
			if (now > f.NextSlots || f.SlotCount != f.Members.Count)
			{
				f.NextSlots = now + 0.5f;
				AssignSlots(f);
			}
			PickSuppressor(f);
			int num2 = Mathf.Max(1, Plugin.Tokens.Value);
			if (Plugin.ChaseRunner.Value && Brain.Running(f.Target))
			{
				num2 = Mathf.Max(num2, f.Members.Count);
			}
			if (f.Members.Count <= num2)
			{
				foreach (Member member4 in f.Members)
				{
					member4.OnDeck = false;
					member4.WaitSince = -1f;
					if (!member4.Token)
					{
						Grant(member4, now, charge: false);
					}
				}
				return;
			}
			Vector3 forward = ((Component)f.Target).transform.forward;
			float num3 = Mathf.Atan2(forward.x, forward.z) * 57.29578f;
			int num4 = 0;
			foreach (Member member5 in f.Members)
			{
				if (member5.Token)
				{
					Character val = Acc.Char.Invoke((BaseAI)(object)member5.Ai);
					bool flag = member5.AttackedAt > member5.TokenSince && member5.HitEta >= member5.AttackedAt && now >= member5.HitEta + 0.1f;
					bool num5 = member5.AttackedAt > member5.TokenSince && (flag || (!val.InAttack() && now - member5.AttackedAt > 0.4f));
					bool flag2 = now - member5.TokenSince > 7f && now - member5.AttackedAt > 2f;
					if (num5 || flag2)
					{
						member5.Token = false;
						member5.Charging = false;
						member5.CooldownUntil = now + 1.2f * Quick(member5);
						member5.WaitSince = now;
					}
					else
					{
						num4++;
					}
				}
			}
			foreach (Member member6 in f.Members)
			{
				if (!member6.Token && member6.WaitSince < 0f)
				{
					member6.WaitSince = now;
				}
			}
			Vector3 position = ((Component)f.Target).transform.position;
			bool flag3 = Plugin.PunishTired.Value && f.Target is Player && ((Player)f.Target).GetStamina() < 5f;
			for (; num4 < num2; num4++)
			{
				Member member = null;
				float num6 = float.MaxValue;
				foreach (Member member7 in f.Members)
				{
					if (member7.Token || (now < member7.CooldownUntil && !flag3))
					{
						continue;
					}
					float num7 = Utils.DistanceXZ(((Component)Acc.Char.Invoke((BaseAI)(object)member7.Ai)).transform.position, position) - Mathf.Min(6f, (now - member7.AttackedAt) * 0.4f);
					if (Plugin.FlankBehind.Value && member7.HasSlot)
					{
						float num8 = Mathf.Abs(Mathf.DeltaAngle(member7.Slot, num3));
						if (num8 > 110f)
						{
							num7 -= 1.5f;
						}
						else if (num8 > 60f)
						{
							num7 -= 0.7f;
						}
					}
					if (num7 < num6)
					{
						num6 = num7;
						member = member7;
					}
				}
				if (member == null)
				{
					break;
				}
				Grant(member, now, charge: false);
			}
			if (Plugin.Patience.Value > 0f && num4 >= num2)
			{
				bool flag4 = false;
				float num9 = -99f;
				foreach (Member member8 in f.Members)
				{
					if (member8.Token && member8.Charging)
					{
						flag4 = true;
					}
					num9 = Mathf.Max(num9, member8.AttackedAt);
				}
				if (!flag4)
				{
					Member member2 = null;
					float num10 = 0f;
					foreach (Member member9 in f.Members)
					{
						if (!member9.Token && !(member9.WaitSince < 0f))
						{
							float num11 = now - member9.WaitSince;
							float num12 = Plugin.Patience.Value * Quick(member9);
							if (now - num9 < 2f)
							{
								num12 += 2f;
							}
							if (num11 > num12 && num11 > num10)
							{
								num10 = num11;
								member2 = member9;
							}
						}
					}
					if (member2 != null)
					{
						Grant(member2, now, charge: true);
					}
				}
			}
			Member member3 = null;
			float num13 = float.MaxValue;
			foreach (Member member10 in f.Members)
			{
				member10.OnDeck = false;
				if (!member10.Token)
				{
					float num14 = Utils.DistanceXZ(((Component)Acc.Char.Invoke((BaseAI)(object)member10.Ai)).transform.position, position) - Mathf.Min(6f, (now - member10.AttackedAt) * 0.4f) + ((now < member10.CooldownUntil) ? 3f : 0f);
					if (num14 < num13)
					{
						num13 = num14;
						member3 = member10;
					}
				}
			}
			if (member3 != null)
			{
				member3.OnDeck = true;
			}
		}

		public static bool MayAttack(MonsterAI ai, Character t)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				return true;
			}
			foreach (Member member in value.Members)
			{
				if ((Object)(object)member.Ai == (Object)(object)ai)
				{
					return member.Token;
				}
			}
			return true;
		}

		public static void Attacked(MonsterAI ai, Character t)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				return;
			}
			foreach (Member member in value.Members)
			{
				if ((Object)(object)member.Ai == (Object)(object)ai)
				{
					member.AttackedAt = Time.time;
					member.SwingStart = Time.time;
					member.HitEta = Time.time + Brain.WindupOf(ai);
				}
			}
		}

		public static void Landed(MonsterAI ai)
		{
			foreach (Fight value in Fights.Values)
			{
				foreach (Member member in value.Members)
				{
					if ((Object)(object)member.Ai == (Object)(object)ai && Time.time - member.SwingStart < 3f)
					{
						member.HitEta = Time.time;
					}
				}
			}
		}

		public static bool OffBeat(MonsterAI ai, Character t, float windup, out string why)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			why = "";
			float value = Plugin.Stagger.Value;
			if (value <= 0f || !Fights.TryGetValue(t, out var value2))
			{
				return true;
			}
			if (Plugin.PunishTired.Value && t is Player && ((Player)t).GetStamina() < 5f)
			{
				return true;
			}
			float time = Time.time;
			float num = time + windup;
			foreach (Member member in value2.Members)
			{
				if (!((Object)(object)member.Ai == (Object)(object)ai) && !(time - member.SwingStart > 3f))
				{
					Character val = Acc.Char.Invoke((BaseAI)(object)member.Ai);
					if (!((Object)(object)val == (Object)null) && !val.IsDead() && !val.IsStaggering() && (!(member.HitEta < time - 0.05f) || val.InAttack()) && num < member.HitEta + value && num > member.HitEta - value)
					{
						why = "taking turns (partner lands in " + (member.HitEta - time).ToString("0.00") + " s)";
						return false;
					}
				}
			}
			return true;
		}

		public static int WaitRank(Character t, MonsterAI ai)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			if (!Fights.TryGetValue(t, out var value))
			{
				return 0;
			}
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			if ((Object)(object)val == (Object)null)
			{
				return 0;
			}
			float num = Utils.DistanceXZ(((Component)val).transform.position, ((Component)t).transform.position);
			int num2 = 0;
			foreach (Member member in value.Members)
			{
				if (!((Object)(object)member.Ai == (Object)(object)ai) && !member.Token && !((Object)(object)member.Ai == (Object)null))
				{
					Character val2 = Acc.Char.Invoke((BaseAI)(object)member.Ai);
					if ((Object)(object)val2 != (Object)null && Utils.DistanceXZ(((Component)val2).transform.position, ((Component)t).transform.position) < num)
					{
						num2++;
					}
				}
			}
			return num2;
		}

		public static IEnumerable<Member> Others(Character t, MonsterAI ai)
		{
			if (!Fights.TryGetValue(t, out var value))
			{
				yield break;
			}
			foreach (Member member in value.Members)
			{
				if ((Object)(object)member.Ai != (Object)(object)ai && (Object)(object)member.Ai != (Object)null)
				{
					yield return member;
				}
			}
		}

		public static void Prune()
		{
			dead.Clear();
			foreach (KeyValuePair<Character, Fight> fight in Fights)
			{
				if ((Object)(object)fight.Key == (Object)null || (fight.Value.Members.Count == 0 && Time.time - fight.Value.LastUpdate > 5f))
				{
					dead.Add(fight.Key);
				}
			}
			foreach (Character item in dead)
			{
				Fights.Remove(item);
			}
		}
	}
	internal static class Brain
	{
		public class State
		{
			public float LastActive;

			public string Mode = "vanilla";

			public Vector3 TargetVel;

			public Vector3 SmoothDir;

			public readonly List<Vector3> Path = new List<Vector3>();

			public Vector3 PathGoal = new Vector3(1E+09f, 0f, 0f);

			public float PathTime = -99f;

			public float DriftSign = 1f;

			public bool Repositioning;

			public bool TurnWalk;

			public float BateSince = -1f;

			public float SwingAt = -1f;

			public bool WasInAttack;

			public float ArsenalAt;

			public ItemData Melee;

			public ItemData Ranged;

			public float RecoverUntil;

			public string WhyNot = "vanilla";

			public float WhyAt = -99f;

			public string Prefab;

			public float FarSince = -1f;

			public float FarGap;

			public float JumpNext;

			public bool OnBeam;

			public int MountTries;

			public float MountPauseUntil;

			public Vector3 SegStart;

			public bool HasSeg;

			public string Style = "advance";

			public int BandSide;

			public float BandUntil;

			public float BandRestUntil;

			public bool BandIn;

			public bool BandOut;

			public int AfterKind;

			public float AfterUntil;

			public float AfterGoal;

			public int AfterSide;

			public int CurveSide;

			public float CurveUntil;

			public bool CurveRolled;

			public float DodgeNext;

			public float DodgeUntil;

			public int DodgeSide;

			public float HiddenSince = -1f;

			public float FlushUntil;

			public Vector3 FlushSpot;

			public bool FlushHasSpot;

			public float ShoutNext;

			public readonly Dictionary<string, float> Used = new Dictionary<string, float>();

			public Vector3 Anchor;

			public bool HasAnchor;
		}

		public static readonly Dictionary<MonsterAI, State> States = new Dictionary<MonsterAI, State>();

		private static float nextPrune;

		public static bool Debug;

		private static readonly Dictionary<MonsterAI, string> sitNow = new Dictionary<MonsterAI, string>();

		private static readonly Dictionary<MonsterAI, KeyValuePair<string, float>> sitCand = new Dictionary<MonsterAI, KeyValuePair<string, float>>();

		private static string useGameCache;

		private static HashSet<string> useGameSet = new HashSet<string>();

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

		private static MethodInfo doAttack;

		private static readonly Dictionary<AgentType, int> agentIds = new Dictionary<AgentType, int>();

		private static MethodInfo getSettings;

		private static readonly FieldRef<Character, Rigidbody> BodyOf = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private static int pieceMask;

		private static int blockMask;

		private static string StyleOf(string prefab)
		{
			string result = "advance";
			int num = -1;
			string[] array = Plugin.Styles.Value.Split(',');
			foreach (string text in array)
			{
				int num2 = text.IndexOf('=');
				if (num2 > 0)
				{
					string text2 = text.Substring(0, num2).Trim();
					string text3 = text.Substring(num2 + 1).Trim().ToLowerInvariant();
					if (text2.Length > num && prefab.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
					{
						result = text3;
						num = text2.Length;
					}
				}
			}
			return result;
		}

		private static float WaitGap(State s)
		{
			if (s.Style == "close")
			{
				return Plugin.NearGap.Value;
			}
			if (s.Style == "cautious")
			{
				return Plugin.FarGap.Value;
			}
			return Plugin.RingGap.Value;
		}

		public static bool HasRanged(MonsterAI ai)
		{
			State state = Get(ai);
			Arsenal(ai, state);
			return state.Ranged != null;
		}

		public static bool RangedRole(MonsterAI ai, Character t)
		{
			Character obj = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
			if ((Object)(object)val == (Object)null || !IsRanged(val.GetCurrentWeapon()))
			{
				return false;
			}
			State state = Get(ai);
			if (!Plugin.Suppress.Value || !Director.IsSup(ai, t))
			{
				return Time.time < state.FlushUntil;
			}
			return true;
		}

		public static void ShoutOf(MonsterAI ai)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Shout.Value || (Object)(object)ai == (Object)null)
			{
				return;
			}
			State state = Get(ai);
			if (!(Time.time < state.ShoutNext))
			{
				state.ShoutNext = Time.time + 6f;
				Character val = Acc.Char.Invoke((BaseAI)(object)ai);
				if ((Object)(object)val != (Object)null)
				{
					((BaseAI)ai).m_alertedEffects.Create(((Component)val).transform.position, ((Component)val).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
		}

		public static void Hurt(MonsterAI ai, float damage)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: 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)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active || Plugin.RetreatChance.Value <= 0f || !Eligible(ai))
			{
				return;
			}
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			Character val2 = Acc.Target.Invoke(ai);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || damage < val.GetMaxHealth() * 0.15f || Random.value > Plugin.RetreatChance.Value)
			{
				return;
			}
			Director.Release(ai, 1.5f);
			State state = Get(ai);
			Vector3 val3 = ((Component)val2).transform.position - ((Component)val).transform.position;
			val3.y = 0f;
			if (!(((Vector3)(ref val3)).sqrMagnitude < 0.01f))
			{
				Vector3 val4 = -((Vector3)(ref val3)).normalized;
				Vector3 val5 = Vector3.Cross(Vector3.up, ((Vector3)(ref val3)).normalized);
				int num = ((!(Random.value < 0.5f)) ? 1 : (-1));
				Vector3 val6 = val4 * 0.4f + val5 * (float)num * 0.92f;
				if (!Free(val, ((Vector3)(ref val6)).normalized, 2f))
				{
					num = -num;
				}
				state.AfterKind = 2;
				state.AfterSide = num;
				state.AfterGoal = ((Vector3)(ref val3)).magnitude + 3f;
				state.AfterUntil = Time.time + 1.5f;
			}
		}

		private static bool AimedAt(Character me, Character t)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Player val = (Player)(object)((t is Player) ? t : null);
			if ((Object)(object)val == (Object)null || ((Humanoid)val).GetAttackDrawPercentage() < 0.3f)
			{
				return false;
			}
			Vector3 val2 = (((Object)(object)((Character)val).m_eye != (Object)null) ? ((Character)val).m_eye.position : (((Component)val).transform.position + Vector3.up * 1.6f));
			Vector3 val3 = me.GetCenterPoint() - val2;
			float magnitude = ((Vector3)(ref val3)).magnitude;
			if (magnitude > 30f || magnitude < 1f)
			{
				return false;
			}
			float num = 8f + Mathf.Atan2(me.GetRadius(), magnitude) * 57.29578f;
			return Vector3.Angle(((Character)val).GetLookDir(), val3) < num;
		}

		public static float WindupOf(MonsterAI ai)
		{
			Character obj = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
			ItemData val2 = (((Object)(object)val != (Object)null) ? val.GetCurrentWeapon() : null);
			if (val2 == null)
			{
				return 0.7f;
			}
			return Reach.Get(val, val2).Windup;
		}

		public static bool InReach(MonsterAI ai, Character t, out string why)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			why = "";
			if (!Plugin.PredictReach.Value)
			{
				return true;
			}
			Character obj = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
			ItemData val2 = (((Object)(object)val != (Object)null) ? val.GetCurrentWeapon() : null);
			if (val2 == null || IsRanged(val2) || !Reach.Melee(val2.m_shared.m_attack))
			{
				return true;
			}
			Reach.Info info = Reach.Get(val, val2);
			Reach.Gaps((Character)(object)val, t, info, out var now, out var then);
			State state = Get(ai);
			why = "slack " + now.ToString("0.0") + "->" + then.ToString("0.0") + " reach " + info.Reach.ToString("0.0") + ((info.N == 0) ? "?" : "");
			if (Mathf.Abs(((Component)t).transform.position.y - ((Component)val).transform.position.y) > Mathf.Max(1.5f, ((Character)val).GetHeight() * 0.6f))
			{
				why += " height";
				return false;
			}
			if (then <= info.Reach - 0.15f && now <= info.Reach + 0.75f)
			{
				state.FarSince = -1f;
				return true;
			}
			if (state.FarSince < 0f || now < state.FarGap - 0.3f)
			{
				state.FarSince = Time.time;
				state.FarGap = now;
			}
			Vector3 val3 = ((Component)t).transform.position - ((Component)val).transform.position;
			val3.y = 0f;
			Vector3 velocity = t.GetVelocity();
			velocity.y = 0f;
			float num = ((((Vector3)(ref val3)).sqrMagnitude > 0.0001f) ? Vector3.Dot(velocity, ((Vector3)(ref val3)).normalized) : 0f);
			if (Time.time - state.FarSince > 1.5f && num < 1f)
			{
				state.FarSince = -1f;
				why += " stuck";
				return true;
			}
			why += " far";
			return false;
		}

		[Conditional("BENCH")]
		public static void Why(MonsterAI ai, string why)
		{
			if (Debug)
			{
				State state = Get(ai);
				state.WhyNot = why;
				state.WhyAt = Time.time;
			}
		}

		private static State Get(MonsterAI ai)
		{
			if (States.TryGetValue(ai, out var value))
			{
				return value;
			}
			value = new State();
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			value.Prefab = Utils.GetPrefabName(((Component)val).gameObject);
			value.DriftSign = ((Random.value > 0.5f) ? 1f : (-1f));
			value.Style = StyleOf(value.Prefab);
			States[ai] = value;
			return value;
		}

		public static bool Starts(string name, string list)
		{
			string[] array = list.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && name.StartsWith(text, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public static bool Eligible(MonsterAI ai)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			if ((Object)(object)val == (Object)null || val.IsTamed() || val.IsBoss() || val.IsFlying() || val.IsSwimming() || !(val is Humanoid))
			{
				return false;
			}
			if ((int)val.GetFaction() == 8)
			{
				return false;
			}
			Character val2 = Acc.Target.Invoke(ai);
			if ((Object)(object)val2 == (Object)null || val2.IsDead())
			{
				return false;
			}
			if (Plugin.UseGameIn.Value.Length > 0 && GameBetterHere(ai, val, val2))
			{
				return false;
			}
			return true;
		}

		public static string Situation(MonsterAI ai, Character me, Character t)
		{
			//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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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)
			Vector3 velocity = t.GetVelocity();
			velocity.y = 0f;
			string text;
			if (((Vector3)(ref velocity)).magnitude < 1f)
			{
				text = "still";
			}
			else
			{
				Vector3 val = ((Component)t).transform.position - ((Component)me).transform.position;
				val.y = 0f;
				float num = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? Vector3.Dot(((Vector3)(ref velocity)).normalized, ((Vector3)(ref val)).normalized) : 0f);
				text = ((num > 0.5f) ? "back_off" : ((num < -0.5f) ? "pass" : "strafe"));
			}
			if (!sitNow.TryGetValue(ai, out var value))
			{
				sitNow[ai] = text;
				return text;
			}
			if (text == value)
			{
				sitCand.Remove(ai);
				return value;
			}
			if (!sitCand.TryGetValue(ai, out var value2) || value2.Key != text)
			{
				sitCand[ai] = new KeyValuePair<string, float>(text, Time.time);
				return value;
			}
			if (Time.time - value2.Value >= 0.5f)
			{
				sitNow[ai] = text;
				sitCand.Remove(ai);
				return text;
			}
			return value;
		}

		private static bool GameBetterHere(MonsterAI ai, Character me, Character t)
		{
			string value = Plugin.UseGameIn.Value;
			if (value != useGameCache)
			{
				useGameCache = value;
				useGameSet = new HashSet<string>();
				string[] array = value.Split(',');
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length > 0)
					{
						useGameSet.Add(text);
					}
				}
			}
			return useGameSet.Contains(Utils.GetPrefabName(((Component)me).gameObject) + ":" + Situation(ai, me, t));
		}

		public static bool FlyerEligible(MonsterAI ai)
		{
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			if ((Object)(object)val == (Object)null || !val.IsFlying() || val.IsTamed() || val.IsBoss())
			{
				return false;
			}
			Character val2 = Acc.Target.Invoke(ai);
			if ((Object)(object)val2 != (Object)null)
			{
				return !val2.IsDead();
			}
			return false;
		}

		private static void Arsenal(MonsterAI ai, State s)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (s.ArsenalAt > 0f && Time.time - s.ArsenalAt < 5f)
			{
				return;
			}
			s.ArsenalAt = Time.time;
			s.Melee = null;
			s.Ranged = null;
			Character obj = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
			if ((Object)(object)val == (Object)null || val.GetInventory() == null)
			{
				return;
			}
			foreach (ItemData allItem in val.GetInventory().GetAllItems())
			{
				if (allItem == null || (int)allItem.m_shared.m_aiTargetType != 0 || allItem.m_shared.m_aiAttackRange <= 0f)
				{
					continue;
				}
				if (allItem.m_shared.m_aiAttackRange > 8f)
				{
					if (s.Ranged == null || allItem.m_shared.m_aiAttackRange > s.Ranged.m_shared.m_aiAttackRange)
					{
						s.Ranged = allItem;
					}
				}
				else if (s.Melee == null || allItem.m_shared.m_aiAttackRange > s.Melee.m_shared.m_aiAttackRange)
				{
					s.Melee = allItem;
				}
			}
		}

		public static bool IsRanged(ItemData w)
		{
			if (w != null)
			{
				return w.m_shared.m_aiAttackRange > 8f;
			}
			return false;
		}

		public static bool HoldsRanged(MonsterAI ai)
		{
			Character obj = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val = (Humanoid)(object)((obj is Humanoid) ? obj : null);
			ItemData val2 = (((Object)(object)val != (Object)null) ? val.GetCurrentWeapon() : null);
			if (val2 == null || val2.m_shared.m_aiAttackRange <= 8f)
			{
				return false;
			}
			State state = Get(ai);
			Arsenal(ai, state);
			return state.Melee == null;
		}

		public static bool RangedAllowed(MonsterAI ai, Character t)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			Character val = Acc.Char.Invoke((BaseAI)(object)ai);
			Humanoid val2 = (Humanoid)(object)((val is Humanoid) ? val : null);
			ItemData val3 = (((Object)(object)val2 != (Object)null) ? val2.GetCurrentWeapon() : null);
			if (!IsRanged(val3))
			{
				return true;
			}
			State state = Get(ai);
			Arsenal(ai, state);
			float num = Utils.DistanceXZ(((Component)val).transform.position, ((Component)t).transform.position) - t.GetRadius();
			float aiAttackRange = val3.m_shared.m_aiAttackRange;
			bool flag = !Blocked(val, t);
			if (state.Melee == null)
			{
				if (flag)
				{
					return num <= aiAttackRange * 0.8f;
				}
				return false;
			}
			if (Plugin.Suppress.Value && (!Plugin.ChaseRunner.Value || !Running(t)) && Director.IsSup(ai, t) && flag && num <= aiAttackRange * 0.8f && num > state.Melee.m_shared.m_aiAttackRange + 2f && !Director.SomeoneEngaged(t, ai))
			{
				return true;
			}
			if (Time.time < state.FlushUntil && flag && num <= aiAttackRange * 0.8f)
			{
				return true;
			}
			Vector3 val4 = ((Component)t).transform.position - ((Component)val).transform.position;
			val4.y = 0f;
			bool flag2 = ((Vector3)(ref val4)).sqrMagnitude > 0.01f && Vector3.Dot(t.GetVelocity(), ((Vector3)(ref val4)).normalized) > 2f;
			bool flag3 = !Pathfinding.instance.HavePath(((Component)val).transform.position, ((Component)t).transform.position, ((BaseAI)ai).m_pathAgentType);
			int num2;
			if (flag && num <= aiAttackRange * 0.7f && num > state.Melee.m_shared.m_aiAttackRange + 4f)
			{
				if (flag3)
				{
					num2 = 1;
					goto IL_01f3;
				}
				if (flag2)
				{
					num2 = ((!Plugin.ChaseRunner.Value) ? 1 : 0);
					if (num2 != 0)
					{
						goto IL_01f3;
					}
				}
				else
				{
					num2 = 0;
				}
			}
			else
			{
				num2 = 0;
			}
			val2.EquipItem(state.Melee, true);
			goto IL_01f3;
			IL_01f3:
			return (byte)num2 != 0;
		}

		public static void AfterEquipBest(Humanoid h)
		{
			if (!Plugin.Active || (Object)(object)h == (Object)null)
			{
				return;
			}
			MonsterAI component = ((Component)h).GetComponent<MonsterAI>();
			if (!((Object)(object)component == (Object)null) && Eligible(component))
			{
				Character val = Acc.Target.Invoke(component);
				if (!((Object)(object)val == (Object)null) && IsRanged(h.GetCurrentWeapon()))
				{
					RangedAllowed(component, val);
				}
			}
		}

		public static void FlyTick(MonsterAI ai, float dt)
		{
			//IL_006f: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to inval