Decompiled source of Payload Speed Pack v0.4.2

PayloadSpeedPack.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Lua;
using Lua.Proxy;
using MoonSharp.Interpreter;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PayloadSpeedPack;

internal class CoverSettings
{
	public float Eagerness = 70f;

	public float Search = 15f;

	public float Hold = 12f;

	public float Dash = 140f;

	public float AwareRange = 25f;

	public bool Duck = true;

	public bool Sharp = true;

	public bool ShootRunning = true;

	public bool TestKeys;

	public int Teams;
}
internal class HandoffTag
{
	public const string OFFER = "CoverHandoff|";

	public const string TAKEN = "CoverTaken|";

	public CoverSettings Settings = new CoverSettings();

	public bool Roles;

	public bool Cart;

	public Vector3 CartPos;

	public float PushRange = 8f;

	public int Attackers = -1;

	public static bool IsTag(string name)
	{
		if (name != null)
		{
			if (!name.StartsWith("CoverHandoff|", StringComparison.Ordinal))
			{
				return name.StartsWith("CoverTaken|", StringComparison.Ordinal);
			}
			return true;
		}
		return false;
	}

	public static HandoffTag Parse(string name)
	{
		//IL_0187: 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 (!IsTag(name))
		{
			return null;
		}
		string[] array = name.Split(new char[1] { '|' });
		if (array.Length < 19 || array[1] != "1")
		{
			return null;
		}
		HandoffTag handoffTag = new HandoffTag();
		CoverSettings settings = handoffTag.Settings;
		settings.Eagerness = F(array[2], settings.Eagerness);
		settings.Search = F(array[3], settings.Search);
		settings.Hold = F(array[4], settings.Hold);
		settings.Dash = F(array[5], settings.Dash);
		settings.Duck = F(array[6], 1f) > 0.5f;
		settings.Teams = (int)F(array[7], 0f);
		settings.Sharp = F(array[8], 1f) > 0.5f;
		settings.ShootRunning = F(array[9], 1f) > 0.5f;
		settings.AwareRange = F(array[10], settings.AwareRange);
		settings.TestKeys = F(array[11], 0f) > 0.5f;
		handoffTag.Roles = F(array[12], 0f) > 0.5f;
		handoffTag.Cart = F(array[13], 0f) > 0.5f;
		handoffTag.CartPos = new Vector3(F(array[14], 0f), F(array[15], 0f), F(array[16], 0f));
		handoffTag.PushRange = F(array[17], 8f);
		handoffTag.Attackers = (int)F(array[18], -1f);
		return handoffTag;
	}

	private static float F(string t, float d)
	{
		if (float.TryParse(t, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
		{
			return result;
		}
		return d;
	}
}
internal class CoverBrain
{
	private class Rec
	{
		public int Index;

		public string State = "free";

		public float Next;

		public Actor Actor;

		public AiActorController Ai;

		public Vector3 Spot;

		public string Kind;

		public Actor Target;

		public bool ForReload;

		public bool Approach;

		public bool Retried;

		public bool Touched;

		public bool NoSprint;

		public bool Sprint0;

		public float Speed0 = 1f;

		public float Started;

		public float Deadline;

		public float CoverStart;

		public float UntilTime;

		public float LastFight;

		public string Pose;

		public float PoseUntil;

		public float DuckCheck = -1f;

		public int LastAmmo = int.MinValue;

		public int RunAmmo = int.MinValue;

		public int ExposedLooks;

		public float NextWatch;

		public float NextClose;

		public float NextRunLook;

		public float NextLook;
	}

	private class React
	{
		public bool Aware;

		public bool PrevFov;

		public bool Sharp;

		public bool BusyFar;

		public bool Cart;

		public bool Side;

		public float Since = -1f;
	}

	private class Bucket
	{
		public int N;

		public int Slow;

		public int CartN;

		public int SideN;

		public int FarN;

		public int Lost;

		public float Sum;

		public float CartSum;

		public float SideSum;

		public float FarSum;

		public List<float> List = new List<float>();
	}

	private class Survey
	{
		public int N;

		public int Covered;

		public int Deaths;

		public float Time;
	}

	private class Claim
	{
		public float X;

		public float Z;

		public float Until;
	}

	private class Keep
	{
		public float X;

		public float Z;

		public float R;

		public bool Approach;
	}

	private class Found
	{
		public Actor E;

		public float D;
	}

	private const float CHECK_EVERY = 1.5f;

	private const int BOTS_PER_FRAME = 6;

	private const int SURVEY_PER_FRAME = 1;

	private const float MIN_RANGE = 8f;

	private const float MAX_RANGE = 250f;

	private const float RETRY_AFTER = 6f;

	private const float ARRIVE = 0.6f;

	private const float NEAR = 4f;

	private const float FIGHT_GAP = 8f;

	private const int DIRECTIONS = 12;

	private const float STATS_EVERY = 60f;

	private const float APPROACH = 60f;

	private const float APPROACH_HOLD = 4f;

	private const float ACTOR_LIST_EVERY = 1f;

	private const float CLOSE_FIGHT = 12f;

	private const int REACT_PER_FRAME = 2;

	private const float WATCH_EVERY = 0.1f;

	private const float REACT_CAP = 10f;

	private const float CART_NEAR = 20f;

	private const float EYE = 1.45f;

	private const int OPAQUE = 3;

	private const int WALKABLE = 2232321;

	private CoverSettings S;

	private float LOW_H = 1f;

	private float HIGH_H = 1.55f;

	private readonly Dictionary<int, Rec> bots = new Dictionary<int, Rec>();

	private readonly Dictionary<int, Rec> active = new Dictionary<int, Rec>();

	private readonly Dictionary<int, React> react = new Dictionary<int, React>();

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

	private readonly Dictionary<int, float> nextRole = new Dictionary<int, float>();

	private readonly Dictionary<int, int[]> fireRec = new Dictionary<int, int[]>();

	private readonly List<Claim> claims = new List<Claim>();

	private readonly Bucket reactOn = new Bucket();

	private readonly Bucket reactOff = new Bucket();

	private readonly Survey survey = new Survey();

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

	private readonly List<float> standH = new List<float>();

	private readonly List<float> crouchH = new List<float>();

	private List<Actor> actorList = new List<Actor>();

	private int cursor;

	private int surveyCursor;

	private int reactCursor;

	private int calibFails;

	private float nextActorList;

	private float nextTidy;

	private float nextStats;

	private float nextCalib;

	private float lastTime;

	private bool calibrated;

	private int[] lastSeen = new int[5];

	private float freeShots;

	private float freeTime;

	private int playerTeam = -1;

	public bool RolesOn;

	private bool hasCart;

	private Vector3 cartPos;

	private float cartRange = 8f;

	private int cartAttack = -1;

	private int went;

	private int low;

	private int full;

	private int forReload;

	private int arrived;

	private int reallyCovered;

	private int gaveUp;

	private int none;

	private int flanked;

	private int shots;

	private int ducks;

	private int duckWorked;

	private int duckChecked;

	private int retries;

	private int fixedCount;

	private int atCart;

	private int toCart;

	private int closeSkips;

	private int runShots;

	private int runLooks;

	private int runFighting;

	private float coverTime;

	private float arriveDist;

	private float runTime;

	private readonly Random rng = new Random();

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

	public CoverBrain(HandoffTag tag)
	{
		S = tag.Settings;
		Apply(tag);
		lastTime = Time.time;
		nextStats = Time.time + 60f;
		try
		{
			playerTeam = GameManager.PlayerTeam();
		}
		catch
		{
			playerTeam = -1;
		}
		string[] array = new string[3] { "both teams", "your team only", "the enemy only" };
		Log(string.Format("Bots Take Cover runs in the Payload Speed Pack plugin now (C#, same settings, {0}): {1:0}% eager, up to {2:0} m, {3:0} s in cover, {4:0}% speed to cover, ducking {5}.", (S.Teams >= 0 && S.Teams < 3) ? array[S.Teams] : "both teams", S.Eagerness, S.Search, S.Hold, S.Dash, S.Duck ? "on" : "off"));
		if (S.Sharp)
		{
			Log($"Sharper reactions are on: bots notice enemies within {S.AwareRange:0} m from any side, and fight an enemy within {12f:0} m instead of going for cover.");
		}
	}

	public void Apply(HandoffTag tag)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		bool sharp = S.Sharp;
		S = tag.Settings;
		RolesOn = tag.Roles;
		hasCart = tag.Cart;
		cartPos = tag.CartPos;
		cartRange = tag.PushRange;
		cartAttack = tag.Attackers;
		if (sharp != S.Sharp && went + reactOn.N + reactOff.N > 0)
		{
			PrintStats();
		}
	}

	private static void Log(string msg)
	{
		string text = "[Cover] " + msg;
		try
		{
			if ((Object)(object)ScriptConsole.instance != (Object)null)
			{
				ScriptConsole.instance.LogInfo(text);
				return;
			}
		}
		catch
		{
		}
		Debug.Log((object)text);
	}

	private void Warn(string label, Exception e)
	{
		string text = label + ": " + e.GetType().Name + ": " + e.Message;
		if (warned.Add(text))
		{
			Log("Problem with " + text + "\n" + e.StackTrace);
		}
	}

	private static float FlatDist(Vector3 a, Vector3 b)
	{
		float num = a.x - b.x;
		float num2 = a.z - b.z;
		return Mathf.Sqrt(num * num + num2 * num2);
	}

	private static float Median(List<float> t)
	{
		if (t.Count == 0)
		{
			return 0f;
		}
		List<float> list = new List<float>(t);
		list.Sort();
		return list[(list.Count + 1) / 2 - 1];
	}

	private bool TeamAllowed(int team)
	{
		if (S.Teams == 0 || playerTeam < 0)
		{
			return true;
		}
		if (S.Teams == 1)
		{
			return team == playerTeam;
		}
		return team != playerTeam;
	}

	private static bool Usable(Actor a)
	{
		if ((Object)(object)a == (Object)null)
		{
			return false;
		}
		if (!a.dead && a.aiControlled && !a.IsSeated() && !((Object)(object)a.seat != (Object)null) && !a.isFrozen && !a.IsOnLadder() && !a.IsSwimming() && !a.immersedInWater && !a.parachuteDeployed)
		{
			return !a.fallenOver;
		}
		return false;
	}

	private static AiActorController AiOf(Actor a)
	{
		if (!((Object)(object)a != (Object)null))
		{
			return null;
		}
		ActorController controller = a.controller;
		return (AiActorController)(object)((controller is AiActorController) ? controller : null);
	}

	private static Actor Enemy(AiActorController ai, out Vector3 aim)
	{
		//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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		aim = Vector3.zero;
		if ((Object)(object)ai == (Object)null)
		{
			return null;
		}
		Actor target = ai.target;
		if ((Object)(object)target == (Object)null || target.dead)
		{
			return null;
		}
		aim = target.CenterPosition();
		return target;
	}

	private static bool AimOf(Actor t, out Vector3 aim)
	{
		//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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		aim = Vector3.zero;
		if ((Object)(object)t == (Object)null || t.dead)
		{
			return false;
		}
		aim = t.CenterPosition();
		return true;
	}

	private bool CoverAim(Rec rec, out Vector3 aim)
	{
		if ((Object)(object)Enemy(rec.Ai, out aim) != (Object)null)
		{
			return true;
		}
		return AimOf(rec.Target, out aim);
	}

	private static bool Blocked(Vector3 pos, Vector3 aim, float height, float reach)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: 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_0025: 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_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_0059: 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_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(pos.x, pos.y + height, pos.z);
		Vector3 val2 = aim - val;
		float magnitude = ((Vector3)(ref val2)).magnitude;
		if (magnitude < 2.5f)
		{
			return false;
		}
		Vector3 val3 = val2 / magnitude;
		float num = magnitude - 1.5f;
		if (reach > 0f && reach < num)
		{
			num = reach;
		}
		return Physics.Linecast(val + val3 * 0.35f, val + val3 * num, 3);
	}

