Decompiled source of NACops MONO v2.1.0

Mods/NACops.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Object;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using NACops;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Pathfinding;
using ScheduleOne;
using ScheduleOne.Audio;
using ScheduleOne.AvatarFramework;
using ScheduleOne.AvatarFramework.Equipping;
using ScheduleOne.Building.Doors;
using ScheduleOne.Combat;
using ScheduleOne.Core.Items.Framework;
using ScheduleOne.DevUtilities;
using ScheduleOne.Dialogue;
using ScheduleOne.Doors;
using ScheduleOne.Economy;
using ScheduleOne.Employees;
using ScheduleOne.EntityFramework;
using ScheduleOne.GameTime;
using ScheduleOne.ItemFramework;
using ScheduleOne.Law;
using ScheduleOne.Levelling;
using ScheduleOne.Management;
using ScheduleOne.Map;
using ScheduleOne.Money;
using ScheduleOne.NPCs;
using ScheduleOne.NPCs.Behaviour;
using ScheduleOne.NPCs.Framework;
using ScheduleOne.ObjectScripts;
using ScheduleOne.Persistence;
using ScheduleOne.PlayerScripts;
using ScheduleOne.Police;
using ScheduleOne.Product;
using ScheduleOne.Property;
using ScheduleOne.Quests;
using ScheduleOne.Storage;
using ScheduleOne.Tools;
using ScheduleOne.UI;
using ScheduleOne.UI.Handover;
using ScheduleOne.UI.MainMenu;
using ScheduleOne.Vehicles;
using ScheduleOne.Vehicles.AI;
using ScheduleOne.Vision;
using ScheduleOne.VoiceOver;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using VLB;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(global::NACops.NACops), "NACops", "2.1.0", "XOWithSauce", null)]
[assembly: MelonColor]
[assembly: MelonOptionalDependencies(new string[] { "FishNet.Runtime" })]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)]
[assembly: VerifyLoaderVersion("0.7.2", true)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("XOWithSauce")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright XOWithSauce 2026 Source MIT")]
[assembly: AssemblyDescription("Schedule I NACops Mod")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyInformationalVersion("2.1.0")]
[assembly: AssemblyProduct("NACops")]
[assembly: AssemblyTitle("NACops")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/XOWithSauce/schedule-nacops")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NACops
{
	public class FootPatrolGenerator
	{
		public static Dictionary<PatrolInstance, List<string>> generatedPatrolInstances = new Dictionary<PatrolInstance, List<string>>();

		public static ConfigLoader.FootPatrolsSerialized serPatrols;

		public static PatrolInstance[] GeneratePatrol(LawActivitySettings template, string day = "")
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (generatedPatrolInstances.Count == 0)
			{
				DebugModule.Log("Generating new patrol routes", "GeneratePatrol");
				Transform parent = ((Component)Singleton<LawController>.Instance).transform.Find("PatrolRoutes");
				if (serPatrols == null)
				{
					serPatrols = ConfigLoader.LoadPatrolsConfig();
				}
				foreach (SerializedFootPatrol loadedPatrol in serPatrols.loadedPatrols)
				{
					GameObject val = new GameObject(loadedPatrol.name);
					DebugModule.Log("Generate object for patrol: " + loadedPatrol.name, "GeneratePatrol");
					DebugModule.Log("- Days: " + string.Join(" ", loadedPatrol.days), "GeneratePatrol");
					FootPatrolRoute val2 = val.AddComponent<FootPatrolRoute>();
					((Object)val2).name = loadedPatrol.name;
					val2.RouteName = loadedPatrol.name;
					val2.StartWaypointIndex = 0;
					Transform[] array = (Transform[])(object)new Transform[loadedPatrol.waypoints.Count];
					for (int i = 0; i < loadedPatrol.waypoints.Count; i++)
					{
						GameObject val3 = new GameObject((i == 0) ? "Waypoint" : $"Waypoint ({i})");
						val3.transform.position = loadedPatrol.waypoints[i];
						val3.transform.parent = val.transform;
						array[i] = val3.transform;
					}
					val2.Waypoints = array;
					val.transform.parent = parent;
					PatrolInstance val4 = new PatrolInstance();
					val4.StartTime = loadedPatrol.startTime;
					val4.EndTime = loadedPatrol.endTime;
					val4.MaxMembers = loadedPatrol.members;
					val4.MinMembers = 1;
					val4.Route = val2;
					val4.OnlyIfCurfewEnabled = loadedPatrol.onlyIfCurfew;
					val4.IntensityRequirement = loadedPatrol.intensityRequirement;
					val.transform.parent = parent;
					val.SetActive(true);
					generatedPatrolInstances.Add(val4, loadedPatrol.days);
				}
			}
			if (day == "")
			{
				int num = template.Patrols.Length;
				int count = generatedPatrolInstances.Count;
				int num2 = num + count;
				PatrolInstance[] array2 = (PatrolInstance[])(object)new PatrolInstance[num2];
				Array.Copy(template.Patrols, array2, num);
				int num3 = num;
				foreach (KeyValuePair<PatrolInstance, List<string>> generatedPatrolInstance in generatedPatrolInstances)
				{
					if (num3 >= num2)
					{
						break;
					}
					array2[num3] = generatedPatrolInstance.Key;
					num3++;
				}
				return array2;
			}
			int num4 = template.Patrols.Length;
			int num5 = 0;
			foreach (KeyValuePair<PatrolInstance, List<string>> generatedPatrolInstance2 in generatedPatrolInstances)
			{
				if (generatedPatrolInstance2.Value.Contains(day))
				{
					num5++;
				}
			}
			if (num5 == 0)
			{
				return template.Patrols;
			}
			int num6 = num4 + num5;
			PatrolInstance[] array3 = (PatrolInstance[])(object)new PatrolInstance[num6];
			Array.Copy(template.Patrols, array3, num4);
			int num7 = num4;
			foreach (KeyValuePair<PatrolInstance, List<string>> generatedPatrolInstance3 in generatedPatrolInstances)
			{
				if (num7 >= num6)
				{
					break;
				}
				if (generatedPatrolInstance3.Value.Contains(day))
				{
					array3[num7] = generatedPatrolInstance3.Key;
					num7++;
				}
			}
			DebugModule.Log($"    {day}: Added {num5} patrols ({num4} -> {num6})", "GeneratePatrol");
			return array3;
		}
	}
	[Serializable]
	public class SerializedFootPatrol
	{
		public int startTime = 1900;

		public int endTime = 500;

		public int members = 2;

		public int intensityRequirement = 1;

		public bool onlyIfCurfew;

		public string name = "NACops Extra Loop";

		public List<string> days;

		public List<Vector3> waypoints = new List<Vector3>();
	}
	public class SentryGenerator
	{
		public static Dictionary<SentryInstance, List<string>> generatedSentryInstances = new Dictionary<SentryInstance, List<string>>();

		public static ConfigLoader.SentrysSerialized serSentries;

		public static SentryInstance[] GenerateSentry(LawActivitySettings template, string day = "")
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			if (generatedSentryInstances.Count == 0)
			{
				DebugModule.Log("Generating new sentry spots", "GenerateSentry");
				Transform val = ((Component)Singleton<LawController>.Instance).transform.Find("Sentry Locations");
				if ((Object)(object)val == (Object)null)
				{
					DebugModule.Log("    Sentry Locations transform is null", "GenerateSentry");
				}
				DebugModule.Log("    Load Sentry Config", "GenerateSentry");
				if (serSentries == null)
				{
					serSentries = ConfigLoader.LoadSentryConfig();
				}
				DebugModule.Log("    Loaded Patrols config count: " + serSentries.loadedSentrys.Count, "GenerateSentry");
				foreach (SerializedSentry loadedSentry in serSentries.loadedSentrys)
				{
					GameObject val2 = new GameObject(loadedSentry.name);
					DebugModule.Log("Generate object for patrol: " + loadedSentry.name, "GenerateSentry");
					DebugModule.Log("- Days: " + string.Join(" ", loadedSentry.days), "GenerateSentry");
					SentryLocation val3 = val2.AddComponent<SentryLocation>();
					val3.Routes = new List<SentryRoute>();
					SentryRoute val4 = new SentryRoute();
					GameObject val5 = new GameObject("Stand point");
					val5.transform.parent = val2.transform;
					val5.transform.SetPositionAndRotation(loadedSentry.standPosition1, Quaternion.Euler(loadedSentry.pos1Rotation));
					GameObject val6 = new GameObject("Stand point (1)");
					val6.transform.parent = val2.transform;
					val6.transform.SetPositionAndRotation(loadedSentry.standPosition2, Quaternion.Euler(loadedSentry.pos2Rotation));
					val4.RoutePoints = (Transform[])(object)new Transform[2] { val5.transform, val6.transform };
					val4.MinutesPerPoint = loadedSentry.minutesPerPoint;
					val3.Routes.Add(val4);
					((Component)val3).gameObject.SetActive(true);
					SentryInstance val7 = new SentryInstance();
					val7.StartTime = loadedSentry.startTime;
					val7.EndTime = loadedSentry.endTime;
					val7.MaxMembers = loadedSentry.members;
					val7.MinMembers = 1;
					val7._potentialLocations = (SentryLocation[])(object)new SentryLocation[1] { val3 };
					val7.OnlyIfCurfewEnabled = loadedSentry.onlyIfCurfew;
					val7.IntensityRequirement = loadedSentry.intensityRequirement;
					val2.transform.parent = val;
					val2.SetActive(true);
					generatedSentryInstances.Add(val7, loadedSentry.days);
				}
			}
			if (day == "")
			{
				int num = template.Sentries.Length;
				int count = generatedSentryInstances.Count;
				int num2 = num + count;
				SentryInstance[] array = (SentryInstance[])(object)new SentryInstance[num2];
				Array.Copy(template.Sentries, array, num);
				int num3 = num;
				foreach (KeyValuePair<SentryInstance, List<string>> generatedSentryInstance in generatedSentryInstances)
				{
					if (num3 >= num2)
					{
						break;
					}
					array[num3] = generatedSentryInstance.Key;
					num3++;
				}
				return array;
			}
			int num4 = template.Sentries.Length;
			int num5 = 0;
			foreach (KeyValuePair<SentryInstance, List<string>> generatedSentryInstance2 in generatedSentryInstances)
			{
				if (generatedSentryInstance2.Value.Contains(day))
				{
					num5++;
				}
			}
			if (num5 == 0)
			{
				return template.Sentries;
			}
			int num6 = num4 + num5;
			SentryInstance[] array2 = (SentryInstance[])(object)new SentryInstance[num6];
			Array.Copy(template.Sentries, array2, num4);
			int num7 = num4;
			foreach (KeyValuePair<SentryInstance, List<string>> generatedSentryInstance3 in generatedSentryInstances)
			{
				if (num7 >= num6)
				{
					break;
				}
				if (generatedSentryInstance3.Value.Contains(day))
				{
					array2[num7] = generatedSentryInstance3.Key;
					num7++;
				}
			}
			DebugModule.Log($"    {day}: Added {num5} sentries ({num4} -> {num6})", "GenerateSentry");
			return array2;
		}
	}
	[Serializable]
	public class SerializedSentry
	{
		public int startTime = 1900;

		public int endTime = 500;

		public int members = 1;

		public int minutesPerPoint = 60;

		public int intensityRequirement = 1;

		public bool onlyIfCurfew;

		public string name;

		public List<string> days;

		public Vector3 standPosition1;

		public Vector3 pos1Rotation;

		public Vector3 standPosition2;

		public Vector3 pos2Rotation;
	}
	public class VehiclePatrolGenerator
	{
		public static Dictionary<VehiclePatrolInstance, List<string>> generatedVehiclePatrolInstances = new Dictionary<VehiclePatrolInstance, List<string>>();

		public static ConfigLoader.VehiclePatrolsSerialized serVehiclePatrols;

		public static VehiclePatrolInstance[] GenerateVehiclePatrol(LawActivitySettings template, string day = "")
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if (generatedVehiclePatrolInstances.Count == 0)
			{
				DebugModule.Log("Generating new vehicle patrol routes", "GenerateVehiclePatrol");
				Transform parent = ((Component)Singleton<LawController>.Instance).transform.Find("VehiclePatrolRoutes");
				if (serVehiclePatrols == null)
				{
					serVehiclePatrols = ConfigLoader.LoadVehiclePatrolsConfig();
				}
				foreach (SerializedVehiclePatrol loadedVehiclePatrol in serVehiclePatrols.loadedVehiclePatrols)
				{
					GameObject val = new GameObject(loadedVehiclePatrol.name);
					DebugModule.Log("Generate object for patrol: " + loadedVehiclePatrol.name, "GenerateVehiclePatrol");
					DebugModule.Log("- Days: " + string.Join(" ", loadedVehiclePatrol.days), "GenerateVehiclePatrol");
					VehiclePatrolRoute val2 = val.AddComponent<VehiclePatrolRoute>();
					((Object)val2).name = loadedVehiclePatrol.name;
					val2.RouteName = loadedVehiclePatrol.name;
					val2.StartWaypointIndex = 0;
					Transform[] array = (Transform[])(object)new Transform[loadedVehiclePatrol.waypoints.Count];
					for (int i = 0; i < loadedVehiclePatrol.waypoints.Count; i++)
					{
						GameObject val3 = new GameObject((i == 0) ? "Waypoint" : $"Waypoint ({i})");
						val3.transform.position = loadedVehiclePatrol.waypoints[i];
						val3.transform.parent = val.transform;
						array[i] = val3.transform;
					}
					val2.Waypoints = array;
					val.transform.parent = parent;
					VehiclePatrolInstance val4 = new VehiclePatrolInstance();
					val4.StartTime = loadedVehiclePatrol.startTime;
					val4.Route = val2;
					val4.IntensityRequirement = loadedVehiclePatrol.intensityRequirement;
					val4.OnlyIfCurfewEnabled = loadedVehiclePatrol.onlyIfCurfew;
					val.transform.parent = parent;
					val.SetActive(true);
					generatedVehiclePatrolInstances.Add(val4, loadedVehiclePatrol.days);
				}
			}
			if (day == "")
			{
				int num = template.VehiclePatrols.Length;
				int count = generatedVehiclePatrolInstances.Count;
				int num2 = num + count;
				VehiclePatrolInstance[] array2 = (VehiclePatrolInstance[])(object)new VehiclePatrolInstance[num2];
				Array.Copy(template.VehiclePatrols, array2, num);
				int num3 = num;
				foreach (KeyValuePair<VehiclePatrolInstance, List<string>> generatedVehiclePatrolInstance in generatedVehiclePatrolInstances)
				{
					if (num3 >= num2)
					{
						break;
					}
					array2[num3] = generatedVehiclePatrolInstance.Key;
					num3++;
				}
				return array2;
			}
			int num4 = template.VehiclePatrols.Length;
			int num5 = 0;
			foreach (KeyValuePair<VehiclePatrolInstance, List<string>> generatedVehiclePatrolInstance2 in generatedVehiclePatrolInstances)
			{
				if (generatedVehiclePatrolInstance2.Value.Contains(day))
				{
					num5++;
				}
			}
			if (num5 == 0)
			{
				return template.VehiclePatrols;
			}
			int num6 = num4 + num5;
			VehiclePatrolInstance[] array3 = (VehiclePatrolInstance[])(object)new VehiclePatrolInstance[num6];
			Array.Copy(template.VehiclePatrols, array3, num4);
			int num7 = num4;
			foreach (KeyValuePair<VehiclePatrolInstance, List<string>> generatedVehiclePatrolInstance3 in generatedVehiclePatrolInstances)
			{
				if (num7 >= num6)
				{
					break;
				}
				if (generatedVehiclePatrolInstance3.Value.Contains(day))
				{
					array3[num7] = generatedVehiclePatrolInstance3.Key;
					num7++;
				}
			}
			DebugModule.Log($"    {day}: Added {num5} vehicle patrols ({num4} -> {num6})", "GenerateVehiclePatrol");
			return array3;
		}
	}
	[Serializable]
	public class SerializedVehiclePatrol
	{
		public int startTime = 2300;

		public int intensityRequirement = 1;

		public bool onlyIfCurfew;

		public string name = "NACops Vehicle Extra Loop";

		public List<string> days;

		public List<Vector3> waypoints = new List<Vector3>();
	}
	[HarmonyPatch(typeof(Customer), "ProcessHandover")]
	public static class Customer_ProcessHandover_Patch
	{
		public static int cooldownHours = 3;

		[HarmonyPrefix]
		public static bool Prefix(Customer __instance, EHandoverOutcome outcome, Contract contract, List<ItemInstance> items, bool handoverByPlayer, bool giveBonuses = true)
		{
			MelonCoroutines.Start(PreProcessHandover(__instance, handoverByPlayer));
			return true;
		}

		public static IEnumerator PreProcessHandover(Customer __instance, bool handoverByPlayer)
		{
			if (!handoverByPlayer)
			{
				yield break;
			}
			if (cooldownHours > 0)
			{
				DebugModule.Log($"Cant run buy bust, on cooldown: {cooldownHours}", "PreProcessHandover");
				yield break;
			}
			if (NACops.currentConfig.BuyBusts)
			{
				MelonCoroutines.Start(SummonBustCop(__instance));
			}
			yield return null;
		}

		public static IEnumerator SummonBustCop(Customer customer)
		{
			int value = Mathf.RoundToInt(customer.NPC.RelationData.RelationDelta * 10f);
			var (num, num2) = ThresholdUtils.Evaluate(NACops.thresholdConfig.BuyBustProbability, value);
			if (NACops.currentConfig.DebugMode || !(Random.Range(num, num2) < 0.5f))
			{
				DebugModule.Log("Spawn buy bust", "SummonBustCop");
				cooldownHours = 3;
				((Component)CopInitHelper.buyBustCop).gameObject.SetActive(true);
				((Component)((Component)CopInitHelper.buyBustCop).transform.Find("Avatar")).gameObject.SetActive(true);
				((Behaviour)((Component)CopInitHelper.buyBustCop).GetComponent<NavMeshAgent>()).enabled = true;
				if (!((NPC)CopInitHelper.buyBustCop).Movement.IsPaused)
				{
					((NPC)CopInitHelper.buyBustCop).Movement.PauseMovement();
				}
				((NPC)CopInitHelper.buyBustCop).Awareness.SetAwarenessActive(true);
				Player local = Player.Local;
				Vector3 val = ((Component)customer).transform.position + ((Component)customer).transform.forward * 3f;
				Vector3 val2 = default(Vector3);
				bool closestReachablePoint = ((NPC)CopInitHelper.buyBustCop).Movement.GetClosestReachablePoint(val, ref val2);
				bool instant = false;
				if (closestReachablePoint && val2 != Vector3.zero)
				{
					((NPC)CopInitHelper.buyBustCop).Movement.Warp(val2);
					((NPC)CopInitHelper.buyBustCop).Movement.ResumeMovement();
					DebugModule.Log("Drug bust officer spawned now at " + ((object)((NPC)CopInitHelper.buyBustCop).CenterPoint/*cast due to .constrained prefix*/).ToString(), "SummonBustCop");
					((VOEmitter)CopInitHelper.buyBustCop.ChatterVO).Play((EVOLineType)2);
					((NPC)CopInitHelper.buyBustCop).Movement.FacePoint(((Component)customer).transform.position, 0.5f);
					local.CrimeData.SetPursuitLevel((EPursuitLevel)3);
					CopInitHelper.buyBustCop.BeginFootPursuit(local.PlayerCode);
					((Behaviour)CopInitHelper.buyBustCop.PursuitBehaviour).Enable_Networked();
					NACops.coros.Add(MelonCoroutines.Start(SetTaser(CopInitHelper.buyBustCop)));
					NACops.coros.Add(MelonCoroutines.Start(LateEnableArrest(CopInitHelper.buyBustCop)));
					local.CrimeData.AddCrime((Crime)new AttemptingToSell(), 10);
				}
				else
				{
					DebugModule.Log("Failed to Get closest reachable position for drug bust", "SummonBustCop");
					instant = true;
				}
				NACops.coros.Add(MelonCoroutines.Start(DisposeSummoned(instant, local)));
			}
			yield break;
		}

		public static IEnumerator LateEnableArrest(PoliceOfficer offc)
		{
			float maxWait = 8f;
			float current = 0f;
			while (true)
			{
				if (!NACops.registered)
				{
					yield break;
				}
				if (current >= maxWait)
				{
					break;
				}
				yield return NACops.Wait01;
				if (offc.PursuitBehaviour.arrestingEnabled)
				{
					offc.PursuitBehaviour.arrestingEnabled = false;
				}
				current += 0.1f;
			}
			offc.PursuitBehaviour.arrestingEnabled = true;
		}

		public static IEnumerator SetTaser(PoliceOfficer offc)
		{
			((NPC)offc).Behaviour.CombatBehaviour.SetWeapon(((Object)(object)offc.TaserPrefab != (Object)null) ? offc.TaserPrefab.AssetPath : string.Empty);
			if (!((Object)(object)((NPC)offc).Behaviour.CombatBehaviour.currentWeapon == (Object)null))
			{
				AvatarWeapon currentWeapon = ((NPC)offc).Behaviour.CombatBehaviour.currentWeapon;
				AvatarRangedWeapon val = (AvatarRangedWeapon)(object)((currentWeapon is AvatarRangedWeapon) ? currentWeapon : null);
				if ((Object)(object)val != (Object)null)
				{
					val.CanShootWhileMoving = true;
					val.MagazineSize = 20;
					val.MaxFireRate = 0.3f;
					((AvatarWeapon)val).MaxUseRange = 24f;
					val.ReloadTime = 0.2f;
					val.RaiseTime = 0.1f;
					val.HitChance_MaxRange = 0.6f;
					val.HitChance_MinRange = 0.9f;
					((AvatarWeapon)val).CooldownDuration = 0.3f;
				}
			}
			yield break;
		}

		public static IEnumerator DisposeSummoned(bool instant, Player target)
		{
			yield return NACops.Wait1;
			if (!NACops.registered)
			{
				yield break;
			}
			int lifeTime = 0;
			int maxTime = 30;
			if (!instant && (Object)(object)target != (Object)null && (Object)(object)CopInitHelper.buyBustCop != (Object)null)
			{
				while (lifeTime <= maxTime && !target.IsArrested && ((NPC)CopInitHelper.buyBustCop).IsConscious)
				{
					lifeTime++;
					yield return NACops.Wait1;
					if (!NACops.registered)
					{
						yield break;
					}
				}
			}
			if (!((NPC)CopInitHelper.buyBustCop).IsConscious)
			{
				yield return NACops.Wait30;
				((NPC)CopInitHelper.buyBustCop).Health.Revive();
			}
			((NPC)CopInitHelper.buyBustCop).Awareness.SetAwarenessActive(false);
			((Component)CopInitHelper.buyBustCop).gameObject.SetActive(false);
			((Component)((Component)CopInitHelper.buyBustCop).transform.Find("Avatar")).gameObject.SetActive(false);
			if (!((NPC)CopInitHelper.buyBustCop).Movement.IsPaused)
			{
				((NPC)CopInitHelper.buyBustCop).Movement.PauseMovement();
			}
			((Behaviour)((Component)CopInitHelper.buyBustCop).GetComponent<NavMeshAgent>()).enabled = false;
			DebugModule.Log("Disposed summoned bustcop", "DisposeSummoned");
		}

		public static void ReduceBuyBustHours()
		{
			if (cooldownHours > 0)
			{
				cooldownHours--;
			}
			DebugModule.Log($"Reduce buy bust hours now: {cooldownHours}", "ReduceBuyBustHours");
		}
	}
	public class UnityContractResolver : DefaultContractResolver
	{
		protected override JsonObjectContract CreateObjectContract(Type objectType)
		{
			JsonObjectContract val = ((DefaultContractResolver)this).CreateObjectContract(objectType);
			if (objectType == typeof(Vector3))
			{
				for (int num = ((Collection<JsonProperty>)(object)val.Properties).Count - 1; num >= 0; num--)
				{
					JsonProperty val2 = ((Collection<JsonProperty>)(object)val.Properties)[num];
					if (val2.PropertyName == "normalized" || val2.PropertyName == "magnitude" || val2.PropertyName == "sqrMagnitude")
					{
						((Collection<JsonProperty>)(object)val.Properties).RemoveAt(num);
					}
				}
			}
			return val;
		}
	}
	public static class ConfigLoader
	{
		[Serializable]
		public class ModConfig
		{
			public bool DebugMode;

			public bool RaidsEnabled = true;

			public bool ExtraOfficerPatrols = true;

			public bool ExtraVehiclePatrols = true;

			public bool ExtraOfficerSentries = true;

			public bool CheckpointsEnabled = true;

			public bool NoOpenCarryWeapons = true;

			public bool PrivateInvestigator = true;

			public bool WeedInvestigator = true;

			public bool CorruptCops = true;

			public bool SnitchingSamples = true;

			public bool BuyBusts = true;

			public bool MassSurveillance = true;

			public bool NearbyCrazyCops = true;

			public bool LethalCops;

			public bool RacistCops;
		}

		[Serializable]
		public class NAOfficerConfig
		{
			public int ModAddedOfficersCount = 8;

			public bool CanEnterBuildings = true;

			public bool ShowNoticeIcons = true;

			public bool OverrideArresting = true;

			public float ArrestTime = 1.25f;

			public float ArrestRange = 3.5f;

			public bool OverrideMovement = true;

			public float MovementSpeedMultiplier = 1.45f;

			public bool OverrideWeapon = true;

			public string RangedWeapon = "m1911";

			public float WeaponDamage = 46f;

			public float WeaponAimTimeMax = 1f;

			public float WeaponAimTimeMin = 0.5f;

			public int WeaponMagSize = 20;

			public float WeaponFireRate = 0.33f;

			public float WeaponMaxRange = 25f;

			public float WeaponReloadTime = 0.5f;

			public float WeaponRaiseTime = 0.2f;

			public float WeaponHitChanceMax = 0.3f;

			public float WeaponHitChanceMin = 0.8f;

			public bool OverrideTaser = true;

			public float TaserDamage = 5f;

			public float TaserAimTimeMax = 1f;

			public float TaserAimTimeMin = 0.5f;

			public float TaserFireRate = 3f;

			public float TaserMaxRange = 15f;

			public float TaserReloadTime = 1f;

			public float TaserRaiseTime = 0.7f;

			public float TaserHitChanceMax = 0.3f;

			public float TaserHitChanceMin = 0.8f;

			public bool OverrideMaxHealth = true;

			public float OfficerMaxHealth = 175f;

			public bool OverrideBodySearch = true;

			public float BodySearchDuration = 6f;

			public float BodySearchChance = 1f;

			public bool OverrideCombatBeh = true;

			public float CombatGiveUpRange = 9999f;

			public float CombatSearchTime = 9999f;

			public float CombatMoveSpeed = 1.3f;

			public int CombatEndAfterHits;

			public bool OverrideVision = true;

			public float VisionRangeMultiplier = 2f;

			public Dictionary<string, float> VisionSpeed = new Dictionary<string, float>
			{
				{ "Suspicious", 0.3f },
				{ "DisobeyingCurfew", 0.3f },
				{ "Vandalizing", 0.3f },
				{ "PettyCrime", 0.2f },
				{ "DrugDealing", 0.4f },
				{ "Wanted", 0.1f },
				{ "Pickpocketing", 0.3f },
				{ "DischargingWeapon", 0.1f },
				{ "Brandishing", 0.1f }
			};
		}

		[Serializable]
		public class RaidConfig
		{
			public float TraverseToPropertySpeed = 0.47f;

			public float ClearPropertySpeed = 0.38f;

			public int MaxDestroyIters = 4;

			public int RaidCopsCount = 3;

			public int DaysUntilCanRaid = 8;

			public int PropertyHeatThreshold = 14;

			public float RaiderMaxHealth = 240f;

			public float RaiderWeaponDmg = 65f;
		}

		[Serializable]
		public class MassSurveillanceConfig
		{
			public bool UseUnidirectionalCameras = true;

			public bool UseOmnidirectionalCameras = true;

			public bool SurveilCrimeStatus = true;

			public bool SurveilBaseCrimes = true;

			public int ActiveCamerasPerDay = 5;

			public int CameraActivationRange = 20;

			public int CameraNoticeSpeed = 2;

			public int CameraNoticeCooldown = 30;

			public bool PayFinesFromBank = true;

			public bool GrowPaymentsWithProgression = true;

			public int CrimePaymentMultiplier = 1;
		}

		[Serializable]
		public class FootPatrolsSerialized
		{
			public List<SerializedFootPatrol> loadedPatrols = new List<SerializedFootPatrol>();
		}

		[Serializable]
		public class VehiclePatrolsSerialized
		{
			public List<SerializedVehiclePatrol> loadedVehiclePatrols = new List<SerializedVehiclePatrol>();
		}

		[Serializable]
		public class SentrysSerialized
		{
			public List<SerializedSentry> loadedSentrys = new List<SerializedSentry>();
		}

		public static ModConfig LoadModConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathModConfig);
			ModConfig modConfig;
			if (File.Exists(pathTo))
			{
				try
				{
					modConfig = JsonConvert.DeserializeObject<ModConfig>(File.ReadAllText(pathTo));
				}
				catch (Exception ex)
				{
					modConfig = new ModConfig();
					MelonLogger.Warning("Failed to read NACops Mod config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Mod config, creating directory and template.");
				modConfig = new ModConfig();
				Save(modConfig);
			}
			return modConfig;
		}

		public static void Save(ModConfig config, bool logConfirm = true)
		{
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathModConfig);
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				if (logConfirm)
				{
					MelonLogger.Warning("NACops Mod config, written to: " + pathTo);
				}
			}
			catch (Exception ex)
			{
				if (logConfirm)
				{
					MelonLogger.Warning("Failed to save NACops Mod config: " + ex);
				}
			}
		}

		public static NAOfficerConfig LoadOfficerConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathOfficerConfig);
			NAOfficerConfig nAOfficerConfig;
			if (File.Exists(pathTo))
			{
				try
				{
					nAOfficerConfig = JsonConvert.DeserializeObject<NAOfficerConfig>(File.ReadAllText(pathTo));
					nAOfficerConfig.ModAddedOfficersCount = Mathf.Clamp(nAOfficerConfig.ModAddedOfficersCount, 0, 20);
					if (!new List<string> { "m1911", "goldenm1911", "shotgun", "revolver" }.Contains(nAOfficerConfig.RangedWeapon))
					{
						nAOfficerConfig.RangedWeapon = "m1911";
					}
					foreach (string item in nAOfficerConfig.VisionSpeed.Keys.ToList())
					{
						nAOfficerConfig.VisionSpeed[item] = Mathf.Clamp(nAOfficerConfig.VisionSpeed[item], 0.01f, 10f);
					}
				}
				catch (Exception ex)
				{
					nAOfficerConfig = new NAOfficerConfig();
					MelonLogger.Warning("Failed to read NACops config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Officers config, creating directory and template.");
				nAOfficerConfig = new NAOfficerConfig();
				Save(nAOfficerConfig);
			}
			return nAOfficerConfig;
		}

		public static void Save(NAOfficerConfig config)
		{
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathOfficerConfig);
				string contents = JsonConvert.SerializeObject((object)config);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("NACops Officers config, written to: " + pathTo);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Officers config: " + ex);
			}
		}

		public static FootPatrolsSerialized LoadPatrolsConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathPatrolsConfig);
			FootPatrolsSerialized footPatrolsSerialized;
			if (File.Exists(pathTo))
			{
				try
				{
					footPatrolsSerialized = JsonConvert.DeserializeObject<FootPatrolsSerialized>(File.ReadAllText(pathTo));
					List<string> list = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
					foreach (SerializedFootPatrol loadedPatrol in footPatrolsSerialized.loadedPatrols)
					{
						loadedPatrol.members = Mathf.Clamp(loadedPatrol.members, 1, 4);
						loadedPatrol.name = (string.IsNullOrEmpty(loadedPatrol.name) ? "NACopsPatrol " : loadedPatrol.name);
						loadedPatrol.intensityRequirement = Mathf.Clamp(loadedPatrol.intensityRequirement, 0, 10);
						if (!TimeManager.IsValid24HourTime(loadedPatrol.startTime.ToString()))
						{
							MelonLogger.Warning("FootPatrolsConfig '" + loadedPatrol.name + "' has invalid start time");
							loadedPatrol.startTime = 1900;
						}
						if (!TimeManager.IsValid24HourTime(loadedPatrol.endTime.ToString()))
						{
							MelonLogger.Warning("FootPatrolsConfig '" + loadedPatrol.name + "' has invalid end time");
							loadedPatrol.endTime = 2330;
						}
						if (loadedPatrol.waypoints.Count == 0)
						{
							MelonLogger.Warning("FootPatrolsConfig is missing Waypoints for " + loadedPatrol.name);
						}
						for (int num = loadedPatrol.days.Count - 1; num != -1; num--)
						{
							if (loadedPatrol.days[num] != string.Empty)
							{
								loadedPatrol.days[num] = loadedPatrol.days[num].ToLower();
								if (!list.Contains(loadedPatrol.days[num]))
								{
									MelonLogger.Warning($"FootPatrolsConfig '{loadedPatrol.name}' has invalid weekday: '{loadedPatrol.days[num]}'");
									loadedPatrol.days.RemoveAt(num);
								}
							}
							else
							{
								loadedPatrol.days.RemoveAt(num);
							}
						}
					}
				}
				catch (Exception ex)
				{
					footPatrolsSerialized = new FootPatrolsSerialized();
					MelonLogger.Warning("Failed to read FootPatrolsSerialized config: " + ex);
				}
			}
			else
			{
				footPatrolsSerialized = new FootPatrolsSerialized();
				footPatrolsSerialized.loadedPatrols = new List<SerializedFootPatrol>();
				Save(footPatrolsSerialized);
			}
			return footPatrolsSerialized;
		}

		public static void Save(FootPatrolsSerialized config)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathPatrolsConfig);
				JsonSerializerSettings val = new JsonSerializerSettings
				{
					ContractResolver = (IContractResolver)(object)new UnityContractResolver()
				};
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1, val);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("Foot Patrols Config has been saved!");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Foot Patrols config: " + ex);
			}
		}

		public static VehiclePatrolsSerialized LoadVehiclePatrolsConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathVehiclePatrolsConfig);
			VehiclePatrolsSerialized vehiclePatrolsSerialized;
			if (File.Exists(pathTo))
			{
				try
				{
					vehiclePatrolsSerialized = JsonConvert.DeserializeObject<VehiclePatrolsSerialized>(File.ReadAllText(pathTo));
					List<string> list = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
					foreach (SerializedVehiclePatrol loadedVehiclePatrol in vehiclePatrolsSerialized.loadedVehiclePatrols)
					{
						loadedVehiclePatrol.name = (string.IsNullOrEmpty(loadedVehiclePatrol.name) ? "NaCopsVehiclePatrol " : loadedVehiclePatrol.name);
						loadedVehiclePatrol.intensityRequirement = Mathf.Clamp(loadedVehiclePatrol.intensityRequirement, 0, 10);
						if (!TimeManager.IsValid24HourTime(loadedVehiclePatrol.startTime.ToString()))
						{
							MelonLogger.Warning("Vehicle Patrol Config '" + loadedVehiclePatrol.name + "' has invalid start time");
							loadedVehiclePatrol.startTime = 1900;
						}
						if (loadedVehiclePatrol.waypoints.Count == 0)
						{
							MelonLogger.Warning("Vehicle Patrol Config is missing Waypoints for " + loadedVehiclePatrol.name);
						}
						for (int num = loadedVehiclePatrol.days.Count - 1; num != -1; num--)
						{
							if (loadedVehiclePatrol.days[num] != string.Empty)
							{
								loadedVehiclePatrol.days[num] = loadedVehiclePatrol.days[num].ToLower();
								if (!list.Contains(loadedVehiclePatrol.days[num]))
								{
									MelonLogger.Warning($"Vehicle Patrol Config '{loadedVehiclePatrol.name}' has invalid weekday: '{loadedVehiclePatrol.days[num]}'");
									loadedVehiclePatrol.days.RemoveAt(num);
								}
							}
							else
							{
								loadedVehiclePatrol.days.RemoveAt(num);
							}
						}
					}
				}
				catch (Exception ex)
				{
					vehiclePatrolsSerialized = new VehiclePatrolsSerialized();
					MelonLogger.Warning("Failed to read Vehicle Patrol config: " + ex);
				}
			}
			else
			{
				vehiclePatrolsSerialized = new VehiclePatrolsSerialized();
				vehiclePatrolsSerialized.loadedVehiclePatrols = new List<SerializedVehiclePatrol>();
				Save(vehiclePatrolsSerialized);
			}
			return vehiclePatrolsSerialized;
		}

		public static void Save(VehiclePatrolsSerialized config)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathVehiclePatrolsConfig);
				JsonSerializerSettings val = new JsonSerializerSettings
				{
					ContractResolver = (IContractResolver)(object)new UnityContractResolver()
				};
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1, val);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("Vehicle Patrols config has been saved!");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Vehicle Patrols config: " + ex);
			}
		}

		public static SentrysSerialized LoadSentryConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathSentrysConfig);
			SentrysSerialized sentrysSerialized;
			if (File.Exists(pathTo))
			{
				try
				{
					sentrysSerialized = JsonConvert.DeserializeObject<SentrysSerialized>(File.ReadAllText(pathTo));
					List<string> list = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
					foreach (SerializedSentry loadedSentry in sentrysSerialized.loadedSentrys)
					{
						loadedSentry.members = Mathf.Clamp(loadedSentry.members, 1, 2);
						loadedSentry.name = (string.IsNullOrEmpty(loadedSentry.name) ? "NACopsSentry " : loadedSentry.name);
						loadedSentry.intensityRequirement = Mathf.Clamp(loadedSentry.intensityRequirement, 0, 10);
						if (!TimeManager.IsValid24HourTime(loadedSentry.startTime.ToString()))
						{
							MelonLogger.Warning("Sentry Config '" + loadedSentry.name + "' has invalid start time");
							loadedSentry.startTime = 1900;
						}
						if (!TimeManager.IsValid24HourTime(loadedSentry.endTime.ToString()))
						{
							MelonLogger.Warning("Sentry Config '" + loadedSentry.name + "' has invalid end time");
							loadedSentry.endTime = 2330;
						}
						if (loadedSentry.minutesPerPoint <= 0 || loadedSentry.minutesPerPoint > 480)
						{
							MelonLogger.Warning("Sentry Config '" + loadedSentry.name + "' has invalid minutes per point value. Range 1-480");
							loadedSentry.minutesPerPoint = 60;
						}
						for (int num = loadedSentry.days.Count - 1; num != -1; num--)
						{
							if (loadedSentry.days[num] != string.Empty)
							{
								loadedSentry.days[num] = loadedSentry.days[num].ToLower();
								if (!list.Contains(loadedSentry.days[num]))
								{
									MelonLogger.Warning($"Sentry Config '{loadedSentry.name}' has invalid weekday: '{loadedSentry.days[num]}'");
									loadedSentry.days.RemoveAt(num);
								}
							}
							else
							{
								loadedSentry.days.RemoveAt(num);
							}
						}
					}
				}
				catch (Exception ex)
				{
					sentrysSerialized = new SentrysSerialized();
					MelonLogger.Warning("Failed to read SentrysSerialized config: " + ex);
				}
			}
			else
			{
				sentrysSerialized = new SentrysSerialized();
				sentrysSerialized.loadedSentrys = new List<SerializedSentry>();
				Save(sentrysSerialized);
			}
			return sentrysSerialized;
		}

		public static void Save(SentrysSerialized config)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathSentrysConfig);
				JsonSerializerSettings val = new JsonSerializerSettings
				{
					ContractResolver = (IContractResolver)(object)new UnityContractResolver()
				};
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1, val);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("Sentry config has been saved!");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Sentry config: " + ex);
			}
		}

		public static string SanitizeAndFormatName(string orgName)
		{
			string text = orgName;
			if (text != null)
			{
				text = text.Replace(" ", "_").ToLower();
				text = text.Replace(",", "");
				text = text.Replace(".", "");
				text = text.Replace("<", "");
				text = text.Replace(">", "");
				text = text.Replace(":", "");
				text = text.Replace("\"", "");
				text = text.Replace("/", "");
				text = text.Replace("\\", "");
				text = text.Replace("|", "");
				text = text.Replace("?", "");
				text = text.Replace("*", "");
			}
			return text + ".json";
		}

		public static PropertiesHeatSerialized LoadPropertyHeats()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathPropertyHeatConfig);
			string organisationName = Singleton<LoadManager>.Instance.ActiveSaveInfo.OrganisationName;
			int saveSlotNumber = Singleton<LoadManager>.Instance.ActiveSaveInfo.SaveSlotNumber;
			string path = $"{saveSlotNumber}_{SanitizeAndFormatName(organisationName)}";
			PropertiesHeatSerialized propertiesHeatSerialized;
			if (File.Exists(Path.Combine(pathTo, path)))
			{
				try
				{
					propertiesHeatSerialized = JsonConvert.DeserializeObject<PropertiesHeatSerialized>(File.ReadAllText(Path.Combine(pathTo, path)));
				}
				catch (Exception ex)
				{
					propertiesHeatSerialized = new PropertiesHeatSerialized();
					propertiesHeatSerialized.loadedPropertyHeats = new List<PropertyHeat>();
					string[] array = new string[6] { "sweatshop", "bungalow", "storageunit", "dockswarehouse", "barn", "manor" };
					foreach (string propertyCode in array)
					{
						PropertyHeat propertyHeat = new PropertyHeat();
						propertyHeat.propertyCode = propertyCode;
						propertiesHeatSerialized.loadedPropertyHeats.Add(propertyHeat);
					}
					MelonLogger.Warning("Failed to read NACops Property Heat config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Property Heat config, creating directory and template.");
				propertiesHeatSerialized = new PropertiesHeatSerialized();
				Save(propertiesHeatSerialized, generateTemplate: true);
			}
			return propertiesHeatSerialized;
		}

		public static void Save(PropertiesHeatSerialized config, bool generateTemplate = false)
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathPropertyHeatConfig);
			if (generateTemplate)
			{
				config.loadedPropertyHeats = new List<PropertyHeat>();
				string[] array = new string[6] { "sweatshop", "bungalow", "storageunit", "dockswarehouse", "barn", "manor" };
				foreach (string propertyCode in array)
				{
					PropertyHeat propertyHeat = new PropertyHeat();
					propertyHeat.propertyCode = propertyCode;
					config.loadedPropertyHeats.Add(propertyHeat);
				}
			}
			try
			{
				string organisationName = Singleton<LoadManager>.Instance.ActiveSaveInfo.OrganisationName;
				int saveSlotNumber = Singleton<LoadManager>.Instance.ActiveSaveInfo.SaveSlotNumber;
				string path = $"{saveSlotNumber}_{SanitizeAndFormatName(organisationName)}";
				string text = Path.Combine(pathTo, path);
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1);
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				File.WriteAllText(text, contents);
				if (generateTemplate)
				{
					MelonLogger.Warning("NACops Property Heat config, written to: " + text);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Property Heat config: " + ex);
			}
		}

		public static ThresholdMappings LoadFrequencyConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathEventFrequencyConfig);
			ThresholdMappings thresholdMappings;
			if (File.Exists(pathTo))
			{
				try
				{
					thresholdMappings = JsonConvert.DeserializeObject<ThresholdMappings>(File.ReadAllText(pathTo));
					foreach (MinMaxThreshold item in thresholdMappings.LethalCopFrequency)
					{
						if (item.MinOf < 0)
						{
							item.MinOf = 0;
						}
						if (item.Min >= item.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at LethalCopFreq Min value, must be smaller than Max value");
							if (item.Max > 0f)
							{
								item.Min = item.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item2 in thresholdMappings.LethalCopRange)
					{
						if (item2.MinOf < 0)
						{
							item2.MinOf = 0;
						}
						if (item2.Min >= item2.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at LethalCopRange Min value, must be smaller than Max value");
							if (item2.Max > 0f)
							{
								item2.Min = item2.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item3 in thresholdMappings.NearbyCrazyFrequency)
					{
						if (item3.MinOf < 0)
						{
							item3.MinOf = 0;
						}
						if (item3.Min >= item3.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at NearbyCrazFreq Min value, must be smaller than Max value");
							if (item3.Max > 0f)
							{
								item3.Min = item3.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item4 in thresholdMappings.NearbyCrazyRange)
					{
						if (item4.MinOf < 0)
						{
							item4.MinOf = 0;
						}
						if (item4.Min >= item4.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at NearbyCrazRange Min value, must be smaller than Max value");
							if (item4.Max > 0f)
							{
								item4.Min = item4.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item5 in thresholdMappings.PIFrequency)
					{
						if (item5.MinOf < 0)
						{
							item5.MinOf = 0;
						}
						if (item5.Min >= item5.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at PIFreq Min value, must be smaller than Max value");
							if (item5.Max > 0f)
							{
								item5.Min = item5.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item6 in thresholdMappings.SnitchProbability)
					{
						if (item6.MinOf < 0)
						{
							item6.MinOf = 0;
						}
						if (item6.Min >= item6.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at SnitchProbability Min value, must be smaller than Max value");
							if (item6.Max > 0f)
							{
								item6.Min = item6.Max * 0.5f;
							}
						}
					}
					foreach (MinMaxThreshold item7 in thresholdMappings.BuyBustProbability)
					{
						if (item7.MinOf < 0)
						{
							item7.MinOf = 0;
						}
						if (item7.Min >= item7.Max)
						{
							MelonLogger.Warning("Found invalid value in progression.json at BuyBustProbability Min value, must be smaller than Max value");
							if (item7.Max > 0f)
							{
								item7.Min = item7.Max * 0.5f;
							}
						}
					}
				}
				catch (Exception ex)
				{
					thresholdMappings = new ThresholdMappings();
					MelonLogger.Warning("Failed to read NACops Event Frequency config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Event Frequency config, creating directory and template.");
				thresholdMappings = new ThresholdMappings();
				Save(thresholdMappings);
			}
			return thresholdMappings;
		}

		public static void Save(ThresholdMappings config)
		{
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathEventFrequencyConfig);
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("NACops Event Frequency config, written to: " + pathTo);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Event Frequency config: " + ex);
			}
		}

		public static RaidConfig LoadRaidConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathRaidConfig);
			RaidConfig raidConfig;
			if (File.Exists(pathTo))
			{
				try
				{
					raidConfig = JsonConvert.DeserializeObject<RaidConfig>(File.ReadAllText(pathTo));
					raidConfig.TraverseToPropertySpeed = Mathf.Clamp(raidConfig.TraverseToPropertySpeed, 0.1f, 1f);
					raidConfig.ClearPropertySpeed = Mathf.Clamp(raidConfig.ClearPropertySpeed, 0.1f, 1f);
					raidConfig.MaxDestroyIters = Mathf.Clamp(raidConfig.MaxDestroyIters, 1, 10);
					raidConfig.RaidCopsCount = Mathf.Clamp(raidConfig.RaidCopsCount, 1, 10);
					raidConfig.DaysUntilCanRaid = Mathf.Clamp(raidConfig.DaysUntilCanRaid, 1, 20);
					raidConfig.PropertyHeatThreshold = Mathf.Clamp(raidConfig.PropertyHeatThreshold, 1, 100);
					raidConfig.RaiderMaxHealth = Mathf.Clamp(raidConfig.RaiderMaxHealth, 1f, 300f);
					raidConfig.RaiderWeaponDmg = Mathf.Clamp(raidConfig.RaiderWeaponDmg, 1f, 100f);
				}
				catch (Exception ex)
				{
					raidConfig = new RaidConfig();
					MelonLogger.Warning("Failed to read NACops Raid config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Raid config, creating directory and template.");
				raidConfig = new RaidConfig();
				Save(raidConfig);
			}
			return raidConfig;
		}

		public static void Save(RaidConfig config)
		{
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathRaidConfig);
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("NACops Raid config, written to: " + pathTo);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Raid config: " + ex);
			}
		}

		public static MassSurveillanceConfig LoadSurveillanceConfig()
		{
			string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathSurveillanceConfig);
			MassSurveillanceConfig massSurveillanceConfig;
			if (File.Exists(pathTo))
			{
				try
				{
					massSurveillanceConfig = JsonConvert.DeserializeObject<MassSurveillanceConfig>(File.ReadAllText(pathTo));
					massSurveillanceConfig.ActiveCamerasPerDay = Mathf.Clamp(massSurveillanceConfig.ActiveCamerasPerDay, 1, 10);
					massSurveillanceConfig.CameraNoticeCooldown = Mathf.Clamp(massSurveillanceConfig.CameraNoticeCooldown, 1, 60);
					massSurveillanceConfig.CameraActivationRange = Mathf.Clamp(massSurveillanceConfig.CameraActivationRange, 1, 50);
					massSurveillanceConfig.CameraNoticeSpeed = Mathf.Clamp(massSurveillanceConfig.CameraNoticeSpeed, 1, 10);
				}
				catch (Exception ex)
				{
					massSurveillanceConfig = new MassSurveillanceConfig();
					MelonLogger.Warning("Failed to read NACops Mass Surveillance config: " + ex);
				}
			}
			else
			{
				MelonLogger.Warning("Missing NACops Mass Surveillance config, creating directory and template.");
				massSurveillanceConfig = new MassSurveillanceConfig();
				Save(massSurveillanceConfig);
			}
			return massSurveillanceConfig;
		}

		public static void Save(MassSurveillanceConfig config)
		{
			try
			{
				string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathSurveillanceConfig);
				string contents = JsonConvert.SerializeObject((object)config, (Formatting)1);
				Directory.CreateDirectory(Path.GetDirectoryName(pathTo));
				File.WriteAllText(pathTo, contents);
				MelonLogger.Warning("NACops Mass Surveillance config, written to: " + pathTo);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Failed to save NACops Mass Surveillance config: " + ex);
			}
		}
	}
	public class ModPrefsHandler
	{
		public MelonPreferences_Category modConfigCategory;

		public void SetupMelonPreferences()
		{
			string text = "NACops XOWithSauce";
			modConfigCategory = MelonPreferences.CreateCategory(text, "NACops");
			modConfigCategory.CreateEntry<bool>("DebugMode", NACops.currentConfig.DebugMode, "Debug Mode Enabled", "Enable debug mode to test features", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("RaidsEnabled", NACops.currentConfig.RaidsEnabled, "Raids Enabled", "Enable raid events", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("ExtraOfficerPatrols", NACops.currentConfig.ExtraOfficerPatrols, "Extra officer foot patrols", "Adds new officer foot patrols from 'Spawn/patrols.json' file", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("ExtraVehiclePatrols", NACops.currentConfig.ExtraVehiclePatrols, "Extra officer vehicle patrols", "Adds new officer vehicle patrols from 'Spawn/vehiclepatrols.json' file", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("ExtraOfficerSentries", NACops.currentConfig.ExtraOfficerSentries, "Extra officer sentries", "Adds new officer stationary sentries from 'Spawn/sentries.json' file", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("CheckpointsEnabled", NACops.currentConfig.CheckpointsEnabled, "Checkpoints Enabled", "Enable the usage of road block checkpoints", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("NoOpenCarryWeapons", NACops.currentConfig.NoOpenCarryWeapons, "No open carry weapons", "Makes holding weapons in hand and in inventory illegal", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("PrivateInvestigator", NACops.currentConfig.PrivateInvestigator, "Private investigator", "Enable the private investigator who spies on the player and gathers evidence for property heat system", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("WeedInvestigator", NACops.currentConfig.WeedInvestigator, "Weed investigator", "Enable a feature where using drugs will cause nearby cops to search for the player", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("CorruptCops", NACops.currentConfig.CorruptCops, "Corrupt cops", "Enable a feature where cops give false charges that cause the players arrest to be more expensive", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("SnitchingSamples", NACops.currentConfig.SnitchingSamples, "Snitching samples", "Enable a feature where giving free samples can result in Investigation crime status", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("BuyBusts", NACops.currentConfig.BuyBusts, "Buy busts", "Enable a feature where after completing a deal an officer can spawn behind the player and attempt to arrest", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("MassSurveillance", NACops.currentConfig.MassSurveillance, "Mass Surveillance", "Enable the usage of Cameras across Hyland Point to monitor the player and report any crimes.", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("NearbyCrazyCops", NACops.currentConfig.NearbyCrazyCops, "Nearby crazy cops", "Enable a feature where cops will randomly find the player nearby and body search", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("LethalCops", NACops.currentConfig.LethalCops, "Lethal cops", "Enable a feature where cops will randomly start lethally hunting the player when nearby", false, false, (ValueValidator)null, (string)null);
			modConfigCategory.CreateEntry<bool>("RacistCops", NACops.currentConfig.RacistCops, "Racist cops", "Enable a feature where cops will hunt down black skin coloured players on sight", false, false, (ValueValidator)null, (string)null);
			for (int i = 0; i < modConfigCategory.Entries.Count; i++)
			{
				string id = modConfigCategory.Entries[i].Identifier;
				((MelonEventBase<LemonAction<object, object>>)(object)modConfigCategory.Entries[i].OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)ThisEntryChanged, 0, false);
				void ThisEntryChanged(object objOld, object objNew)
				{
					OnEntryChange(id, objOld, objNew);
				}
			}
			MelonPreferences.SaveCategory<MelonPreferences_Category>(text, false);
			DebugModule.Log("Melon preferences created", "SetupMelonPreferences");
		}

		public static void OnEntryChange(string identifier, object objOld, object objNew)
		{
			FieldInfo[] fields = NACops.currentConfig.GetType().GetFields();
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.Name.Contains(identifier))
				{
					fieldInfo.SetValue(NACops.currentConfig, (bool)objNew);
				}
			}
			ConfigLoader.Save(NACops.currentConfig, logConfirm: false);
		}
	}
	public static class ModDataPaths
	{
		private static readonly string BASE_USERDATA_NAME = "XO_WithSauce-NACops";

		private static readonly string TS_PACKAGE_NAME = "XO_WithSauce-NACops_";

		private static readonly string packagePathUserData = Path.Combine(MelonEnvironment.UserDataDirectory, TS_PACKAGE_NAME + "MONO", BASE_USERDATA_NAME);

		private static readonly string manualPathUserData = Path.Combine(MelonEnvironment.UserDataDirectory, BASE_USERDATA_NAME);

		public static readonly string pathModConfig = "config.json";

		public static readonly string pathOfficerConfig = "officer.json";

		public static readonly string pathRaidConfig = "raid.json";

		public static readonly string pathEventFrequencyConfig = "progression.json";

		public static readonly string pathSurveillanceConfig = "surveillance.json";

		public static readonly string pathPatrolsConfig = Path.Combine("Spawn", "patrols.json");

		public static readonly string pathVehiclePatrolsConfig = Path.Combine("Spawn", "vehiclepatrols.json");

		public static readonly string pathSentrysConfig = Path.Combine("Spawn", "sentrys.json");

		public static readonly string pathPropertyHeatConfig = "HeatData";

		private static bool hasCheckedInstallationPath = false;

		private static bool isModManagerInstallation = false;

		public static string GetPathTo(string modDataDestination)
		{
			if (!hasCheckedInstallationPath)
			{
				if (Directory.Exists(packagePathUserData))
				{
					isModManagerInstallation = true;
				}
				if (Directory.Exists(manualPathUserData))
				{
					isModManagerInstallation = false;
				}
				hasCheckedInstallationPath = true;
			}
			return Path.Combine(isModManagerInstallation ? packagePathUserData : manualPathUserData, modDataDestination);
		}
	}
	public static class ConsoleModule
	{
		[Flags]
		public enum CommandSupport
		{
			None = 0,
			List = 1,
			Spawn = 2,
			SpawnNoIndex = 4,
			Visualize = 8,
			Build = 0x10
		}

		public abstract class ConsoleCommandBase
		{
			public virtual string Name { get; }

			public virtual CommandSupport SupportedMethods { get; }

			public virtual void List()
			{
				DebugModule.Log("Not implemented", "List");
			}

			public virtual void Spawn(int index)
			{
				DebugModule.Log("Not implemented", "Spawn");
			}

			public virtual void Visualize(int index)
			{
				DebugModule.Log("Not implemented", "Visualize");
			}

			public virtual void Build(string arg)
			{
				DebugModule.Log("Build Argument: " + arg + " Not implemented", "Build");
			}

			protected static void CleanVisual()
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Expected O, but got Unknown
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Expected O, but got Unknown
				if (DebugModule.pathVisualizer != null && DebugModule.pathVisualizer.Count > 0)
				{
					foreach (GameObject item in DebugModule.pathVisualizer)
					{
						Object.Destroy((Object)(object)item);
					}
				}
				DebugModule.pathVisualizer.Clear();
				if ((Object)(object)DebugModule.lineRenderMat == (Object)null)
				{
					DebugModule.lineRenderMat = new Material(Shader.Find("Sprites/Default"));
				}
				if ((Object)(object)DebugModule.cameraBeamMat == (Object)null)
				{
					DebugModule.cameraBeamMat = new Material(Shader.Find("Universal Render Pipeline/Lit"));
				}
			}

			protected static void DrawPath(string name, Vector3[] points)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_0039: 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)
				GameObject val = new GameObject("Path_" + name);
				DebugModule.pathVisualizer.Add(val);
				LineRenderer obj = val.AddComponent<LineRenderer>();
				((Renderer)obj).material = DebugModule.lineRenderMat;
				obj.widthMultiplier = 0.5f;
				obj.startColor = Color.blue;
				obj.endColor = Color.red;
				obj.positionCount = points.Length;
				obj.SetPositions(points);
			}
		}

		public class FootPatrolTarget : ConsoleCommandBase
		{
			public static List<Vector3> recordedPathNodes = new List<Vector3>();

			public static string currentPathName;

			public override string Name => "footpatrol";

			public override CommandSupport SupportedMethods => CommandSupport.List | CommandSupport.Spawn | CommandSupport.Visualize | CommandSupport.Build;

			public override void List()
			{
				string text = "";
				int num = 0;
				text += "\nIndex: Name";
				foreach (PatrolInstance key in FootPatrolGenerator.generatedPatrolInstances.Keys)
				{
					text += $"\n{num}: {((Object)key.Route).name}";
					num++;
				}
				text += "\n-------";
				DebugModule.Log(text, "List");
			}

			public override void Spawn(int index)
			{
				List<PatrolInstance> list = FootPatrolGenerator.generatedPatrolInstances.Keys.ToList();
				PatrolInstance instance;
				int originalStart;
				int originalEnd;
				if (index < list.Count)
				{
					instance = list[index];
					if (instance.ActiveGroup != null)
					{
						DebugModule.Log("Foot patrol group is already active", "Spawn");
						return;
					}
					originalStart = instance.StartTime;
					originalEnd = instance.EndTime;
					instance.StartTime = NetworkSingleton<TimeManager>.Instance.CurrentTime;
					instance.EndTime = TimeManager.AddMinutesTo24HourTime(originalStart, 240);
					instance.StartPatrol();
					DebugModule.Log("Patrol " + ((Object)instance.Route).name + " Spawned", "Spawn");
					NACops.coros.Add(MelonCoroutines.Start(EndSoon()));
				}
				IEnumerator EndSoon()
				{
					yield return (object)new WaitForSeconds(240f);
					instance.EndPatrol();
					instance.StartTime = originalStart;
					instance.EndTime = originalEnd;
				}
			}

			public override void Visualize(int index)
			{
				ConsoleCommandBase.CleanVisual();
				List<PatrolInstance> list = FootPatrolGenerator.generatedPatrolInstances.Keys.ToList();
				if (index >= 0 && index < list.Count)
				{
					FootPatrolRoute route = list[index].Route;
					Vector3[] points = route.Waypoints.Select((Transform waypoint) => waypoint.position + Vector3.up * 8f).ToArray();
					ConsoleCommandBase.DrawPath(((Object)route).name, points);
					DebugModule.Log("Patrol " + ((Object)route).name + " Visualized", "Visualize");
				}
			}

			public override void Build(string arg)
			{
				if (arg.ToLower() == "start")
				{
					BuildStart();
				}
				else if (isBuilding)
				{
					BuildEnd();
				}
			}

			public void BuildStart()
			{
				if (isBuilding)
				{
					DebugModule.Log("Already building a path or a sentry!\n    Use: nacops build " + Name + " stop\n    to stop building", "BuildStart");
					return;
				}
				isBuilding = true;
				currentPathName = $"{Name}_{Guid.NewGuid()}";
				DebugModule.Log("Started building path with name " + currentPathName + "\nWalk around to create new path nodes!", "BuildStart");
				NACops.coros.Add(MelonCoroutines.Start(FollowPlayer()));
			}

			public IEnumerator FollowPlayer()
			{
				Transform centerPointTransform = Player.Local.CenterPointTransform;
				GameObject val = new GameObject("Path");
				DebugModule.pathVisualizer.Add(val);
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				LineRenderer val2 = val.AddComponent<LineRenderer>();
				((Renderer)val2).material = DebugModule.lineRenderMat;
				val2.widthMultiplier = 0.5f;
				val2.startColor = Color.blue;
				val2.endColor = Color.red;
				val2.positionCount = recordedPathNodes.Count;
				val2.SetPositions(recordedPathNodes.ToArray());
				while (NACops.registered && isBuilding)
				{
					if (Vector3.Distance(centerPointTransform.position, recordedPathNodes[recordedPathNodes.Count - 1]) > 6f)
					{
						BuildNode(val2);
					}
				}
				yield return null;
			}

			public void BuildNode(LineRenderer lineRenderer)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				lineRenderer.positionCount = recordedPathNodes.Count;
				lineRenderer.SetPositions(recordedPathNodes.ToArray());
			}

			public void BuildEnd()
			{
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_010d: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				isBuilding = false;
				ConsoleCommandBase.CleanVisual();
				if (recordedPathNodes.Count == 0)
				{
					DebugModule.Log("No recorded nodes found.", "BuildEnd");
					return;
				}
				if (recordedPathNodes.Count < 4)
				{
					DebugModule.Log("Build more path nodes to save.", "BuildEnd");
					recordedPathNodes.Clear();
					return;
				}
				SerializedFootPatrol serializedFootPatrol = new SerializedFootPatrol();
				serializedFootPatrol.startTime = 1900;
				serializedFootPatrol.endTime = 500;
				serializedFootPatrol.members = 2;
				serializedFootPatrol.intensityRequirement = 1;
				serializedFootPatrol.onlyIfCurfew = false;
				serializedFootPatrol.name = currentPathName;
				serializedFootPatrol.days = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
				List<Vector3> list = new List<Vector3>();
				list.Add(recordedPathNodes[0]);
				foreach (Vector3 recordedPathNode in recordedPathNodes)
				{
					if (Vector3.Distance(recordedPathNode, list[list.Count - 1]) > 24f)
					{
						list.Add(recordedPathNode);
					}
				}
				serializedFootPatrol.waypoints = new List<Vector3>(list);
				FootPatrolGenerator.serPatrols.loadedPatrols.Add(serializedFootPatrol);
				DebugModule.Log("Finished building: " + currentPathName, "BuildEnd");
				DebugModule.Log($"Recorded path nodes: {recordedPathNodes.Count}\n    Reload the game to apply changes.", "BuildEnd");
				ConfigLoader.Save(FootPatrolGenerator.serPatrols);
				recordedPathNodes.Clear();
			}
		}

		public class VehiclePatrolTarget : ConsoleCommandBase
		{
			public static List<Vector3> recordedPathNodes = new List<Vector3>();

			public static string currentPathName;

			public override string Name => "vehiclepatrol";

			public override CommandSupport SupportedMethods => CommandSupport.List | CommandSupport.Spawn | CommandSupport.Visualize | CommandSupport.Build;

			public override void List()
			{
				string text = "";
				int num = 0;
				text += "\nIndex: Name";
				foreach (VehiclePatrolInstance key in VehiclePatrolGenerator.generatedVehiclePatrolInstances.Keys)
				{
					text += $"\n{num}: {((Object)key.Route).name}";
					num++;
				}
				text += "\n-------";
				DebugModule.Log(text, "List");
			}

			public override void Spawn(int index)
			{
				List<VehiclePatrolInstance> list = VehiclePatrolGenerator.generatedVehiclePatrolInstances.Keys.ToList();
				VehiclePatrolInstance instance;
				int originalStart;
				if (index < list.Count)
				{
					instance = list[index];
					if ((Object)(object)instance.activeOfficer != (Object)null)
					{
						DebugModule.Log("Vehicle patrol is already active", "Spawn");
						return;
					}
					originalStart = instance.StartTime;
					instance.StartTime = NetworkSingleton<TimeManager>.Instance.CurrentTime;
					instance.StartPatrol();
					DebugModule.Log("Vehicle Patrol " + ((Object)instance.Route).name + " Spawned", "Spawn");
					NACops.coros.Add(MelonCoroutines.Start(EndSoon()));
				}
				IEnumerator EndSoon()
				{
					yield return (object)new WaitForSeconds(240f);
					instance.StartTime = originalStart;
				}
			}

			public override void Visualize(int index)
			{
				ConsoleCommandBase.CleanVisual();
				List<VehiclePatrolInstance> list = VehiclePatrolGenerator.generatedVehiclePatrolInstances.Keys.ToList();
				if (index >= 0 && index < list.Count)
				{
					VehiclePatrolRoute route = list[index].Route;
					Vector3[] points = route.Waypoints.Select((Transform waypoint) => waypoint.position + Vector3.up * 8f).ToArray();
					ConsoleCommandBase.DrawPath(((Object)route).name, points);
					DebugModule.Log("Veicle Patrol " + ((Object)route).name + " Visualized", "Visualize");
				}
			}

			public override void Build(string arg)
			{
				if (arg.ToLower() == "start")
				{
					BuildStart();
				}
				else if (isBuilding)
				{
					BuildEnd();
				}
			}

			public void BuildStart()
			{
				if (isBuilding)
				{
					DebugModule.Log("Already building a path or a sentry!\n    Use: nacops build " + Name + " stop\n    to stop building", "BuildStart");
					return;
				}
				isBuilding = true;
				currentPathName = $"{Name}_{Guid.NewGuid()}";
				DebugModule.Log("Started building path with name " + currentPathName + "\nWalk on the road to create new path nodes!", "BuildStart");
				NACops.coros.Add(MelonCoroutines.Start(FollowPlayer()));
			}

			public IEnumerator FollowPlayer()
			{
				Transform tr = Player.Local.CenterPointTransform;
				GameObject val = new GameObject("Path");
				DebugModule.pathVisualizer.Add(val);
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				LineRenderer lineRenderer = val.AddComponent<LineRenderer>();
				((Renderer)lineRenderer).material = DebugModule.lineRenderMat;
				lineRenderer.widthMultiplier = 0.5f;
				lineRenderer.startColor = Color.blue;
				lineRenderer.endColor = Color.red;
				lineRenderer.positionCount = recordedPathNodes.Count;
				lineRenderer.SetPositions(recordedPathNodes.ToArray());
				while (NACops.registered && isBuilding)
				{
					yield return NACops.Wait1;
					if (Vector3.Distance(tr.position, recordedPathNodes[recordedPathNodes.Count - 1]) > 6f)
					{
						BuildNode(lineRenderer);
					}
				}
				yield return null;
			}

			public void BuildNode(LineRenderer lineRenderer)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				lineRenderer.positionCount = recordedPathNodes.Count;
				lineRenderer.SetPositions(recordedPathNodes.ToArray());
			}

			public void BuildEnd()
			{
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0106: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				isBuilding = false;
				ConsoleCommandBase.CleanVisual();
				if (recordedPathNodes.Count == 0)
				{
					DebugModule.Log("No recorded nodes found.", "BuildEnd");
					return;
				}
				if (recordedPathNodes.Count < 4)
				{
					DebugModule.Log("Build more path nodes to save.", "BuildEnd");
					recordedPathNodes.Clear();
					return;
				}
				SerializedVehiclePatrol serializedVehiclePatrol = new SerializedVehiclePatrol();
				serializedVehiclePatrol.startTime = 1900;
				serializedVehiclePatrol.intensityRequirement = 1;
				serializedVehiclePatrol.onlyIfCurfew = false;
				serializedVehiclePatrol.name = currentPathName;
				serializedVehiclePatrol.days = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
				List<Vector3> list = new List<Vector3>();
				list.Add(recordedPathNodes[0]);
				foreach (Vector3 recordedPathNode in recordedPathNodes)
				{
					if (Vector3.Distance(recordedPathNode, list[list.Count - 1]) > 24f)
					{
						list.Add(recordedPathNode);
					}
				}
				serializedVehiclePatrol.waypoints = new List<Vector3>(list);
				VehiclePatrolGenerator.serVehiclePatrols.loadedVehiclePatrols.Add(serializedVehiclePatrol);
				DebugModule.Log("Finished building: " + currentPathName, "BuildEnd");
				DebugModule.Log($"Recorded path nodes: {recordedPathNodes.Count}\n    Reload the game to apply changes.", "BuildEnd");
				ConfigLoader.Save(VehiclePatrolGenerator.serVehiclePatrols);
				recordedPathNodes.Clear();
			}
		}

		public class SentryTarget : ConsoleCommandBase
		{
			public static List<Vector3> recordedPathNodes = new List<Vector3>();

			public static string currentPathName;

			public override string Name => "sentry";

			public override CommandSupport SupportedMethods => CommandSupport.List | CommandSupport.Spawn | CommandSupport.Visualize | CommandSupport.Build;

			public override void List()
			{
				string text = "";
				int num = 0;
				text += "\nIndex: Name";
				foreach (SentryInstance key in SentryGenerator.generatedSentryInstances.Keys)
				{
					text += $"\n{num}: {((Object)((Component)key._potentialLocations[0]).gameObject).name}";
					num++;
				}
				text += "\n-------";
				DebugModule.Log(text, "List");
			}

			public override void Spawn(int index)
			{
				List<SentryInstance> list = SentryGenerator.generatedSentryInstances.Keys.ToList();
				SentryInstance instance;
				int originalStart;
				int originalEnd;
				if (index < list.Count)
				{
					instance = list[index];
					if (instance._potentialLocations[0].AssignedOfficers.Count > 0)
					{
						DebugModule.Log("Sentry is already active", "Spawn");
						return;
					}
					originalStart = instance.StartTime;
					originalEnd = instance.EndTime;
					instance.StartTime = NetworkSingleton<TimeManager>.Instance.CurrentTime;
					instance.EndTime = TimeManager.AddMinutesTo24HourTime(originalStart, 240);
					instance.StartEntry();
					DebugModule.Log("Sentry " + ((Object)((Component)instance._potentialLocations[0]).gameObject).name + " Spawned", "Spawn");
					NACops.coros.Add(MelonCoroutines.Start(EndSoon()));
				}
				IEnumerator EndSoon()
				{
					yield return (object)new WaitForSeconds(240f);
					instance.EndSentry();
					instance.StartTime = originalStart;
					instance.EndTime = originalEnd;
				}
			}

			public override void Visualize(int index)
			{
				//IL_004c: 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_005a: 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_0062: 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_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				ConsoleCommandBase.CleanVisual();
				List<SentryInstance> list = SentryGenerator.generatedSentryInstances.Keys.ToList();
				if (index >= 0 && index < list.Count)
				{
					SentryInstance val = list[index];
					for (int i = 0; i < val._potentialLocations[0].Routes.Count; i++)
					{
						Vector3 position = val._potentialLocations[0].Routes[0].RoutePoints[i].position;
						Vector3[] points = (Vector3[])(object)new Vector3[2]
						{
							position,
							position + Vector3.up * 8f
						};
						ConsoleCommandBase.DrawPath($"{((Object)((Component)val._potentialLocations[0]).gameObject).name}_{i}", points);
					}
					DebugModule.Log("Sentry " + ((Object)((Component)val._potentialLocations[0]).gameObject).name + " Visualized", "Visualize");
				}
			}

			public override void Build(string arg)
			{
				if (arg.ToLower() == "start")
				{
					BuildStart();
				}
				else if (isBuilding)
				{
					NACops.coros.Add(MelonCoroutines.Start(BuildEnd()));
				}
			}

			public void BuildStart()
			{
				if (isBuilding)
				{
					DebugModule.Log("Already building a path or sentry!\n    Use: nacops build " + Name + " stop\n    to stop building", "BuildStart");
					return;
				}
				isBuilding = true;
				currentPathName = $"{Name}_{Guid.NewGuid()}";
				DebugModule.Log(currentPathName + ": Set 1st Sentry Point\n    Walk to 2nd sentry point and type:\nnacops build " + Name + " stop", "BuildStart");
				MakeVertBeam();
			}

			public void MakeVertBeam()
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				Transform centerPointTransform = Player.Local.CenterPointTransform;
				GameObject val = new GameObject("Path");
				DebugModule.pathVisualizer.Add(val);
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				LineRenderer val2 = val.AddComponent<LineRenderer>();
				((Renderer)val2).material = DebugModule.lineRenderMat;
				val2.widthMultiplier = 0.5f;
				val2.startColor = Color.blue;
				val2.endColor = Color.red;
				val2.positionCount = 2;
				Vector3[] positions = (Vector3[])(object)new Vector3[2]
				{
					centerPointTransform.position,
					centerPointTransform.position + Vector3.up * 5f
				};
				val2.SetPositions(positions);
			}

			public IEnumerator BuildEnd()
			{
				recordedPathNodes.Add(Player.Local.CenterPointTransform.position);
				isBuilding = false;
				if (recordedPathNodes.Count == 0)
				{
					DebugModule.Log("No recorded nodes found.", "BuildEnd");
					yield break;
				}
				if (recordedPathNodes.Count != 2)
				{
					DebugModule.Log("Build more sentry nodes to save.", "BuildEnd");
					recordedPathNodes.Clear();
					yield break;
				}
				SerializedSentry serializedSentry = new SerializedSentry();
				serializedSentry.startTime = 1900;
				serializedSentry.endTime = 500;
				serializedSentry.members = 1;
				serializedSentry.intensityRequirement = 1;
				serializedSentry.onlyIfCurfew = false;
				serializedSentry.name = currentPathName;
				serializedSentry.days = new List<string> { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
				serializedSentry.standPosition1 = recordedPathNodes[0];
				serializedSentry.standPosition2 = recordedPathNodes[1];
				SentryGenerator.serSentries.loadedSentrys.Add(serializedSentry);
				DebugModule.Log("Finished building: " + currentPathName, "BuildEnd");
				DebugModule.Log($"Recorded path nodes: {recordedPathNodes.Count}\n    Reload the game to apply changes.", "BuildEnd");
				ConfigLoader.Save(SentryGenerator.serSentries);
				recordedPathNodes.Clear();
				yield return NACops.Wait5;
				ConsoleCommandBase.CleanVisual();
			}
		}

		public class RaidTarget : ConsoleCommandBase
		{
			public override string Name => "raid";

			public override CommandSupport SupportedMethods => CommandSupport.List | CommandSupport.Spawn;

			public override void List()
			{
				lock (NACops.heatConfigLock)
				{
					List<PropertyHeat> list = new List<PropertyHeat>(NACops.heatConfig);
					string text = "";
					int num = 0;
					text += "\nIndex: Name";
					foreach (PropertyHeat item in list)
					{
						text += $"\n{num}: {item.propertyCode}\n    DaysSinceRaid: {item.daysSinceLastRaid}\n    Heat: {item.propertyHeat}";
						num++;
					}
					text += "\n-------";
					DebugModule.Log(text, "List");
				}
			}

			public override void Spawn(int index)
			{
				if (index < 0 || index >= NACops.heatConfig.Count)
				{
					return;
				}
				Property val = null;
				foreach (Property property in Property.Properties)
				{
					if (property.PropertyCode == NACops.heatConfig[index].propertyCode)
					{
						val = property;
					}
				}
				if (Object.op_Implicit((Object)(object)val))
				{
					if ((Object)(object)val.NPCSpawnPoint == (Object)null)
					{
						DebugModule.Log("No valid destination for property: " + val.propertyName, "Spawn");
					}
					else if (val is Business)
					{
						DebugModule.Log("Cant start raid on a business", "Spawn");
					}
					else
					{
						NACops.coros.Add(MelonCoroutines.Start(RaidPropertyEvent.BeginRaidEvent(val)));
					}
				}
			}

			public override void Visualize(int index)
			{
				DebugModule.Log("Not supported", "Visualize");
			}
		}

		public class InvestigatorTarget : ConsoleCommandBase
		{
			public override string Name => "investigator";

			public override CommandSupport SupportedMethods => CommandSupport.SpawnNoIndex;

			public override void List()
			{
				DebugModule.Log("Not supported", "List");
			}

			public override void Spawn(int index)
			{
				if (PrivateInvestigator.investigatorActive)
				{
					DebugModule.Log("Investigator is already active!", "Spawn");
					return;
				}
				DebugModule.Log("Spawning Private Investigator", "Spawn");
				NACops.coros.Add(MelonCoroutines.Start(PrivateInvestigator.HandlePIMonitor()));
			}

			public override void Visualize(int index)
			{
				DebugModule.Log("Not supported", "Visualize");
			}
		}

		public class CopAnalyticsTarget : ConsoleCommandBase
		{
			public static TextMeshProUGUI AnalyticsTextPanel;

			public override string Name => "analytics";

			public override CommandSupport SupportedMethods => CommandSupport.Visualize;

			public override void Visualize(int index)
			{
				if ((Object)(object)AnalyticsTextPanel == (Object)null)
				{
					MelonCoroutines.Start(MakeUI());
				}
				else if ((Object)(object)AnalyticsTextPanel != (Object)null && ((Behaviour)AnalyticsTextPanel).enabled)
				{
					DebugModule.Log("Disabling Analytics text", "Visualize");
					((Behaviour)AnalyticsTextPanel).enabled = false;
				}
				else if ((Object)(object)AnalyticsTextPanel != (Object)null)
				{
					DebugModule.Log("Enabling Analytics text", "Visualize");
					((Behaviour)AnalyticsTextPanel).enabled = true;
				}
			}

			public IEnumerator MakeUI()
			{
				AnalyticsTextPanel = new GameObject("CurrentLawIntensity").AddComponent<TextMeshProUGUI>();
				SetupAnalyticsUI(AnalyticsTextPanel);
				DebugModule.Log("Finished instantiating UI", "MakeUI");
				NACops.coros.Add(MelonCoroutines.Start(UpdateUI()));
				yield break;
			}

			public IEnumerator UpdateUI()
			{
				SetAnalyticsString();
				while (true)
				{
					yield return NACops.Wait30;
					if (!NACops.registered)
					{
						break;
					}
					if (((Behaviour)AnalyticsTextPanel).enabled)
					{
						SetAnalyticsString();
					}
				}
			}

			public void SetAnalyticsString()
			{
				string text = "";
				text += $"LAW INTENSITY: {Singleton<LawController>.Instance.internalLawIntensity}\n";
				text += $"IN POOL: {PoliceStation.PoliceStations[0].OfficerPool.Count}\n";
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				int num5 = 0;
				foreach (PoliceOfficer officer in PoliceOfficer.Officers)
				{
					if (!((NPC)officer).isInBuilding)
					{
						num++;
					}
					if ((Object)(object)((NPC)officer).Behaviour.activeBehaviour != (Object)null)
					{
						if ((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.CheckpointBehaviour)
						{
							num2++;
						}
						if ((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.FootPatrolBehaviour)
						{
							num3++;
						}
						if ((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.SentryBehaviour)
						{
							num4++;
						}
						if ((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.VehiclePatrolBehaviour)
						{
							num5++;
						}
					}
				}
				text += $"ACTIVE: {num}/{PoliceOfficer.Officers.Count}\n";
				int num6 = 0;
				int num7 = 0;
				int num8 = 0;
				int num9 = 0;
				int num10 = 0;
				int num11 = 0;
				int num12 = 0;
				int num13 = 0;
				int num14 = 0;
				int num15 = 0;
				int num16 = 0;
				LawActivitySettings settings = Singleton<LawController>.Instance.GetSettings();
				int currentTime = NetworkSingleton<TimeManager>.Instance.CurrentTime;
				List<string> list = new List<string>();
				CheckpointInstance[] checkpoints = settings.Checkpoints;
				foreach (CheckpointInstance val in checkpoints)
				{
					if (TimeManager.IsGivenTimeWithinRange(currentTime, val.StartTime, val.EndTime))
					{
						num7 += val.MinMembers;
						num8 += val.MaxMembers;
						num6++;
					}
				}
				list.Add($"Checkpoints: {num6} | static members: {num7}-{num8} | actual performing: {num2}\n");
				PatrolInstance[] patrols = settings.Patrols;
				foreach (PatrolInstance val2 in patrols)
				{
					if (TimeManager.IsGivenTimeWithinRange(currentTime, val2.StartTime, val2.EndTime))
					{
						num10 += val2.MinMembers;
						num11 += val2.MaxMembers;
						num9++;
					}
				}
				list.Add($"FootPatrols: {num9} | static members: {num10}-{num11} | actual performing: {num3}\n");
				SentryInstance[] sentries = settings.Sentries;
				foreach (SentryInstance val3 in sentries)
				{
					if (TimeManager.IsGivenTimeWithinRange(currentTime, val3.StartTime, val3.EndTime))
					{
						num13 += val3.MinMembers;
						num14 += val3.MaxMembers;
						num12++;
					}
				}
				list.Add($"Sentries: {num12} | static members: {num13}-{num14} | actual performing: {num4}\n");
				VehiclePatrolInstance[] vehiclePatrols = settings.VehiclePatrols;
				foreach (VehiclePatrolInstance val4 in vehiclePatrols)
				{
					if (TimeManager.IsGivenTimeWithinRange(currentTime, val4.StartTime, TimeManager.AddMinutesTo24HourTime(val4.latestStartTime, 60)))
					{
						num16++;
						num15++;
					}
				}
				list.Add($"VehiclePatrols: {num15} | static members: {num16} | actual performing: {num5}\n");
				int num17 = num7 + num10 + num13 + num16;
				int num18 = num8 + num11 + num14 + num16;
				int value = Mathf.Abs(PoliceOfficer.Officers.Count - num17);
				string value2 = ((PoliceOfficer.Officers.Count > num17) ? $"Surplus {value}" : $"Missing {value}");
				text += $"OFFICERS REQUIRED NOW: {num17}-{num18} | {value2}\n";
				int value3 = num2 + num3 + num4 + num5;
				int value4 = Mathf.RoundToInt((float)(num17 + num18) / 2f);
				int value5 = num6 + num9 + num12 + num15;
				text += $"ACTIVITIES TOTAL: {value5} | STATIC MEDIAN: {value4} | BEHACTIVE: {value3}\n";
				foreach (string item in list)
				{
					text += item;
				}
				((TMP_Text)AnalyticsTextPanel).text = text;
			}

			public void SetupAnalyticsUI(TextMeshProUGUI comp)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: 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_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				((TMP_Text)comp).transform.SetParent(((Component)Singleton<HUD>.Instance.canvas).transform, false);
				((TMP_Text)comp).alignment = (TextAlignmentOptions)257;
				((TMP_Text)comp).fontSize = 16f;
				((Graphic)comp).color = Color.red;
				((TMP_Text)comp).rectTransform.anchorMin = new Vector2(0f, 1f);
				((TMP_Text)comp).rectTransform.anchorMax = new Vector2(0f, 1f);
				((TMP_Text)comp).rectTransform.pivot = new Vector2(0f, 1f);
				((TMP_Text)comp).rectTransform.anchoredPosition = new Vector2(40f, -40f);
				((TMP_Text)comp).rectTransform.sizeDelta = new Vector2(600f, 500f);
			}
		}

		public class SurveillanceTarget : ConsoleCommandBase
		{
			public static bool hasDrawnVisuals;

			public override string Name => "surveillance";

			public override CommandSupport SupportedMethods => CommandSupport.SpawnNoIndex | CommandSupport.Visualize;

			public override void Spawn(int index)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: 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)
				DebugModule.Log("Enabling nearest Flock instance", "Spawn");
				Vector3 position = Player.Local.CenterPointTransform.position;
				HylandFlockInstance hylandFlockInstance = null;
				float num = 100f;
				foreach (HylandFlockInstance allCamera in MassSurveillance.allCameras)
				{
					if (!allCamera.activeToday)
					{
						float num2 = Vector3.Distance(position, ((Component)allCamera).transform.position);
						if (num2 < num)
						{
							num = num2;
							hylandFlockInstance = allCamera;
						}
					}
				}
				hylandFlockInstance.ActivateInstance();
				MassSurveillance.activeCameras.Add(hylandFlockInstance);
				DebugModule.Log("Enabled", "Spawn");
			}

			public override void Visualize(int index)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//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_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				ConsoleCommandBase.CleanVisual();
				if (hasDrawnVisuals)
				{
					hasDrawnVisuals = false;
					return;
				}
				for (int i = 0; i < MassSurveillance.activeCameras.Count; i++)
				{
					Vector3 position = ((Component)MassSurveillance.activeCameras[i]).transform.position;
					Vector3[] points = (Vector3[])(object)new Vector3[2]
					{
						position,
						position + Vector3.up * 40f
					};
					ConsoleCommandBase.DrawPath($"ActiveFlock_{i}", points);
				}
				hasDrawnVisuals = true;
				DebugModule.Log("Active cameras visualized", "Visualize");
			}
		}

		public static bool isBuilding = false;

		public static bool isLoggingEnabled = false;

		public static readonly HashSet<string> ConsoleMethodNames = new HashSet<string> { "Help", "List", "Spawn", "Visualize", "BuildStart", "BuildEnd", "RunCommand" };
	}
	public static class DebugModule
	{
		public static Material lineRenderMat;

		public static List<GameObject> pathVisualizer = new List<GameObject>();

		public static Material cameraBeamMat;

		public static Dictionary<string, ConsoleModule.ConsoleCommandBase> consoleTargets = new Dictionary<string, ConsoleModule.ConsoleCommandBase>
		{
			{
				"footpatrol",
				new ConsoleModule.FootPatrolTarget()
			},
			{
				"vehiclepatrol",
				new ConsoleModule.VehiclePatrolTarget()
			},
			{
				"sentry",
				new ConsoleModule.SentryTarget()
			},
			{
				"raid",
				new ConsoleModule.RaidTarget()
			},
			{
				"investigator",
				new ConsoleModule.InvestigatorTarget()
			},
			{
				"surveillance",
				new ConsoleModule.SurveillanceTarget()
			},
			{
				"analytics",
				new ConsoleModule.CopAnalyticsTarget()
			}
		};

		public static void Log(string msg, [CallerMemberName] string memberName = "")
		{
			if (ConsoleModule.isLoggingEnabled || ConsoleModule.ConsoleMethodNames.Contains(memberName))
			{
				MelonLogger.Msg("[" + memberName + "] " + msg);
			}
		}

		public static void RunCommand(List<string> args)
		{
			if (args.Count == 2 && args[1].ToLower() == "help")
			{
				Help();
				return;
			}
			if (args.Count == 3 && args[1].ToLower() == "enable" && args[2].ToLower() == "logs")
			{
				ConsoleModule.isLoggingEnabled = true;
				return;
			}
			if (args.Count < 3)
			{
				Log("Usage: nacops (action) (target) (index or argument)\n    Try: nacops help", "RunCommand");
				return;
			}
			string text = args[1].ToLower();
			string text2 = args[2].ToLower();
			int num = ((args.Count > 3 && int.TryParse(args[3], out num)) ? num : (-1));
			bool flag = false;
			if (num == -1 && args.Count > 3 && (args[3].ToLower() == "start" || args[3].ToLower() == "stop"))
			{
				flag = true;
			}
			if (!consoleTargets.TryGetValue(text2, out var value))
			{
				Log("Unknown command target '" + text2 + "'", "RunCommand");
				return;
			}
			ConsoleModule.CommandSupport commandSupport = text switch
			{
				"list" => ConsoleModule.CommandSupport.List, 
				"spawn" => ConsoleModule.CommandSupport.Spawn | ConsoleModule.CommandSupport.SpawnNoIndex, 
				"visualize" => ConsoleModule.CommandSupport.Visualize, 
				"build" => ConsoleModule.CommandSupport.Build, 
				_ => ConsoleModule.CommandSupport.None, 
			};
			if ((value.SupportedMethods & commandSupport) == 0)
			{
				Log($"Command target '{text2}' does not support requested method '{commandSupport}'", "RunCommand");
				return;
			}
			if (commandSupport == ConsoleModule.CommandSupport.Build && !flag)
			{
				Log("Command requested method 'build " + text2 + "' only supports arguments 'start' and 'stop'", "RunCommand");
				return;
			}
			switch (commandSupport)
			{
			case ConsoleModule.CommandSupport.List:
				value.List();
				break;
			case ConsoleModule.CommandSupport.Spawn | ConsoleModule.CommandSupport.SpawnNoIndex:
				value.Spawn(num);
				break;
			case ConsoleModule.CommandSupport.Visualize:
				value.Visualize(num);
				break;
			case ConsoleModule.CommandSupport.Build:
				value.Build(args[3]);
				break;
			}
		}

		public static void Help()
		{
			string text = "";
			text += "\nSupported Commands:";
			text += "\n\n# ENABLE FULL LOGGING";
			text += "\nnacops enable logs";
			foreach (ConsoleModule.ConsoleCommandBase value in consoleTargets.Values)
			{
				text = text + "\n\n# " + value.Name.ToUpper();
				if (value.SupportedMethods.HasFlag(ConsoleModule.CommandSupport.List))
				{
					text = text + "\nnacops list " + value.Name;
				}
				if (value.SupportedMethods.HasFlag(ConsoleModule.CommandSupport.Spawn))
				{
					text = text + "\nnacops spawn " + value.Name + " (index)";
				}
				if (value.SupportedMethods.HasFlag(ConsoleModule.CommandSupport.SpawnNoIndex))
				{
					text = text + "\nnacops spawn " + value.Name;
				}
				if (value.SupportedMethods.HasFlag(ConsoleModule.CommandSupport.Visualize))
				{
					text = ((!(value is ConsoleModule.CopAnalyticsTarget) && !(value is ConsoleModule.SurveillanceTarget)) ? (text + "\nnacops visualize " + value.Name + " (index)") : (text + "\nnacops visualize " + value.Name));
				}
				if (value.SupportedMethods.HasFlag(ConsoleModule.CommandSupport.Build))
				{
					text = text + "\nnacops build " + value.Name + " start";
					text = text + "\nnacops build " + value.Name + " stop";
				}
			}
			Log(text, "Help");
		}
	}
	[HarmonyPatch(typeof(Console), "SubmitCommand", new Type[] { typeof(List<string>) })]
	public static class Console_SubmitCommand_ListString_Patch
	{
		public static bool Prefix(Console __instance, List<string> args)
		{
			if (args.Count == 0)
			{
				return true;
			}
			if (args[0].ToLower() == "nacops")
			{
				DebugModule.RunCommand(args);
				return true;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Console), "SubmitCommand", new Type[] { typeof(string) })]
	public static class Console_SubmitCommand_String_Patch
	{
		public static bool Prefix(Console __instance, string args)
		{
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeProduct")]
	public static class Player_ConsumeProduct_Patch
	{
		public static bool evaluating;

		public static bool Prefix(Player __instance, ProductItemInstance product)
		{
			DebugModule.Log("ConsumePrefix", "Prefix");
			if (!evaluating && NACops.currentDrugApprehender.Count < 1)
			{
				evaluating = true;
				DebugModule.Log("CorosBegin", "Prefix");
				NACops.coros.Add(MelonCoroutines.Start(DrugConsumedCoro(__instance, product)));
			}
			return true;
		}

		public static IEnumerator DrugConsumedCoro(Player player, ProductItemInstance product)
		{
			if (!NACops.currentConfig.WeedInvestigator)
			{
				yield break;
			}
			bool num = product is WeedInstance;
			bool flag = product is MethInstance;
			bool flag2 = product is CocaineInstance;
			bool flag3 = product is ShroomInstance;
			bool flag4 = num || flag || flag2 || flag3;
			DebugModule.Log("Is Supported Instance for Apprehender: " + flag4, "DrugConsumedCoro");
			if (flag4)
			{
				DebugModule.Log("Instance casted, check officers count: " + NACops.allActiveOfficers.Count, "DrugConsumedCoro");
				PoliceOfficer noticeOfficer = null;
				float smallestDistance = 49f;
				bool direct = false;
				foreach (PoliceOfficer offc in NACops.allActiveOfficers)
				{
					yield return NACops.Wait01;
					if (!BaseUtility.GUIDInUse.Contains(((NPC)offc).BakedGUID) && !NACops.currentDrugApprehender.Contains(offc) && !(Vector3.Distance(((Component)offc).transform.position, ((Component)player).transform.position) > 50f) && !((NPC)offc).Health.IsDead && !((NPC)offc).Health.IsKnockedOut)
					{
						if (((NPC)offc).Awareness.VisionCone.IsPlayerVisible(player) && ((NPC)offc).Movement.CanMove() && !((NPC)offc).IsInVehicle && !((NPC)offc).isInBuilding)
						{
							offc.BeginFootPursuit(player.PlayerCode);
							NACops.coros.Add(MelonCoroutines.Start(BaseUtility.GiveFalseCharges(3, player)));
							direct = true;
							DebugModule.Log("Apprehend immediate direct", "DrugConsumedCoro");
							break;
						}
						float num2 = Vector3.Distance(((Component)offc).transform.position, ((Component)player).transform.position);
						if (num2 < smallestDistance && !((NPC)offc).IsInVehicle && !((NPC)offc).isInBuilding)
						{
							smallestDistance = num2;
							noticeOfficer = offc;
						}
					}
				}
				if ((Object)(object)noticeOfficer == (Object)null || direct)
				{
					DebugModule.Log("No apprehender candidate found", "DrugConsumedCoro");
					evaluating = false;
					yield break;
				}
				NACops.currentDrugApprehender.Add(noticeOfficer);
				DebugModule.Log("Proceed apprehender candidate", "DrugConsumedCoro");
				NACops.coros.Add(MelonCoroutines.Start(ApprehenderOfficerClear(noticeOfficer)));
				bool apprehending = false;
				((NPC)noticeOfficer).Movement.FacePoint(((Component)player).transform.position, 0.4f);
				yield return NACops.Wait05;
				if (((NPC)noticeOfficer).Awareness.VisionCone.IsPlayerVisible(player))
				{
					DebugModule.Log("Apprehend immediate candidate", "DrugConsumedCoro");
					noticeOfficer.BeginBodySearch(player.PlayerCode);
					NACops.coros.Add(MelonCoroutines.Start(BaseUtility.GiveFalseCharges(3, player)));
					apprehending = true;
				}
				if ((Object)(object)noticeOfficer != (Object)null && !apprehending)
				{
					for (int i = 0; i <= 6; i++)
					{
						DebugModule.Log("Apprehend Search suspect", "DrugConsumedCoro");
						if (!NACops.registered)
						{
							yi