	private static bool Busy(Actor a, out bool reloading)
	{
		reloading = false;
		Weapon activeWeapon = a.activeWeapon;
		if ((Object)(object)activeWeapon == (Object)null)
		{
			return false;
		}
		if (activeWeapon.reloading)
		{
			reloading = true;
			return true;
		}
		return !activeWeapon.CanFire();
	}

	private bool SharpOn()
	{
		return S.Sharp;
	}

	private static bool InSight(Actor a, Actor e)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		if (!AimOf(e, out var aim))
		{
			return false;
		}
		Vector3 val = a.Position();
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(val.x, val.y + 1.45f, val.z);
		Vector3 val3 = aim - val2;
		float magnitude = ((Vector3)(ref val3)).magnitude;
		if (magnitude < 1.5f)
		{
			return true;
		}
		Vector3 val4 = val3 / magnitude;
		return !Physics.Linecast(val2 + val4 * 0.35f, aim - val4 * 0.6f, 3);
	}

	private static List<Found> EnemiesNear(Actor a, float range)
	{
		//IL_0007: 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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		List<Found> list = new List<Found>();
		Vector3 val = a.Position();
		List<Actor> list2 = ActorManager.AliveActorsInRange(val, range);
		if (list2 == null)
		{
			return list;
		}
		for (int i = 0; i < list2.Count; i++)
		{
			Actor val2 = list2[i];
			if ((Object)(object)val2 == (Object)null || ((Hurtable)val2).team == ((Hurtable)a).team || val2.dead)
			{
				continue;
			}
			Vector3 b = val2.Position();
			if (!(Mathf.Abs(b.y - val.y) >= 6f))
			{
				float num = FlatDist(val, b);
				if (num <= range)
				{
					Found found = new Found();
					found.E = val2;
					found.D = num;
					list.Add(found);
				}
			}
		}
		list.Sort((Found x, Found y) => x.D.CompareTo(y.D));
		return list;
	}

	private static Actor FirstInSight(Actor a, List<Found> found)
	{
		for (int i = 0; i < found.Count && i < 3; i++)
		{
			if (InSight(a, found[i].E))
			{
				return found[i].E;
			}
		}
		return null;
	}

	private static Actor NearestEnemy(Actor a, float range, bool mustSee)
	{
		List<Found> list = EnemiesNear(a, range);
		if (list.Count == 0)
		{
			return null;
		}
		if (!mustSee)
		{
			return list[0].E;
		}
		return FirstInSight(a, list);
	}

	private static void SetAware(AiActorController ai, React r, bool want)
	{
		if (want)
		{
			if (!r.Aware)
			{
				r.PrevFov = ai.modifier.ignoreFovCheck;
				if (!r.PrevFov)
				{
					ai.modifier.ignoreFovCheck = true;
				}
				r.Aware = true;
			}
		}
		else if (r.Aware)
		{
			if (!r.PrevFov)
			{
				ai.modifier.ignoreFovCheck = false;
			}
			r.Aware = false;
		}
	}

	private void AddReaction(float t, React r)
	{
		Bucket bucket = (r.Sharp ? reactOn : reactOff);
		bucket.N++;
		bucket.Sum += t;
		if (t > 2f)
		{
			bucket.Slow++;
		}
		if (bucket.List.Count < 400)
		{
			bucket.List.Add(t);
		}
		if (r.Cart)
		{
			bucket.CartN++;
			bucket.CartSum += t;
		}
		if (r.Side)
		{
			bucket.SideN++;
			bucket.SideSum += t;
		}
		if (r.BusyFar)
		{
			bucket.FarN++;
			bucket.FarSum += t;
		}
	}

	private void ReactTo(Actor a, float now)
	{
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: 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_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)a == (Object)null || !a.aiControlled)
		{
			return;
		}
		AiActorController val = AiOf(a);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		if (!react.TryGetValue(a.actorIndex, out var value))
		{
			value = new React();
			react[a.actorIndex] = value;
		}
		if (a.dead)
		{
			SetAware(val, value, want: false);
			value.Since = -1f;
			return;
		}
		bool flag = SharpOn();
		List<Found> list = EnemiesNear(a, S.AwareRange);
		bool flag2 = list.Count > 0;
		SetAware(val, value, flag && flag2);
		Actor target = val.target;
		bool busyFar = false;
		if ((Object)(object)target != (Object)null && !target.dead)
		{
			if (FlatDist(a.Position(), target.Position()) <= S.AwareRange)
			{
				if (value.Since >= 0f)
				{
					if (value.Since <= now)
					{
						AddReaction(now - value.Since, value);
					}
					value.Since = -1f;
				}
				return;
			}
			busyFar = true;
		}
		Actor val2 = (flag2 ? FirstInSight(a, list) : null);
		if ((Object)(object)val2 != (Object)null)
		{
			if (value.Since < 0f)
			{
				value.Since = now;
				value.Sharp = flag;
				value.BusyFar = busyFar;
				value.Cart = hasCart && FlatDist(a.Position(), cartPos) <= 20f;
				value.Side = false;
				Vector3 val3 = ((ActorController)val).FacingDirection();
				Vector3 val4 = val2.Position();
				Vector3 val5 = a.Position();
				float num = val4.x - val5.x;
				float num2 = val4.z - val5.z;
				float num3 = Mathf.Sqrt(num * num + num2 * num2);
				float num4 = Mathf.Sqrt(val3.x * val3.x + val3.z * val3.z);
				if (num3 > 0.5f && num4 > 0.01f)
				{
					value.Side = (num * val3.x + num2 * val3.z) / (num3 * num4) < 0.5f;
				}
			}
			else if (now - value.Since > 10f && value.Since <= now)
			{
				AddReaction(10f, value);
				value.Since = now + 1000f;
			}
		}
		else if (value.Since >= 0f)
		{
			if (value.Since <= now)
			{
				(value.Sharp ? reactOn : reactOff).Lost++;
			}
			value.Since = -1f;
		}
	}

	private string RoleOf(Actor a, float now)
	{
		if (!RolesOn || (Object)(object)a == (Object)null)
		{
			return null;
		}
		if (roles.TryGetValue(a.actorIndex, out var value) && nextRole.TryGetValue(a.actorIndex, out var value2) && now < value2)
		{
			return value;
		}
		value = Classify(MainWeapon(a));
		roles[a.actorIndex] = value;
		nextRole[a.actorIndex] = now + 8f;
		return value;
	}

	private static Weapon MainWeapon(Actor a)
	{
		if (a.weapons != null && a.weapons.Length > 0 && (Object)(object)a.weapons[0] != (Object)null)
		{
			return a.weapons[0];
		}
		return a.activeWeapon;
	}

	private static string Classify(Weapon w)
	{
		//IL_002d: 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)
		if ((Object)(object)w == (Object)null)
		{
			return "rifle";
		}
		WeaponEntry weaponEntry = w.weaponEntry;
		Configuration configuration = w.configuration;
		if (configuration == null)
		{
			return "rifle";
		}
		int num = ((weaponEntry == null) ? (-1) : ((int)weaponEntry.mainRole));
		int num2 = ((weaponEntry == null) ? (-1) : ((int)weaponEntry.distance));
		if (num == 3 || num == 2 || num == 13 || configuration.projectilesPerShot > 3)
		{
			return "close";
		}
		if (num == 1 && configuration.aimFov < 30f)
		{
			return "sniper";
		}
		if (configuration.auto && (num2 == 0 || configuration.effectiveRange < 60f))
		{
			return "close";
		}
		if (configuration.auto && configuration.ammo >= 50)
		{
			return "support";
		}
		return "rifle";
	}

	private float HoldScale(Actor a, float now)
	{
		return RoleOf(a, now) switch
		{
			"sniper" => 2f, 
			"support" => 1.5f, 
			"close" => 0.5f, 
			_ => 1f, 
		};
	}

	private void ShowMe(float now)
	{
		//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_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: 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_0208: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		Actor val = (((Object)(object)ActorManager.instance != (Object)null) ? ActorManager.instance.player : null);
		if ((Object)(object)val == (Object)null || val.dead)
		{
			Log("Spawn first, then press H.");
			return;
		}
		Rec rec = null;
		float num = -1f;
		foreach (Rec value in active.Values)
		{
			if (!(value.State != "cover") && !((Object)(object)value.Actor == (Object)null) && !value.Actor.dead)
			{
				float num2 = now - value.CoverStart;
				if (value.Kind == "low")
				{
					num2 += 100f;
				}
				if (((Hurtable)value.Actor).team == ((Hurtable)val).team)
				{
					num2 += 1000f;
				}
				if (num2 > num)
				{
					rec = value;
					num = num2;
				}
			}
		}
		if (rec == null)
		{
			Log("No bot is in cover right now. Try again in a few seconds.");
			return;
		}
		Actor actor = rec.Actor;
		Vector3 val2 = actor.Position();
		float num3 = 0f;
		float num4 = 1f;
		float num5 = 0f;
		if ((Object)(object)Enemy(rec.Ai, out var aim) != (Object)null)
		{
			float num6 = aim.x - val2.x;
			float num7 = aim.z - val2.z;
			num5 = Mathf.Sqrt(num6 * num6 + num7 * num7);
			if (num5 > 0.1f)
			{
				num3 = num6 / num5;
				num4 = num7 / num5;
			}
		}
		Vector3 val3 = default(Vector3);
		((Vector3)(ref val3))..ctor(val2.x - num3 * 5f + num4 * 2f, val2.y + 0.5f, val2.z - num4 * 5f - num3 * 2f);
		RaycastHit val4 = default(RaycastHit);
		if (Physics.Raycast(new Ray(val3 + new Vector3(0f, 4f, 0f), Vector3.down), ref val4, 10f, 2232321))
		{
			val3 = ((RaycastHit)(ref val4)).point + new Vector3(0f, 0.2f, 0f);
		}
		Vector3 val5 = new Vector3(val2.x + num3 * 10f, val2.y, val2.z + num4 * 10f) - val3;
		val.SetPositionAndRotation(val3, Quaternion.Euler(0f, Mathf.Atan2(val5.x, val5.z) * 57.29578f, 0f));
		Log(string.Format("Showing you {0} ({1}) in {2} cover for {3} s, its enemy is {4} m away.", actor.name, (((Hurtable)actor).team == ((Hurtable)val).team) ? "your team" : "enemy", (rec.Kind == "low") ? "low" : "tall", (int)(now - rec.CoverStart), (int)num5));
	}

	private Keep KeepNear(Vector3 pos, int team)
	{
		//IL_000a: 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)
		if (!hasCart)
		{
			return null;
		}
		float num = FlatDist(pos, cartPos);
		if (num <= cartRange + 4f)
		{
			atCart++;
			Keep keep = new Keep();
			keep.X = cartPos.x;
			keep.Z = cartPos.z;
			keep.R = Mathf.Max(2f, cartRange - 1f);
			return keep;
		}
		if (cartAttack >= 0 && team == cartAttack && num <= 60f)
		{
			toCart++;
			Keep keep2 = new Keep();
			keep2.X = cartPos.x;
			keep2.Z = cartPos.z;
			keep2.R = num - 4f;
			keep2.Approach = true;
			return keep2;
		}
		return null;
	}

	private bool Claimed(float x, float z, float now)
	{
		for (int i = 0; i < claims.Count; i++)
		{
			Claim claim = claims[i];
			if (claim.Until > now)
			{
				float num = claim.X - x;
				float num2 = claim.Z - z;
				if (num * num + num2 * num2 < 2.25f)
				{
					return true;
				}
			}
		}
		return false;
	}

	private bool FindCover(Vector3 pos, Vector3 aim, float now, bool allowFull, float maxR, Keep keep, out Vector3 best, out string bestKind)
	{
		//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_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
		best = Vector3.zero;
		bestKind = null;
		float num = aim.x - pos.x;
		float num2 = aim.z - pos.z;
		float num3 = Mathf.Sqrt(num * num + num2 * num2);
		if (num3 < 0.001f)
		{
			return false;
		}
		float num4 = num / num3;
		float num5 = num2 / num3;
		float num6 = float.NegativeInfinity;
		bool flag = false;
		float num7 = (float)Math.PI / 6f;
		float num8 = ((maxR > 0f) ? maxR : S.Search) + 0.1f;
		RaycastHit val = default(RaycastHit);
		for (float num9 = 2f; num9 <= num8; num9 += 2f)
		{
			for (int i = 0; i < 12; i++)
			{
				float num10 = (float)i * num7 + num9 * 0.37f;
				float num11 = pos.x + Mathf.Cos(num10) * num9;
				float num12 = pos.z + Mathf.Sin(num10) * num9;
				float num13 = (num11 - pos.x) * num4 + (num12 - pos.z) * num5;
				bool flag2 = true;
				if (keep != null)
				{
					float num14 = num11 - keep.X;
					float num15 = num12 - keep.Z;
					flag2 = num14 * num14 + num15 * num15 <= keep.R * keep.R;
				}
				if (!flag2 || num13 >= Mathf.Max(3f, num9 * 0.6f) || Claimed(num11, num12, now) || !Physics.Raycast(new Ray(new Vector3(num11, pos.y + 3f, num12), Vector3.down), ref val, 7f, 2232321))
				{
					continue;
				}
				Vector3 point = ((RaycastHit)(ref val)).point;
				if (Mathf.Abs(point.y - pos.y) > 2.5f || WaterLevel.IsInWater(new Vector3(point.x, point.y + 0.6f, point.z)) || !Blocked(point, aim, LOW_H, 4f))
				{
					continue;
				}
				string text = "low";
				if (Blocked(point, aim, HIGH_H, 4f))
				{
					text = "full";
				}
				float num16 = 10f - num9 * 0.4f - Mathf.Max(0f, num13) * 0.3f;
				if (text == "low")
				{
					num16 += 3f;
				}
				if (num16 > num6 && (text == "low" || allowFull))
				{
					if (text == "low" && Blocked(point, aim, HIGH_H, 0f))
					{
						text = "full";
						num16 -= 3f;
					}
					if (num16 > num6 && (text == "low" || allowFull))
					{
						best = point;
						num6 = num16;
						bestKind = text;
						flag = true;
					}
				}
			}
			if (flag && bestKind == "low" && num9 >= 4f)
			{
				break;
			}
		}
		return flag;
	}

	private void RestoreSprint(Rec rec)
	{
		if (rec.NoSprint)
		{
			rec.NoSprint = false;
			if (rec.Sprint0 && (Object)(object)rec.Ai != (Object)null)
			{
				rec.Ai.modifier.canSprint = true;
			}
		}
	}

	private void Count(string reason)
	{
		why.TryGetValue(reason, out var value);
		why[reason] = value + 1;
	}

	private void Release(Rec rec, float now, string reason)
	{
		Actor actor = rec.Actor;
		AiActorController ai = rec.Ai;
		try
		{
			if (rec.Pose == "down" && (Object)(object)actor != (Object)null)
			{
				actor.ForceStance((Stance)0);
			}
		}
		catch (Exception e)
		{
			Warn("standing up", e);
		}
		try
		{
			if ((Object)(object)ai != (Object)null)
			{
				ai.CancelPath(true);
			}
		}
		catch (Exception e2)
		{
			Warn("cancelling a path", e2);
		}
		try
		{
			if ((Object)(object)ai != (Object)null)
			{
				ai.ReleaseDefaultMovementOverride();
			}
		}
		catch (Exception e3)
		{
			Warn("handing a bot back", e3);
		}
		if ((Object)(object)actor != (Object)null)
		{
			actor.speedMultiplier = rec.Speed0;
		}
		if (rec.State == "cover")
		{
			coverTime += now - rec.CoverStart;
		}
		if (rec.State == "moving")
		{
			runTime += now - rec.Started;
		}
		RestoreSprint(rec);
		rec.State = "free";
		rec.Pose = null;
		rec.Next = now + 6f;
		active.Remove(rec.Index);
		if (reason == "timeout" || reason == "nopath")
		{
			gaveUp++;
		}
		if (reason == "flanked")
		{
			flanked++;
		}
		Count(reason);
	}

	private bool StartMove(Actor a, Rec rec, Vector3 spot, string kind, Actor target, float now, bool reloading)
	{
		//IL_0031: 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_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		AiActorController val = AiOf(a);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if (val.isDefaultMovementOverridden)
		{
			rec.Next = now + 6f;
			return false;
		}
		try
		{
			val.OverrideDefaultMovement();
			val.Goto(spot, true);
		}
		catch (Exception e)
		{
			Warn("moving a bot", e);
			try
			{
				val.ReleaseDefaultMovementOverride();
			}
			catch
			{
			}
			rec.Next = now + 6f;
			return false;
		}
		rec.Actor = a;
		rec.Ai = val;
		rec.Spot = spot;
		rec.Kind = kind;
		rec.Target = target;
		rec.ForReload = reloading;
		rec.Speed0 = a.speedMultiplier;
		if (rec.Speed0 < 0.2f)
		{
			rec.Speed0 = 1f;
		}
		a.speedMultiplier = rec.Speed0 * S.Dash / 100f;
		rec.State = "moving";
		rec.Started = now;
		rec.RunAmmo = int.MinValue;
		rec.NoSprint = false;
		if (S.ShootRunning && SharpOn())
		{
			rec.Sprint0 = val.modifier.canSprint;
			val.modifier.canSprint = false;
			rec.NoSprint = true;
		}
		rec.Deadline = now + FlatDist(a.Position(), spot) / 2.5f + 3f;
		rec.Pose = null;
		rec.LastAmmo = int.MinValue;
		rec.Retried = false;
		rec.Touched = true;
		active[rec.Index] = rec;
		Claim claim = new Claim();
		claim.X = spot.x;
		claim.Z = spot.z;
		claim.Until = rec.Deadline + S.Hold;
		claims.Add(claim);
		went++;
		if (kind == "low")
		{
			low++;
		}
		else
		{
			full++;
		}
		if (reloading)
		{
			forReload++;
		}
		return true;
	}

	private bool Check(Actor a, float now, bool canSearch)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Invalid comparison between Unknown and I4
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: 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_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)a == (Object)null || !a.aiControlled)
		{
			return false;
		}
		if (!bots.TryGetValue(a.actorIndex, out var value))
		{
			value = new Rec();
			value.Index = a.actorIndex;
			bots[a.actorIndex] = value;
		}
		if (value.State != "free" || now < value.Next)
		{
			return false;
		}
		if (!TeamAllowed(((Hurtable)a).team) || !Usable(a))
		{
			value.Next = now + 1.5f;
			return false;
		}
		AiActorController ai = AiOf(a);
		Vector3 aim;
		Actor val = Enemy(ai, out aim);
		if ((Object)(object)val == (Object)null)
		{
			value.Next = now + 1.5f;
			return false;
		}
		Vector3 val2 = a.Position();
		float num = FlatDist(val2, aim);
		if (num < 8f || num > 250f)
		{
			value.Next = now + 1.5f;
			return false;
		}
		if ((int)a.stance == 2 || Blocked(val2, aim, LOW_H, 0f))
		{
			value.Next = now + 1.5f;
			return false;
		}
		Busy(a, out var reloading);
		float num2 = S.Eagerness;
		switch (RoleOf(a, now))
		{
		case "close":
			num2 = S.Eagerness * 0.25f;
			break;
		case "sniper":
		case "support":
			num2 = 100f;
			break;
		}
		if (!reloading && (float)rng.Next(1, 101) > num2)
		{
			value.Next = now + 1.5f;
			return false;
		}
		if (!canSearch)
		{
			return false;
		}
		if (SharpOn() && (Object)(object)NearestEnemy(a, 12f, mustSee: true) != (Object)null)
		{
			closeSkips++;
			value.Next = now + 1.5f;
			return true;
		}
		Keep keep = KeepNear(val2, ((Hurtable)a).team);
		if (!FindCover(val2, aim, now, reloading, 0f, keep, out var best, out var bestKind))
		{
			none++;
			value.Next = now + 6f;
			return true;
		}
		value.Approach = keep?.Approach ?? false;
		StartMove(a, value, best, bestKind, val, now, reloading);
		return true;
	}

	private void DuckIn(Rec rec, float now, bool busy)
	{
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Invalid comparison between Unknown and I4
		Actor actor = rec.Actor;
		string text = (busy ? "down" : "up");
		if (text != (rec.Pose ?? "up") && now >= rec.PoseUntil)
		{
			try
			{
				actor.ForceStance((Stance)(text == "down"));
				rec.Pose = text;
				if (text == "down")
				{
					rec.PoseUntil = now + 0.6f;
					rec.DuckCheck = now + 0.4f;
					ducks++;
				}
				else
				{
					rec.PoseUntil = now + 1.2f;
				}
			}
			catch (Exception e)
			{
				Warn("ducking", e);
			}
		}
		if (rec.DuckCheck >= 0f && now >= rec.DuckCheck)
		{
			rec.DuckCheck = -1f;
			duckChecked++;
			if ((int)actor.stance == 1)
			{
				duckWorked++;
			}
		}
	}

	private void Watch(Rec rec, float now)
	{
		//IL_0216: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: 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_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b0: 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_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
		Actor actor = rec.Actor;
		if (now < rec.NextWatch)
		{
			return;
		}
		rec.NextWatch = now + 0.1f;
		if (!Usable(actor))
		{
			Release(rec, now, ((Object)(object)actor == (Object)null || actor.dead) ? "died" : "busy");
			return;
		}
		if (SharpOn() && now >= rec.NextClose)
		{
			rec.NextClose = now + 0.3f;
			if ((Object)(object)NearestEnemy(actor, 12f, mustSee: true) != (Object)null)
			{
				Release(rec, now, "enemy close");
				return;
			}
		}
		Vector3 aim;
		if (rec.State == "moving")
		{
			Weapon activeWeapon = actor.activeWeapon;
			if ((Object)(object)activeWeapon != (Object)null)
			{
				int ammo = activeWeapon.ammo;
				if (rec.RunAmmo != int.MinValue && ammo < rec.RunAmmo)
				{
					runShots += rec.RunAmmo - ammo;
				}
				rec.RunAmmo = ammo;
			}
			if (now >= rec.NextRunLook)
			{
				rec.NextRunLook = now + 0.5f;
				runLooks++;
				if ((Object)(object)Enemy(rec.Ai, out aim) != (Object)null)
				{
					runFighting++;
				}
			}
			Vector3 val = actor.Position();
			float num = FlatDist(val, rec.Spot);
			bool flag = now > rec.Started + 1.5f && !((ActorController)rec.Ai).HasPath();
			if (num < 0.6f || (flag && num < 2.5f))
			{
				bool flag2 = CoverAim(rec, out aim);
				bool flag3 = flag2 && Blocked(val, aim, LOW_H, 0f);
				if (flag2 && !flag3 && !rec.Retried && FindCover(val, aim, now, allowFull: true, 5f, KeepNear(val, ((Hurtable)actor).team), out var best, out var bestKind))
				{
					bool flag4 = true;
					try
					{
						rec.Ai.Goto(best, true);
					}
					catch
					{
						flag4 = false;
					}
					if (flag4)
					{
						rec.Retried = true;
						rec.Spot = best;
						rec.Kind = bestKind;
						rec.Started = now;
						rec.Deadline = now + FlatDist(val, best) / 2.5f + 3f;
						Claim claim = new Claim();
						claim.X = best.x;
						claim.Z = best.z;
						claim.Until = rec.Deadline + S.Hold;
						claims.Add(claim);
						retries++;
						return;
					}
				}
				runTime += now - rec.Started;
				RestoreSprint(rec);
				rec.State = "cover";
				rec.CoverStart = now;
				rec.UntilTime = now + (rec.Approach ? 4f : (S.Hold * HoldScale(actor, now)));
				rec.LastFight = now;
				rec.ExposedLooks = 0;
				try
				{
					rec.Ai.CancelPath(true);
				}
				catch
				{
				}
				try
				{
					rec.Ai.ReleaseDefaultMovementOverride();
				}
				catch
				{
				}
				actor.speedMultiplier = 0f;
				arrived++;
				arriveDist += num;
				if (flag3)
				{
					reallyCovered++;
				}
			}
			else if (now > rec.Deadline)
			{
				Release(rec, now, "timeout");
			}
			else if (flag)
			{
				Release(rec, now, "nopath");
			}
			return;
		}
		Weapon activeWeapon2 = actor.activeWeapon;
		if ((Object)(object)activeWeapon2 != (Object)null)
		{
			int ammo2 = activeWeapon2.ammo;
			if (rec.LastAmmo != int.MinValue && ammo2 < rec.LastAmmo)
			{
				shots += rec.LastAmmo - ammo2;
			}
			rec.LastAmmo = ammo2;
		}
		bool reloading;
		bool busy = Busy(actor, out reloading);
		if (S.Duck && rec.Kind == "low")
		{
			DuckIn(rec, now, busy);
		}
		if ((Object)(object)Enemy(rec.Ai, out aim) != (Object)null)
		{
			rec.LastFight = now;
		}
		bool flag5 = CoverAim(rec, out aim);
		if (rec.Kind == "full" && !reloading && now > rec.CoverStart + 2f)
		{
			Release(rec, now, "done");
		}
		else if (now > rec.UntilTime || now - rec.LastFight > 8f)
		{
			Release(rec, now, "done");
		}
		else
		{
			if (!flag5 || !(rec.NextLook < now))
			{
				return;
			}
			rec.NextLook = now + 2f;
			if (Blocked(actor.Position(), aim, LOW_H, 0f))
			{
				rec.ExposedLooks = 0;
				return;
			}
			rec.ExposedLooks++;
			if (rec.ExposedLooks >= 2)
			{
				Release(rec, now, "flanked");
			}
		}
	}

	private void SurveyBot(Actor a, float now)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Invalid comparison between Unknown and I4
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		if (!Usable(a) || (Object)(object)Enemy(AiOf(a), out var aim) == (Object)null)
		{
			return;
		}
		Vector3 val = a.Position();
		float num = FlatDist(val, aim);
		if (num < 8f || num > 250f)
		{
			return;
		}
		survey.N++;
		if ((int)a.stance == 2 || Blocked(val, aim, LOW_H, 0f))
		{
			survey.Covered++;
		}
		if (active.ContainsKey(a.actorIndex))
		{
			fireRec.Remove(a.actorIndex);
			return;
		}
		Weapon activeWeapon = a.activeWeapon;
		if ((Object)(object)activeWeapon == (Object)null)
		{
			return;
		}
		int ammo = activeWeapon.ammo;
		int num2 = (int)(now * 1000f);
		if (fireRec.TryGetValue(a.actorIndex, out var value) && num2 - value[1] < 3000)
		{
			freeTime += (float)(num2 - value[1]) / 1000f;
			if (ammo < value[0])
			{
				freeShots += value[0] - ammo;
			}
		}
		fireRec[a.actorIndex] = new int[2] { ammo, num2 };
	}

	private void Calibrate(Actor a)
	{
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Invalid comparison between Unknown and I4
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if (calibrated || (Object)(object)a == (Object)null || a.dead || a.IsSeated())
		{
			return;
		}
		List<float> list = null;
		if ((int)a.stance == 1)
		{
			list = crouchH;
		}
		else if ((int)a.stance == 0)
		{
			list = standH;
		}
		if (list == null || list.Count >= 15)
		{
			return;
		}
		Transform val = null;
		try
		{
			val = (((Object)(object)a.ragdoll != (Object)null) ? a.ragdoll.HumanBoneTransformAnimated((HumanBodyBones)10) : null);
		}
		catch
		{
			val = null;
		}
		if ((Object)(object)val == (Object)null)
		{
			calibFails++;
			if (calibFails >= 20)
			{
				calibrated = true;
				Log($"Could not measure head heights. Using cover heights {LOW_H:0.00} / {HIGH_H:0.00} m.");
			}
			return;
		}
		float num = val.position.y - a.Position().y;
		if (num > 0.2f && num < 2.5f)
		{
			list.Add(num);
		}
		if (standH.Count >= 15 && crouchH.Count >= 15)
		{
			calibrated = true;
			float num2 = Median(standH);
			float num3 = Median(crouchH);
			float num4 = num3 + 0.1f;
			float num5 = num2 - 0.07f;
			string text = "kept";
			if (num4 > 0.7f && num4 < 1.45f && num5 > 1.2f && num5 < 2f && num5 - num4 > 0.25f)
			{
				LOW_H = num4;
				HIGH_H = num5;
				text = "now using";
			}
			Log($"Measured head heights: standing {num2:0.00} m, crouching {num3:0.00} m. Cover heights {text}: hides a crouching head at {LOW_H:0.00} m, shoot over below {HIGH_H:0.00} m.");
		}
	}

	private void Tidy(float now)
	{
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		for (int i = 0; i < actorList.Count; i++)
		{
			Actor val = actorList[i];
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			num++;
			if (!val.aiControlled || val.dead)
			{
				continue;
			}
			num2++;
			AiActorController val2 = AiOf(val);
			if ((Object)(object)Enemy(val2, out var _) != (Object)null)
			{
				num3++;
			}
			bots.TryGetValue(val.actorIndex, out var value);
			bool flag = active.ContainsKey(val.actorIndex);
			if (value != null && value.NoSprint && !flag)
			{
				RestoreSprint(value);
				fixedCount++;
			}
			if ((Object)(object)val2 != (Object)null && val2.isDefaultMovementOverridden)
			{
				num4++;
			}
			if (val.speedMultiplier < 0.05f)
			{
				num5++;
				if (value != null && value.Touched && !flag)
				{
					val.speedMultiplier = 1f;
					fixedCount++;
				}
			}
		}
		lastSeen = new int[5] { num, num2, num3, num4, num5 };
	}

	public void OnActorDied(Actor actor, bool silent)
	{
		if (!silent && !((Object)(object)actor == (Object)null) && actor.aiControlled)
		{
			survey.Deaths++;
		}
	}

	public void Tick(float now)
	{
		float num = now - lastTime;
		lastTime = now;
		survey.Time += num;
		List<Rec> list = new List<Rec>(active.Values);
		for (int i = 0; i < list.Count; i++)
		{
			try
			{
				Watch(list[i], now);
			}
			catch (Exception e)
			{
				Warn("watching a bot", e);
				try
				{
					Release(list[i], now, "error");
				}
				catch
				{
				}
			}
		}
		if (now >= nextActorList)
		{
			nextActorList = now + 1f;
			List<Actor> list2 = (((Object)(object)ActorManager.instance != (Object)null) ? ActorManager.instance.actors : null);
			actorList = ((list2 != null) ? new List<Actor>(list2) : new List<Actor>());
		}
		int count = actorList.Count;
		if (count > 0)
		{
			bool flag = false;
			for (int j = 0; j < Math.Min(6, count); j++)
			{
				cursor = (cursor + 1) % count;
				try
				{
					if (Check(actorList[cursor], now, !flag))
					{
						flag = true;
					}
				}
				catch (Exception e2)
				{
					Warn("checking a bot", e2);
				}
			}
			for (int k = 0; k < Math.Min(1, count); k++)
			{
				surveyCursor = (surveyCursor + 1) % count;
				try
				{
					SurveyBot(actorList[surveyCursor], now);
				}
				catch (Exception e3)
				{
					Warn("measuring", e3);
				}
			}
			for (int l = 0; l < Math.Min(2, count); l++)
			{
				reactCursor = (reactCursor + 1) % count;
				try
				{
					ReactTo(actorList[reactCursor], now);
				}
				catch (Exception e4)
				{
					Warn("noticing enemies", e4);
				}
			}
			if (!calibrated && now >= nextCalib)
			{
				nextCalib = now + 0.25f;
				try
				{
					Calibrate(actorList[rng.Next(count)]);
				}
				catch (Exception e5)
				{
					Warn("measuring head heights", e5);
					calibrated = true;
				}
			}
		}
		if (now >= nextTidy)
		{
			nextTidy = now + 5f;
			try
			{
				Tidy(now);
			}
			catch (Exception e6)
			{
				Warn("tidying up", e6);
			}
		}
		if (claims.Count > 64)
		{
			claims.RemoveAll((Claim c) => c.Until <= now);
		}
		if (S.TestKeys && Input.GetKeyDown((KeyCode)121))
		{
			PrintStats();
		}
		if (S.TestKeys && Input.GetKeyDown((KeyCode)104))
		{
			try
			{
				ShowMe(now);
			}
			catch (Exception e7)
			{
				Warn("showing a bot", e7);
			}
		}
		if (now >= nextStats)
		{
			nextStats = now + 60f;
			PrintStats();
		}
	}

	public void Shutdown()
	{
		float time = Time.time;
		foreach (Rec item in new List<Rec>(active.Values))
		{
			try
			{
				Release(item, time, "end");
			}
			catch
			{
			}
		}
		foreach (Actor actor in actorList)
		{
			if ((Object)(object)actor == (Object)null || !react.TryGetValue(actor.actorIndex, out var value) || !value.Aware)
			{
				continue;
			}
			AiActorController val = AiOf(actor);
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					SetAware(val, value, want: false);
				}
				catch
				{
				}
			}
		}
		Log("Bots Take Cover (plugin) stopped.");
	}

	private string ReactText(Bucket b)
	{
		if (b.N == 0)
		{
			return "nothing measured yet";
		}
		string text = $"{b.N} times, {b.Sum / (float)b.N:0.0} s on average (half within {Median(b.List):0.0} s), {(int)Math.Floor(100.0 * (double)b.Slow / (double)b.N + 0.5)}% took over 2 s";
		if (b.CartN > 0)
		{
			text += $"; near the cart {b.CartN} times, {b.CartSum / (float)b.CartN:0.0} s";
		}
		if (b.SideN > 0)
		{
			text += $"; enemy at its side or behind it {b.SideN} times, {b.SideSum / (float)b.SideN:0.0} s";
		}
		if (b.FarN > 0)
		{
			text += $"; busy with an enemy farther away {b.FarN} times, {b.FarSum / (float)b.FarN:0.0} s";
		}
		if (b.Lost > 0)
		{
			text += $"; lost sight before reacting {b.Lost} times";
		}
		return text;
	}

	public void PrintStats()
	{
		int num = 0;
		int num2 = 0;
		foreach (Rec value2 in active.Values)
		{
			if (value2.State == "moving")
			{
				num++;
			}
			else
			{
				num2++;
			}
		}
		string text = "no fights measured yet";
		if (survey.N > 0)
		{
			text = $"{(int)Math.Floor(100.0 * (double)survey.Covered / (double)survey.N + 0.5)}% of bots in a fight were behind cover ({survey.N} checks)";
			if (survey.Time > 20f)
			{
				text += $", {(float)survey.Deaths * 60f / survey.Time:0.0} bot deaths a minute";
			}
		}
		Log("So far " + text + ".");
		float num3 = ((arrived > 0) ? (arriveDist / (float)arrived) : 0f);
		List<string> list = new List<string>();
		foreach (KeyValuePair<string, int> item in why)
		{
			list.Add(item.Key + " " + item.Value);
		}
		list.Sort(StringComparer.Ordinal);
		string text2 = ((coverTime > 5f) ? $"{(float)shots * 60f / coverTime:0.0}" : "-");
		string text3 = ((freeTime > 5f) ? $"{freeShots * 60f / freeTime:0.0}" : "-");
		Log($"Bots ran for cover {went} times ({low} low, {full} tall, {forReload} of them to reload), {arrived} got there ({reallyCovered} really covered, stopped {num3:0.0} m from the spot on average, {retries} moved again), {gaveUp} gave up, {flanked} flanked, {none} found none. Shots fired from cover: {shots} in {(int)coverTime} bot-seconds. Ducked {ducks} times (crouched {duckWorked} of {duckChecked} checked). Right now: {num} running, {num2} in cover. Shots a minute: {text2} per bot in cover, {text3} per bot fighting the normal way.");
		if (list.Count > 0)
		{
			Log("Why bots left cover (or stopped running to it): " + string.Join(", ", list.ToArray()) + ".");
		}
		if (runTime > 1f)
		{
			int num4 = ((runLooks > 0) ? ((int)Math.Floor(100.0 * (double)runFighting / (double)runLooks + 0.5)) : 0);
			Log($"Running to cover: {(int)runTime} s in all, had an enemy to shoot at {num4}% of the time, fired {runShots} shots on the way ({(float)runShots * 60f / runTime:0.0} a minute).");
		}
		string text4 = "no payload cart";
		if (hasCart)
		{
			text4 = $"payload cart found, {atCart} searches kept within {(int)Math.Floor(cartRange - 1f)} m of it, {toCart} searches by attackers on their way to it only looked closer to it";
		}
		Log($"Check: {lastSeen[0]} soldiers in the game, {lastSeen[1]} bots alive, {lastSeen[2]} of them fighting someone, {lastSeen[3]} steered by a script, {lastSeen[4]} standing still on purpose. Stuck bots set free: {fixedCount}. {text4}.");
		string text5 = $"How fast bots turn on an enemy within {S.AwareRange:0} m in plain sight (time until they fight one that close). ";
		if (reactOff.N > 0 || reactOff.Lost > 0)
		{
			Log(text5 + "Sharper reactions ON: " + ReactText(reactOn) + ". OFF: " + ReactText(reactOff) + ".");
		}
		else
		{
			Log(text5 + "Sharper reactions on: " + ReactText(reactOn) + ".");
		}
		why.TryGetValue("enemy close", out var value);
		Log($"Close fights: {value + closeSkips} times a bot dropped (or did not start) going for cover to fight an enemy within {12f:0} m.");
	}
}
internal static class CoverHost
{
	private static readonly List<ScriptedBehaviour> scripts = new List<ScriptedBehaviour>();

	private static ScriptedBehaviour owner;

	private static CoverBrain brain;

	private static string lastName;

	private static float nextScan;

	public static bool Running => brain != null;

	public static void Register(ScriptedBehaviour sb)
	{
		if (!((Object)(object)sb == (Object)null))
		{
			string text = null;
			try
			{
				text = (((Object)(object)sb.source != (Object)null) ? ((Object)sb.source).name : null);
			}
			catch
			{
				text = null;
			}
			if (string.IsNullOrEmpty(text))
			{
				text = sb.behaviour;
			}
			if ((!(text != "CoverMutator") || !(text != "SoloCover")) && !scripts.Contains(sb))
			{
				scripts.Add(sb);
			}
		}
	}

	public static void Update()
	{
		if (Time.unscaledTime >= nextScan)
		{
			nextScan = Time.unscaledTime + 1f;
			try
			{
				Scan();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Cover] " + ex));
			}
		}
		if (brain != null)
		{
			long timestamp = Stopwatch.GetTimestamp();
			try
			{
				brain.Tick(Time.time);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("[Cover] " + ex2));
			}
			Meter.AddNamed("Bots Take Cover (plugin)", Stopwatch.GetTimestamp() - timestamp);
		}
	}

	private static void Scan()
	{
		if (brain != null && ((Object)(object)owner == (Object)null || !((Behaviour)owner).isActiveAndEnabled || !Plugin.CoverInPlugin.Value))
		{
			Stop();
		}
		for (int num = scripts.Count - 1; num >= 0; num--)
		{
			ScriptedBehaviour val = scripts[num];
			if ((Object)(object)val == (Object)null)
			{
				scripts.RemoveAt(num);
			}
			else if (Plugin.CoverInPlugin.Value && ((Behaviour)val).isActiveAndEnabled)
			{
				string text = ((Object)((Component)val).gameObject).name;
				if (HandoffTag.IsTag(text) && (brain == null || !((Object)(object)owner == (Object)(object)val) || !(text == lastName)))
				{
					HandoffTag handoffTag = HandoffTag.Parse(text);
					if (handoffTag != null)
					{
						if (brain == null || (Object)(object)owner != (Object)(object)val)
						{
							if (brain != null)
							{
								Stop();
							}
							owner = val;
							brain = new CoverBrain(handoffTag);
						}
						else
						{
							brain.Apply(handoffTag);
						}
						if (text.StartsWith("CoverHandoff|", StringComparison.Ordinal))
						{
							text = "CoverTaken|" + text.Substring("CoverHandoff|".Length);
							((Object)((Component)val).gameObject).name = text;
						}
						lastName = text;
					}
				}
			}
		}
	}

	private static void Stop()
	{
		try
		{
			if (brain != null)
			{
				brain.Shutdown();
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("[Cover] stopping: " + ex));
		}
		brain = null;
		owner = null;
		lastName = null;
	}

	public static void OnActorDied(Actor actor, bool silent)
	{
		if (brain == null)
		{
			return;
		}
		try
		{
			brain.OnActorDied(actor, silent);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(ScriptedBehaviour), "Awake")]
internal static class CoverScriptWatch
{
	[HarmonyPostfix]
	private static void Postfix(ScriptedBehaviour __instance)
	{
		try
		{
			CoverHost.Register(__instance);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(Actor), "Die")]
internal static class CoverDeathWatch
{
	[HarmonyPrefix]
	private static void Prefix(Actor __instance, out bool __state)
	{
		__state = (Object)(object)__instance != (Object)null && !__instance.dead;
	}

	[HarmonyPostfix]
	private static void Postfix(Actor __instance, bool __state, bool isSilentKill)
	{
		if (__state && (Object)(object)__instance != (Object)null && __instance.dead && CoverHost.Running)
		{
			CoverHost.OnActorDied(__instance, isSilentKill);
		}
	}
}
[BepInPlugin("com.kvatchhero.payloadspeedpack", "Payload Speed Pack", "0.4.0")]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "com.kvatchhero.payloadspeedpack";

	public const string NAME = "Payload Speed Pack";

	public const string VERSION = "0.4.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> FixVehicleDriving;

	internal static ConfigEntry<bool> FixSquadless;

	internal static ConfigEntry<bool> GuardSightLoop;

	internal static ConfigEntry<bool> CoverInPlugin;

	internal static ConfigEntry<bool> TankChecksInPlugin;

	internal static ConfigEntry<bool> TimedEyesight;

	internal static ConfigEntry<float> EyesightRound;

	internal static ConfigEntry<int> EyesightMaxPerFrame;

	internal static ConfigEntry<KeyCode> MeterKey;

	internal static ConfigEntry<bool> MeterShown;

	internal static ConfigEntry<float> LogEvery;

	private string meterText;

	private float nextDisplay;

	private float nextLog;

	private GUIStyle style;

	private void Awake()
	{
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Expected O, but got Unknown
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Expected O, but got Unknown
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		FixVehicleDriving = ((BaseUnityPlugin)this).Config.Bind<bool>("Vehicles", "FixOldVehicleDriving", true, "Bots driving old-style tanks and cars use the game's car/tank driving code instead of the plane code (which throws errors).");
		FixSquadless = ((BaseUnityPlugin)this).Config.Bind<bool>("Bots", "FixBotsWithoutSquad", true, "Bots that were never put in a squad (made or spawned by a script) no longer break the game's targeting for every bot on the map.");
		CoverInPlugin = ((BaseUnityPlugin)this).Config.Bind<bool>("Cover", "RunInPlugin", true, "The Bots Take Cover mutator hands its work to the plugin (same settings, much faster). Off: the mutator does it itself.");
		TankChecksInPlugin = ((BaseUnityPlugin)this).Config.Bind<bool>("Tanks", "ChecksInPlugin", true, "Payload's escort tanks do their ground and room checks in the plugin (the same checks, much faster). Off: the script does them itself. (Read when the game starts.)");
		GuardSightLoop = ((BaseUnityPlugin)this).Config.Bind<bool>("Bots", "GuardSightLoop", true, "If an error happens in the game's sight check, skip that one pair of soldiers instead of the check stopping there every frame.");
		TimedEyesight = ((BaseUnityPlugin)this).Config.Bind<bool>("Eyesight", "TimedEyesight", true, "Bots re-check who they can see on a timer instead of once every 42 frames (never slower than the game's own).");
		EyesightRound = ((BaseUnityPlugin)this).Config.Bind<float>("Eyesight", "RoundSeconds", 0.5f, "Seconds for one full round of 'who can see whom' checks.");
		EyesightMaxPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("Eyesight", "MaxChecksPerFrame", 400, "Most sight checks in one frame (the game's own limit is 200).");
		MeterKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Meter", "ToggleKey", (KeyCode)289, "Key that shows or hides the frame meter.");
		MeterShown = ((BaseUnityPlugin)this).Config.Bind<bool>("Meter", "ShownAtStart", false, "Show the frame meter when the game starts.");
		LogEvery = ((BaseUnityPlugin)this).Config.Bind<float>("Meter", "LogEverySeconds", 60f, "Write the meter to the BepInEx log this often (0 = never).");
		Harmony harmony = new Harmony("com.kvatchhero.payloadspeedpack");
		Patch(harmony, typeof(VehicleInputFix), "vehicle fix");
		Patch(harmony, typeof(SightTimer), "eyesight timer");
		Patch(harmony, typeof(SquadlessFix), "bots without a squad");
		Patch(harmony, typeof(SightLoopGuard), "sight check guard");
		Patch(harmony, typeof(CoverScriptWatch), "cover: finding the Bots Take Cover script");
		Patch(harmony, typeof(CoverDeathWatch), "cover: counting deaths");
		Patch(harmony, typeof(TimeBotUpdate), "meter: bots");
		Patch(harmony, typeof(TimeBotDecisions), "meter: bot decisions");
		Patch(harmony, typeof(TimeSoldierUpdate), "meter: soldiers");
		Patch(harmony, typeof(TimeSoldierLateUpdate), "meter: soldiers (late)");
		Patch(harmony, typeof(TimeScriptUpdate), "meter: scripts");
		Patch(harmony, typeof(TimeScriptLateUpdate), "meter: scripts (late)");
		Patch(harmony, typeof(TimeScriptFixedUpdate), "meter: scripts (physics)");
		GameObject val = new GameObject("PayloadSpeedPack");
		Object.DontDestroyOnLoad((Object)(object)val);
		Log.LogInfo((object)string.Concat("Payload Speed Pack 0.4.0 loaded. Press ", MeterKey.Value, " in a match for the frame meter."));
	}

	private static void Patch(Harmony harmony, Type type, string label)
	{
		try
		{
			harmony.CreateClassProcessor(type).Patch();
			Log.LogInfo((object)("Patched: " + label));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Could not patch " + label + ": " + ex));
		}
	}

	private void Update()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		Meter.EndFrame(Time.unscaledDeltaTime);
		CoverHost.Update();
		LuaBridge.Update();
		if (Input.GetKeyDown(MeterKey.Value))
		{
			MeterShown.Value = !MeterShown.Value;
		}
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime >= nextDisplay)
		{
			nextDisplay = unscaledTime + 0.5f;
			meterText = Meter.Display.Report(oneLine: false);
			Meter.Display.Reset();
		}
		if (LogEvery.Value > 0f && unscaledTime >= nextLog)
		{
			if (nextLog > 0f && Meter.Logged.Frames > 0)
			{
				Log.LogInfo((object)Meter.Logged.Report(oneLine: true));
			}
			Meter.Logged.Reset();
			nextLog = unscaledTime + LogEvery.Value;
		}
	}

	private void OnGUI()
	{
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Expected O, but got Unknown
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		if (MeterShown.Value && !string.IsNullOrEmpty(meterText))
		{
			if (style == null)
			{
				style = new GUIStyle(GUI.skin.box);
				style.alignment = (TextAnchor)0;
				style.fontSize = 13;
				style.padding = new RectOffset(8, 8, 6, 6);
			}
			string text = string.Concat("Payload Speed Pack (", MeterKey.Value, " hides)\n", meterText);
			Vector2 val = style.CalcSize(new GUIContent(text));
			GUI.Box(new Rect(10f, 70f, val.x, val.y), text, style);
		}
	}
}
internal class Window
{
	public int Frames;

	public double Seconds;

	public long Bots;

	public long Decisions;

	public long Sight;

	public long Soldiers;

	public long Scripts;

	public Dictionary<string, long> PerScript = new Dictionary<string, long>();

	public int Pairs;

	public int PerFrame;

	public int LandVehicleFixes;

	public int PlaneErrors;

	public int SquadlessChecks;

	public int SightErrors;

	public void Reset()
	{
		Frames = 0;
		Seconds = 0.0;
		Bots = (Decisions = (Sight = (Soldiers = (Scripts = 0L))));
		PerScript.Clear();
		LandVehicleFixes = (PlaneErrors = (SquadlessChecks = (SightErrors = 0)));
	}

	private double Ms(long ticks)
	{
		if (Frames <= 0)
		{
			return 0.0;
		}
		return (double)ticks * 1000.0 / (double)Stopwatch.Frequency / (double)Frames;
	}

	public string Report(bool oneLine)
	{
		if (Frames == 0 || Seconds <= 0.0)
		{
			return "";
		}
		double num = Seconds * 1000.0 / (double)Frames;
		double num2 = (double)Frames / Seconds;
		double num3 = Ms(Bots);
		double num4 = Ms(Decisions);
		double num5 = Ms(Sight);
		double num6 = Ms(Soldiers);
		double num7 = Ms(Scripts);
		double num8 = Math.Max(0.0, num - num3 - num4 - num5 - num6 - num7);
		double num9 = ((PerFrame > 0) ? (Math.Ceiling((double)Pairs / (double)PerFrame) * num / 1000.0) : 0.0);
		List<KeyValuePair<string, long>> list = new List<KeyValuePair<string, long>>(PerScript);
		list.Sort((KeyValuePair<string, long> a, KeyValuePair<string, long> b) => b.Value.CompareTo(a.Value));
		StringBuilder stringBuilder = new StringBuilder();
		string text = (oneLine ? ", " : "\n");
		stringBuilder.AppendFormat("{0:0} fps ({1:0.0} ms a frame){2}", num2, num, oneLine ? ": " : "\n");
		stringBuilder.AppendFormat("Bots moving and aiming   {0,5:0.00} ms{1}", num3, text);
		stringBuilder.AppendFormat("Bot decisions            {0,5:0.00} ms{1}", num4, text);
		stringBuilder.AppendFormat("Bot eyesight             {0,5:0.00} ms (all {2} pairs every {3:0.00} s){1}", num5, text, Pairs, num9);
		stringBuilder.AppendFormat("Soldiers (bodies)        {0,5:0.00} ms{1}", num6, text);
		stringBuilder.AppendFormat("Mutator scripts          {0,5:0.00} ms{1}", num7, text);
		for (int num10 = 0; num10 < list.Count && num10 < 6; num10++)
		{
			if (oneLine)
			{
				stringBuilder.AppendFormat("[{0} {1:0.00}]{2}", list[num10].Key, Ms(list[num10].Value), text);
			}
			else
			{
				stringBuilder.AppendFormat("   {0,-22}{1,5:0.00} ms\n", Short(list[num10].Key), Ms(list[num10].Value));
			}
		}
		stringBuilder.AppendFormat("Everything else          {0,5:0.00} ms (drawing, physics, sound){1}", num8, text);
		if (LandVehicleFixes > 0 || PlaneErrors > 0)
		{
			stringBuilder.AppendFormat("Vehicle fixes: {0:0} old-style vehicles driven by bots, {1} plane errors caught{2}", (double)LandVehicleFixes / Math.Max(1.0, Frames), PlaneErrors, text);
		}
		if (SquadlessChecks > 0 || SightErrors > 0)
		{
			stringBuilder.AppendFormat("Bot fixes: {0} targeting checks by bots without a squad, {1} sight check errors skipped", SquadlessChecks, SightErrors);
		}
		return stringBuilder.ToString().TrimEnd(',', ' ', '\n');
	}

	private static string Short(string s)
	{
		if (s.Length <= 21)
		{
			return s;
		}
		return s.Substring(0, 21);
	}
}
internal static class Meter
{
	public static readonly Window Display = new Window();

	public static readonly Window Logged = new Window();

	public static long Bots;

	public static long Decisions;

	public static long Sight;

	public static long Soldiers;

	public static long Scripts;

	public static readonly Dictionary<string, long> PerScript = new Dictionary<string, long>();

	public static int Pairs;

	public static int PerFrame;

	public static int LandVehicleFixes;

	public static int PlaneErrors;

	public static int SquadlessChecks;

	public static int SightErrors;

	public static long BotStart;

	public static long DecisionStart;

	public static long SightStart;

	public static long SoldierStart;

	public static long SoldierLateStart;

	public static void AddScript(ScriptedBehaviour script, long ticks)
	{
		Scripts += ticks;
		string text = script.behaviour;
		if (string.IsNullOrEmpty(text))
		{
			text = (((Object)(object)script.source != (Object)null) ? ((Object)script.source).name : "script");
		}
		PerScript.TryGetValue(text, out var value);
		PerScript[text] = value + ticks;
	}

	public static void AddNamed(string name, long ticks)
	{
		Scripts += ticks;
		PerScript.TryGetValue(name, out var value);
		PerScript[name] = value + ticks;
	}

	public static void EndFrame(float dt)
	{
		Add(Display, dt);
		Add(Logged, dt);
		Bots = (Decisions = (Sight = (Soldiers = (Scripts = 0L))));
		PerScript.Clear();
		LandVehicleFixes = (PlaneErrors = (SquadlessChecks = (SightErrors = 0)));
	}

	private static void Add(Window w, float dt)
	{
		w.Frames++;
		w.Seconds += dt;
		w.Bots += Bots;
		w.Decisions += Decisions;
		w.Sight += Sight;
		w.Soldiers += Soldiers;
		w.Scripts += Scripts;
		foreach (KeyValuePair<string, long> item in PerScript)
		{
			w.PerScript.TryGetValue(item.Key, out var value);
			w.PerScript[item.Key] = value + item.Value;
		}
		w.Pairs = Pairs;
		w.PerFrame = PerFrame;
		w.LandVehicleFixes += LandVehicleFixes;
		w.PlaneErrors += PlaneErrors;
		w.SquadlessChecks += SquadlessChecks;
		w.SightErrors += SightErrors;
	}
}
[HarmonyPatch(typeof(AiActorController), "GenerateAirplaneInput")]
internal static class VehicleInputFix
{
	private static readonly HashSet<int> reported = new HashSet<int>();

	[HarmonyPrefix]
	private static bool Prefix(AiActorController __instance, ref Vector4 __result, ref Vector2 ___carInput)
	{
		//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_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.FixVehicleDriving.Value)
		{
			return true;
		}
		Actor actor = ((ActorController)__instance).actor;
		Vehicle val = (((Object)(object)actor != (Object)null && (Object)(object)actor.seat != (Object)null) ? actor.seat.vehicle : null);
		if ((Object)(object)val == (Object)null)
		{
			__result = Vector4.zero;
			return false;
		}
		if (val is Airplane || val is Plane)
		{
			return true;
		}
		if (val is Tank || val is Car)
		{
			___carInput = __instance.GenerateCarInput();
			__result = Vector4.zero;
			Meter.LandVehicleFixes++;
			Report(val, actor, "is now driven with the car/tank code");
			return false;
		}
		__result = Vector4.zero;
		Report(val, actor, "is a vehicle type the bots have no driving code for, so it is left standing");
		return false;
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, AiActorController __instance, ref Vector4 __result)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if (__exception == null)
		{
			return null;
		}
		__result = Vector4.zero;
		Meter.PlaneErrors++;
		Actor val = (((Object)(object)__instance != (Object)null) ? ((ActorController)__instance).actor : null);
		Vehicle vehicle = (((Object)(object)val != (Object)null && (Object)(object)val.seat != (Object)null) ? val.seat.vehicle : null);
		Report(vehicle, val, "threw an error in the plane code (caught): " + __exception.GetType().Name + ": " + __exception.Message);
		return null;
	}

	private static void Report(Vehicle vehicle, Actor actor, string what)
	{
		int item = (((Object)(object)vehicle != (Object)null) ? ((Object)vehicle).GetInstanceID() : 0);
		if (reported.Add(item))
		{
			string text = ((!((Object)(object)vehicle != (Object)null)) ? "(no vehicle)" : (string.IsNullOrEmpty(vehicle.name) ? ((Object)((Component)vehicle).gameObject).name : vehicle.name));
			string text2 = (((Object)(object)vehicle != (Object)null) ? ((object)vehicle).GetType().Name : "-");
			string text3 = (((Object)(object)actor != (Object)null) ? actor.name : "?");
			Plugin.Log.LogWarning((object)("[Vehicles] '" + text + "' (" + text2 + ") driven by " + text3 + " " + what + "."));
		}
	}
}
[HarmonyPatch(typeof(AiActorController), "GetWeaponEffectivenessAgainstTarget")]
internal static class SquadlessFix
{
	private static Squad standIn;

	private static readonly HashSet<int> reported = new HashSet<int>();

	[HarmonyPrefix]
	private static void Prefix(AiActorController __instance)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Expected O, but got Unknown
		if (Plugin.FixSquadless.Value && !((Object)(object)__instance == (Object)null) && __instance.squad == null)
		{
			if (standIn == null)
			{
				standIn = (Squad)FormatterServices.GetUninitializedObject(typeof(Squad));
			}
			__instance.squad = standIn;
			Meter.SquadlessChecks++;
			Actor actor = ((ActorController)__instance).actor;
			int item = (((Object)(object)actor != (Object)null) ? ((Object)actor).GetInstanceID() : 0);
			if (reported.Add(item))
			{
				Plugin.Log.LogWarning((object)("[Bots] " + (((Object)(object)actor != (Object)null) ? ("'" + actor.name + "'") : "A bot") + " is not in a squad (made or spawned by a script). The game's targeting would break on it, and then stop for every bot on the map; the plugin handles it."));
			}
		}
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, AiActorController __instance)
	{
		if (standIn != null && (Object)(object)__instance != (Object)null && __instance.squad == standIn)
		{
			__instance.squad = null;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(ActorManager), "UpdateActorInteractions")]
internal static class SightLoopGuard
{
	private static int errors;

	private static int inARow;

	private static float nextLog;

	[HarmonyFinalizer]
	private static Exception Finalizer(Exception __exception, ref int ___interactionIteratorTeam0, ref int ___interactionIteratorTeam1)
	{
		if (__exception == null)
		{
			inARow = 0;
			return null;
		}
		if (!Plugin.GuardSightLoop.Value)
		{
			return __exception;
		}
		Meter.SightErrors++;
		errors++;
		inARow++;
		if (inARow >= 3)
		{
			___interactionIteratorTeam0 = 0;
			___interactionIteratorTeam1 = 0;
			inARow = 0;
		}
		else
		{
			___interactionIteratorTeam1++;
		}
		if (Time.unscaledTime >= nextLog)
		{
			nextLog = Time.unscaledTime + 60f;
			Plugin.Log.LogWarning((object)("[Bots] Caught an error in the game's sight check (" + errors + " since the last message) and skipped that pair of soldiers, so the check goes on for everyone else: " + __exception.GetType().Name + ": " + __exception.Message + "\n" + __exception.StackTrace));
			errors = 0;
		}
		return null;
	}
}
[HarmonyPatch(typeof(ActorManager), "UpdateActorInteractions")]
internal static class SightTimer
{
	[HarmonyPrefix]
	private static void Prefix(ref int ___interactionUpdatesPerFrame, int[] ___nextActorIndexTeam)
	{
		Meter.SightStart = Stopwatch.GetTimestamp();
		if (___nextActorIndexTeam != null && ___nextActorIndexTeam.Length >= 2)
		{
			int num = ___nextActorIndexTeam[0] * ___nextActorIndexTeam[1];
			int num2 = Mathf.Min(Mathf.CeilToInt((float)num / 42f), 200);
			int perFrame = ___interactionUpdatesPerFrame;
			if (Plugin.TimedEyesight.Value && num > 0)
			{
				float num3 = Mathf.Clamp(Time.unscaledDeltaTime, 0.001f, 0.25f);
				int num4 = Mathf.CeilToInt((float)num * num3 / Mathf.Max(0.1f, Plugin.EyesightRound.Value));
				perFrame = (___interactionUpdatesPerFrame = Mathf.Clamp(Mathf.Max(num4, num2), 1, Mathf.Max(num2, Plugin.EyesightMaxPerFrame.Value)));
			}
			Meter.Pairs = num;
			Meter.PerFrame = perFrame;
		}
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		Meter.Sight += Stopwatch.GetTimestamp() - Meter.SightStart;
	}
}
[HarmonyPatch(typeof(AiActorController), "Update")]
internal static class TimeBotUpdate
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		Meter.BotStart = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		Meter.Bots += Stopwatch.GetTimestamp() - Meter.BotStart;
	}
}
[HarmonyPatch(typeof(ActorManager), "UpdateAI")]
internal static class TimeBotDecisions
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		Meter.DecisionStart = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		Meter.Decisions += Stopwatch.GetTimestamp() - Meter.DecisionStart;
	}
}
[HarmonyPatch(typeof(Actor), "Update")]
internal static class TimeSoldierUpdate
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		Meter.SoldierStart = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		Meter.Soldiers += Stopwatch.GetTimestamp() - Meter.SoldierStart;
	}
}
[HarmonyPatch(typeof(Actor), "LateUpdate")]
internal static class TimeSoldierLateUpdate
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		Meter.SoldierLateStart = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		Meter.Soldiers += Stopwatch.GetTimestamp() - Meter.SoldierLateStart;
	}
}
[HarmonyPatch(typeof(ScriptedBehaviour), "Update")]
internal static class TimeScriptUpdate
{
	[HarmonyPrefix]
	private static void Prefix(out long __state)
	{
		__state = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix(ScriptedBehaviour __instance, long __state)
	{
		Meter.AddScript(__instance, Stopwatch.GetTimestamp() - __state);
	}
}
[HarmonyPatch(typeof(ScriptedBehaviour), "LateUpdate")]
internal static class TimeScriptLateUpdate
{
	[HarmonyPrefix]
	private static void Prefix(out long __state)
	{
		__state = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix(ScriptedBehaviour __instance, long __state)
	{
		Meter.AddScript(__instance, Stopwatch.GetTimestamp() - __state);
	}
}
[HarmonyPatch(typeof(ScriptedBehaviour), "FixedUpdate")]
internal static class TimeScriptFixedUpdate
{
	[HarmonyPrefix]
	private static void Prefix(out long __state)
	{
		__state = Stopwatch.GetTimestamp();
	}

	[HarmonyPostfix]
	private static void Postfix(ScriptedBehaviour __instance, long __state)
	{
		Meter.AddScript(__instance, Stopwatch.GetTimestamp() - __state);
	}
}
internal static class LuaBridge
{
	public const int VERSION = 1;

	private static Script registeredIn;

	private static float nextCheck;

	private static int failures;

	private static readonly FieldInfo scriptField = AccessTools.Field(typeof(ScriptEngine), "script");

	public static void Update()
	{
		if (!(Time.unscaledTime < nextCheck))
		{
			nextCheck = Time.unscaledTime + 1f;
			Ensure();
		}
	}

	public static void Ensure()
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		if (failures >= 3)
		{
			return;
		}
		try
		{
			if ((Object)(object)RavenscriptManager.instance == (Object)null)
			{
				return;
			}
			ScriptEngine engine = RavenscriptManager.engine;
			if ((Object)(object)engine == (Object)null || scriptField == null)
			{
				return;
			}
			object? value = scriptField.GetValue(engine);
			Script val = (Script)((value is Script) ? value : null);
			if (val != null && !object.ReferenceEquals(val, registeredIn))
			{
				Table val2 = new Table(val);
				val2.Set("version", DynValue.NewNumber(1.0));
				if (Plugin.TankChecksInPlugin.Value)
				{
					val2.Set("TankSpot", DynValue.NewCallback((Func<ScriptExecutionContext, CallbackArguments, DynValue>)TankChecks.TankSpot, "TankSpot"));
					val2.Set("TankBox", DynValue.NewCallback((Func<ScriptExecutionContext, CallbackArguments, DynValue>)TankChecks.TankBox, "TankBox"));
					val2.Set("TankBodies", DynValue.NewCallback((Func<ScriptExecutionContext, CallbackArguments, DynValue>)TankChecks.TankBodies, "TankBodies"));
				}
				val.Globals.Set("SpeedPack", DynValue.NewTable(val2));
				registeredIn = val;
				Plugin.Log.LogInfo((object)("[Lua] Added the SpeedPack table to the game's Lua (escort tank checks in C#: " + (Plugin.TankChecksInPlugin.Value ? "on" : "off") + ")."));
			}
		}
		catch (Exception ex)
		{
			failures++;
			Plugin.Log.LogError((object)("[Lua] Could not add the SpeedPack table to the game's Lua: " + ex));
		}
	}
}
internal static class TankChecks
{
	private const int MASK = 2232321;

	private static readonly List<Rigidbody> tankBodies = new List<Rigidbody>();

	private static readonly RaycastHit[] hitBuffer = (RaycastHit[])(object)new RaycastHit[32];

	private static readonly Collider[] colliderBuffer = (Collider[])(object)new Collider[64];

	private static readonly Dictionary<Type, FieldInfo> valueFields = new Dictionary<Type, FieldInfo>();

	private static double Num(CallbackArguments a, int i)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Invalid comparison between Unknown and I4
		DynValue val = a[i];
		if (val == null || (int)val.Type != 3)
		{
			return 0.0;
		}
		return val.Number;
	}

	private static bool Bool(CallbackArguments a, int i)
	{
		DynValue val = a[i];
		if (val != null)
		{
			return val.CastToBool();
		}
		return false;
	}

	private static Rigidbody Body(DynValue v)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Invalid comparison between Unknown and I4
		if (v == null || (int)v.Type != 8 || v.UserData == null)
		{
			return null;
		}
		object obj = v.UserData.Object;
		if (obj == null)
		{
			return null;
		}
		Rigidbody val = (Rigidbody)((obj is Rigidbody) ? obj : null);
		if (!object.ReferenceEquals(val, null))
		{
			return val;
		}
		RigidbodyProxy val2 = (RigidbodyProxy)((obj is RigidbodyProxy) ? obj : null);
		if (val2 != null)
		{
			return val2._value;
		}
		Type type = obj.GetType();
		if (!valueFields.TryGetValue(type, out var value))
		{
			value = type.GetField("_value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			valueFields[type] = value;
		}
		if (!(value != null))
		{
			return null;
		}
		object? value2 = value.GetValue(obj);
		return (Rigidbody)((value2 is Rigidbody) ? value2 : null);
	}

	private static bool SameBody(Rigidbody a, Rigidbody b)
	{
		//IL_0034: 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)
		if (object.ReferenceEquals(a, null) || object.ReferenceEquals(b, null))
		{
			return false;
		}
		if (object.ReferenceEquals(a, b))
		{
			return true;
		}
		if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
		{
			return false;
		}
		Vector3 val = a.position - b.position;
		return ((Vector3)(ref val)).sqrMagnitude < 0.0004f;
	}

	private static bool IsTank(Rigidbody rb)
	{
		if (object.ReferenceEquals(rb, null))
		{
			return false;
		}
		for (int i = 0; i < tankBodies.Count; i++)
		{
			if (SameBody(rb, tankBodies[i]))
			{
				return true;
			}
		}
		return false;
	}

	private static bool BoxCircle(double ax, double az, double ahx, double ahz, double ayaw, double cx, double cz, double r)
	{
		double num = ayaw * Math.PI / 180.0;
		double num2 = cx - ax;
		double num3 = cz - az;
		double num4 = num2 * Math.Cos(num) - num3 * Math.Sin(num);
		double num5 = num2 * Math.Sin(num) + num3 * Math.Cos(num);
		double num6 = Math.Max(0.0 - ahx, Math.Min(ahx, num4));
		double num7 = Math.Max(0.0 - ahz, Math.Min(ahz, num5));
		return (num4 - num6) * (num4 - num6) + (num5 - num7) * (num5 - num7) < r * r;
	}

	private static bool Ground(double x, double top, double z, bool onCart, double cartY, out double y)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		y = 0.0;
		Ray val = default(Ray);
		((Ray)(ref val))..ctor(new Vector3((float)x, (float)top, (float)z), Vector3.down);
		RaycastHit val2 = default(RaycastHit);
		if (!Physics.Raycast(val, ref val2, 10f, 2232321))
		{
			return false;
		}
		double num = ((RaycastHit)(ref val2)).point.y;
		if ((!onCart || !(num > cartY + 0.25)) && !IsTank(((RaycastHit)(ref val2)).rigidbody))
		{
			y = num;
			return true;
		}
		RaycastHit[] array = hitBuffer;
		int num2 = Physics.RaycastNonAlloc(val, hitBuffer, 10f, 2232321);
		if (num2 >= hitBuffer.Length)
		{
			array = Physics.RaycastAll(val, 10f, 2232321);
			num2 = array.Length;
		}
		bool flag = false;
		for (int i = 0; i < num2; i++)
		{
			if (!IsTank(((RaycastHit)(ref array[i])).rigidbody))
			{
				double num3 = ((RaycastHit)(ref array[i])).point.y;
				if ((!onCart || !(num3 > cartY + 0.25)) && (!flag || num3 > y))
				{
					y = num3;
					flag = true;
				}
			}
		}
		return flag;
	}

	private static bool BoxBlocked(Vector3 center, Vector3 half, Quaternion rot, Rigidbody self, bool ignoreCart, double cartX, double cartZ)
	{
		//IL_0006: 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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array = colliderBuffer;
		int num = Physics.OverlapBoxNonAlloc(center, half, colliderBuffer, rot, 2232321);
		if (num >= colliderBuffer.Length)
		{
			array = Physics.OverlapBox(center, half, rot, 2232321);
			num = array.Length;
		}
		for (int i = 0; i < num; i++)
		{
			Collider val = array[i];
			if ((Object)(object)val == (Object)null || val.isTrigger || (!object.ReferenceEquals(self, null) && SameBody(val.attachedRigidbody, self)))
			{
				continue;
			}
			if (ignoreCart)
			{
				Bounds bounds = val.bounds;
				Vector3 center2 = ((Bounds)(ref bounds)).center;
				double num2 = (double)center2.x - cartX;
				double num3 = (double)center2.z - cartZ;
				if (num2 * num2 + num3 * num3 < 2.5)
				{
					continue;
				}
			}
			return true;
		}
		return false;
	}

	public static DynValue TankBodies(ScriptExecutionContext ctx, CallbackArguments args)
	{
		tankBodies.Clear();
		for (int i = 0; i < args.Count; i++)
		{
			Rigidbody val = Body(args[i]);
			if (!object.ReferenceEquals(val, null))
			{
				tankBodies.Add(val);
			}
		}
		return DynValue.NewNumber((double)tankBodies.Count);
	}

	public static DynValue TankSpot(ScriptExecutionContext ctx, CallbackArguments a)
	{
		//IL_033d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0342: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: 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)
		double num = Num(a, 0);
		double num2 = Num(a, 1);
		double num3 = Num(a, 2);
		double top = Num(a, 3);
		double num4 = Num(a, 4);
		double num5 = Num(a, 5);
		double num6 = Num(a, 6);
		double num7 = Num(a, 7);
		double num8 = Num(a, 8);
		double num9 = Num(a, 9);
		Rigidbody self = Body(a[10]);
		bool flag = Bool(a, 11);
		double cartX = Num(a, 12);
		double cartY = Num(a, 13);
		double cartZ = Num(a, 14);
		double cartYaw = Num(a, 15);
		bool flag2 = Bool(a, 16);
		double num10 = num3 * Math.PI / 180.0;
		double num11 = Math.Sin(num10);
		double num12 = Math.Cos(num10);
		double rx = num12;
		double rz = 0.0 - num11;
		if (!GroundAt(num, num2, num11, num12, rx, rz, 0.0, 0.0, top, flag, cartX, cartY, cartZ, cartYaw, out var y) || !GroundAt(num, num2, num11, num12, rx, rz, 0.0, num5 * 0.8, top, flag, cartX, cartY, cartZ, cartYaw, out var y2) || !GroundAt(num, num2, num11, num12, rx, rz, 0.0, (0.0 - num5) * 0.8, top, flag, cartX, cartY, cartZ, cartYaw, out var y3) || !GroundAt(num, num2, num11, num12, rx, rz, (0.0 - num4) * 0.8, 0.0, top, flag, cartX, cartY, cartZ, cartYaw, out var y4) || !GroundAt(num, num2, num11, num12, rx, rz, num4 * 0.8, 0.0, top, flag, cartX, cartY, cartZ, cartYaw, out var y5))
		{
			return DynValue.NewNumber(1.0);
		}
		double num13 = Math.Tan(num8 * Math.PI / 180.0);
		if (Math.Abs(y2 - y3) > num13 * num5 * 1.6 || Math.Abs(y4 - y5) > num13 * num4 * 1.6 + 0.3)
		{
			return DynValue.NewNumber(2.0);
		}
		double num14 = (y2 + y3 + y4 + y5) / 4.0;
		if (Math.Abs(y - num14) > num9)
		{
			return DynValue.NewNumber(3.0);
		}
		double num15 = (0.0 - Math.Atan((y2 - y3) / (num5 * 1.6))) * 180.0 / Math.PI;
		double num16 = Math.Atan((y5 - y4) / (num4 * 1.6)) * 180.0 / Math.PI;
		double num17 = num6 - num7;
		Vector3 center = default(Vector3);
		((Vector3)(ref center))..ctor((float)num, (float)(num14 + num7 + num17 / 2.0), (float)num2);
		Vector3 half = default(Vector3);
		((Vector3)(ref half))..ctor((float)(num4 + 0.1), (float)(num17 / 2.0), (float)(num5 + 0.15));
		Quaternion rot = Quaternion.Euler((float)num15, (float)num3, (float)num16);
		bool flag3 = BoxBlocked(center, half, rot, self, flag2 && flag, cartX, cartZ);
		return DynValue.NewTuple((DynValue[])(object)new DynValue[5]
		{
			DynValue.NewNumber(0.0),
			DynValue.NewNumber(num14),
			DynValue.NewNumber(num15),
			DynValue.NewNumber(num16),
			DynValue.NewBoolean(flag3)
		});
	}

	private static bool GroundAt(double px, double pz, double fx, double fz, double rx, double rz, double side, double along, double top, bool hasCart, double cartX, double cartY, double cartZ, double cartYaw, out double y)
	{
		double num = px + fx * along + rx * side;
		double num2 = pz + fz * along + rz * side;
		bool onCart = hasCart && BoxCircle(cartX, cartZ, 0.8, 1.3, cartYaw, num, num2, 0.01);
		return Ground(num, top, num2, onCart, cartY, out y);
	}

	public static DynValue TankBox(ScriptExecutionContext ctx, CallbackArguments a)
	{
		//IL_0056: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		Vector3 center = default(Vector3);
		((Vector3)(ref center))..ctor((float)Num(a, 0), (float)Num(a, 1), (float)Num(a, 2));
		Vector3 half = default(Vector3);
		((Vector3)(ref half))..ctor((float)Num(a, 3), (float)Num(a, 4), (float)Num(a, 5));
		Quaternion rot = Quaternion.Euler((float)Num(a, 6), (float)Num(a, 7), (float)Num(a, 8));
		return DynValue.NewBoolean(BoxBlocked(center, half, rot, Body(a[9]), Bool(a, 10), Num(a, 11), Num(a, 12)));
	}
}