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> generatedPatrolInstances = new Dictionary>(); 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.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(); ((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> generatedPatrolInstance in generatedPatrolInstances) { if (num3 >= num2) { break; } array2[num3] = generatedPatrolInstance.Key; num3++; } return array2; } int num4 = template.Patrols.Length; int num5 = 0; foreach (KeyValuePair> 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> 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 days; public List waypoints = new List(); } public class SentryGenerator { public static Dictionary> generatedSentryInstances = new Dictionary>(); 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.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(); val3.Routes = new List(); 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> generatedSentryInstance in generatedSentryInstances) { if (num3 >= num2) { break; } array[num3] = generatedSentryInstance.Key; num3++; } return array; } int num4 = template.Sentries.Length; int num5 = 0; foreach (KeyValuePair> 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> 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 days; public Vector3 standPosition1; public Vector3 pos1Rotation; public Vector3 standPosition2; public Vector3 pos2Rotation; } public class VehiclePatrolGenerator { public static Dictionary> generatedVehiclePatrolInstances = new Dictionary>(); 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.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(); ((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> generatedVehiclePatrolInstance in generatedVehiclePatrolInstances) { if (num3 >= num2) { break; } array2[num3] = generatedVehiclePatrolInstance.Key; num3++; } return array2; } int num4 = template.VehiclePatrols.Length; int num5 = 0; foreach (KeyValuePair> 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> 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 days; public List waypoints = new List(); } [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 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()).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()).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)(object)val.Properties).Count - 1; num >= 0; num--) { JsonProperty val2 = ((Collection)(object)val.Properties)[num]; if (val2.PropertyName == "normalized" || val2.PropertyName == "magnitude" || val2.PropertyName == "sqrMagnitude") { ((Collection)(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 VisionSpeed = new Dictionary { { "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 loadedPatrols = new List(); } [Serializable] public class VehiclePatrolsSerialized { public List loadedVehiclePatrols = new List(); } [Serializable] public class SentrysSerialized { public List loadedSentrys = new List(); } public static ModConfig LoadModConfig() { string pathTo = ModDataPaths.GetPathTo(ModDataPaths.pathModConfig); ModConfig modConfig; if (File.Exists(pathTo)) { try { modConfig = JsonConvert.DeserializeObject(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(File.ReadAllText(pathTo)); nAOfficerConfig.ModAddedOfficersCount = Mathf.Clamp(nAOfficerConfig.ModAddedOfficersCount, 0, 20); if (!new List { "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(File.ReadAllText(pathTo)); List list = new List { "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(); 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(File.ReadAllText(pathTo)); List list = new List { "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(); 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(File.ReadAllText(pathTo)); List list = new List { "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(); 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.Instance.ActiveSaveInfo.OrganisationName; int saveSlotNumber = Singleton.Instance.ActiveSaveInfo.SaveSlotNumber; string path = $"{saveSlotNumber}_{SanitizeAndFormatName(organisationName)}"; PropertiesHeatSerialized propertiesHeatSerialized; if (File.Exists(Path.Combine(pathTo, path))) { try { propertiesHeatSerialized = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(pathTo, path))); } catch (Exception ex) { propertiesHeatSerialized = new PropertiesHeatSerialized(); propertiesHeatSerialized.loadedPropertyHeats = new List(); 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(); 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.Instance.ActiveSaveInfo.OrganisationName; int saveSlotNumber = Singleton.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(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(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(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("DebugMode", NACops.currentConfig.DebugMode, "Debug Mode Enabled", "Enable debug mode to test features", false, false, (ValueValidator)null, (string)null); modConfigCategory.CreateEntry("RaidsEnabled", NACops.currentConfig.RaidsEnabled, "Raids Enabled", "Enable raid events", false, false, (ValueValidator)null, (string)null); modConfigCategory.CreateEntry("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("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("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("CheckpointsEnabled", NACops.currentConfig.CheckpointsEnabled, "Checkpoints Enabled", "Enable the usage of road block checkpoints", false, false, (ValueValidator)null, (string)null); modConfigCategory.CreateEntry("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("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("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("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("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("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("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("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("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("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>)(object)modConfigCategory.Entries[i].OnEntryValueChangedUntyped).Subscribe((LemonAction)ThisEntryChanged, 0, false); void ThisEntryChanged(object objOld, object objNew) { OnEntryChange(id, objOld, objNew); } } MelonPreferences.SaveCategory(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(); ((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 recordedPathNodes = new List(); 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 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.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 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(); ((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 { "mon", "tue", "wed", "thu", "fri", "sat", "sun" }; List list = new List(); 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(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 recordedPathNodes = new List(); 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 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.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 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(); ((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 { "mon", "tue", "wed", "thu", "fri", "sat", "sun" }; List list = new List(); 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(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 recordedPathNodes = new List(); 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 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.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 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(); ((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 { "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 list = new List(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(); 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.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.Instance.GetSettings(); int currentTime = NetworkSingleton.Instance.CurrentTime; List list = new List(); 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.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 ConsoleMethodNames = new HashSet { "Help", "List", "Spawn", "Visualize", "BuildStart", "BuildEnd", "RunCommand" }; } public static class DebugModule { public static Material lineRenderMat; public static List pathVisualizer = new List(); public static Material cameraBeamMat; public static Dictionary consoleTargets = new Dictionary { { "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 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) })] public static class Console_SubmitCommand_ListString_Patch { public static bool Prefix(Console __instance, List 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) { yield break; } if (i > 3 && Random.Range(1f, 0f) > 0.95f) { break; } ((NPC)noticeOfficer).Movement.FacePoint(player.CenterPointTransform.position, 0.3f); yield return NACops.Wait05; if (!NACops.registered) { yield break; } if (((NPC)noticeOfficer).Health.IsDead || ((NPC)noticeOfficer).Health.IsKnockedOut) { break; } if (((NPC)noticeOfficer).Awareness.VisionCone.IsPlayerVisible(player)) { noticeOfficer.BeginBodySearch(player.PlayerCode); if (Random.Range(1f, 0f) > 0.8f) { NACops.coros.Add(MelonCoroutines.Start(BaseUtility.GiveFalseCharges(1, player))); } break; } yield return NACops.Wait05; if (NACops.registered) { if (((NPC)noticeOfficer).Health.IsDead || ((NPC)noticeOfficer).Health.IsKnockedOut) { break; } ((NPC)noticeOfficer).Movement.SetDestination(player.CenterPointTransform.position); yield return NACops.Wait1; if (NACops.registered) { if (((NPC)noticeOfficer).Health.IsDead || ((NPC)noticeOfficer).Health.IsKnockedOut) { break; } continue; } yield break; } yield break; } } } DebugModule.Log("evaluate apprehender end", "DrugConsumedCoro"); evaluating = false; yield return null; } public static IEnumerator ApprehenderOfficerClear(PoliceOfficer offc) { if (!((Object)(object)offc == (Object)null)) { yield return NACops.Wait30; DebugModule.Log(" apprehender clear", "ApprehenderOfficerClear"); if (NACops.currentDrugApprehender.Contains(offc)) { NACops.currentDrugApprehender.Remove(offc); } } } } public static class LethalCops { private static float minWait; private static float maxWait; private static float minRange; private static float maxRange; private static List randWaits; private static WaitForSeconds currentAwait; public static IEnumerator RunNearbyLethalCops() { if (!NACops.networkManager.IsServer) { yield break; } (float min, float max) tuple = ThresholdUtils.Evaluate(NACops.thresholdConfig.LethalCopFrequency, NetworkSingleton.Instance.ElapsedDays); minWait = tuple.min; maxWait = tuple.max; randWaits = new List { new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)) }; DebugModule.Log("Nearby Lethal Cop Enabled", "RunNearbyLethalCops"); while (true) { DebugModule.Log("Nearby Lethal Cop Evaluate", "RunNearbyLethalCops"); currentAwait = randWaits[Random.Range(0, randWaits.Count)]; yield return currentAwait; if (!NACops.registered) { break; } if (!NACops.currentConfig.LethalCops) { continue; } var (num, num2) = ThresholdUtils.Evaluate(NACops.thresholdConfig.LethalCopFrequency, NetworkSingleton.Instance.ElapsedDays); if (num != minWait || num2 != maxWait) { randWaits.Clear(); for (int i = 0; i < 3; i++) { randWaits.Add(new WaitForSeconds(Random.Range(num, num2))); } } (float min, float max) tuple3 = ThresholdUtils.Evaluate(NACops.thresholdConfig.LethalCopRange, (int)NetworkSingleton.Instance.LifetimeEarnings); minRange = tuple3.min; maxRange = tuple3.max; float minDistance = Random.Range(minRange, maxRange); foreach (Player player in Player.PlayerList) { player.CrimeData.CheckNearestOfficer(); PoliceOfficer officer = player.CrimeData.NearestOfficer; if (!((Object)(object)officer == (Object)null) && BaseUtility.CanProceed(officer, player, minDistance)) { BaseUtility.GUIDInUse.Add(((NPC)officer).BakedGUID); ((NPC)officer).Movement.FacePoint(((Component)Player.Local).transform.position, 0.4f); yield return NACops.Wait05; if (!NACops.registered) { yield break; } if (((NPC)officer).Awareness.VisionCone.IsPlayerVisible(player)) { player.CrimeData.SetPursuitLevel((EPursuitLevel)4); officer.BeginFootPursuit(player.PlayerCode); } if (BaseUtility.GUIDInUse.Contains(((NPC)officer).BakedGUID)) { BaseUtility.GUIDInUse.Remove(((NPC)officer).BakedGUID); } } } } } } public static class NearbyCrazyCops { private static float minWait; private static float maxWait; private static float minRange; private static float maxRange; private static List randWaits; private static WaitForSeconds currentAwait; public static IEnumerator RunNearbyCrazyCops() { if (!NACops.networkManager.IsServer) { yield break; } DebugModule.Log("Nearby Crazy Cop Starting", "RunNearbyCrazyCops"); (float min, float max) tuple = ThresholdUtils.Evaluate(NACops.thresholdConfig.NearbyCrazyFrequency, NetworkSingleton.Instance.ElapsedDays); minWait = tuple.min; maxWait = tuple.max; randWaits = new List { new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)) }; while (true) { currentAwait = randWaits[Random.Range(0, randWaits.Count)]; yield return currentAwait; if (!NACops.registered) { break; } if (!NACops.currentConfig.NearbyCrazyCops) { continue; } DebugModule.Log("Nearby Crazy Cop Evaluate", "RunNearbyCrazyCops"); Object.FindObjectsOfType(true); var (num, num2) = ThresholdUtils.Evaluate(NACops.thresholdConfig.NearbyCrazyFrequency, NetworkSingleton.Instance.ElapsedDays); if (num != minWait || num2 != maxWait) { randWaits.Clear(); for (int i = 0; i < 3; i++) { randWaits.Add(new WaitForSeconds(Random.Range(num, num2))); } } (float min, float max) tuple3 = ThresholdUtils.Evaluate(NACops.thresholdConfig.NearbyCrazyRange, (int)NetworkSingleton.Instance.LifetimeEarnings); minRange = tuple3.min; maxRange = tuple3.max; float num3 = Random.Range(minRange, maxRange); foreach (Player player in Player.PlayerList) { player.CrimeData.CheckNearestOfficer(); PoliceOfficer nearestOfficer = player.CrimeData.NearestOfficer; if (!((Object)(object)nearestOfficer == (Object)null) && BaseUtility.CanProceed(nearestOfficer, player, num3, ignoreVehicle: true)) { if (((NPC)nearestOfficer).IsInVehicle && player.IsInVehicle) { nearestOfficer.VehiclePursuitBehaviour.AssignTarget(player); nearestOfficer.VehiclePursuitBehaviour.beginAsSighted = true; ((Behaviour)nearestOfficer.VehiclePursuitBehaviour).Activate(); } else if (!((NPC)nearestOfficer).IsInVehicle && !player.IsInVehicle) { NACops.coros.Add(MelonCoroutines.Start(GreedyBodySearchFind(nearestOfficer, player, num3))); } break; } } } } public static IEnumerator GreedyBodySearchFind(PoliceOfficer officer, Player player, float minDistance) { ((VOEmitter)officer.ChatterVO).Play((EVOLineType)13); ((NPC)officer).Movement.FacePoint(((Component)player).transform.position, 0.4f); BaseUtility.GUIDInUse.Add(((NPC)officer).BakedGUID); yield return NACops.Wait05; if (!NACops.registered) { yield break; } if (((NPC)officer).Awareness.VisionCone.IsPlayerVisible(player) && !player.CrimeData.BodySearchPending) { DebugModule.Log("Begin bodysearch nearby crazy", "GreedyBodySearchFind"); officer.BeginBodySearch(player.PlayerCode); if (Random.Range(0f, 1f) > 0.8f) { NACops.coros.Add(MelonCoroutines.Start(BaseUtility.GiveFalseCharges(2, player))); } if (BaseUtility.GUIDInUse.Contains(((NPC)officer).BakedGUID)) { BaseUtility.GUIDInUse.Remove(((NPC)officer).BakedGUID); } } else { Vector3 val = default(Vector3); ((NPC)officer).Movement.GetClosestReachablePoint(player.CenterPointTransform.position, ref val); if (val != Vector3.zero && ((NPC)officer).Movement.CanMove() && ((NPC)officer).Movement.CanGetTo(val, 1f)) { ((NPC)officer).Movement.SetDestination(val); } if (BaseUtility.GUIDInUse.Contains(((NPC)officer).BakedGUID)) { BaseUtility.GUIDInUse.Remove(((NPC)officer).BakedGUID); } } } } public enum ECameraType { Unidirectional, Omnidirectional } public enum ECameraDisableAccess { None, BusinessComputer } public class HylandFlockInstance : MonoBehaviour { public static readonly float LINE_WIDTH_MIN = 0.0005f; public static readonly float LINE_WIDTH_MAX = 0.015f; public static readonly int RAYCAST_STEPS = 3; public static readonly float SEEN_CACHE_LIFETIME = 120f; private FlockInstanceRunner _runner; public bool IsActive; public bool IsBroken; public bool IsPlayerNearby; public bool IsOnCooldown; public float cooldownElapsed; public float cacheLifetimeElapsed; public float cacheEvidenceRatio; public FlockActivationZone activationZone; public Light cameraLight; public LineRenderer lineRenderer; public GameObject fxParticles; public Rigidbody rb; public BoxCollider bc; public PhysicsDamageable damageable; public List cameraSeenStateCache = new List(); public Vector3 toPlayerCenter; public Vector3 toPlayerEyes; public Vector3 currentCastPos; public ECameraType type; public ECameraDisableAccess disableType; public bool activeToday; public bool isPlayerSighted; public float consecutiveHits; public bool isOffline; public void Awake() { Utils.GetOrAddComponent(((Component)this).gameObject); Utils.GetOrAddComponent(((Component)this).gameObject); Utils.GetOrAddComponent(((Component)this).gameObject); Utils.GetOrAddComponent(((Component)this).gameObject); } public void Initialize() { //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Expected O, but got Unknown //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) _runner = new FlockInstanceRunner(this); Transform val = null; Transform val2 = null; DebugModule.Log("Setup camera " + TransformUtilities.GetScenePath(((Component)this).transform), "Initialize"); if ((Object)(object)((Component)this).gameObject == (Object)null) { DebugModule.Log("Something went wrong while initializing camera!", "Initialize"); return; } if ((Object)(object)((Component)this).gameObject.GetComponent() == (Object)null) { ((Component)this).gameObject.AddComponent(); } if ((Object)(object)((Component)this).gameObject.GetComponent() == (Object)null) { ((Component)this).gameObject.AddComponent(); } if ((Object)(object)((Component)this).gameObject.GetComponent() == (Object)null) { ((Component)this).gameObject.AddComponent(); } if ((Object)(object)((Component)this).gameObject.GetComponent() == (Object)null) { ((Component)this).gameObject.AddComponent(); } if (type == ECameraType.Unidirectional && (Object)(object)((Component)this).transform.parent != (Object)null && ((Component)this).transform.parent.childCount > 0) { Transform val3 = ((Component)this).transform.parent; if ((Object)(object)val3 != (Object)null) { while (val3.childCount > 0) { val3 = val3.GetChild(0); } val2 = val3; } else { DebugModule.Log("Failed to find transform parent of Unidirectional camera", "Initialize"); } } val = val2; if (type == ECameraType.Unidirectional) { if ((Object)(object)val == (Object)null) { DebugModule.Log("Failed to instantiate camera, missing direction reference", "Initialize"); return; } Vector3 val4 = ((Component)val).transform.position + Vector3.up * 0.04f + val.forward * 0.32f; ((Component)this).transform.SetPositionAndRotation(val4, val.rotation); } else if (type == ECameraType.Omnidirectional) { ((Component)this).transform.localRotation = Quaternion.LookRotation(Vector3.down, Vector3.forward); ((Component)this).transform.localPosition = new Vector3(0f, -0.33f, 0.45f); } cameraLight = ((Component)this).gameObject.GetComponent(); cameraLight.intensity = 0f; cameraLight.range = 0.25f; cameraLight.color = Color.blue; GameObject val5 = new GameObject("LineRenderer"); val5.transform.SetParent(((Component)this).transform); if (type == ECameraType.Unidirectional) { val5.transform.position = ((Component)val).transform.position + Vector3.up * 0.04f + val.forward * 0.27f; } else if (type == ECameraType.Omnidirectional) { val5.transform.position = ((Component)this).transform.position; } val5.transform.localRotation = Quaternion.Euler(0f, 0f, 0f); lineRenderer = val5.AddComponent(); ((Renderer)lineRenderer).material = MassSurveillance.lineRendererMaterial; lineRenderer.widthMultiplier = LINE_WIDTH_MIN; lineRenderer.SetPosition(0, val5.transform.position); GameObject val6 = new GameObject("ActivationZone"); val6.transform.SetParent(MassSurveillance.activationZoneParent); activationZone = val6.AddComponent(); ((Component)activationZone).transform.position = ((Component)this).transform.position; activationZone.parentInstance = this; ((Component)activationZone).gameObject.SetActive(false); rb = ((Component)this).gameObject.GetComponent(); rb.isKinematic = true; bc = ((Component)this).gameObject.GetComponent(); bc.size = new Vector3(0.45f, 0.45f); damageable = ((Component)this).gameObject.GetComponent(); damageable.Rb = rb; damageable.onImpacted = OnCameraImpacted; } public void Update() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if (!NACops.registered || !IsActive || IsBroken) { return; } if (cameraSeenStateCache.Count > 0 && consecutiveHits == 0f) { cacheLifetimeElapsed += Time.deltaTime; if (cacheLifetimeElapsed >= SEEN_CACHE_LIFETIME) { ClearSeenCache(); } } if (IsOnCooldown) { cooldownElapsed += Time.deltaTime; if (cooldownElapsed >= (float)NACops.surveillanceConfig.CameraNoticeCooldown) { cooldownElapsed = 0f; IsOnCooldown = false; } } else if (IsPlayerNearby && isPlayerSighted) { lineRenderer.SetPosition(1, Player.Local.Avatar.CenterPoint); } } public void ActivateInstance() { activeToday = true; IsActive = true; IsBroken = false; IsPlayerNearby = false; IsOnCooldown = false; cooldownElapsed = 0f; cameraLight.intensity = 3f; ((Component)activationZone).gameObject.SetActive(true); NACops.coros.Add(MelonCoroutines.Start(_runner.SearchForPlayer())); NACops.coros.Add(MelonCoroutines.Start(_runner.HandleLight())); NACops.coros.Add(MelonCoroutines.Start(_runner.HandleLineWidth())); } public void DeactivateInstance() { if (IsBroken) { fxParticles.SetActive(false); RandomIntervalEvent component = fxParticles.GetComponent(); if (((Behaviour)component).enabled) { ((Behaviour)component).enabled = false; } } activeToday = false; IsActive = false; ((Component)activationZone).gameObject.SetActive(false); IsBroken = false; IsPlayerNearby = false; IsOnCooldown = false; cooldownElapsed = 0f; consecutiveHits = 0f; cacheLifetimeElapsed = 0f; cacheEvidenceRatio = 0f; cameraSeenStateCache.Clear(); cameraLight.intensity = 0f; } public void SetPlayerNearby(bool isNearby) { if (NACops.registered) { IsPlayerNearby = isNearby; if ((Object)(object)lineRenderer != (Object)null) { lineRenderer.loop = isNearby; } } } public bool RaycastPlayer() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) if (MassSurveillance.isEvaluatingRaycast) { return false; } MassSurveillance.isEvaluatingRaycast = true; float num = NACops.surveillanceConfig.CameraActivationRange; Vector3.Distance(((Component)this).transform.position, Player.Local.Avatar.CenterPoint); toPlayerCenter = Player.Local.Avatar.CenterPoint - ((Component)this).transform.position; toPlayerEyes = Player.Local.EyePosition - ((Component)this).transform.position; float num2 = Vector3.Angle(((Component)this).transform.forward, toPlayerCenter); DebugModule.Log("ANGLE: " + num2, "RaycastPlayer"); bool flag = true; switch (type) { case ECameraType.Unidirectional: if (num2 > 55f) { flag = false; } break; } bool flag2 = true; if (flag) { for (int i = 0; i < RAYCAST_STEPS; i++) { currentCastPos = Vector3.Lerp(toPlayerEyes, toPlayerCenter, (float)(i / RAYCAST_STEPS - 1)); int num3 = Physics.RaycastNonAlloc(((Component)this).transform.position, currentCastPos, MassSurveillance.raycastHitBuffer, num, MassSurveillance.raycastIgnoreZone); Array.Sort(MassSurveillance.raycastHitBuffer, 0, num3, MassSurveillance.raycastCompare); for (int j = 0; j < num3; j++) { RaycastHit val = MassSurveillance.raycastHitBuffer[j]; if ((MassSurveillance.obstacleLayer & (1 << ((Component)((RaycastHit)(ref val)).collider).gameObject.layer)) != 0) { flag2 = false; break; } if (((Component)((RaycastHit)(ref val)).collider).gameObject.layer == MassSurveillance.playerLayer) { flag2 = true; break; } } if (flag2) { break; } } } else { flag2 = false; } MassSurveillance.isEvaluatingRaycast = false; return flag2; } public void CaptureEntityVisualState() { foreach (EntityVisualState visualState in Player.Local.VisibilityComponent.VisualStates) { if (!(visualState.label == "Visible")) { if (!cameraSeenStateCache.Contains(visualState.label)) { cameraSeenStateCache.Add(visualState.label); } else { cacheEvidenceRatio += Random.Range(0.001f, 0.0001f); } } } } public void OnCameraImpacted(Impact impact) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) DebugModule.Log($"Camera impacted with:Type {impact.ImpactType} Dmg {impact.ImpactDamage}", "OnCameraImpacted"); if (!IsActive || IsBroken) { return; } IsBroken = true; if ((Object)(object)MassSurveillance.fxSparksTemplate == (Object)null) { DebugModule.Log("FX template object is missing reference", "OnCameraImpacted"); return; } if ((Object)(object)fxParticles == (Object)null) { fxParticles = Object.Instantiate(MassSurveillance.fxSparksTemplate); } fxParticles.transform.SetParent(((Component)this).transform); fxParticles.transform.SetPositionAndRotation(((Component)this).transform.position, ((Component)this).transform.rotation); fxParticles.SetActive(true); RandomIntervalEvent component = fxParticles.GetComponent(); if (!((Behaviour)component).enabled) { ((Behaviour)component).enabled = true; } ((Renderer)lineRenderer).forceRenderingOff = true; cameraLight.intensity = 0f; NetworkSingleton.Instance.AddXP(50); } public void ClearSeenCache() { DebugModule.Log("Clear seen states", "ClearSeenCache"); cacheLifetimeElapsed = 0f; cacheEvidenceRatio = 0f; cameraSeenStateCache.Clear(); } public void SetupCameraDisableAccess() { if (disableType != ECameraDisableAccess.None) { isOffline = true; } } } public class FlockInstanceRunner { private HylandFlockInstance _instance; public FlockInstanceRunner(HylandFlockInstance instance) { _instance = instance; } public IEnumerator SearchForPlayer() { while (true) { if (!_instance.IsPlayerNearby || _instance.IsOnCooldown) { yield return NACops.Wait05; if (!NACops.registered || !_instance.IsActive || _instance.IsBroken) { break; } if (_instance.consecutiveHits > 0f) { _instance.consecutiveHits = Mathf.Clamp(_instance.consecutiveHits - 0.1f, 0f, (float)NACops.surveillanceConfig.CameraNoticeSpeed); } continue; } bool hits = false; while (_instance.IsActive) { yield return NACops.Wait05; if (!NACops.registered || !_instance.IsActive || _instance.IsBroken) { yield break; } if (!_instance.IsPlayerNearby) { break; } hits = _instance.RaycastPlayer(); if (hits) { break; } if (_instance.consecutiveHits > 0f) { _instance.consecutiveHits = Mathf.Clamp(_instance.consecutiveHits - 0.1f, 0f, (float)NACops.surveillanceConfig.CameraNoticeSpeed); } } _instance.lineRenderer.SetPosition(1, Player.Local.Avatar.CenterPoint); _instance.isPlayerSighted = true; ((Renderer)_instance.lineRenderer).forceRenderingOff = false; float nextStateCapture = 0.5f; float currentVisibility = Player.Local.VisibilityComponent.CurrentVisibility; _instance.CaptureEntityVisualState(); while (hits) { yield return NACops.Wait01; if (!NACops.registered || !_instance.IsActive || _instance.IsBroken) { yield break; } if (!_instance.IsPlayerNearby) { break; } hits = _instance.RaycastPlayer(); if (Random.Range(0f, 90f) < currentVisibility) { _instance.consecutiveHits += 0.1f; } if (_instance.consecutiveHits >= nextStateCapture) { _instance.CaptureEntityVisualState(); nextStateCapture += 0.5f; currentVisibility = Player.Local.VisibilityComponent.CurrentVisibility; } if (_instance.consecutiveHits >= (float)NACops.surveillanceConfig.CameraNoticeSpeed) { DebugModule.Log("Exceeded max time in sight", "SearchForPlayer"); break; } } DebugModule.Log($"Got {_instance.consecutiveHits} time in sight!", "SearchForPlayer"); if (_instance.consecutiveHits >= (float)NACops.surveillanceConfig.CameraNoticeSpeed) { MassSurveillance.OnCameraFullyNoticed(_instance.cameraSeenStateCache, _instance.cacheEvidenceRatio); _instance.IsOnCooldown = true; _instance.consecutiveHits = 0f; } _instance.isPlayerSighted = false; ((Renderer)_instance.lineRenderer).forceRenderingOff = true; } } public IEnumerator HandleLight() { float startIntensityPassive = 0.5f; float endIntensityPassive = 3f; float endIntensityActive = 5f; float startRangeActive = 0.25f; float endRangeActive = 0.5f; float duration = NACops.surveillanceConfig.CameraNoticeSpeed; while (true) { yield return NACops.Wait1; if (!NACops.registered || !_instance.IsActive) { break; } if (!_instance.IsPlayerNearby) { continue; } while (!_instance.isPlayerSighted) { float elapsed; if (!Mathf.Approximately(_instance.cameraLight.intensity, startIntensityPassive) || !Mathf.Approximately(_instance.cameraLight.range, startRangeActive)) { float currentIntensity = _instance.cameraLight.intensity; float currentRange = _instance.cameraLight.range; elapsed = 0f; while (elapsed < 1f && NACops.registered && !_instance.isPlayerSighted && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num = elapsed / 1f; _instance.cameraLight.intensity = Mathf.Lerp(currentIntensity, startIntensityPassive, num); _instance.cameraLight.range = Mathf.Lerp(currentRange, startRangeActive, num); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } } elapsed = 0f; while (elapsed < duration && NACops.registered && !_instance.isPlayerSighted && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num2 = elapsed / duration; _instance.cameraLight.intensity = Mathf.Lerp(startIntensityPassive, endIntensityPassive, num2); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } _instance.cameraLight.intensity = endIntensityPassive; elapsed = 0f; while (elapsed < duration && NACops.registered && !_instance.isPlayerSighted && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num3 = elapsed / duration; _instance.cameraLight.intensity = Mathf.Lerp(endIntensityPassive, startIntensityPassive, num3); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } _instance.cameraLight.intensity = startIntensityPassive; } float startIntensity = _instance.cameraLight.intensity; while (_instance.isPlayerSighted) { if (Mathf.Approximately(startIntensity, endIntensityActive)) { DebugModule.Log("Max light reachhed", "HandleLight"); yield return NACops.Wait05; if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (!_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } continue; } float elapsed = 0f; while (elapsed < duration && NACops.registered && _instance.isPlayerSighted && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num4 = elapsed / duration; _instance.cameraLight.intensity = Mathf.Lerp(startIntensity, endIntensityActive, num4); _instance.cameraLight.range = Mathf.Lerp(startRangeActive, endRangeActive, num4); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (_instance.isPlayerSighted && _instance.IsPlayerNearby) { _instance.cameraLight.intensity = endIntensityActive; } break; } } } public IEnumerator HandleLineWidth() { float duration = NACops.surveillanceConfig.CameraNoticeSpeed; while (true) { yield return NACops.Wait05; if (!NACops.registered || !_instance.IsActive || _instance.IsBroken) { break; } if (!_instance.isPlayerSighted || !_instance.IsPlayerNearby) { continue; } while (_instance.isPlayerSighted) { float elapsed = 0f; if (!Mathf.Approximately(_instance.lineRenderer.widthMultiplier, HylandFlockInstance.LINE_WIDTH_MIN)) { _instance.lineRenderer.widthMultiplier = HylandFlockInstance.LINE_WIDTH_MIN; } while (elapsed < duration / 2f && NACops.registered && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num = elapsed / (duration / 2f); _instance.lineRenderer.widthMultiplier = Mathf.Lerp(HylandFlockInstance.LINE_WIDTH_MIN, HylandFlockInstance.LINE_WIDTH_MAX, num); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (!_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } _instance.lineRenderer.widthMultiplier = HylandFlockInstance.LINE_WIDTH_MAX; elapsed = 0f; while (elapsed < duration / 2f && NACops.registered && !_instance.IsBroken && _instance.IsActive && _instance.IsPlayerNearby) { float num2 = elapsed / (duration / 2f); _instance.lineRenderer.widthMultiplier = Mathf.Lerp(HylandFlockInstance.LINE_WIDTH_MAX, HylandFlockInstance.LINE_WIDTH_MIN, num2); elapsed += Time.deltaTime; yield return NACops.frameEnd; } if (!NACops.registered || _instance.IsBroken || !_instance.IsActive) { yield break; } if (!_instance.isPlayerSighted || !_instance.IsPlayerNearby) { break; } _instance.lineRenderer.widthMultiplier = HylandFlockInstance.LINE_WIDTH_MIN; } _instance.lineRenderer.widthMultiplier = 0f; } } } public class FlockActivationZone : MonoBehaviour { public HylandFlockInstance parentInstance; public SphereCollider sc; public Rigidbody rb; public void Awake() { ((Component)this).gameObject.layer = MassSurveillance.activationZoneLayer; sc = Utils.GetOrAddComponent((MonoBehaviour)(object)this); ((Collider)sc).isTrigger = true; sc.radius = NACops.surveillanceConfig.CameraActivationRange; rb = Utils.GetOrAddComponent((MonoBehaviour)(object)this); rb.isKinematic = true; } private void OnTriggerEnter(Collider other) { if (((Component)other).gameObject.layer == 6 && (Object)(object)((Component)other).gameObject.GetComponentInParent() != (Object)null) { parentInstance.SetPlayerNearby(isNearby: true); } } private void OnTriggerExit(Collider other) { if (((Component)other).gameObject.layer == 6 && (Object)(object)((Component)other).gameObject.GetComponentInParent() != (Object)null) { parentInstance.SetPlayerNearby(isNearby: false); } } } public static class SurveillanceCameraPaths { public static readonly List unidirectional = new List { "Map/Hyland Point/Region_Downtown/Casino/casino/Security Camera (Barrel) (1)", "Map/Hyland Point/Region_Downtown/Diner/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Storage warehouse/Storage warehouse/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Small warehouse/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/ChemicalPlant/Chemical Plant A/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Pawn shop/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Casino/casino/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/RE Office/Security Camera (Barrel)", "Map/Hyland Point/Region_Uptown/Medical Practice/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Hardware Store/Small hardware store/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/HardwardStore/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Slums Gas Station/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/North apartments/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/ChemicalPlant/Warehouse01/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Pawn shop/Interior/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Dealership/Dealership/Security Camera (Barrel)", "@Properties/Sweatshop/Chinese Restaurant/Security Camera (Barrel)", "@Properties/Sweatshop/Chinese Restaurant/Security Camera (Barrel) (1)", "Map/Hyland Point/Region_Northtown/North apartments/Security Camera (Barrel) (1)", "Map/Hyland Point/Region_Northtown/Arcade (1)/UpperBlankWall (3)/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Corner Store/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Arcade (1)/arcade/Overhang/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Police station/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Shooting range/Shooting range/Security Camera (Barrel)", "Map/Hyland Point/Region_Northtown/Storage warehouse/Storage warehouse/Security Camera (Barrel) (1)", "Map/Hyland Point/Region_Northtown/Industrial Building A/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Restaurant/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Gas Station/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Slums Gas Station/slums gas station/Shop (Content Disabler)/Security Camera (Barrel) (1)", "Map/Hyland Point/Region_Downtown/TownCenter/Bank/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/Gas Station/gas station/Interior/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Slums Gas Station/slums gas station/Shop (Content Disabler)/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Tattoo Parlour New/Interior/GameObject/Security Camera (Barrel)", "Map/Hyland Point/Region_Westville/Cabin/Security Camera (Barrel)", "Map/Hyland Point/Region_Downtown/GroceryStore/Security Camera (Barrel)", "@Businesses/Taco Ticklers/Security Camera (Barrel)", "@Businesses/Taco Ticklers/Security Camera (Barrel) (1)", "@Businesses/Taco Ticklers/Security Camera (Barrel) (2)", "@Businesses/Car Wash/Security Camera (Barrel)" }; public static readonly List omnidirectional = new List { "Map/Hyland Point/Region_Westville/Slums Gas Station/Security Camera (Round)", "Map/Hyland Point/Region_Downtown/Courthouse/Security Camera (Round)", "Map/Hyland Point/Region_Downtown/Police station/Security Camera (Round)", "Map/Hyland Point/Region_Docks/Fish Warehouse/Security Camera (Round)", "Map/Hyland Point/Region_Downtown/TownCenter/Bank/Security Camera (Round)", "Map/Hyland Point/Region_Northtown/Construction yard/Fence/Construction Warehouse/Security Camera (Round)", "@Businesses/Laundromat/Security Camera (Round)", "@Businesses/PostOffice/Security Camera (Round)" }; } public static class MassSurveillance { private static bool _surveilSeenStatesEvaluating = false; private static bool _surveilCrimeStatusEvaluating = false; private static bool _hasDispatchedNearby = false; public static Material lineRendererMaterial; public static GameObject fxSparksTemplate; public static int playerLayer; public static int obstacleLayer; public static int activationZoneLayer; public static int raycastIgnoreZone; public static LayerMask visibilityBlockingLayers; public static List allCameras = new List(); public static List activeCameras = new List(); public static Transform activationZoneParent; public static bool isEvaluatingRaycast = false; public static HitComparer raycastCompare = new HitComparer(); public static RaycastHit[] raycastHitBuffer = (RaycastHit[])(object)new RaycastHit[2]; public static IEnumerator SetupMassSurveillance() { lineRendererMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit")); lineRendererMaterial.color = Color.blue; playerLayer = LayerMask.NameToLayer("Player"); obstacleLayer = LayerMask.op_Implicit(Object.FindObjectOfType(true).VisibilityBlockingLayers); activationZoneLayer = LayerMask.NameToLayer("Invisible"); raycastIgnoreZone = ~LayerMask.GetMask(new string[2] { "Invisible", "Ignore Raycast" }); fxSparksTemplate = Object.Instantiate(((Component)((Component)Object.FindObjectOfType(true)).transform.Find("FX_Sparks_01")).gameObject); fxSparksTemplate.SetActive(false); activationZoneParent = new GameObject("FlockActivationZones").transform; foreach (string item in SurveillanceCameraPaths.unidirectional) { GameObject val = GameObject.Find(item); if (Object.op_Implicit((Object)(object)val)) { GameObject val2 = new GameObject("FlockCamera"); val2.transform.SetParent(val.transform); HylandFlockInstance hylandFlockInstance = val2.AddComponent(); hylandFlockInstance.type = ECameraType.Unidirectional; if (item.Contains("@Business")) { hylandFlockInstance.disableType = ECameraDisableAccess.BusinessComputer; } else { hylandFlockInstance.disableType = ECameraDisableAccess.None; } allCameras.Add(hylandFlockInstance); } else { DebugModule.Log("Expected to find camera at transform path and failed to find:\n" + item, "SetupMassSurveillance"); } } foreach (string item2 in SurveillanceCameraPaths.omnidirectional) { GameObject val3 = GameObject.Find(item2); if (Object.op_Implicit((Object)(object)val3)) { GameObject val4 = new GameObject("FlockCamera"); val4.transform.SetParent(val3.transform); HylandFlockInstance hylandFlockInstance2 = val4.AddComponent(); hylandFlockInstance2.type = ECameraType.Omnidirectional; if (item2.Contains("@Business")) { hylandFlockInstance2.disableType = ECameraDisableAccess.BusinessComputer; } else { hylandFlockInstance2.disableType = ECameraDisableAccess.None; } allCameras.Add(hylandFlockInstance2); } else { DebugModule.Log("Expected to find camera at transform path and failed to find:\n" + item2, "SetupMassSurveillance"); } } foreach (HylandFlockInstance allCamera in allCameras) { allCamera.Initialize(); if (!((Component)allCamera).gameObject.activeSelf) { ((Component)allCamera).gameObject.SetActive(true); } if (!((Behaviour)allCamera).enabled) { ((Behaviour)allCamera).enabled = true; } } TimeManager instance = NetworkSingleton.Instance; instance.onSleepEnd = (Action)Delegate.Combine(instance.onSleepEnd, new Action(RotateCameraActivity)); Player.Local.onArrested += OnPlayerArrestedClearCache; PenaltyHandler_ProcessCrimeList_Patch.BuildCrimeTable(); DebugModule.Log("Done setting up mass surveillance", "SetupMassSurveillance"); yield return (object)new WaitUntil((Func)(() => NACops.hasInitiatedAllOfficers)); RotateCameraActivity(); } public static void ResetMassSurveillance() { _surveilSeenStatesEvaluating = false; _surveilCrimeStatusEvaluating = false; _hasDispatchedNearby = false; lineRendererMaterial = null; fxSparksTemplate = null; allCameras.Clear(); activeCameras.Clear(); activationZoneParent = null; isEvaluatingRaycast = false; } public static void RotateCameraActivity() { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!NACops.currentConfig.MassSurveillance) { return; } DebugModule.Log("Rotating camera activity", "RotateCameraActivity"); int activeCamerasPerDay = NACops.surveillanceConfig.ActiveCamerasPerDay; List list = new List(); List list2 = new List(); float num = NACops.surveillanceConfig.CameraActivationRange; ListExtensions.Shuffle((IList)allCameras, -1); foreach (HylandFlockInstance allCamera in allCameras) { if (list.Count >= activeCamerasPerDay) { break; } if (allCamera.isOffline || (activeCameras.Count > 0 && activeCameras.Contains(allCamera))) { continue; } if (list2.Count > 0) { bool flag = false; foreach (Vector3 item in list2) { if (Vector3.Distance(item, ((Component)allCamera).transform.position) < num) { flag = true; } } if (flag) { continue; } } list.Add(allCamera); list2.Add(((Component)allCamera).transform.position); DebugModule.Log($"Selected {allCamera.type} camera at {((Component)allCamera).transform.position} for todays cameras", "RotateCameraActivity"); } list2.Clear(); if (activeCameras.Count > 0) { foreach (HylandFlockInstance activeCamera in activeCameras) { activeCamera.DeactivateInstance(); } activeCameras.Clear(); } foreach (HylandFlockInstance item2 in list) { DebugModule.Log("Enable cam", "RotateCameraActivity"); item2.ActivateInstance(); activeCameras.Add(item2); } list.Clear(); DebugModule.Log("Rotated daily camera activity", "RotateCameraActivity"); } public static void OnCameraFullyNoticed(List seenStateCache, float cacheEvidenceRatio = -1f) { string seenCacheStr = ""; seenStateCache.ForEach(delegate(string x) { seenCacheStr = seenCacheStr + x + " "; }); DebugModule.Log("Running camera notice events for: " + seenCacheStr, "OnCameraFullyNoticed"); DebugModule.Log($"SeenStates evaluating: {_surveilSeenStatesEvaluating}", "OnCameraFullyNoticed"); DebugModule.Log($"Crime status evaluating: {_surveilCrimeStatusEvaluating}", "OnCameraFullyNoticed"); if (NACops.surveillanceConfig.SurveilBaseCrimes && !_surveilSeenStatesEvaluating) { NACops.coros.Add(MelonCoroutines.Start(SurveilSeenStates(seenStateCache, cacheEvidenceRatio))); } if (NACops.surveillanceConfig.SurveilCrimeStatus && !_surveilCrimeStatusEvaluating) { NACops.coros.Add(MelonCoroutines.Start(SurveilCrimeStatus())); } } public static IEnumerator SurveilSeenStates(List seenStateCache, float cacheEvidenceRatio = -1f) { _surveilSeenStatesEvaluating = true; DebugModule.Log("Evaluate seen states start", "SurveilSeenStates"); float num = 1f + Mathf.Clamp01(cacheEvidenceRatio); float num2 = 0f; using (List.Enumerator enumerator = seenStateCache.GetEnumerator()) { while (enumerator.MoveNext()) { switch (enumerator.Current) { case "Suspicious": num2 += 0.01f; break; case "DisobeyingCurfew": num2 += 0.15f; Player.Local.CrimeData.AddCrime((Crime)new ViolatingCurfew(), 1); break; case "Vandalizing": num2 += 0.2f; Player.Local.CrimeData.AddCrime((Crime)new Vandalism(), 1); break; case "PettyCrime": num2 += 0.05f; break; case "DrugDealing": num2 += 0.3f; Player.Local.CrimeData.AddCrime((Crime)new AttemptingToSell(), 1); Player.Local.CrimeData.AddCrime((Crime)new DrugTrafficking(), 1); Player.Local.CrimeData.AddCrime((Crime)new TransportingIllicitItems(), 1); break; case "Wanted": num2 += 0.75f; Player.Local.CrimeData.AddCrime((Crime)new Evading(), 1); Player.Local.CrimeData.AddCrime((Crime)new FailureToComply(), 1); break; case "Pickpocketing": num2 += 0.2f; Player.Local.CrimeData.AddCrime((Crime)new Theft(), 1); break; case "DischargingWeapon": num2 += 0.45f; Player.Local.CrimeData.AddCrime((Crime)new BrandishingWeapon(), 1); Player.Local.CrimeData.AddCrime((Crime)new DischargeFirearm(), 1); break; case "Brandishing": num2 += 0.15f; Player.Local.CrimeData.AddCrime((Crime)new BrandishingWeapon(), 1); break; } num2 = Mathf.Clamp01(num2 * num); } } DebugModule.Log($"Accumulated severity: {num2} (x{num})", "SurveilSeenStates"); if (Random.Range(0f, 0.85f) <= num2) { DebugModule.Log("Chance hits!", "SurveilSeenStates"); DispatchNearby(); DebugModule.Log("Dispatch call finished", "SurveilSeenStates"); } DebugModule.Log("Finished surveil seen states evaluation", "SurveilSeenStates"); _surveilSeenStatesEvaluating = false; yield break; } public static IEnumerator SurveilCrimeStatus() { _surveilCrimeStatusEvaluating = true; if ((int)Player.Local.CrimeData.CurrentPursuitLevel != 0) { DebugModule.Log("Record last known position and Reset duration", "SurveilCrimeStatus"); Player.Local.RecordLastKnownPosition(true); Player.Local.CrimeData.CurrentPursuitLevelDuration = 0f; Player.Local.CrimeData.TimeSincePursuitStart = 0f; } _surveilCrimeStatusEvaluating = false; yield break; } public static void DispatchNearby() { //IL_005d: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) if (_hasDispatchedNearby) { DebugModule.Log("Dispatch is still on cooldown!", "DispatchNearby"); return; } NACops.coros.Add(MelonCoroutines.Start(WaitDispatchCooldown())); DebugModule.Log("Dispatch nearby proceed!", "DispatchNearby"); bool flag = PoliceStation.PoliceStations[0].OfficerPool.Count > 1; if (Vector3.Distance(Player.Local.CenterPointTransform.position, ((Component)PoliceStation.PoliceStations[0]).transform.position) < 20f) { if (flag) { DebugModule.Log("Dispatch nearby from police station", "DispatchNearby"); if ((int)Player.Local.CrimeData.CurrentPursuitLevel == 0) { Player.Local.CrimeData.SetPursuitLevel((EPursuitLevel)1); } PoliceStation.PoliceStations[0].Dispatch(1, Player.Local, (EDispatchType)2, true); return; } DebugModule.Log("Station has no officers in pool, check nearby", "DispatchNearby"); } DebugModule.Log("Dispatch check nearby", "DispatchNearby"); float num = 50f; float num2 = 100f; List list = new List(); int num3 = 2; foreach (PoliceOfficer allActiveOfficer in NACops.allActiveOfficers) { if ((Object)(object)allActiveOfficer == (Object)null || !((NPC)allActiveOfficer).IsConscious || ((NPC)allActiveOfficer).isInBuilding) { continue; } float num4 = Vector3.Distance(((Component)allActiveOfficer).transform.position, Player.Local.CenterPointTransform.position); if (!(num4 > num) && num4 < num2) { num2 = num4; if (!list.Contains(allActiveOfficer)) { list.Add(allActiveOfficer); } if (list.Count >= num3) { break; } } } DebugModule.Log($"Selected count: {list.Count}", "DispatchNearby"); if (list.Count > 0) { if ((int)Player.Local.CrimeData.CurrentPursuitLevel == 0) { Player.Local.CrimeData.SetPursuitLevel((EPursuitLevel)1); } foreach (PoliceOfficer item in list) { if (!((Object)(object)((NPC)item).Behaviour.activeBehaviour == (Object)null)) { if ((Object)(object)((NPC)item).Behaviour.activeBehaviour == (Object)(object)item.VehiclePatrolBehaviour && (Object)(object)((NPC)item).CurrentVehicle != (Object)null) { DebugModule.Log("Begin vehicle pursuit of noticed player", "DispatchNearby"); item.BeginVehiclePursuit_Networked(Player.Local.PlayerCode, ((NetworkBehaviour)((NPC)item).CurrentVehicle).NetworkObject, true); } else if ((Object)(object)((NPC)item).Behaviour.activeBehaviour == (Object)(object)item.PursuitBehaviour) { DebugModule.Log("Reset foot pursuit of noticed player", "DispatchNearby"); item.PursuitBehaviour.currentPursuitLevelDuration = 0f; ((CombatBehaviour)item.PursuitBehaviour).currentSearchDestination = Player.Local.Avatar.CenterPoint; } else if ((Object)(object)((NPC)item).Behaviour.activeBehaviour == (Object)(object)item.VehiclePursuitBehaviour) { DebugModule.Log("Reset vehicle pursuit of noticed player", "DispatchNearby"); item.VehiclePursuitBehaviour.timeSincePursuitStart = 0f; item.VehiclePursuitBehaviour.timeSinceLastSighting = 0f; } else { DebugModule.Log("Begin foot pursuit of noticed player", "DispatchNearby"); item.BeginFootPursuit_Networked(Player.Local.PlayerCode, true); } } } DebugModule.Log("Finished dispatching nearby", "DispatchNearby"); } else { DebugModule.Log("Could not find officers nearby to attend to noticed player", "DispatchNearby"); if (flag && PoliceStation.PoliceStations[0].AvailableVehicleCount > 0) { DebugModule.Log("Try dispatch vehicle from station", "DispatchNearby"); PoliceStation.PoliceStations[0].Dispatch(1, Player.Local, (EDispatchType)1, true); } } } public static IEnumerator WaitDispatchCooldown() { if (!_hasDispatchedNearby) { _hasDispatchedNearby = true; yield return NACops.Wait30; if (NACops.registered) { _hasDispatchedNearby = false; DebugModule.Log("Dispatch finished cooldown", "WaitDispatchCooldown"); } } } public static void OnPlayerArrestedClearCache() { if (!NACops.currentConfig.MassSurveillance || activeCameras.Count <= 0) { return; } foreach (HylandFlockInstance activeCamera in activeCameras) { activeCamera.ClearSeenCache(); } } } public class HitComparer : IComparer { public int Compare(RaycastHit x, RaycastHit y) { bool flag = (Object)(object)((RaycastHit)(ref x)).collider != (Object)null; bool flag2 = (Object)(object)((RaycastHit)(ref y)).collider != (Object)null; if (flag && !flag2) { return -1; } if (!flag && flag2) { return 1; } if (!flag && !flag2) { return 0; } return ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance); } } [Serializable] public class CrimeOverride { public float fineAmount; public string description = string.Empty; public CrimeOverride() { } public CrimeOverride(Crime crime) { string name = ((object)crime).GetType().Name; switch (name) { case "Assault": fineAmount = 75f; break; case "AttemptingToSell": fineAmount = 150f; break; case "BrandishingWeapon": fineAmount = 50f; break; case "DeadlyAssault": fineAmount = 150f; break; case "DischargeFirearm": fineAmount = 50f; break; case "DrugTrafficking": fineAmount = 50f; break; case "Evading": fineAmount = 50f; break; case "FailureToComply": fineAmount = 50f; break; case "PossessingControlledSubstances": fineAmount = 5f; description = "controlled substances"; break; case "PossessingHighSeverityDrug": fineAmount = 30f; description = "high-severity drugs"; break; case "PossessingLowSeverityDrug": fineAmount = 10f; description = "low-severity drugs"; break; case "PossessingModerateSeverityDrug": fineAmount = 20f; description = "moderate-severity drugs"; break; case "Theft": fineAmount = 50f; break; case "TransportingIllicitItems": fineAmount = 50f; break; case "Vandalism": fineAmount = 50f; break; case "VehicularAssault": fineAmount = 150f; break; case "ViolatingCurfew": fineAmount = 100f; break; default: DebugModule.Log("Failed to find fine amount for " + name, "CrimeOverride"); break; } } } [HarmonyPatch(typeof(PenaltyHandler), "ProcessCrimeList")] public static class PenaltyHandler_ProcessCrimeList_Patch { private static readonly string name = "ProcessCrimeList"; public static Dictionary crimeTable = new Dictionary(); public static void BuildCrimeTable() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown if (crimeTable.Count <= 0) { BuildCrimeOverrideOfType((Crime)new Assault()); BuildCrimeOverrideOfType((Crime)new AttemptingToSell()); BuildCrimeOverrideOfType((Crime)new BrandishingWeapon()); BuildCrimeOverrideOfType((Crime)new DeadlyAssault()); BuildCrimeOverrideOfType((Crime)new DischargeFirearm()); BuildCrimeOverrideOfType((Crime)new DrugTrafficking()); BuildCrimeOverrideOfType((Crime)new Evading()); BuildCrimeOverrideOfType((Crime)new FailureToComply()); BuildCrimeOverrideOfType((Crime)new PossessingControlledSubstances()); BuildCrimeOverrideOfType((Crime)new PossessingHighSeverityDrug()); BuildCrimeOverrideOfType((Crime)new PossessingLowSeverityDrug()); BuildCrimeOverrideOfType((Crime)new PossessingModerateSeverityDrug()); BuildCrimeOverrideOfType((Crime)new Theft()); BuildCrimeOverrideOfType((Crime)new TransportingIllicitItems()); BuildCrimeOverrideOfType((Crime)new Vandalism()); BuildCrimeOverrideOfType((Crime)new VehicularAssault()); BuildCrimeOverrideOfType((Crime)new ViolatingCurfew()); DebugModule.Log("Finished building crime table overrides", "BuildCrimeTable"); } } public static void BuildCrimeOverrideOfType(Crime crime) { CrimeOverride value = new CrimeOverride(crime); string text = ((object)crime).GetType().Name; if (!crimeTable.ContainsKey(text)) { crimeTable.Add(text, value); } else { DebugModule.Log("Failed to build crime override with name: " + text, "BuildCrimeOverrideOfType"); } } public static bool Prefix(Dictionary crimes, ref List __result) { DebugModule.Log("Evaluate conditions", name); if (crimeTable == null || crimeTable.Count == 0) { DebugModule.Log("Crime table is unassigned or empty!", name); return true; } if (NACops.surveillanceConfig.CrimePaymentMultiplier == 1 && !NACops.surveillanceConfig.GrowPaymentsWithProgression && !NACops.surveillanceConfig.PayFinesFromBank) { DebugModule.Log("Surveillance config has disabled crime payment modifications, return.", name); return true; } DebugModule.Log("Proceed", name); __result = new List(); float num = 0f; float num2 = NACops.surveillanceConfig.CrimePaymentMultiplier; if (NACops.surveillanceConfig.GrowPaymentsWithProgression) { float num3 = Mathf.Clamp01(NetworkSingleton.Instance.LifetimeEarnings / 3000000f); float num4 = Mathf.Clamp01((float)NetworkSingleton.Instance.Tier / 100f); num2 = Mathf.Lerp(1f, 10f, num3); num2 += Mathf.Lerp(0f, 10f, num4); } DebugModule.Log($"Crime fine Multiplier: {num2}", name); foreach (Crime item in crimes.Keys.ToList()) { string text = ((object)item).GetType().Name; int num5 = crimes[item]; if (crimeTable.TryGetValue(text, out var value)) { if (value.description != string.Empty) { __result.Add($"{num5} {value.description} confiscated"); float num6 = Mathf.Round(value.fineAmount * (float)num5 * num2); DebugModule.Log($"{num5} {value.description} confiscated: {num6}", "Prefix"); num += num6; } else { float num7 = Mathf.Round(value.fineAmount * num2); DebugModule.Log($"{text}: {num7}", "Prefix"); num += num7; } } } if (NACops.surveillanceConfig.CrimePaymentMultiplier == 0 || num == 0f) { __result.Add("(No fines issued)"); return false; } DebugModule.Log($"Crime payment: {num}", name); float cashBalance = NetworkSingleton.Instance.cashBalance; float onlineBalance = NetworkSingleton.Instance.onlineBalance; bool flag = false; bool flag2 = false; float num8 = 0f; if (cashBalance >= num) { flag = true; } else { flag = true; flag2 = true; num8 = num - cashBalance; } if (flag && flag2) { DebugModule.Log("Cash not sufficient", "Prefix"); if (cashBalance > 0f) { NetworkSingleton.Instance.ChangeCashBalance(0f - cashBalance, true, false); __result.Add(MoneyManager.FormatAmount(cashBalance, true, false) + " fine (paid in cash)"); } else { __result.Add(MoneyManager.FormatAmount(num, true, false) + " fine (insufficient cash)"); } if (NACops.surveillanceConfig.PayFinesFromBank && onlineBalance > 0f) { if (onlineBalance > 0f) { float num9 = 0f; num9 = ((!(onlineBalance >= num8)) ? onlineBalance : num8); NetworkSingleton.Instance.CreateOnlineTransaction("Hyland Point Police", 0f - num9, 1f, "Crime charge"); __result.Add(MoneyManager.FormatAmount(num9, true, false) + " fine (paid from bank)"); } else { __result.Add(MoneyManager.FormatAmount(num8, true, false) + " fine (insufficient bank balance)"); } } } else { DebugModule.Log("Cash sufficient", "Prefix"); if (cashBalance > 0f) { NetworkSingleton.Instance.ChangeCashBalance(0f - num, true, false); __result.Add(MoneyManager.FormatAmount(num, true, false) + " fine (paid in cash)"); } } return false; } } public static class BuildInfo { public const string Name = "NACops"; public const string Description = "Crazyyyy cops"; public const string Author = "XOWithSauce"; public const string Company = null; public const string Version = "2.1.0"; public const string DownloadLink = null; } public class NACops : MelonMod { [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { typeof(string) })] public static class SaveManager_Save_String_Patch { public static bool Prefix(SaveManager __instance, string saveFolderPath) { if (!isSaving) { isSaving = true; lock (heatConfigLock) { ConfigLoader.Save(new PropertiesHeatSerialized { loadedPropertyHeats = new List(heatConfig) }); } } isSaving = false; return true; } } [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { })] public static class SaveManager_Save_Patch { public static bool Prefix(SaveManager __instance) { return true; } } [HarmonyPatch(typeof(LoadManager), "ExitToMenu")] public static class LoadManager_ExitToMenu_Patch { public static bool Prefix(LoadManager __instance, SaveInfo autoLoadSave = null, Data mainMenuPopup = null, bool preventLeaveLobby = false) { ExitPreTask(); return true; } } [HarmonyPatch(typeof(DeathScreen), "LoadSaveClicked")] public static class DeathScreen_LoadSaveClicked_Patch { public static bool Prefix(DeathScreen __instance) { ExitPreTask(); return true; } } public static ConfigLoader.ModConfig currentConfig; public static ConfigLoader.NAOfficerConfig officerConfig; public static ThresholdMappings thresholdConfig; public static ConfigLoader.RaidConfig raidConfig; public static ConfigLoader.MassSurveillanceConfig surveillanceConfig; public static object heatConfigLock = new object(); public static List heatConfig; public static bool isSaving = false; public static List coros = new List(); public static readonly HashSet allActiveOfficers = new HashSet(); public static HashSet currentDrugApprehender = new HashSet(); public static bool registered = false; public static bool lastSaveLoad = false; public static bool firstTimeLoad = false; public static bool hasInitiatedAllOfficers = false; public static NetworkManager networkManager; public static List generatedLawSettings = new List(); public static WaitForEndOfFrame frameEnd = new WaitForEndOfFrame(); public static WaitForSeconds Wait01 = new WaitForSeconds(0.1f); public static WaitForSeconds Wait05 = new WaitForSeconds(0.5f); public static WaitForSeconds Wait1 = new WaitForSeconds(1f); public static WaitForSeconds Wait2 = new WaitForSeconds(2f); public static WaitForSeconds Wait5 = new WaitForSeconds(5f); public static WaitForSeconds Wait30 = new WaitForSeconds(30f); public static NACops Instance { get; private set; } public static ModPrefsHandler Prefs { get; private set; } public static void SyncConfig() { bool flag = false; FieldInfo[] fields = currentConfig.GetType().GetFields(); foreach (FieldInfo fieldInfo in fields) { MelonPreferences_Entry entry = Prefs.modConfigCategory.GetEntry(fieldInfo.Name); if (entry != null) { if ((bool)fieldInfo.GetValue(currentConfig) == (bool)entry.BoxedValue) { DebugModule.Log("No changed value for :" + fieldInfo.Name, "SyncConfig"); continue; } flag = true; DebugModule.Log("Update config value for :" + fieldInfo.Name, "SyncConfig"); fieldInfo.SetValue(currentConfig, entry.BoxedValue); } } if (flag) { ConfigLoader.Save(currentConfig, logConfirm: false); } } public override void OnInitializeMelon() { ((MelonBase)this).OnInitializeMelon(); Instance = this; currentConfig = ConfigLoader.LoadModConfig(); Prefs = new ModPrefsHandler(); Prefs.SetupMelonPreferences(); SyncConfig(); MelonLogger.Msg("NACops Mod Loaded"); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (buildIndex == 1 && (Object)(object)Singleton.Instance != (Object)null && !registered && !firstTimeLoad) { firstTimeLoad = true; Singleton.Instance.onLoadComplete.AddListener(new UnityAction(OnLoadCompleteCb)); } if (buildIndex != 1 && registered) { ExitPreTask(); } } private void OnLoadCompleteCb() { if (!registered) { registered = true; coros.Add(MelonCoroutines.Start(Setup())); } } public static IEnumerator Setup() { yield return (object)new WaitUntil((Func)(() => Singleton.Instance.IsGameLoaded)); DebugModule.Log("Loading configs", "Setup"); currentConfig = ConfigLoader.LoadModConfig(); officerConfig = ConfigLoader.LoadOfficerConfig(); heatConfig = ConfigLoader.LoadPropertyHeats().loadedPropertyHeats; thresholdConfig = ConfigLoader.LoadFrequencyConfig(); raidConfig = ConfigLoader.LoadRaidConfig(); surveillanceConfig = ConfigLoader.LoadSurveillanceConfig(); networkManager = Object.FindObjectOfType(true); yield return MelonCoroutines.Start(CopInitHelper.ReplicateCopNPC()); coros.Add(MelonCoroutines.Start(OfficersInit())); coros.Add(MelonCoroutines.Start(MassSurveillance.SetupMassSurveillance())); RaidPropertyEvent.SetRaidSprite(); yield return MelonCoroutines.Start(AddDayPassRaid()); yield return MelonCoroutines.Start(StationInit()); coros.Add(MelonCoroutines.Start(OpenCarryInit())); TimeManager instance = NetworkSingleton.Instance; instance.onHourPass = (Action)Delegate.Combine(instance.onHourPass, new Action(Customer_ProcessHandover_Patch.ReduceBuyBustHours)); DebugModule.Log("Setup complete", "Setup"); } public static IEnumerator OfficersInit() { DebugModule.Log("Officers Init", "OfficersInit"); allActiveOfficers.Clear(); yield return Wait01; if (officerConfig.ModAddedOfficersCount != 0) { yield return MelonCoroutines.Start(CopInitHelper.SpawnOfficersRuntime()); } else { for (int i = 0; i < PoliceOfficer.Officers.Count; i++) { CopInitHelper.generatedOfficerPool.Add(PoliceOfficer.Officers[i]); } } foreach (PoliceOfficer item in CopInitHelper.generatedOfficerPool) { allActiveOfficers.Add(item); } yield return MelonCoroutines.Start(CopInitHelper.CreateInvestigator()); yield return MelonCoroutines.Start(CopInitHelper.CreateBuyBustCop()); yield return MelonCoroutines.Start(OfficerOverrides.SetOfficers()); coros.Add(MelonCoroutines.Start(RunCoros())); hasInitiatedAllOfficers = true; DebugModule.Log("All officer npcs initiated", "OfficersInit"); } public static IEnumerator OpenCarryInit() { PlayerSingleton.instance.onEquippedSlotChanged = (Action)Delegate.Combine(PlayerSingleton.instance.onEquippedSlotChanged, new Action(NoticeOpenCarry.OnSlotChanged)); Player.Local.onArrested += NoticeOpenCarry.OnPlayerArrested; NoticeOpenCarry.SetWeaponsLegalStatus(); DebugModule.Log("Enabled No Open Carry Weapons", "OpenCarryInit"); yield break; } public static IEnumerator AddDayPassRaid() { if (currentConfig.RaidsEnabled) { TimeManager instance = NetworkSingleton.Instance; instance.onSleepEnd = (Action)Delegate.Combine(instance.onSleepEnd, new Action(RaidPropertyEvent.OnDayPassEvaluateRaid)); } yield break; } public static IEnumerator StationInit() { DebugModule.Log("Generating Law settings", "StationInit"); DebugModule.Log("Apply Custom to All Days", "StationInit"); foreach (KeyValuePair item in new Dictionary { { "mon", Singleton.Instance.MondaySettings }, { "tue", Singleton.Instance.TuesdaySettings }, { "wed", Singleton.Instance.WednesdaySettings }, { "thu", Singleton.Instance.ThursdaySettings }, { "fri", Singleton.Instance.FridaySettings }, { "sat", Singleton.Instance.SaturdaySettings }, { "sun", Singleton.Instance.SundaySettings } }) { DebugModule.Log("Generating patrols, vehicle patrols and sentries for day: " + item.Key, "StationInit"); _ = item.Key; LawActivitySettings val = new LawActivitySettings(); val.Curfews = item.Value.Curfews; if (currentConfig.CheckpointsEnabled) { val.Checkpoints = item.Value.Checkpoints; } else { val.Checkpoints = (CheckpointInstance[])(object)new CheckpointInstance[0]; } if (currentConfig.ExtraOfficerPatrols) { DebugModule.Log("Gen patrol", "StationInit"); val.Patrols = FootPatrolGenerator.GeneratePatrol(item.Value, item.Key); } else { val.Patrols = item.Value.Patrols; } if (currentConfig.ExtraVehiclePatrols) { DebugModule.Log("Gen vehicle patrol", "StationInit"); val.VehiclePatrols = VehiclePatrolGenerator.GenerateVehiclePatrol(item.Value, item.Key); } else { val.VehiclePatrols = item.Value.VehiclePatrols; } if (currentConfig.ExtraOfficerSentries) { DebugModule.Log("Gen sentries", "StationInit"); val.Sentries = SentryGenerator.GenerateSentry(item.Value, item.Key); } else { val.Sentries = item.Value.Sentries; } generatedLawSettings.Add(val); switch (item.Key) { case "mon": Singleton.Instance.MondaySettings = val; break; case "tue": Singleton.Instance.TuesdaySettings = val; break; case "wed": Singleton.Instance.WednesdaySettings = val; break; case "thu": Singleton.Instance.ThursdaySettings = val; break; case "fri": Singleton.Instance.FridaySettings = val; break; case "sat": Singleton.Instance.SaturdaySettings = val; break; case "sun": Singleton.Instance.SundaySettings = val; break; } } yield break; } public static IEnumerator RunCoros() { DebugModule.Log("Coros begin", "RunCoros"); coros.Add(MelonCoroutines.Start(NearbyCrazyCops.RunNearbyCrazyCops())); coros.Add(MelonCoroutines.Start(LethalCops.RunNearbyLethalCops())); coros.Add(MelonCoroutines.Start(RacistOfficers.EvaluateOfficersVision())); coros.Add(MelonCoroutines.Start(PrivateInvestigator.RunInvestigator())); yield break; } private static void ExitPreTask() { registered = false; foreach (object coro in coros) { if (coro != null) { MelonCoroutines.Stop(coro); } } allActiveOfficers.Clear(); coros.Clear(); currentDrugApprehender.Clear(); Player_ConsumeProduct_Patch.evaluating = false; hasInitiatedAllOfficers = false; Customer_ProcessHandover_Patch.cooldownHours = 3; CopInitHelper.generatedOfficerPool.Clear(); generatedLawSettings.Clear(); CopInitHelper.copBaseClone = null; CopInitHelper.investigator = null; CopInitHelper.investigatorID = 0; PrivateInvestigator.isTakingPhotos = false; CopInitHelper.buyBustCop = null; CopInitHelper.buyBustCopID = 0; FootPatrolGenerator.generatedPatrolInstances.Clear(); FootPatrolGenerator.serPatrols = null; VehiclePatrolGenerator.generatedVehiclePatrolInstances.Clear(); VehiclePatrolGenerator.serVehiclePatrols = null; SentryGenerator.generatedSentryInstances.Clear(); SentryGenerator.serSentries = null; NoticeOpenCarry.HasSetBrandishing = false; NoticeOpenCarry.IsCheckingSlot = false; OfficerOverrides.rangedWeaponPrefab = null; if (RuntimeImpostor.createdTextures.Count > 0) { foreach (Texture2D value in RuntimeImpostor.createdTextures.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } RuntimeImpostor.createdTextures.Clear(); } if (AvatarUtility.instancedSettings.Count > 0) { foreach (KeyValuePair instancedSetting in AvatarUtility.instancedSettings) { if ((Object)(object)instancedSetting.Value != (Object)null) { Object.DestroyImmediate((Object)(object)instancedSetting.Value); } } AvatarUtility.instancedSettings.Clear(); } networkManager = null; heatConfig.Clear(); RaidPropertyEvent.ResetRaidEvent(); MassSurveillance.ResetMassSurveillance(); AvatarUtility.maleVOs.Clear(); AvatarUtility.femaleVOs.Clear(); DebugModule.pathVisualizer.Clear(); ConsoleModule.CopAnalyticsTarget.AnalyticsTextPanel = null; ConsoleModule.SurveillanceTarget.hasDrawnVisuals = false; ConsoleModule.FootPatrolTarget.currentPathName = ""; ConsoleModule.FootPatrolTarget.recordedPathNodes.Clear(); ConsoleModule.SentryTarget.currentPathName = ""; ConsoleModule.SentryTarget.recordedPathNodes.Clear(); ConsoleModule.VehiclePatrolTarget.currentPathName = ""; ConsoleModule.VehiclePatrolTarget.recordedPathNodes.Clear(); ConsoleModule.isBuilding = false; ConsoleModule.CopAnalyticsTarget.AnalyticsTextPanel = null; } } public static class CopInitHelper { public static List generatedOfficerPool = new List(); public static GameObject copBaseClone; public static PoliceOfficer investigator; public static int investigatorID; public static PoliceOfficer buyBustCop; public static int buyBustCopID; public static IEnumerator ReplicateCopNPC() { DebugModule.Log("Replicating COP NPC", "ReplicateCopNPC"); PoliceOfficer val = Object.FindObjectOfType(); AvatarSettings copySettings = ((NPC)val).Avatar.CurrentSettings; if ((Object)(object)val == (Object)null) { DebugModule.Log("No officer found", "ReplicateCopNPC"); yield break; } GameObject obj = ((Component)val).gameObject; obj.SetActive(false); GameObject val2 = (copBaseClone = Object.Instantiate(obj)); val2.transform.position = Vector3.zero; val2.transform.rotation = Quaternion.identity; NPC npc = val2.GetComponent(); NetworkObject newNob = val2.GetComponent(); PoliceOfficer offc = val2.GetComponent(); offc.AutoDeactivate = false; ((Object)val2).name = "RuntimeOfficer"; yield return MelonCoroutines.Start(InitiateClone(newNob, NACops.networkManager)); npc.NPCData.BasicInfo.ID = "officerPrefab"; if (!NPCManager.NPCRegistry.Contains(npc)) { NPCManager.NPCRegistry.Add(npc); } npc.Avatar.LoadAvatarSettings(copySettings); offc.PursuitBehaviour.arrestingEnabled = false; try { NACops.networkManager.ServerManager.Spawn(newNob, (NetworkConnection)null, default(Scene)); } catch (Exception value) { DebugModule.Log($"Failed to spawn officer {value}", "ReplicateCopNPC"); } ((NPC)offc).Behaviour.ScheduleManager.DisableSchedule(); ((NPC)offc).Movement.PauseMovement(); if (PoliceOfficer.Officers.Contains(offc)) { PoliceOfficer.Officers.Remove(offc); } CapsuleCollider component = ((Component)((Component)((DialogueController)((Component)offc).GetComponentInChildren()).IntObj).transform.Find("Sphere")).GetComponent(); component.height = 1.85f; component.radius = 0.5f; obj.SetActive(true); DebugModule.Log("Finished replicating COP NPC", "ReplicateCopNPC"); } public static IEnumerator InitiateClone(NetworkObject newNob, NetworkManager netManager, NPCData dataPreset = null) { NPC npc = ((Component)newNob).GetComponent(); ((Component)((Component)newNob).transform.Find("Avatar")).gameObject.SetActive(true); ((Component)((Component)newNob).transform.Find("Avatar/BodyContainer")).gameObject.SetActive(true); ((Behaviour)((Component)newNob).GetComponent()).enabled = true; ((Component)newNob).gameObject.SetActive(true); yield return NACops.Wait01; yield return NACops.frameEnd; ((Component)((Component)newNob).transform.Find("Avatar")).gameObject.SetActive(false); ((Component)((Component)newNob).transform.Find("Avatar/BodyContainer")).gameObject.SetActive(false); ((Behaviour)((Component)newNob).GetComponent()).enabled = false; if (((Component)newNob).gameObject.activeSelf) { ((Component)newNob).gameObject.SetActive(false); } Behaviour behaviour = npc.Behaviour.GetBehaviour("Customer attend deal"); if (Object.op_Implicit((Object)(object)behaviour)) { Object.Destroy((Object)(object)((Component)behaviour).gameObject); npc.Behaviour.OnValidate(); } try { MethodInfo methodInfo = AccessTools.Method(typeof(NetworkObject), "UpdateNetworkBehaviours", new Type[2] { typeof(NetworkObject), typeof(byte).MakeByRefType() }, (Type[])null); if (methodInfo == null) { DebugModule.Log("updateNetworkBehMethod not found.", "InitiateClone"); } else { methodInfo.Invoke(newNob, new object[2] { newNob, (byte)0 }); } } catch (Exception ex) { DebugModule.Log(ex.ToString(), "InitiateClone"); } if (dataPreset != null) { npc.ApplyNPCData(dataPreset); } try { MethodInfo methodInfo2 = AccessTools.Method(typeof(NetworkObject), "Preinitialize_Internal", new Type[4] { typeof(NetworkManager), typeof(int), typeof(NetworkConnection), typeof(bool) }, (Type[])null); if (methodInfo2 == null) { DebugModule.Log("Method Preinitialize_Internal not found.", "InitiateClone"); } else { methodInfo2.Invoke(newNob, new object[4] { netManager, 150, null, true }); } } catch (Exception ex2) { DebugModule.Log(ex2.ToString(), "InitiateClone"); } try { MethodInfo methodInfo3 = AccessTools.Method(typeof(NetworkObject), "Initialize", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo3 == null) { DebugModule.Log("NetworkObject.Initialize internal method not found.", "InitiateClone"); } else { methodInfo3.Invoke(newNob, new object[2] { true, true }); } } catch (Exception ex3) { DebugModule.Log(ex3.ToString(), "InitiateClone"); } try { newNob.SetIsNetworked(false); } catch (Exception value) { DebugModule.Log($"Failed to set network object networking to false: {value}", "InitiateClone"); } npc.Awareness.SetAwarenessActive(false); } public static IEnumerator SpawnOfficersRuntime() { PoliceStation station = PoliceStation.PoliceStations[0]; for (int i = 0; i < PoliceOfficer.Officers.Count; i++) { generatedOfficerPool.Add(PoliceOfficer.Officers[i]); } for (int j = 0; j < NACops.officerConfig.ModAddedOfficersCount; j++) { DebugModule.Log($"Spawning {j}", "SpawnOfficersRuntime"); GameObject copNet = Object.Instantiate(copBaseClone); NetworkObject component = copNet.GetComponent(); PoliceOfficer offc = copNet.gameObject.GetComponent(); offc.AutoDeactivate = false; ((Object)copNet).name = $"NACop_{j}"; yield return MelonCoroutines.Start(InitiateClone(component, NACops.networkManager)); NPC component2 = copNet.gameObject.GetComponent(); component2.NPCData.BasicInfo.ID = $"NACop_{j}"; component2.NPCData.BasicInfo.FirstName = "Officer"; component2.NPCData.BasicInfo.LastName = ""; component2.NPCData.Inventory.CanBePickpocketed = true; component2.NPCData.WeatherBehaviour.UseUmbrellaChance = 0f; component2.Actions._canUseUmbrella = false; if (!NPCManager.NPCRegistry.Contains(component2)) { NPCManager.NPCRegistry.Add(component2); } NACops.networkManager.ServerManager.Spawn(copNet, (NetworkConnection)null, default(Scene)); copNet.gameObject.SetActive(true); ((Component)((NPC)offc).DialogueHandler).GetComponent().Choices.Clear(); ((Component)copNet.transform.Find("Avatar")).gameObject.SetActive(true); AvatarSettings createdSettings = null; AvatarUtility.SetRandomAvatar(offc, ref createdSettings); AvatarUtility.SetVOEmitter((NPC)(object)offc); yield return AvatarUtility.GenerateImpostor(offc, createdSettings); ((Behaviour)copNet.GetComponent()).enabled = true; offc.AutoDeactivate = true; ((NPC)offc).Awareness.SetAwarenessActive(true); ((NPC)offc).Movement.Warp(station.SpawnPoint); ((NPCEnterableBuilding)station).NPCEnteredBuilding((NPC)(object)offc, ((NPCEnterableBuilding)station).Doors[0]); generatedOfficerPool.Add(offc); } DebugModule.Log("Extended cops array", "SpawnOfficersRuntime"); } public static IEnumerator CreateInvestigator() { GameObject copNet = Object.Instantiate(copBaseClone); NetworkObject component = copNet.GetComponent(); PoliceOfficer offc = copNet.gameObject.GetComponent(); offc.AutoDeactivate = false; offc.ChatterEnabled = false; offc.BodySearchChance = 0f; ((Object)copNet).name = "NACop_Investigator"; yield return MelonCoroutines.Start(InitiateClone(component, NACops.networkManager)); NPC component2 = copNet.gameObject.GetComponent(); component2.NPCData.BasicInfo.ID = "NACop_Investigator"; component2.NPCData.BasicInfo.FirstName = "Investigator"; component2.NPCData.BasicInfo.LastName = ""; component2.NPCData.Inventory.CanBePickpocketed = false; component2.NPCData.WeatherBehaviour.UseUmbrellaChance = 0f; component2.Actions._canUseUmbrella = false; if (!NPCManager.NPCRegistry.Contains(component2)) { NPCManager.NPCRegistry.Add(component2); } NACops.networkManager.ServerManager.Spawn(copNet, (NetworkConnection)null, default(Scene)); ((Component)((NPC)offc).DialogueHandler).GetComponent().Choices.Clear(); investigator = offc; investigatorID = ((Object)((Component)((Component)investigator).transform.root).gameObject).GetInstanceID(); ((NPC)investigator).Behaviour.ScheduleManager.DisableSchedule(); if (PoliceOfficer.Officers.Contains(investigator)) { PoliceOfficer.Officers.Remove(investigator); } ((NPC)offc).Awareness.SetAwarenessActive(false); DebugModule.Log("Done spawning Investigator", "CreateInvestigator"); } public static IEnumerator CreateBuyBustCop() { GameObject copNet = Object.Instantiate(copBaseClone); NetworkObject component = copNet.GetComponent(); PoliceOfficer offc = copNet.gameObject.GetComponent(); offc.AutoDeactivate = false; ((Object)copNet).name = "NACop_BuyBust"; yield return MelonCoroutines.Start(InitiateClone(component, NACops.networkManager)); NPC component2 = copNet.gameObject.GetComponent(); component2.NPCData.BasicInfo.ID = "NACop_BuyBust"; component2.NPCData.BasicInfo.FirstName = "Officer"; component2.NPCData.BasicInfo.LastName = ""; component2.NPCData.Inventory.CanBePickpocketed = false; component2.NPCData.WeatherBehaviour.UseUmbrellaChance = 0f; component2.Actions._canUseUmbrella = false; if (!NPCManager.NPCRegistry.Contains(component2)) { NPCManager.NPCRegistry.Add(component2); } NACops.networkManager.ServerManager.Spawn(copNet, (NetworkConnection)null, default(Scene)); ((Component)((NPC)offc).DialogueHandler).GetComponent().Choices.Clear(); copNet.gameObject.SetActive(true); ((Component)copNet.transform.Find("Avatar")).gameObject.SetActive(true); AvatarSettings createdSettings = null; AvatarUtility.SetRandomAvatar(offc, ref createdSettings); AvatarUtility.SetVOEmitter((NPC)(object)offc); yield return AvatarUtility.GenerateImpostor(offc, createdSettings); copNet.gameObject.SetActive(false); ((Component)copNet.transform.Find("Avatar")).gameObject.SetActive(false); buyBustCop = offc; buyBustCopID = ((Object)((Component)((Component)buyBustCop).transform.root).gameObject).GetInstanceID(); ((NPC)buyBustCop).Behaviour.ScheduleManager.DisableSchedule(); if (PoliceOfficer.Officers.Contains(offc)) { PoliceOfficer.Officers.Remove(offc); } ((NPC)offc).Awareness.SetAwarenessActive(false); DebugModule.Log("Done spawning buy bust officer", "CreateBuyBustCop"); } } public static class NoticeOpenCarry { public static readonly List weaponIDs = new List { "baseballbat", "fryingpan", "machete", "revolver", "goldenm1911", "m1911", "pumpshotgun" }; public static bool HasSetBrandishing = false; public static bool IsCheckingSlot = false; public static void CheckSlotItem() { int equippedSlotIndex = PlayerSingleton.Instance.EquippedSlotIndex; if (equippedSlotIndex >= 0 && equippedSlotIndex < 8) { ItemInstance itemInstance = Player.Local._inventory[equippedSlotIndex].ItemInstance; if (itemInstance != null) { if (weaponIDs.Contains(((BaseItemInstance)itemInstance).ID)) { SetNoticable(enabled: true); } else { SetNoticable(enabled: false); } } else { SetNoticable(enabled: false); } } else { SetNoticable(enabled: false); } IsCheckingSlot = false; DebugModule.Log("Checked slot", "CheckSlotItem"); } public static void OnSlotChanged(int _) { if (NACops.currentConfig.NoOpenCarryWeapons && !IsCheckingSlot) { IsCheckingSlot = true; CheckSlotItem(); } } public static void OnPlayerArrested() { if (NACops.currentConfig.NoOpenCarryWeapons) { ((EntityVisibility)Player.Local.VisualState).RemoveState("Brandishing", 0f); } } public static void SetNoticable(bool enabled) { if (enabled && !HasSetBrandishing) { HasSetBrandishing = true; ((EntityVisibility)Player.Local.VisualState).ApplyState("Brandishing", (EVisualState)9, 0f); DebugModule.Log("Player Brandishing", "SetNoticable"); } else if (!enabled && HasSetBrandishing) { HasSetBrandishing = false; DebugModule.Log("RemoveState Brandishing", "SetNoticable"); ((EntityVisibility)Player.Local.VisualState).RemoveState("Brandishing", 0f); } } public static void SetWeaponsLegalStatus() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!NACops.currentConfig.NoOpenCarryWeapons) { return; } Func func = Registry.GetItem; foreach (string weaponID in weaponIDs) { ((BaseItemDefinition)func(weaponID)).legalStatus = (ELegalStatus)4; } } } [HarmonyPatch(typeof(PursuitBehaviour), "UpdateArrest")] public static class PursuitBehaviour_UpdateArrest_Patch { public static bool Prefix(PursuitBehaviour __instance, float tick) { //IL_002e: 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) if (!NACops.officerConfig.OverrideArresting) { return true; } if ((Object)(object)__instance.TargetPlayer == (Object)null) { return false; } if (!__instance.arrestingEnabled) { return false; } if (Vector3.Distance(((Behaviour)__instance).Npc.CenterPoint, __instance.TargetPlayer.Avatar.CenterPoint) < NACops.officerConfig.ArrestRange && ((CombatBehaviour)__instance).IsTargetRecentlyVisible) { __instance.timeWithinArrestRange += tick; if (__instance.timeWithinArrestRange > 0.5f) { __instance.wasInArrestCircleLastFrame = true; } } else { if (__instance.wasInArrestCircleLastFrame) { __instance.leaveArrestCircleCount++; __instance.wasInArrestCircleLastFrame = false; } __instance.timeWithinArrestRange = Mathf.Clamp(__instance.timeWithinArrestRange - tick, 0f, float.MaxValue); } if (((NetworkBehaviour)__instance.TargetPlayer).IsOwner && __instance.timeWithinArrestRange / NACops.officerConfig.ArrestTime > __instance.TargetPlayer.CrimeData.CurrentArrestProgress) { __instance.TargetPlayer.CrimeData.SetArrestProgress(__instance.timeWithinArrestRange / NACops.officerConfig.ArrestTime); } return false; } } [HarmonyPatch(typeof(PursuitBehaviour), "UpdateLethalBehaviour")] public static class PursuitBehaviour_UpdateLethalBehaviour_Patch { private static readonly string functionName = "UpdateLethalBehaviour"; public static bool Prefix(PursuitBehaviour __instance) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown if (!NACops.officerConfig.OverrideWeapon) { return true; } if (NACops.officerConfig.RangedWeapon.ToLower() == "m1911") { return true; } float num = Vector3.Distance(((Component)__instance).transform.position, __instance.TargetPlayer.Avatar.CenterPoint); ((CombatBehaviour)__instance).SetMovementSpeed(Mathf.Lerp(0.7f, 0.9f, Mathf.Clamp01(num / 6f)), "combat", 5); if ((Object)(object)((CombatBehaviour)__instance).currentWeapon != (Object)null) { if (__instance.officer.GunPrefab.AssetPath == ((AvatarEquippable)((CombatBehaviour)__instance).currentWeapon).AssetPath) { return false; } ((CombatBehaviour)__instance).ClearWeapon(); } if ((Object)(object)((CombatBehaviour)__instance).VirtualPunchWeapon == (Object)null) { return true; } if (((AvatarWeapon)((CombatBehaviour)__instance).VirtualPunchWeapon).onSuccessfulHit == null) { ((AvatarWeapon)((CombatBehaviour)__instance).VirtualPunchWeapon).onSuccessfulHit = new UnityEvent(); } ((AvatarWeapon)((CombatBehaviour)__instance).VirtualPunchWeapon).onSuccessfulHit.RemoveListener(new UnityAction(((CombatBehaviour)__instance).SucessfulHit)); if ((Object)(object)((NPC)__instance.officer).Avatar.CurrentEquippable != (Object)null) { ((NPC)__instance.officer).Avatar.CurrentEquippable.Unequip(); } ((NPC)__instance.officer).Avatar.CurrentEquippable = Object.Instantiate(((Component)OfficerOverrides.rangedWeaponPrefab).gameObject, (Transform)null).GetComponent(); ((NPC)__instance.officer).Avatar.CurrentEquippable.Equip(((NPC)__instance.officer).Avatar); ref AvatarWeapon currentWeapon = ref ((CombatBehaviour)__instance).currentWeapon; AvatarEquippable currentEquippable = ((NPC)__instance.officer).Avatar.CurrentEquippable; currentWeapon = (AvatarWeapon)(object)((currentEquippable is AvatarWeapon) ? currentEquippable : null); if (((CombatBehaviour)__instance).currentWeapon.onSuccessfulHit == null) { ((CombatBehaviour)__instance).currentWeapon.onSuccessfulHit = new UnityEvent(); } ((CombatBehaviour)__instance).currentWeapon.onSuccessfulHit.AddListener(new UnityAction(((CombatBehaviour)__instance).SucessfulHit)); if ((Object)(object)((CombatBehaviour)__instance).currentWeapon == (Object)null) { return false; } ((CombatBehaviour)__instance).OnCurrentWeaponChanged(((CombatBehaviour)__instance).currentWeapon); return false; } } public static class OfficerOverrides { public static AvatarEquippable rangedWeaponPrefab; public static IEnumerator SetOfficers() { bool hasInstantiatedRangedWeapon = false; bool hasOverridenWeaponPrefab = false; bool hasOverridenTaserPrefab = false; DebugModule.Log("Set officers foreach stats for " + NACops.allActiveOfficers.Count, "SetOfficers"); foreach (PoliceOfficer allActiveOfficer in NACops.allActiveOfficers) { PoliceOfficer officer = allActiveOfficer; yield return NACops.Wait01; ((NPC)officer).Awareness.VisionCone.WorldspaceIconsEnabled = NACops.officerConfig.ShowNoticeIcons; if (NACops.officerConfig.CanEnterBuildings) { ((NPC)officer).Movement.Agent.areaMask = 57; } if (NACops.officerConfig.OverrideBodySearch) { officer.BodySearchDuration = NACops.officerConfig.BodySearchDuration; officer.BodySearchChance = NACops.officerConfig.BodySearchChance; } if (NACops.officerConfig.OverrideMovement) { ((NPC)officer).Movement.MoveSpeedMultiplier = NACops.officerConfig.MovementSpeedMultiplier; } if (NACops.officerConfig.OverrideCombatBeh) { ((NPC)officer).Behaviour.CombatBehaviour.GiveUpRange = NACops.officerConfig.CombatGiveUpRange; ((NPC)officer).Behaviour.CombatBehaviour.DefaultSearchTime = NACops.officerConfig.CombatSearchTime; ((NPC)officer).Behaviour.CombatBehaviour.DefaultMovementSpeed = NACops.officerConfig.CombatMoveSpeed; ((NPC)officer).Behaviour.CombatBehaviour.GiveUpAfterSuccessfulHits = NACops.officerConfig.CombatEndAfterHits; } if (NACops.officerConfig.OverrideMaxHealth) { ((NPC)officer).NPCData.Health.MaxHealth = NACops.officerConfig.OfficerMaxHealth; ((NPC)officer).Health.Health = NACops.officerConfig.OfficerMaxHealth; } if (NACops.officerConfig.OverrideWeapon && !hasOverridenWeaponPrefab) { DebugModule.Log("Setup Override Weapon", "SetOfficers"); string text = NACops.officerConfig.RangedWeapon.ToLower() switch { "m1911" => string.Empty, "goldenm1911" => "Avatar/Equippables/M1911_Gold", "revolver" => "Avatar/Equippables/Revolver", "shotgun" => "Avatar/Equippables/PumpShotgun", _ => string.Empty, }; if (!hasInstantiatedRangedWeapon && text != string.Empty) { DebugModule.Log("Instantiating custom weapon from path: " + text, "SetOfficers"); Object obj = Resources.Load(text); GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { DebugModule.Log("Custom weapon was not found in built resources", "SetOfficers"); } else { rangedWeaponPrefab = Object.Instantiate(val, new Vector3(0f, -5f, 0f), Quaternion.identity, (Transform)null).GetComponent(); if (!((Component)rangedWeaponPrefab).gameObject.activeSelf) { ((Component)rangedWeaponPrefab).gameObject.SetActive(true); } } hasInstantiatedRangedWeapon = true; } if (hasInstantiatedRangedWeapon && (Object)(object)rangedWeaponPrefab != (Object)null) { officer.GunPrefab = rangedWeaponPrefab; } AvatarEquippable gunPrefab = officer.GunPrefab; AvatarRangedWeapon val2 = (AvatarRangedWeapon)(object)((gunPrefab is AvatarRangedWeapon) ? gunPrefab : null); if ((Object)(object)val2 != (Object)null) { val2.MagazineSize = NACops.officerConfig.WeaponMagSize; val2.MaxFireRate = NACops.officerConfig.WeaponFireRate; ((AvatarWeapon)val2).CooldownDuration = NACops.officerConfig.WeaponFireRate; ((AvatarWeapon)val2).MaxUseRange = NACops.officerConfig.WeaponMaxRange; val2.ReloadTime = NACops.officerConfig.WeaponReloadTime; val2.RaiseTime = NACops.officerConfig.WeaponRaiseTime; val2.HitChance_MaxRange = NACops.officerConfig.WeaponHitChanceMax; val2.HitChance_MinRange = NACops.officerConfig.WeaponHitChanceMin; val2.Damage = NACops.officerConfig.WeaponDamage; val2.AimTime_Max = NACops.officerConfig.WeaponAimTimeMax; val2.AimTime_Min = NACops.officerConfig.WeaponAimTimeMin; } hasOverridenWeaponPrefab = true; } if (hasInstantiatedRangedWeapon && (Object)(object)rangedWeaponPrefab != (Object)null) { officer.GunPrefab = rangedWeaponPrefab; string text2 = ""; Vector3 zero = Vector3.zero; Vector3 zero2 = Vector3.zero; Vector3 zero3 = Vector3.zero; switch (NACops.officerConfig.RangedWeapon.ToLower()) { case "goldenm1911": text2 = "M1911"; ((Vector3)(ref zero))..ctor(0.008f, 0.008f, 0.008f); ((Vector3)(ref zero2))..ctor(0.0016f, -0.0001f, -0.0007f); ((Vector3)(ref zero3))..ctor(290f, 330f, 220f); break; case "revolver": text2 = "Revolver_"; ((Vector3)(ref zero))..ctor(0.008f, 0.008f, 0.008f); ((Vector3)(ref zero2))..ctor(0.0016f, -0.0001f, -0.0008f); ((Vector3)(ref zero3))..ctor(90f, 10f, 0f); break; case "shotgun": text2 = "Shotgun"; ((Vector3)(ref zero))..ctor(0.008f, 0.008f, 0.008f); ((Vector3)(ref zero2))..ctor(0.0016f, -0.0005f, -0.0005f); ((Vector3)(ref zero3))..ctor(80f, 150f, 150f); break; } Transform obj2 = ((Component)rangedWeaponPrefab).transform.Find(text2); if ((Object)(object)obj2 == (Object)null) { DebugModule.Log("Failed to instantiate belt gun model! Missing prefab gun model transform object at " + TransformUtilities.GetScenePath(((Component)rangedWeaponPrefab).transform) + " / " + text2, "SetOfficers"); } GameObject val3 = Object.Instantiate(((Component)obj2).gameObject); val3.transform.parent = ((Component)officer.belt).transform.GetChild(0); val3.transform.localScale = zero; val3.transform.SetLocalPositionAndRotation(zero2, Quaternion.Euler(zero3)); officer.belt.GunObject.SetActive(false); officer.belt.GunObject = val3; if (!val3.gameObject.activeSelf) { val3.gameObject.SetActive(true); } } if (NACops.officerConfig.OverrideTaser && !hasOverridenTaserPrefab) { DebugModule.Log("Overriding taser prefab", "SetOfficers"); AvatarEquippable taserPrefab = officer.TaserPrefab; AvatarRangedWeapon val4 = (AvatarRangedWeapon)(object)((taserPrefab is AvatarRangedWeapon) ? taserPrefab : null); if ((Object)(object)val4 != (Object)null) { val4.MaxFireRate = NACops.officerConfig.TaserFireRate; ((AvatarWeapon)val4).CooldownDuration = NACops.officerConfig.TaserFireRate; ((AvatarWeapon)val4).MaxUseRange = NACops.officerConfig.TaserMaxRange; val4.ReloadTime = NACops.officerConfig.TaserReloadTime; val4.RaiseTime = NACops.officerConfig.TaserRaiseTime; val4.HitChance_MaxRange = NACops.officerConfig.TaserHitChanceMax; val4.HitChance_MinRange = NACops.officerConfig.TaserHitChanceMin; val4.Damage = NACops.officerConfig.TaserDamage; val4.AimTime_Max = NACops.officerConfig.TaserAimTimeMax; val4.AimTime_Min = NACops.officerConfig.TaserAimTimeMin; } DebugModule.Log(" Overridden Taser", "SetOfficers"); hasOverridenTaserPrefab = true; } if (!NACops.officerConfig.OverrideVision) { continue; } ((NPC)officer).Awareness.VisionCone.RangeMultiplier = NACops.officerConfig.VisionRangeMultiplier; PoliceOfficer obj3 = officer; ((NPC)obj3).onExitVehicle = (Action)Delegate.Combine(((NPC)obj3).onExitVehicle, new Action(OfficerExitedVehicle)); foreach (KeyValuePair> stateSetting in ((NPC)officer).Awareness.VisionCone.stateSettings) { foreach (KeyValuePair item in ((NPC)officer).Awareness.VisionCone.stateSettings[stateSetting.Key]) { if ((int)item.Key != 0) { if (NACops.officerConfig.VisionSpeed.TryGetValue(((object)item.Key/*cast due to .constrained prefix*/).ToString(), out var value)) { float noticeTimeMultiplier = value / 0.2f; ((NPC)officer).Awareness.VisionCone.stateSettings[stateSetting.Key][item.Key].NoticeTimeMultiplier = noticeTimeMultiplier; } else { DebugModule.Log("Failed to find matching state container entry from config vision state settings: " + ((object)item.Key/*cast due to .constrained prefix*/).ToString(), "SetOfficers"); } } } } DebugModule.Log(" Overridden Vision", "SetOfficers"); void OfficerExitedVehicle(LandVehicle _) { MelonCoroutines.Start(ResetVisionRange(officer)); } } DebugModule.Log("Officer properties complete", "SetOfficers"); } public static IEnumerator ResetVisionRange(PoliceOfficer offc) { yield return NACops.Wait05; if (NACops.registered) { ((NPC)offc).Awareness.VisionCone.RangeMultiplier = NACops.officerConfig.VisionRangeMultiplier; } } } public static class RacistOfficers { public static IEnumerator EvaluateOfficersVision() { if (!NACops.networkManager.IsServer) { yield break; } DebugModule.Log("Racist officers enabled", "EvaluateOfficersVision"); List blackPlayers = new List(); foreach (Player player2 in Player.PlayerList) { if (!player2.Avatar.IsWhite()) { blackPlayers.Add(player2); } } if (blackPlayers.Count == 0) { yield break; } while (NACops.registered) { yield return NACops.Wait2; if (!NACops.registered) { break; } if (!NACops.currentConfig.RacistCops) { continue; } foreach (Player player in blackPlayers) { if ((Object)(object)player.CurrentProperty != (Object)null) { continue; } bool flag = false; foreach (PoliceOfficer allActiveOfficer in NACops.allActiveOfficers) { if (!((NPC)allActiveOfficer).Health.IsDead && !((NPC)allActiveOfficer).Health.IsKnockedOut && ((NPC)allActiveOfficer).Awareness.VisionCone.IsPlayerVisible(player)) { flag = true; break; } } if (!flag) { continue; } foreach (PoliceOfficer officer in NACops.allActiveOfficers) { yield return NACops.Wait05; if (!NACops.registered) { yield break; } if ((!Object.op_Implicit((Object)(object)((NPC)officer).Behaviour.activeBehaviour) || (!((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.PursuitBehaviour) && !((Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.VehiclePursuitBehaviour))) && Vector3.Distance(((NPC)officer).CenterPoint, player.CenterPointTransform.position) < 80f) { if (officer.PursuitBehaviour.arrestingEnabled) { NACops.coros.Add(MelonCoroutines.Start(TempDisableArrest(officer))); } if ((int)player.CrimeData.CurrentPursuitLevel != 4) { player.CrimeData.SetPursuitLevel((EPursuitLevel)4); } if (((NPC)officer).isInBuilding) { ((NPC)officer).ExitBuilding((NPCEnterableBuilding)(object)PoliceStation.PoliceStations[0]); } if (!((NPC)officer).IsInVehicle && (Object)(object)((NPC)officer).Behaviour.activeBehaviour != (Object)(object)officer.PursuitBehaviour) { officer.BeginFootPursuit(player.PlayerCode); } else if (((NPC)officer).IsInVehicle && (Object)(object)((NPC)officer).Behaviour.activeBehaviour != (Object)(object)officer.VehiclePursuitBehaviour) { officer.VehiclePursuitBehaviour.AssignTarget(player); officer.VehiclePursuitBehaviour.StartPursuit(); } } } yield return NACops.Wait30; } } } public static IEnumerator TempDisableArrest(PoliceOfficer offc) { yield return NACops.Wait30; if (NACops.registered) { offc.PursuitBehaviour.arrestingEnabled = true; yield return false; } } } public static class PrivateInvestigator { public static readonly List randomMaleNames = new List { "Danny", "Andrew", "Christopher", "Davey", "Jonathan", "Justin" }; public static readonly List randomFemaleNames = new List { "Sophie", "Katie", "Holly", "Lucy", "Emily", "Charlotte" }; public static readonly List PIdisabledVisualStates = new List { (EVisualState)9, (EVisualState)2, (EVisualState)5, (EVisualState)7, (EVisualState)1 }; public static readonly Dictionary> PropertyPreferPositions = new Dictionary> { { "motelroom", new List<(Vector3, Vector3)> { (new Vector3(-66.52f, 1.69f, 86.2f), new Vector3(-68.7f, 1.69f, 85f)) } }, { "sweatshop", new List<(Vector3, Vector3)> { (new Vector3(-64.54f, 151.2f), new Vector3(-61.9f, -3.04f, 149.2f)) } }, { "bungalow", new List<(Vector3, Vector3)> { (new Vector3(-177.3f, -3.04f, 110.5f), new Vector3(-175.1f, -2.74f, 112.1f)) } }, { "storageunit", new List<(Vector3, Vector3)> { (new Vector3(-2.2f, 1.07f, 94.7f), new Vector3(-2.9f, 1.07f, 95.9f)) } }, { "dockswarehouse", new List<(Vector3, Vector3)> { (new Vector3(-82.2f, -1.5f, -36.2f), new Vector3(-84f, -1.5f, -37.7f)), (new Vector3(-79f, -1.5f, -57.7f), new Vector3(-83.9f, -1.3f, -55.4f)) } }, { "barn", new List<(Vector3, Vector3)> { (new Vector3(174.5f, 0.98f, -15.6f), new Vector3(176.4f, 0.97f, -13.7f)), (new Vector3(173.4f, 0.98f, -4.6f), new Vector3(177.5f, 0.96f, -6.6f)) } }, { "manor", new List<(Vector3, Vector3)> { (new Vector3(151.9f, 10.98f, -61.1f), new Vector3(153.8f, 11.5f, -60.7f)), (new Vector3(175.4f, 10.96f, -52.7f), new Vector3(173f, 11.5f, -53.3f)) } } }; public static float maxInvestigationTime = 240f; private static float minWait; private static float maxWait; private static List randWaits; private static WaitForSeconds currentAwait; private static int playerLayer = -1; private static int obstacleLayerMask = -1; public static bool investigatorActive = false; public static bool isTakingPhotos = false; public static AudioClip cameraZapClip; public static AudioSource PICameraAudio; public static Light PICameraLight; public static LensFlareDataElementSRP PILensFlare; public static LensFlareDataSRP scriptableFlareData; public unsafe static IEnumerator RunInvestigator() { DebugModule.Log("Private Investigator evaluating", "RunInvestigator"); playerLayer = LayerMask.NameToLayer("Player"); obstacleLayerMask = LayerMask.GetMask(new string[3] { "Terrain", "Default", "Vehicle" }); AvatarEquippable taserPrefab = PoliceOfficer.Officers[0].TaserPrefab; AvatarRangedWeapon val = (AvatarRangedWeapon)(object)((taserPrefab is AvatarRangedWeapon) ? taserPrefab : null); if ((Object)(object)val != (Object)null) { AudioSourceController fireSound = val.FireSound; RandomizedAudioSourceController val2 = (RandomizedAudioSourceController)(object)((fireSound is RandomizedAudioSourceController) ? fireSound : null); if ((Object)(object)val2 != (Object)null) { cameraZapClip = val2.Clips[0]; } } (float min, float max) tuple = ThresholdUtils.Evaluate(NACops.thresholdConfig.PIFrequency, (int)NetworkSingleton.Instance.LifetimeEarnings); minWait = tuple.min; maxWait = tuple.max; randWaits = new List { new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)), new WaitForSeconds(Random.Range(minWait, maxWait)) }; while (true) { currentAwait = randWaits[Random.Range(0, randWaits.Count)]; yield return currentAwait; if (!NACops.registered) { break; } if (!NACops.currentConfig.PrivateInvestigator) { continue; } var (num, num2) = ThresholdUtils.Evaluate(NACops.thresholdConfig.PIFrequency, NetworkSingleton.Instance.ElapsedDays); if (num != minWait || num2 != maxWait) { randWaits.Clear(); for (int i = 0; i < 3; i++) { randWaits.Add(new WaitForSeconds(Random.Range(num, num2))); } minWait = num; maxWait = num2; } DebugModule.Log("PI Evaluate", "RunInvestigator"); EDay currentDay = NetworkSingleton.Instance.CurrentDay; if (!((object)(*(EDay*)(¤tDay))/*cast due to .constrained prefix*/).ToString().Contains("Saturday") && !((object)(*(EDay*)(¤tDay))/*cast due to .constrained prefix*/).ToString().Contains("Sunday") && !investigatorActive) { DebugModule.Log("PI Proceed", "RunInvestigator"); NACops.coros.Add(MelonCoroutines.Start(HandlePIMonitor())); } } } public static bool IsNearRoadNode(Vector3 pos = default(Vector3)) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) DebugModule.Log("Check road graph", "IsNearRoadNode"); Vector3 zero = Vector3.zero; zero = ((!(pos != default(Vector3))) ? ((Component)CopInitHelper.investigator).transform.position : pos); List closestLinks = NodeLink.GetClosestLinks(zero, 1); float num = 0f; if (closestLinks != null && closestLinks.Count > 0) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(closestLinks[0].Start2D.x, closestLinks[0].midPosition.y, closestLinks[0].Start2D.y); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(closestLinks[0].End2D.x, closestLinks[0].midPosition.y, closestLinks[0].End2D.y); Vector3 closestPointOnFiniteLine = NavigationUtility.GetClosestPointOnFiniteLine(zero, val, val2); num = Vector3.Distance(zero, closestPointOnFiniteLine); DebugModule.Log($"Closest dist: {num} | too close: {num < 3f} ", "IsNearRoadNode"); } return num < 3f; } public static IEnumerator HandlePIMonitor() { investigatorActive = true; ((Component)CopInitHelper.investigator).gameObject.SetActive(true); ((Component)((Component)CopInitHelper.investigator).transform.Find("Avatar")).gameObject.SetActive(true); ((Behaviour)((Component)CopInitHelper.investigator).GetComponent()).enabled = true; if (!((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.PauseMovement(); } ((NPC)CopInitHelper.investigator).Awareness.SetAwarenessActive(true); yield return AvatarUtility.PIAvatar(CopInitHelper.investigator); AvatarUtility.SetVOEmitter((NPC)(object)CopInitHelper.investigator); yield return BaseUtility.AttemptWarp(CopInitHelper.investigator, Player.Local.CenterPointTransform); ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); ((NPC)CopInitHelper.investigator).Movement.SpeedController.AddSpeedControl(new SpeedControl("combat", 5, 0.15f)); float elapsed = 0f; int proximityDelta = 0; int sightedAmount = 0; float maxWarpCd = 15f; float lastWarp = 0f; float timeSinceLastTurn = 0f; bool isMakingCall = false; float phoneHeldInHandSecs = 0f; bool didFinishMakingACall = false; float photosTakenInSecs = 0f; bool didFinishTakingPhotos = false; bool isMovingPrioPos = false; bool isInPrioPos = false; Vector3 prioPos = default(Vector3); Vector3 prioRot = default(Vector3); float timeSpentMovingToPrio = 0f; float timeSinceMonitorReposition = 0f; UnityAction afterAction = null; afterAction = new UnityAction(AfterInvestigation); ((Behaviour)CopInitHelper.investigator.PursuitBehaviour).onBegin.AddListener(afterAction); Dictionary sightedProperties = new Dictionary(); bool shouldWaitRandom = false; Vector3 val = default(Vector3); Vector3 val3 = default(Vector3); Vector3 val6 = default(Vector3); while (true) { if (!shouldWaitRandom) { yield return NACops.Wait2; } else if (shouldWaitRandom) { yield return NACops.Wait5; } if (!NACops.registered) { yield break; } float distance = Vector3.Distance(((Component)CopInitHelper.investigator).transform.position, ((Component)Player.Local).transform.position); float num = Mathf.Lerp(0.1f, 0.55f, Mathf.Clamp01(distance / 80f)); ((NPC)CopInitHelper.investigator).Movement.SpeedController.AddSpeedControl(new SpeedControl("combat", 5, num)); DebugModule.Log($"({distance}m) PI Speed now: " + ((NPC)CopInitHelper.investigator).Movement.SpeedController.ActiveSpeedControl.speed, "HandlePIMonitor"); if (!CanPIProceed(elapsed, distance)) { break; } float num2 = 2f; if (shouldWaitRandom) { num2 = 5f; shouldWaitRandom = false; } lastWarp += num2; elapsed += num2; if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { timeSinceLastTurn += num2; } if (isMakingCall) { phoneHeldInHandSecs += num2; } if (isTakingPhotos) { photosTakenInSecs += num2; } if (distance <= 26f && !isMakingCall && !isTakingPhotos && !isMovingPrioPos) { timeSinceMonitorReposition += num2; } if (isMovingPrioPos) { timeSpentMovingToPrio += num2; } if (didFinishMakingACall) { didFinishMakingACall = false; } if (didFinishTakingPhotos) { didFinishTakingPhotos = false; } bool canSeePlayerCurrently; if (((Behaviour)((NPC)CopInitHelper.investigator).Awareness.VisionCone).enabled && ((NPC)CopInitHelper.investigator).Awareness.VisionCone.IsPlayerVisible(Player.Local)) { canSeePlayerCurrently = true; sightedAmount++; } else { canSeePlayerCurrently = false; } if (isMovingPrioPos) { DebugModule.Log("Move to Prio pos!", "HandlePIMonitor"); if (timeSpentMovingToPrio >= 20f) { isInPrioPos = false; isMovingPrioPos = false; timeSpentMovingToPrio = 0f; } else if (((NPC)CopInitHelper.investigator).Movement.HasDestination && ((NPC)CopInitHelper.investigator).Movement.CurrentDestination == prioPos) { DebugModule.Log("Still travelling to prio pos...", "HandlePIMonitor"); } else if ((!((NPC)CopInitHelper.investigator).Movement.HasDestination || !((NPC)CopInitHelper.investigator).Movement.IsMoving) && Vector3.Distance(((NPC)CopInitHelper.investigator).CenterPoint, prioPos) > 2f) { DebugModule.Log("Reset traverse to the prio pos", "HandlePIMonitor"); ((NPC)CopInitHelper.investigator).Movement.SetDestination(prioPos); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } } else if (!((NPC)CopInitHelper.investigator).Movement.HasDestination && !((NPC)CopInitHelper.investigator).Movement.IsMoving) { if (Vector3.Distance(((NPC)CopInitHelper.investigator).CenterPoint, prioPos) < 1.85f) { DebugModule.Log("Now in priority position!", "HandlePIMonitor"); ((NPC)CopInitHelper.investigator).Movement.FacePoint(prioRot, 0.5f); isInPrioPos = true; isMovingPrioPos = false; timeSpentMovingToPrio = 0f; DebugModule.Log("Start taking photos", "HandlePIMonitor"); isTakingPhotos = true; MelonCoroutines.Start(StartTakePhotos()); } else { DebugModule.Log("Not nearby prio pos!", "HandlePIMonitor"); } } continue; } if (isMakingCall) { DebugModule.Log("Attending call...", "HandlePIMonitor"); proximityDelta++; if (phoneHeldInHandSecs >= Random.Range(10f, 20f) || distance > 35f) { DebugModule.Log("End taking a call", "HandlePIMonitor"); didFinishMakingACall = true; isMakingCall = false; ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, string.Empty); phoneHeldInHandSecs = 0f; } else if (phoneHeldInHandSecs <= 5f) { ((NPC)CopInitHelper.investigator).PlayVO((EVOLineType)1, false); } else { int num3 = Random.Range(0, 4); if (Random.Range(0, 4) == 0) { switch (num3) { case 0: ((NPC)CopInitHelper.investigator).PlayVO((EVOLineType)11, false); break; case 1: ((NPC)CopInitHelper.investigator).PlayVO((EVOLineType)14, false); break; case 2: ((NPC)CopInitHelper.investigator).PlayVO((EVOLineType)17, false); break; case 3: ((NPC)CopInitHelper.investigator).PlayVO((EVOLineType)6, false); break; } } } if (isMakingCall) { continue; } } if (isTakingPhotos) { DebugModule.Log("Taking video...", "HandlePIMonitor"); sightedAmount++; if (!((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.PauseMovement(); } if (isInPrioPos) { ((NPC)CopInitHelper.investigator).Movement.FacePoint(prioRot, 2f); if ((Object)(object)Player.Local.CurrentProperty != (Object)null && distance < 26f) { DebugModule.Log("++Evidence!", "HandlePIMonitor"); if (sightedProperties.ContainsKey(Player.Local.CurrentProperty.PropertyCode)) { sightedProperties[Player.Local.CurrentProperty.PropertyCode]++; } else { sightedProperties.Add(Player.Local.CurrentProperty.PropertyCode, 1); } } } else { ((NPC)CopInitHelper.investigator).Movement.FacePoint(((Component)Player.Local).transform.position, 2f); } if (Random.Range(0, 3) == 0) { MelonCoroutines.Start(SnapPhotoSimulated()); } float num4 = (isInPrioPos ? Random.Range(20f, 40f) : Random.Range(12f, 20f)); if (photosTakenInSecs >= num4 || distance > 35f) { DebugModule.Log("End taking Photos", "HandlePIMonitor"); isTakingPhotos = false; didFinishTakingPhotos = true; ((NPC)CopInitHelper.investigator).Avatar.Animation.SetBool("UseSprayCan", false); yield return NACops.Wait05; ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, string.Empty); Object.DestroyImmediate((Object)(object)scriptableFlareData); PICameraAudio = null; PICameraLight = null; PILensFlare = null; scriptableFlareData = null; ((NPC)CopInitHelper.investigator).Avatar.LookController.OverrideIKWeight(0.2f); photosTakenInSecs = 0f; if (isInPrioPos) { isInPrioPos = false; prioPos = default(Vector3); prioRot = default(Vector3); } } if (isTakingPhotos) { continue; } } if (distance >= 80f && distance < 120f) { DebugModule.Log("PI Should Warp - dist " + distance, "HandlePIMonitor"); if (lastWarp < maxWarpCd) { if (!((NPC)CopInitHelper.investigator).Movement.HasDestination) { ((NPC)CopInitHelper.investigator).Movement.GetClosestReachablePoint(Player.Local.CenterPointTransform.position, ref val); if (val != Vector3.zero) { ((NPC)CopInitHelper.investigator).Movement.SetDestination(val); } } } else { DebugModule.Log("PI Try Warp - dist " + distance, "HandlePIMonitor"); ((NPC)CopInitHelper.investigator).Movement.PauseMovement(); yield return BaseUtility.AttemptWarp(CopInitHelper.investigator, Player.Local.CenterPointTransform); ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); DebugModule.Log("PI New dist " + distance, "HandlePIMonitor"); lastWarp = 0f; } } else if (distance >= 26f && distance < 80f) { Vector3 val2 = SampleNearby(Player.Local.CenterPointTransform.position); ((NPC)CopInitHelper.investigator).Movement.GetClosestReachablePoint(val2, ref val3); if (val3 == Vector3.zero || IsNearRoadNode(val3)) { continue; } _ = Vector3.zero; Vector3 val4 = ((!((NPC)CopInitHelper.investigator).Movement.HasDestination) ? ((NPC)CopInitHelper.investigator).CenterPoint : ((NPC)CopInitHelper.investigator).Movement.CurrentDestination); float num5 = Vector3.Distance(val4, Player.Local.CenterPointTransform.position); float num6 = Vector3.Distance(val3, Player.Local.CenterPointTransform.position); bool flag = num5 > num6 && num5 - num6 > 8f; if (distance > 55f) { DebugModule.Log("PI Traverse - dist " + distance, "HandlePIMonitor"); if (((NPC)CopInitHelper.investigator).Movement.IsPaused || !((NPC)CopInitHelper.investigator).Movement.HasDestination) { ((NPC)CopInitHelper.investigator).Movement.SetDestination(val3); ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } else if (flag) { ((NPC)CopInitHelper.investigator).Movement.SetDestination(val3); } shouldWaitRandom = true; continue; } bool flag2 = CanSeeFromPosition(val3, Player.Local.CenterPointTransform.position, num6); if ((flag && Random.Range(0, 4) == 0) || !((NPC)CopInitHelper.investigator).Movement.HasDestination || flag2) { DebugModule.Log($"PI Traversing Better Distance:{flag} | noDest: {!((NPC)CopInitHelper.investigator).Movement.HasDestination} | Can See:{flag2}", "HandlePIMonitor"); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } ((NPC)CopInitHelper.investigator).Movement.SetDestination(val3); shouldWaitRandom = Random.Range(0, 2) == 0; } } else { if (!(distance <= 26f)) { continue; } DebugModule.Log("PI Monitoring", "HandlePIMonitor"); bool flag3 = false; if ((canSeePlayerCurrently || (Object)(object)Player.Local.CurrentProperty != (Object)null || (distance <= 8f && Random.Range(0, 3) == 0)) && (!((NPC)CopInitHelper.investigator).Movement.IsPaused || ((NPC)CopInitHelper.investigator).Movement.HasDestination)) { flag3 = Random.Range(0, 5) == 0; if (flag3) { if (!IsNearRoadNode()) { DebugModule.Log("Pause nearby!", "HandlePIMonitor"); ((NPC)CopInitHelper.investigator).Movement.PauseMovement(); } else { DebugModule.Log("Pause: Cant stop near a road node!", "HandlePIMonitor"); flag3 = false; } } } proximityDelta++; if ((Object)(object)Player.Local.CurrentProperty != (Object)null) { if (sightedProperties.ContainsKey(Player.Local.CurrentProperty.PropertyCode)) { sightedProperties[Player.Local.CurrentProperty.PropertyCode]++; } else { sightedProperties.Add(Player.Local.CurrentProperty.PropertyCode, 1); } } if ((Object)(object)Player.Local.CurrentProperty != (Object)null && !flag3 && Random.Range(0, 100) == 0 && PropertyPreferPositions.ContainsKey(Player.Local.CurrentProperty.PropertyCode)) { DebugModule.Log("Start moving priority pos", "HandlePIMonitor"); isMovingPrioPos = true; List<(Vector3, Vector3)> list = PropertyPreferPositions[Player.Local.CurrentProperty.PropertyCode]; (prioPos, prioRot) = list[Random.Range(0, list.Count)]; ((NPC)CopInitHelper.investigator).Movement.SetDestination(prioPos); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } continue; } bool flag4 = false; if (!flag3 && ((Player.Local.IsPointVisibleToPlayer(((NPC)CopInitHelper.investigator).CenterPoint, 12f, 0.1f) && Random.Range(0, 3) == 0) || distance < 6f)) { flag4 = true; DebugModule.Log("reposition now", "HandlePIMonitor"); } shouldWaitRandom = Random.Range(0, 4) == 0; bool flag5 = ((distance > 6f && Random.Range(0, 2) == 0) || timeSinceLastTurn >= 6f) && !((NPC)CopInitHelper.investigator).Movement.IsMoving; if (flag5 && !shouldWaitRandom) { timeSinceLastTurn = 0f; ((NPC)CopInitHelper.investigator).Movement.FacePoint(((Component)Player.Local).transform.position, 0.7f); } else if (flag5 && shouldWaitRandom) { ((NPC)CopInitHelper.investigator).Movement.FacePoint(((Component)Player.Local).transform.position, 1.5f); timeSinceLastTurn = 0f; } if (!flag4 && !((NPC)CopInitHelper.investigator).Movement.IsMoving) { if (!isMakingCall && !isTakingPhotos && !didFinishMakingACall && Random.Range(0, 80) == 0) { DebugModule.Log("Start making a call", "HandlePIMonitor"); isMakingCall = true; ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, ((NPC)CopInitHelper.investigator).Behaviour.CallPoliceBehaviour.PhonePrefab.AssetPath); continue; } if (!isMakingCall && !isTakingPhotos && !didFinishTakingPhotos && Random.Range(0, 100) == 0) { DebugModule.Log("Start taking a video", "HandlePIMonitor"); isTakingPhotos = true; MelonCoroutines.Start(StartTakePhotos()); continue; } } if (!((!canSeePlayerCurrently && ((Object)(object)Player.Local.CurrentProperty == (Object)null || Random.Range(0, 10) == 0)) || flag4)) { continue; } Vector3 val5 = SampleNearby(Player.Local.CenterPointTransform.position); ((NPC)CopInitHelper.investigator).Movement.GetClosestReachablePoint(val5, ref val6); if (val6 == Vector3.zero || IsNearRoadNode(val6)) { continue; } float num7 = Vector3.Distance(val6, Player.Local.CenterPointTransform.position); bool flag6 = CanSeeFromPosition(val6, Player.Local.CenterPointTransform.position, num7); bool flag7 = Player.Local.IsPointVisibleToPlayer(val6, 30f, 0.1f); if ((flag4 && num7 > 4f && (flag7 || Random.Range(0, 4) == 0)) || timeSinceMonitorReposition > 20f) { DebugModule.Log("PI Repositioning", "HandlePIMonitor"); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } ((NPC)CopInitHelper.investigator).Movement.SetDestination(val6); shouldWaitRandom = true; timeSinceMonitorReposition = 0f; } else if (flag6 || (!((NPC)CopInitHelper.investigator).Movement.HasDestination && !((NPC)CopInitHelper.investigator).Movement.IsMoving && Random.Range(0, 10) == 0)) { DebugModule.Log("PI Traversing Better position.", "HandlePIMonitor"); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } ((NPC)CopInitHelper.investigator).Movement.SetDestination(val6); timeSinceMonitorReposition = 0f; } } } if (isMakingCall) { ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, string.Empty); } if (isTakingPhotos) { ((NPC)CopInitHelper.investigator).Avatar.Animation.SetBool("UseSprayCan", false); ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, string.Empty); ((NPC)CopInitHelper.investigator).Avatar.LookController.OverrideIKWeight(0.2f); isTakingPhotos = false; } if (sightedProperties.Count > 0) { lock (NACops.heatConfigLock) { foreach (PropertyHeat item in NACops.heatConfig) { if (sightedProperties.ContainsKey(item.propertyCode)) { EPursuitLevel currentPursuitLevel = Player.Local.CrimeData.CurrentPursuitLevel; int num8 = sightedProperties[item.propertyCode]; float num9 = 1f; switch (currentPursuitLevel - 2) { case 0: num9 = 1.2f; break; case 1: num9 = 1.45f; break; case 2: num9 = 1.7f; break; } if (num8 >= 30 && proximityDelta > 35 && sightedAmount >= 10 && (Object)(object)Player.Local.CurrentProperty != (Object)null && Player.Local.CurrentProperty.PropertyCode == item.propertyCode) { DebugModule.Log("Property heat increased +++", "HandlePIMonitor"); item.propertyHeat += Mathf.RoundToInt(Random.Range(6f, 9f) * num9); } else if (num8 >= 16 && proximityDelta > 20 && sightedAmount >= 10 && (Object)(object)Player.Local.CurrentProperty != (Object)null && Player.Local.CurrentProperty.PropertyCode == item.propertyCode) { item.propertyHeat += Mathf.RoundToInt(Random.Range(4f, 6f) * num9); DebugModule.Log("Property heat increased ++", "HandlePIMonitor"); } else if (item.propertyHeat < 8 && num8 >= 10 && proximityDelta >= 20 && sightedAmount >= 10) { item.propertyHeat += Mathf.RoundToInt(Random.Range(2f, 4f) * num9); DebugModule.Log("Property heat increased +", "HandlePIMonitor"); } else if (item.propertyHeat > 5 && elapsed > 60f && proximityDelta > 20 && sightedAmount >= 8) { item.propertyHeat -= Mathf.RoundToInt(Random.Range(1f, 5f) * num9); DebugModule.Log("Property heat decreased", "HandlePIMonitor"); } } } } } DebugModule.Log("PI Finished", "HandlePIMonitor"); DebugModule.Log("Sighted amnt: " + sightedAmount, "HandlePIMonitor"); DebugModule.Log("Proximity delta: " + proximityDelta, "HandlePIMonitor"); DebugModule.Log("Investigation:", "HandlePIMonitor"); foreach (KeyValuePair item2 in sightedProperties) { DebugModule.Log($"{item2.Key} - Investigation delta: {item2.Value}", "HandlePIMonitor"); } AfterInvestigation(); yield return NACops.Wait30; if (!NACops.registered) { yield break; } DebugModule.Log("Despawning PI", "HandlePIMonitor"); if (!((NPC)CopInitHelper.investigator).IsConscious) { ((NPC)CopInitHelper.investigator).Health.Revive(); } ((NPC)CopInitHelper.investigator).Awareness.SetAwarenessActive(false); ((Component)CopInitHelper.investigator).gameObject.SetActive(false); ((Component)((Component)CopInitHelper.investigator).transform.Find("Avatar")).gameObject.SetActive(false); if (!((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.PauseMovement(); } ((Behaviour)((Component)CopInitHelper.investigator).GetComponent()).enabled = false; try { if (RuntimeImpostor.createdTextures.ContainsKey(CopInitHelper.investigatorID)) { if ((Object)(object)RuntimeImpostor.createdTextures[CopInitHelper.investigatorID] != (Object)null) { Object.Destroy((Object)(object)RuntimeImpostor.createdTextures[CopInitHelper.investigatorID]); } RuntimeImpostor.createdTextures.Remove(CopInitHelper.investigatorID); } } catch (Exception ex) { MelonLogger.Error((object)ex); } isTakingPhotos = false; investigatorActive = false; void AfterInvestigation() { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown if (afterAction != null) { ((Behaviour)CopInitHelper.investigator.PursuitBehaviour).onBegin.RemoveListener(afterAction); ((NPC)CopInitHelper.investigator).Awareness.SetAwarenessActive(false); afterAction = null; if (!((NPC)CopInitHelper.investigator).Health.IsDead && !((NPC)CopInitHelper.investigator).Health.IsKnockedOut) { if (((Behaviour)((NPC)CopInitHelper.investigator).Awareness.VisionCone).enabled) { ((NPC)CopInitHelper.investigator).Awareness.SetAwarenessActive(false); } if ((Object)(object)((NPC)CopInitHelper.investigator).Behaviour.activeBehaviour != (Object)null && ((Object)(object)((NPC)CopInitHelper.investigator).Behaviour.activeBehaviour == (Object)(object)((NPC)CopInitHelper.investigator).Behaviour.CombatBehaviour || (Object)(object)((NPC)CopInitHelper.investigator).Behaviour.activeBehaviour == (Object)(object)CopInitHelper.investigator.PursuitBehaviour)) { ((Behaviour)CopInitHelper.investigator.PursuitBehaviour).Disable(); } ((NPC)CopInitHelper.investigator).Movement.SpeedController.AddSpeedControl(new SpeedControl("combat", 5, 0.85f)); ((NPC)CopInitHelper.investigator).Movement.SetDestination(((NPCEnterableBuilding)PoliceStation.PoliceStations[0]).Doors[0].AccessPoint); if (((NPC)CopInitHelper.investigator).Movement.IsPaused) { ((NPC)CopInitHelper.investigator).Movement.ResumeMovement(); } } } } } public static IEnumerator StartTakePhotos() { DebugModule.Log("Equip phone", "StartTakePhotos"); ((NPC)CopInitHelper.investigator).SetEquippable_Client((NetworkConnection)null, "Avatar/Equippables/Phone_Lowered"); yield return NACops.Wait01; if (NACops.registered) { ((NPC)CopInitHelper.investigator).Avatar.Animation.SetBool("RightArm_HoldPhone_Lowered", false); yield return NACops.Wait01; if (NACops.registered) { ((NPC)CopInitHelper.investigator).Avatar.Animation.SetBool("UseSprayCan", true); ((Component)((NPC)CopInitHelper.investigator).Avatar.CurrentEquippable).transform.localPosition = new Vector3(0.0001f, 0.0009f, 0.0008f); ((Component)((NPC)CopInitHelper.investigator).Avatar.CurrentEquippable).transform.localRotation = Quaternion.Euler(90f, 0f, 0f); DebugModule.Log("Equip done, setup components", "StartTakePhotos"); GameObject val = new GameObject("Sound"); val.transform.SetParent(((Component)((NPC)CopInitHelper.investigator).Avatar.CurrentEquippable).transform); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); PICameraAudio = val.AddComponent(); PICameraAudio.maxDistance = 7f; PICameraAudio.minDistance = 1f; PICameraAudio.pitch = 3f; PICameraAudio.spatialize = true; PICameraAudio.spatialBlend = 1f; PICameraAudio.spread = 0.23f; PICameraAudio.rolloffMode = (AudioRolloffMode)1; PICameraAudio.velocityUpdateMode = (AudioVelocityUpdateMode)2; PICameraAudio.volume = 0.07f; PICameraAudio.clip = cameraZapClip; DebugModule.Log("Camera Light", "StartTakePhotos"); Transform parent = ((Component)((NPC)CopInitHelper.investigator).Avatar.CurrentEquippable).transform.Find("phone/Camera"); GameObject val2 = new GameObject("CamLight"); val2.transform.SetParent(parent); val2.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.Euler(0f, 180f, 0f)); PICameraLight = val2.AddComponent(); PICameraLight.innerSpotAngle = 70f; PICameraLight.intensity = 0f; PICameraLight.range = 12f; PICameraLight.shadows = (LightShadows)2; PICameraLight.spotAngle = 140f; PICameraLight.type = (LightType)0; DebugModule.Log("Lens Flare ", "StartTakePhotos"); LensFlareComponentSRP val3 = val2.AddComponent(); scriptableFlareData = ScriptableObject.CreateInstance(); PILensFlare = new LensFlareDataElementSRP(); PILensFlare.count = 5; PILensFlare.edgeOffset = 1f; PILensFlare.fallOff = 0.3f; PILensFlare.intensityVariation = 0.1f; PILensFlare.localIntensity = 0f; PILensFlare.uniformScale = 0f; PILensFlare.sdfRoundness = 0.3f; PILensFlare.sideCount = 6; PILensFlare.lengthSpread = 3f; PILensFlare.enableRadialDistortion = true; PILensFlare.flareType = (SRPLensFlareType)2; PILensFlare.tint = new Color(1f, 1f, 1f, 0.5f); PILensFlare.sizeXY = new Vector2(5f, 5f); PILensFlare.targetSizeDistortion = new Vector2(12f, 12f); PILensFlare.blendMode = (SRPLensFlareBlendMode)0; scriptableFlareData.elements = (LensFlareDataElementSRP[])(object)new LensFlareDataElementSRP[1] { PILensFlare }; val3.lensFlareData = scriptableFlareData; val3.intensity = 1f; val3.maxAttenuationDistance = 12f; val3.maxAttenuationScale = 3f; val3.useOcclusion = true; val3.volumetricCloudOcclusion = true; val3.scale = 1f; ((NPC)CopInitHelper.investigator).Avatar.LookController.OverrideIKWeight(0.3f); DebugModule.Log("Done Setup", "StartTakePhotos"); } } } public static IEnumerator SnapPhotoSimulated() { if (!((Object)(object)PICameraLight == (Object)null) && PILensFlare != null && !((Object)(object)PICameraAudio == (Object)null)) { DebugModule.Log("Light start", "SnapPhotoSimulated"); float elapsed = 0f; float lightUpTime = 0.2f; float camMaxLight = 2f; float flareMaxIntensity = 3f; float flareMaxScale = 2f; while (elapsed < lightUpTime && NACops.registered && isTakingPhotos) { elapsed += Time.deltaTime; float num = elapsed / lightUpTime; PICameraLight.intensity = Mathf.Lerp(0f, camMaxLight, num * num); PILensFlare.localIntensity = Mathf.Lerp(0f, flareMaxIntensity, num * num); PILensFlare.uniformScale = Mathf.Lerp(0f, flareMaxScale, num * num); yield return NACops.frameEnd; } if (isTakingPhotos) { PICameraAudio.Play(); PICameraLight.intensity = 0f; PILensFlare.localIntensity = 0f; PILensFlare.uniformScale = 0f; } DebugModule.Log("Photo taken", "SnapPhotoSimulated"); } } public static bool CanSeeFromPosition(Vector3 pos, Vector3 target, float distance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Vector3 val = pos + Vector3.up * 1.75f; Vector3 val2 = target - val; RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(val, ((Vector3)(ref val2)).normalized, ref val3, distance + 2f)) { if ((obstacleLayerMask & (1 << ((Component)((RaycastHit)(ref val3)).collider).gameObject.layer)) != 0) { DebugModule.Log("New Destination cannot see", "CanSeeFromPosition"); return false; } if (((Component)((RaycastHit)(ref val3)).collider).gameObject.layer == playerLayer) { DebugModule.Log("New Destination can see", "CanSeeFromPosition"); return true; } } else { DebugModule.Log("No Raycast hits for sightline check", "CanSeeFromPosition"); } return false; } public static bool CanPIProceed(float timeElapsed, float distance) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!((NPC)CopInitHelper.investigator).Movement.CanMove() || timeElapsed >= maxInvestigationTime || (int)Player.Local.CrimeData.CurrentPursuitLevel != 0) { return false; } if (distance >= 120f || !((NPC)CopInitHelper.investigator).Movement.CanGetTo(((Component)Player.Local).transform.position, 120f)) { return false; } return true; } public static Vector3 SampleNearby(Vector3 target) { //IL_006a: 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) float num = Random.Range(6f, 24f); float num2 = Random.Range(6f, 24f); num *= ((Random.Range(0f, 1f) > 0.5f) ? 1f : (-1f)); num2 *= ((Random.Range(0f, 1f) > 0.5f) ? 1f : (-1f)); return target + new Vector3(num, 0f, num2); } } [Serializable] public class PropertyHeat { public string propertyCode; public int propertyHeat; public int daysSinceLastRaid; } [Serializable] public class PropertiesHeatSerialized { public List loadedPropertyHeats = new List(); } public static class RaidPropertyEvent { public enum ERaidType { PropertyRaid, BusinessRaid, Other } public enum EOfficerRaidRole { Undecided, DestroyGrowEquipment, DestroyLabEquipment, SearchContainer } public enum ERaidDestroyType { None, DestroyPot, DestroyShroomBed, DestroyDryingRack, DestroyLabOven, DestroyChemistryStation, DestroyCauldron, DestroyMixing } public class RaidOfficer { public string Name; public PoliceOfficer officer; public EOfficerRaidRole role; public Property targetProperty; public BuildableItem currentTargetObj; public int destroyedItems; public int currentActionIter; } public static readonly List raiderDisabledVisualStates = new List { (EVisualState)1, (EVisualState)5, (EVisualState)7 }; public static readonly int maxSearchAttempts = 8; public static readonly int maxActionIters = 12; public static Sprite m1911Sprite; public static Sprite homeSprite; public static Slider raidSlider; public static TextMeshProUGUI raidText; public static RectTransform fillRt; public static RectTransform handleRt; public static Image sliderFillImage; public static Image homeImage; public static Image handleGunImage; public static CanvasGroup notificationGroup; public static bool raidersHaveSpawned = false; public static bool raidActive = false; private static int raidOfficersAlive = 3; public static List raidOfficerObjIDs = new List(); private static List currentRaidOfficers = new List(); private static List deadRaidOfficers = new List(); private static List officersArrived = new List(); private static bool officersReady = false; private static bool employeesScared = false; private static Dictionary distancesToProperty = new Dictionary(); private static object toBeDestroyedLock = new object(); private static HashSet toBeDestroyed = new HashSet(); private static HashSet searchedContainers = new HashSet(); public static readonly List raidOfficerLines = new List { "We are shutting this business down!", "Get on the ground!", "Hyland Point Police! Drop your weapons!", "We are raiding this property! Do not resist!", "Put your hands in the air!", "We have a cease and desist order!" }; public static void OnDayPassEvaluateRaid() { NACops.coros.Add(MelonCoroutines.Start(WaitDayPass())); } public static IEnumerator WaitDayPass() { yield return NACops.Wait5; if (!NACops.registered) { yield break; } yield return (object)new WaitUntil((Func)(() => !NACops.isSaving && !Singleton.Instance.IsSaving)); if (!NACops.registered) { yield break; } yield return NACops.Wait5; if (!NACops.registered) { yield break; } DebugModule.Log("Sleep ended Evaluate Raid", "WaitDayPass"); lock (NACops.heatConfigLock) { foreach (Property property in Property.OwnedProperties) { PropertyHeat propertyHeat = NACops.heatConfig.Find((PropertyHeat x) => x.propertyCode == property.propertyCode); if (propertyHeat != null) { propertyHeat.daysSinceLastRaid++; if (propertyHeat.propertyHeat > 12) { propertyHeat.propertyHeat--; } } } List currentHeats = new List(NACops.heatConfig); if (currentHeats == null) { DebugModule.Log("Failed to update heats", "WaitDayPass"); yield break; } ListExtensions.Shuffle((IList)currentHeats, -1); string selectedCode = string.Empty; int i; for (i = currentHeats.Count - 1; i >= 0; i--) { if (currentHeats[i].daysSinceLastRaid >= NACops.raidConfig.DaysUntilCanRaid && currentHeats[i].propertyHeat >= NACops.raidConfig.PropertyHeatThreshold) { Property val = Property.OwnedProperties.Find((Property x) => x.PropertyCode == currentHeats[i].propertyCode); if (IsPropertyValidForRaid(val)) { selectedCode = val.propertyCode; NACops.coros.Add(MelonCoroutines.Start(BeginRaidEvent(val))); break; } } } if (selectedCode != string.Empty) { PropertyHeat propertyHeat2 = NACops.heatConfig.Find((PropertyHeat x) => x.propertyCode == selectedCode); if (propertyHeat2 != null) { propertyHeat2.daysSinceLastRaid = 0; propertyHeat2.propertyHeat = 0; } } } yield return null; } public static IEnumerator BeginRaidEvent(Property property) { if (!raidActive) { raidActive = true; yield return MelonCoroutines.Start(SpawnRaidCops(property)); yield return NACops.Wait1; DebugModule.Log($"Sending raid to {property.propertyName} ({property.propertyCode})", "BeginRaidEvent"); NACops.coros.Add(MelonCoroutines.Start(TraverseCurrentToProperty(property))); } else { DebugModule.Log("Raid is already active", "BeginRaidEvent"); } yield return null; } public static void ResetRaidEvent(bool resetUI = false) { raidActive = false; currentRaidOfficers.Clear(); deadRaidOfficers.Clear(); raidOfficersAlive = NACops.raidConfig.RaidCopsCount; officersArrived.Clear(); officersReady = false; employeesScared = false; distancesToProperty.Clear(); raidOfficerObjIDs.Clear(); if (resetUI) { raidText = null; homeSprite = null; m1911Sprite = null; raidSlider = null; fillRt = null; handleRt = null; sliderFillImage = null; homeImage = null; handleGunImage = null; notificationGroup = null; } lock (toBeDestroyedLock) { toBeDestroyed.Clear(); searchedContainers.Clear(); } } public static IEnumerator SpawnRaidCops(Property targetProperty) { for (int i = 0; i < NACops.raidConfig.RaidCopsCount; i++) { GameObject copNet = Object.Instantiate(CopInitHelper.copBaseClone); NetworkObject component = copNet.GetComponent(); PoliceOfficer offc = copNet.gameObject.GetComponent(); offc.AutoDeactivate = false; ((Object)copNet).name = $"NACop_Raider_{i}"; yield return MelonCoroutines.Start(CopInitHelper.InitiateClone(component, NACops.networkManager)); NPC component2 = copNet.gameObject.GetComponent(); component2.NPCData.BasicInfo.ID = $"NACop_Raider_{i}"; component2.NPCData.BasicInfo.FirstName = "Officer"; component2.NPCData.BasicInfo.LastName = ""; component2.NPCData.Inventory.CanBePickpocketed = false; component2.NPCData.WeatherBehaviour.UseUmbrellaChance = 0f; component2.Actions._canUseUmbrella = false; if (!NPCManager.NPCRegistry.Contains(component2)) { NPCManager.NPCRegistry.Add(component2); } else { DebugModule.Log("NPC already registered in NPCRegistry", "SpawnRaidCops"); } NACops.networkManager.ServerManager.Spawn(copNet, (NetworkConnection)null, default(Scene)); copNet.gameObject.SetActive(true); ((Component)((NPC)offc).DialogueHandler).GetComponent().Choices.Clear(); ((Component)copNet.transform.Find("Avatar")).gameObject.SetActive(true); ((Behaviour)copNet.GetComponent()).enabled = true; RaidOfficer item = new RaidOfficer { Name = ((Object)offc).name, officer = offc, role = EOfficerRaidRole.Undecided, targetProperty = targetProperty }; ((NPC)offc).Behaviour.ScheduleManager.DisableSchedule(); ((NPC)offc).Movement.PauseMovement(); ((NPC)offc).Movement.Agent.areaMask = 57; offc.PursuitBehaviour.arrestingEnabled = false; ((NPC)offc).Movement.Warp(((NPCEnterableBuilding)Singleton.Instance.PoliceStation).Doors[0].AccessPoint); NACops.coros.Add(MelonCoroutines.Start(AvatarUtility.SetRaiderAvatar(offc))); currentRaidOfficers.Add(item); ((NPC)offc).NPCData.Health.MaxHealth = NACops.raidConfig.RaiderMaxHealth; ((NPC)offc).Health.Health = NACops.raidConfig.RaiderMaxHealth; ((NPC)offc).Behaviour.CombatBehaviour.SetWeapon(((Object)(object)offc.GunPrefab != (Object)null) ? offc.GunPrefab.AssetPath : string.Empty); AvatarWeapon currentWeapon = ((NPC)offc).Behaviour.CombatBehaviour.currentWeapon; AvatarWeapon obj = ((currentWeapon is AvatarRangedWeapon) ? currentWeapon : null); ((AvatarRangedWeapon)obj).CanShootWhileMoving = true; ((AvatarRangedWeapon)obj).Damage = NACops.raidConfig.RaiderWeaponDmg; obj.CooldownDuration = 0.6f; obj.MinUseRange = 0.1f; ((AvatarRangedWeapon)obj).MaxFireRate = 0.8f; ((NPC)offc).Movement.SpeedController.AddSpeedControl(new SpeedControl("combat", 5, NACops.raidConfig.TraverseToPropertySpeed)); raidOfficerObjIDs.Add(((Object)((Component)((Component)offc).transform.root).gameObject).GetInstanceID()); } AssignRaidOfficerRole(targetProperty); raidOfficersAlive = NACops.raidConfig.RaidCopsCount; } public static void AssignRaidOfficerRole(Property property) { int maxOfficersPerRole = 2 * Mathf.Max(1, Mathf.RoundToInt((float)NACops.raidConfig.RaidCopsCount / 3f)); Dictionary assignedCounts = new Dictionary { { EOfficerRaidRole.SearchContainer, 0 }, { EOfficerRaidRole.DestroyGrowEquipment, 0 }, { EOfficerRaidRole.DestroyLabEquipment, 0 } }; Dictionary totalForRoles = GetTotalForRoles(property); DebugModule.Log("Role Select", "AssignRaidOfficerRole"); foreach (RaidOfficer currentRaidOfficer in currentRaidOfficers) { List list = (from role in assignedCounts where role.Value < maxOfficersPerRole select role.Key).ToList(); if (list == null || list.Count == 0) { DebugModule.Log("All roles have been fulfilled for raid, cant assign role", "AssignRaidOfficerRole"); break; } EOfficerRaidRole eOfficerRaidRole = (currentRaidOfficer.role = (from x in totalForRoles where assignedCounts[x.Key] < maxOfficersPerRole orderby x.Value descending select x).FirstOrDefault().Key); totalForRoles[eOfficerRaidRole] -= 4; assignedCounts[eOfficerRaidRole]++; DebugModule.Log($"Assigned role {eOfficerRaidRole} to {currentRaidOfficer.Name}", "AssignRaidOfficerRole"); } } public unsafe static IEnumerator TraverseCurrentToProperty(Property property) { NACops.coros.Add(MelonCoroutines.Start(RaidNotification(property))); DebugModule.Log("Traverse Raid Cops", "TraverseCurrentToProperty"); float offsetFromCenter = 1.35f; int i = 0; Transform targetLocation = ((!(property.propertyCode == "manor")) ? property.NPCSpawnPoint : ((Component)property).transform.Find("Manor Gate")); Vector3 groupPosition = default(Vector3); foreach (RaidOfficer offc in currentRaidOfficers) { Vector3 val = Vector3.zero; switch (i % 4) { case 0: val = Vector3.forward; break; case 1: val = Vector3.right; break; case 2: val = Vector3.left; break; case 3: val = Vector3.back; break; } ((NPC)offc.officer).Movement.GetClosestReachablePoint(targetLocation.position + val * offsetFromCenter, ref groupPosition); DebugModule.Log(((object)(*(Vector3*)(&groupPosition))/*cast due to .constrained prefix*/).ToString(), "TraverseCurrentToProperty"); yield return NACops.Wait1; if (NACops.registered) { ((NPC)offc.officer).Movement.ObstacleAvoidanceEnabled = true; ((NPC)offc.officer).Movement.Agent.avoidancePriority = 10; ((NPC)offc.officer).Movement.ResumeMovement(); ((NPC)offc.officer).Movement.SetDestination(groupPosition, (Action)null, 4f, 5f); NACops.coros.Add(MelonCoroutines.Start(MonitorTraversal(offc, groupPosition))); i++; continue; } yield break; } yield return null; } public static IEnumerator MonitorTraversal(RaidOfficer offc, Vector3 groupPosition) { //IL_000e: 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) NPCMovement movement = ((NPC)offc.officer).Movement; if (!distancesToProperty.ContainsKey(offc)) { distancesToProperty.Add(offc, Vector3.Distance(movement.FootPosition, groupPosition)); } float maxTraversalTime = 130f; float current = 0f; while (true) { yield return NACops.Wait05; if (!NACops.registered) { break; } current += 0.5f; if (officersArrived.Contains(offc)) { break; } _ = movement.CurrentDestination; if (movement.CurrentDestination == Vector3.zero) { DebugModule.Log("Raid Cop path is failing to V3.zero", "MonitorTraversal"); } if (!CanContinue(offc)) { DebugModule.Log("Officer cant continue while traversal", "MonitorTraversal"); if (distancesToProperty.ContainsKey(offc)) { distancesToProperty.Remove(offc); } break; } if (distancesToProperty.ContainsKey(offc)) { distancesToProperty[offc] = Vector3.Distance(movement.FootPosition, groupPosition); } if (Vector3.Distance(movement.FootPosition, groupPosition) < 5f || current >= maxTraversalTime) { DebugModule.Log("Officer arrived", "MonitorTraversal"); movement.EndSetDestination((WalkResult)4); officersArrived.Add(offc); OnArrivedAtProperty(offc); if (officersArrived.Count >= raidOfficersAlive) { DebugModule.Log("Last Officer arrived", "MonitorTraversal"); } break; } if (!movement.HasDestination && movement.CanMove()) { DebugModule.Log("Officer does not have destination but can continue, reset", "MonitorTraversal"); ((NPC)offc.officer).Movement.SetDestination(groupPosition); if (movement.IsPaused) { movement.ResumeMovement(); } } } } public static void OnArrivedAtProperty(RaidOfficer offc) { NACops.coros.Add(MelonCoroutines.Start(WaitForAllArrived(offc))); } public static IEnumerator WaitForAllArrived(RaidOfficer offc) { yield return NACops.Wait2; if (!NACops.registered) { yield break; } ((NPC)offc.officer).Movement.PauseMovement(); DebugModule.Log("Wait for Arrival", "WaitForAllArrived"); int maxWait = 30; int time = 0; while (NACops.registered) { time++; if (officersArrived.Count >= raidOfficersAlive || time >= maxWait) { break; } if (!CanContinue(offc)) { DebugModule.Log("RaidOfficer died during arrival wait", "WaitForAllArrived"); yield break; } yield return NACops.Wait2; } if (!CanContinue(offc)) { DebugModule.Log("RaidOfficer cant continue after arrival", "WaitForAllArrived"); yield break; } ((NPC)offc.officer).Movement.SpeedController.AddSpeedControl(new SpeedControl("combat", 5, NACops.raidConfig.ClearPropertySpeed)); if (Random.Range(0f, 1f) > 0.8f) { AvatarWeapon currentWeapon = ((NPC)offc.officer).Behaviour.CombatBehaviour.currentWeapon; AvatarRangedWeapon val = (AvatarRangedWeapon)(object)((currentWeapon is AvatarRangedWeapon) ? currentWeapon : null); if ((Object)(object)val != (Object)null) { val.SetIsRaised(true); } } officersReady = true; BeginRoleAction(offc); NACops.coros.Add(MelonCoroutines.Start(LateScareEmployees(offc))); yield return null; } public static IEnumerator LateScareEmployees(RaidOfficer offc) { if (employeesScared) { yield break; } employeesScared = true; yield return NACops.Wait5; if (!NACops.registered || !raidActive) { yield break; } List employees = new List(offc.targetProperty.Employees); if (employees.Count == 0) { yield break; } foreach (Employee employee in employees) { yield return NACops.Wait05; if (NACops.registered && raidActive) { ((NPC)employee).Behaviour.FleeBehaviour.SetPointToFlee(employee.AssignedProperty.EmployeeIdlePoints[0].position); ((NPC)employee).Behaviour.AddEnabledBehaviour((Behaviour)(object)((NPC)employee).Behaviour.FleeBehaviour); continue; } yield break; } yield return NACops.Wait5; yield return NACops.Wait5; if (!NACops.registered || !raidActive) { yield break; } foreach (Employee employee in employees) { yield return NACops.Wait05; if (NACops.registered && raidActive) { ((NPC)employee).Behaviour.FleeBehaviour.SetPointToFlee(employee.AssignedProperty.EmployeeIdlePoints[0].position); ((NPC)employee).Behaviour.AddEnabledBehaviour((Behaviour)(object)((NPC)employee).Behaviour.FleeBehaviour); continue; } yield break; } } public static void BeginRoleAction(RaidOfficer offc) { offc.currentActionIter++; if (offc.currentActionIter >= maxActionIters) { DebugModule.Log("Officer has exhausted action attempts, despawn", offc.Name); if (!deadRaidOfficers.Contains(offc)) { NACops.coros.Add(MelonCoroutines.Start(Despawn(offc))); } return; } if (offc.role == EOfficerRaidRole.Undecided) { DebugModule.Log("Officer has no raid role, despawn", offc.Name); if (!deadRaidOfficers.Contains(offc)) { NACops.coros.Add(MelonCoroutines.Start(Despawn(offc))); } return; } if (offc.destroyedItems >= NACops.raidConfig.MaxDestroyIters) { DebugModule.Log("Officer reached max destroy iters, despawn", offc.Name); if (!deadRaidOfficers.Contains(offc)) { NACops.coros.Add(MelonCoroutines.Start(Despawn(offc))); } return; } if (Random.Range(0f, 1f) > 0.8f) { ((NPC)offc.officer).DialogueHandler.ShowWorldspaceDialogue_5s(raidOfficerLines[Random.Range(0, raidOfficerLines.Count)]); ((NPC)offc.officer).PlayVO((EVOLineType)2, true); } NACops.coros.Add(MelonCoroutines.Start(DestroyEquipment(offc))); } public static IEnumerator DestroyEquipment(RaidOfficer offc) { ERaidDestroyType destroyType = ERaidDestroyType.None; BuildableItem destroyTarget = null; if (offc.role == EOfficerRaidRole.DestroyGrowEquipment) { List buildablesOfType = offc.targetProperty.GetBuildablesOfType(); List buildablesOfType2 = offc.targetProperty.GetBuildablesOfType(); List buildablesOfType3 = offc.targetProperty.GetBuildablesOfType(); if (buildablesOfType != null && buildablesOfType.Count > 0 && buildablesOfType.Count >= buildablesOfType2.Count && buildablesOfType.Count >= buildablesOfType3.Count) { DebugModule.Log("select pots", offc.Name); destroyType = ERaidDestroyType.DestroyPot; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType, containers: false); } else if (buildablesOfType2 != null && buildablesOfType2.Count > 0 && buildablesOfType2.Count >= buildablesOfType.Count && buildablesOfType2.Count >= buildablesOfType3.Count) { DebugModule.Log("select shroombeds", offc.Name); destroyType = ERaidDestroyType.DestroyShroomBed; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType2, containers: false); } else { if (buildablesOfType3 == null || buildablesOfType3.Count <= 0) { DebugModule.Log("no selectable item types left", offc.Name); offc.currentActionIter = maxActionIters; BeginRoleAction(offc); yield break; } DebugModule.Log("select drying racks", offc.Name); destroyType = ERaidDestroyType.DestroyDryingRack; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType3, containers: false); } } else if (offc.role == EOfficerRaidRole.DestroyLabEquipment) { List buildablesOfType4 = offc.targetProperty.GetBuildablesOfType(); List buildablesOfType5 = offc.targetProperty.GetBuildablesOfType(); List buildablesOfType6 = offc.targetProperty.GetBuildablesOfType(); List buildablesOfType7 = offc.targetProperty.GetBuildablesOfType(); if (buildablesOfType4 != null && buildablesOfType4.Count > 0) { DebugModule.Log("select mixing station mk2", offc.Name); destroyType = ERaidDestroyType.DestroyMixing; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType4, containers: false); } else if (buildablesOfType5 != null && buildablesOfType5.Count > 0 && buildablesOfType5.Count >= buildablesOfType6.Count && buildablesOfType5.Count >= buildablesOfType7.Count) { DebugModule.Log("select lab ovens", offc.Name); destroyType = ERaidDestroyType.DestroyLabOven; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType5, containers: false); } else if (buildablesOfType6 != null && buildablesOfType6.Count > 0 && buildablesOfType6.Count >= buildablesOfType5.Count && buildablesOfType6.Count >= buildablesOfType7.Count) { DebugModule.Log("select chem stations", offc.Name); destroyType = ERaidDestroyType.DestroyChemistryStation; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType6, containers: false); } else { if (buildablesOfType7 == null || buildablesOfType7.Count <= 0) { DebugModule.Log("no selectable item types left", offc.Name); offc.currentActionIter = maxActionIters; BeginRoleAction(offc); yield break; } DebugModule.Log("select cauldrons", offc.Name); destroyType = ERaidDestroyType.DestroyCauldron; destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType7, containers: false); } } else if (offc.role == EOfficerRaidRole.SearchContainer) { List buildablesOfType8 = offc.targetProperty.GetBuildablesOfType(); if (buildablesOfType8 == null || buildablesOfType8.Count <= 0) { DebugModule.Log("no selectable item types left", offc.Name); offc.currentActionIter = maxActionIters; BeginRoleAction(offc); yield break; } DebugModule.Log("select storage entities", offc.Name); destroyTarget = RaidPropertyEvent.GetValidBuildable(buildablesOfType8, containers: true); } if ((Object)(object)destroyTarget == (Object)null) { DebugModule.Log("Destroy Target is null after search", offc.Name); yield return NACops.Wait05; if (NACops.registered) { BeginRoleAction(offc); } yield break; } ITransitEntity entity = null; switch (destroyType) { case ERaidDestroyType.DestroyPot: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(Pot t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyShroomBed: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(MushroomBed t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyDryingRack: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(DryingRack t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyLabOven: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(LabOven t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyChemistryStation: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(ChemistryStation t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyCauldron: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(Cauldron t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.DestroyMixing: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(MixingStationMk2 t) { entity = ((Component)t).GetComponent(); }); break; case ERaidDestroyType.None: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(PlaceableStorageEntity t) { entity = ((Component)t).GetComponent(); }); break; } Transform val = null; if (entity != null) { val = NavMeshUtility.GetReachableAccessPoint(entity, (NPC)(object)offc.officer); } int targetInstanceID; Action walkCallback; bool callbackConsumed; if ((Object)(object)val != (Object)null) { DebugModule.Log("Reachable Access Point found", offc.Name); offc.currentTargetObj = destroyTarget; targetInstanceID = ((Object)destroyTarget).GetInstanceID(); DebugModule.Log($"Set {offc.Name} {offc.role} {((Object)destroyTarget).name} ({targetInstanceID})", "DestroyEquipment"); walkCallback = null; callbackConsumed = false; walkCallback = OnTraverseToEntityEnded; if (((NPC)offc.officer).Movement.IsPaused) { ((NPC)offc.officer).Movement.ResumeMovement(); } if (!((NPC)offc.officer).Movement.CanGetTo(val.position, 1f)) { yield return NACops.Wait05; DebugModule.Log("Officer cant pathfind to target position", offc.Name); yield return RemoveToBeDestroyed(destroyTarget, destroyType); BeginRoleAction(offc); } else if (!((NPC)offc.officer).Movement.CanMove()) { yield return NACops.Wait05; DebugModule.Log("Officer cant move!", offc.Name); yield return RemoveToBeDestroyed(destroyTarget, destroyType); BeginRoleAction(offc); } else { ((NPC)offc.officer).Movement.SetDestination(val.position, walkCallback, true, 2f, 1f); NACops.coros.Add(MelonCoroutines.Start(WaitEndSetDestination(offc, IsWalkCallbackConsumed))); } } else { DebugModule.Log("No reachable access point found for " + entity.Name, offc.Name); yield return NACops.Wait05; if (NACops.registered) { BeginRoleAction(offc); } } bool IsWalkCallbackConsumed() { return callbackConsumed; } void OnTraverseToEntityEnded(WalkResult result) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (walkCallback != null && !callbackConsumed) { walkCallback = null; callbackConsumed = true; NACops.coros.Add(MelonCoroutines.Start(WaitRunCallback(offc, result, destroyType, destroyTarget, targetInstanceID))); } else { DebugModule.Log("Walk callback was null when traverse to entity ended!", offc.Name); } } } public static BuildableItem GetValidBuildable(List buildables, bool containers = false) where T : BuildableItem { if (buildables == null || buildables.Count == 0) { DebugModule.Log("Buildables list is null or empty", "GetValidBuildable"); return null; } BuildableItem val = null; int num = 0; bool flag = false; lock (toBeDestroyedLock) { do { num++; if (num >= maxSearchAttempts) { break; } val = (BuildableItem)(object)buildables[Random.Range(0, buildables.Count)]; if ((Object)(object)val == (Object)null || toBeDestroyed.Contains(((Object)val).GetInstanceID())) { continue; } if (!containers) { flag = true; break; } if (containers) { string iD = ((BaseItemInstance)val.ItemInstance).ID; if (iD.IndexOf("safe", StringComparison.OrdinalIgnoreCase) >= 0 || iD.IndexOf("bed", StringComparison.OrdinalIgnoreCase) >= 0 || searchedContainers.Contains(((Object)val).GetInstanceID())) { continue; } if (((PlaceableStorageEntity)((val is PlaceableStorageEntity) ? val : null)).StorageEntity.ItemCount > 0) { flag = true; } } if (!flag) { val = null; } } while (!flag); if ((Object)(object)val != (Object)null && !containers) { toBeDestroyed.Add(((Object)val).GetInstanceID()); } else if ((Object)(object)val != (Object)null && containers) { searchedContainers.Add(((Object)val).GetInstanceID()); } } return val; } public static IEnumerator WaitRunCallback(RaidOfficer offc, WalkResult result, ERaidDestroyType type, BuildableItem destroyTarget, int targetInstanceID) { //IL_000e: 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) yield return NACops.Wait1; if (NACops.registered) { NACops.coros.Add(MelonCoroutines.Start(OnWalkToEntity(offc, result, type, destroyTarget, targetInstanceID))); } } public static IEnumerator OnWalkToEntity(RaidOfficer offc, WalkResult result, ERaidDestroyType type, BuildableItem destroyTarget, int targetInstanceID) { //IL_000e: 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) DebugModule.Log($"Walk to entity Ended: {result}", offc.Name); if ((int)result != 4) { if (!CanContinue(offc)) { DebugModule.Log("Officer interrupted during traverse to entity", "OnWalkToEntity"); RemoveToBeDestroyed(destroyTarget, type); } else { DebugModule.Log("Officer failed traverse and can continue", offc.Name); RemoveToBeDestroyed(destroyTarget, type); BeginRoleAction(offc); } yield break; } yield return NACops.Wait2; if (!CanContinue(offc)) { RemoveToBeDestroyed(destroyTarget, type); DebugModule.Log("Officer cant continue after waiting at entity", offc.Name); yield break; } if ((Object)(object)destroyTarget == (Object)null || destroyTarget.IsDestroyed) { DebugModule.Log($"Destroy Target is null: {(Object)(object)destroyTarget == (Object)null}\nor IsDestroyed: {destroyTarget.IsDestroyed}", offc.Name); BeginRoleAction(offc); yield break; } string name = ((BaseItemInstance)destroyTarget.ItemInstance).Name; switch (type) { case ERaidDestroyType.DestroyPot: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(Pot _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyShroomBed: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(MushroomBed _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyDryingRack: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(DryingRack _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyLabOven: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(LabOven _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyChemistryStation: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(ChemistryStation _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyCauldron: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(Cauldron _) { ResetEntityConfig(_.Configuration); }); break; case ERaidDestroyType.DestroyMixing: RaidPropertyEvent.Casted(destroyTarget, (Action)delegate(MixingStationMk2 _) { ResetEntityConfig(((MixingStation)_).Configuration); }); break; } if (offc.role == EOfficerRaidRole.SearchContainer) { StorageEntity storage = ((PlaceableStorageEntity)((destroyTarget is PlaceableStorageEntity) ? destroyTarget : null)).StorageEntity; if ((Object)(object)storage == (Object)null) { DebugModule.Log("Storage is null after arriving!", offc.Name); BeginRoleAction(offc); yield break; } EAccessSettings originalSettings = storage.AccessSettings; storage.AccessSettings = (EAccessSettings)0; for (int i = 0; i < storage.ItemSlots.Count; i++) { yield return NACops.Wait05; if (!CanContinue(offc)) { storage.AccessSettings = originalSettings; DebugModule.Log("Officer interrupted during storage emptying", offc.Name); yield break; } if (!storage.ItemSlots[i].IsLocked && storage.ItemSlots[i].ItemInstance != null && (int)((BaseItemDefinition)storage.ItemSlots[i].ItemInstance.Definition).legalStatus != 0) { yield return NACops.Wait05; if (!CanContinue(offc)) { storage.AccessSettings = originalSettings; DebugModule.Log("Officer interrupted during storage emptying", offc.Name); yield break; } ((NPC)offc.officer).SetAnimationTrigger("GrabItem"); storage.ItemSlots[i].ClearItemInstanceRequested(); } } storage.AccessSettings = originalSettings; offc.destroyedItems++; offc.currentTargetObj = null; DebugModule.Log($"Succesfully Emptied Storage: {storage.StorageEntityName} | Total: {offc.destroyedItems}", offc.Name); BeginRoleAction(offc); } else if (offc.role != EOfficerRaidRole.Undecided) { ((NPC)offc.officer).SetAnimationTrigger("GrabItem"); DestroyBuiltItem(destroyTarget, targetInstanceID); offc.destroyedItems++; offc.currentTargetObj = null; DebugModule.Log($"Succesfully Destroyed Target: {name} | Total: {offc.destroyedItems}", offc.Name); BeginRoleAction(offc); } } public static IEnumerator WaitEndSetDestination(RaidOfficer offc, Func checkConsumed) { int maxWaitSecs = 15; for (int i = 0; i < maxWaitSecs; i += 5) { yield return NACops.Wait5; if (checkConsumed() || !NACops.registered) { yield break; } } if (!checkConsumed()) { if ((Object)(object)offc.currentTargetObj != (Object)null && Vector3.Distance(((NPC)offc.officer).CenterPoint, ((Component)offc.currentTargetObj).transform.position) < 2f) { ((NPC)offc.officer).Movement.EndSetDestination((WalkResult)4); } else { ((NPC)offc.officer).Movement.EndSetDestination((WalkResult)1); } } } public static void Casted(BuildableItem item, Action callback) where T : BuildableItem { callback((T)(object)((item is T) ? item : null)); } public static void ResetEntityConfig(EntityConfiguration conf) { conf.Reset(); } public static IEnumerator RemoveToBeDestroyed(BuildableItem item, bool containerNotSearched = false) { lock (toBeDestroyedLock) { if ((Object)(object)item != (Object)null) { int instanceID = ((Object)item).GetInstanceID(); if (toBeDestroyed.Contains(instanceID)) { toBeDestroyed.Remove(instanceID); } if (containerNotSearched && searchedContainers.Contains(instanceID)) { searchedContainers.Remove(instanceID); } } } yield break; } public static IEnumerator RemoveToBeDestroyed(BuildableItem item, ERaidDestroyType type = ERaidDestroyType.None) { if (type != ERaidDestroyType.None) { yield return RemoveToBeDestroyed(item, containerNotSearched: false); } else { yield return RemoveToBeDestroyed(item, containerNotSearched: true); } } public static void DestroyBuiltItem(BuildableItem item, int targetInstanceID) { item.Destroy_Server(); } public static bool CanContinue(RaidOfficer offc) { if (!NACops.registered) { return false; } if (((NPC)offc.officer).Health.IsDead || ((NPC)offc.officer).Health.IsKnockedOut) { DebugModule.Log("Cant continue due to being dead", "CanContinue"); if (!deadRaidOfficers.Contains(offc)) { NACops.coros.Add(MelonCoroutines.Start(Despawn(offc))); } return false; } if ((Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour != (Object)null && ((Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour == (Object)(object)((NPC)offc.officer).Behaviour.CombatBehaviour || (Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour == (Object)(object)offc.officer.PursuitBehaviour)) { DebugModule.Log("Cant continue due to combat or crime status", "CanContinue"); if (((NPC)offc.officer).Movement.IsPaused) { ((NPC)offc.officer).Movement.ResumeMovement(); } NACops.coros.Add(MelonCoroutines.Start(WaitCombatEnd(offc))); return false; } return true; } public static IEnumerator Despawn(RaidOfficer offc) { if (offc == null || (Object)(object)offc.officer == (Object)null || (Object)(object)((Component)offc.officer).gameObject == (Object)null || !currentRaidOfficers.Contains(offc)) { DebugModule.Log("Raid Officer already marked for despawn", "Despawn"); yield break; } if (raidOfficersAlive > 0) { raidOfficersAlive--; } deadRaidOfficers.Add(offc); if (((NPC)offc.officer).Movement.CanMove()) { ((NPC)offc.officer).Movement.SetDestination(((NPCEnterableBuilding)PoliceStation.PoliceStations[0]).Doors[0].AccessPoint); } yield return NACops.Wait30; if (!NACops.registered) { yield break; } DebugModule.Log("Despawning " + offc.Name, "Despawn"); NPC component = ((Component)offc.officer).gameObject.GetComponent(); if ((Object)(object)component != (Object)null && NPCManager.NPCRegistry.Contains(component)) { NPCManager.NPCRegistry.Remove(component); } if ((Object)(object)component != (Object)null && (Object)(object)((Component)component).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)component).gameObject); } if (currentRaidOfficers.Contains(offc)) { currentRaidOfficers.Remove(offc); } if (currentRaidOfficers.Count == 0) { DebugModule.Log("Last raid cop despawned", "Despawn"); if (raidActive) { ResetRaidEvent(); } } } public static IEnumerator WaitCombatEnd(RaidOfficer offc) { yield return (object)new WaitUntil((Func)(() => !NACops.registered || offc == null || (Object)(object)offc.officer == (Object)null || ((NPC)offc.officer).Health.IsDead || ((NPC)offc.officer).Health.IsKnockedOut || (Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour == (Object)null || ((Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour != (Object)(object)((NPC)offc.officer).Behaviour.CombatBehaviour && (Object)(object)((NPC)offc.officer).Behaviour.activeBehaviour != (Object)(object)offc.officer.PursuitBehaviour))); if (NACops.registered) { DebugModule.Log("Combat ended or dead, despawn", offc.Name); if (offc != null && !deadRaidOfficers.Contains(offc)) { NACops.coros.Add(MelonCoroutines.Start(Despawn(offc))); } } } public static Dictionary GetTotalForRoles(Property property) { List buildablesOfType = property.GetBuildablesOfType(); List buildablesOfType2 = property.GetBuildablesOfType(); List buildablesOfType3 = property.GetBuildablesOfType(); List buildablesOfType4 = property.GetBuildablesOfType(); List buildablesOfType5 = property.GetBuildablesOfType(); List buildablesOfType6 = property.GetBuildablesOfType(); List buildablesOfType7 = property.GetBuildablesOfType(); List buildablesOfType8 = property.GetBuildablesOfType(); int num = buildablesOfType.Count + buildablesOfType2.Count + buildablesOfType3.Count; int num2 = buildablesOfType4.Count + buildablesOfType5.Count + buildablesOfType6.Count + buildablesOfType7.Count; int count = buildablesOfType8.Count; DebugModule.Log("Total valid raidable in Property: " + (num + num2 + count), "GetTotalForRoles"); DebugModule.Log($"GrowTot: {num} - Pots:{buildablesOfType.Count}, Shroom:{buildablesOfType2.Count}, Drying:{buildablesOfType3.Count}", "GetTotalForRoles"); DebugModule.Log($"LabTot: {num2} - Ovens:{buildablesOfType4.Count}, Chem:{buildablesOfType5.Count}, Cauldron:{buildablesOfType6.Count}, Mix: {buildablesOfType7.Count}", "GetTotalForRoles"); DebugModule.Log($"Storage: {count}", "GetTotalForRoles"); return new Dictionary { { EOfficerRaidRole.DestroyGrowEquipment, num }, { EOfficerRaidRole.DestroyLabEquipment, num2 }, { EOfficerRaidRole.SearchContainer, count } }; } public static bool IsPropertyValidForRaid(Property property) { if (!property.IsOwned) { DebugModule.Log("Cant raid unowned properties", "IsPropertyValidForRaid"); return false; } if ((Object)(object)property.NPCSpawnPoint == (Object)null) { DebugModule.Log("Cant raid property without a spawnpoint", "IsPropertyValidForRaid"); return false; } if (property is Business) { DebugModule.Log("Cant start raid on a business", "IsPropertyValidForRaid"); return false; } Dictionary totalForRoles = GetTotalForRoles(property); int num = 0; int num2 = 0; foreach (KeyValuePair item in totalForRoles) { num += item.Value; if (item.Value > Mathf.Max(2, Mathf.RoundToInt((float)NACops.raidConfig.MaxDestroyIters * 0.5f) * NACops.raidConfig.RaidCopsCount)) { num2++; } } if (num2 < 2 * Mathf.Max(1, Mathf.RoundToInt((float)NACops.raidConfig.RaidCopsCount / 3f))) { DebugModule.Log("Property does not have enough built items for raid", "IsPropertyValidForRaid"); return false; } return true; } public static IEnumerator RaidNotification(Property property) { if ((Object)(object)raidSlider == (Object)null) { HUD val = Object.FindObjectOfType(); GameObject val2 = new GameObject("RaidSlider"); val2.SetActive(false); notificationGroup = val2.AddComponent(); val2.transform.SetParent(((Component)val.canvas).transform, false); raidSlider = val2.AddComponent(); raidSlider.maxValue = 1f; raidSlider.minValue = 0f; RectTransform component = val2.GetComponent(); component.anchoredPosition = new Vector2(0f, 350f); component.anchorMax = new Vector2(0.5f, 0.5f); component.anchorMin = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(600f, 30f); GameObject val3 = new GameObject("Fill", new Type[1] { typeof(Image) }); GameObject val4 = new GameObject("Handle", new Type[1] { typeof(Image) }); GameObject val5 = new GameObject("HomeIcon", new Type[1] { typeof(Image) }); GameObject val6 = new GameObject("Text", new Type[1] { typeof(TextMeshProUGUI) }); val3.transform.SetParent(((Component)raidSlider).transform); val4.transform.SetParent(((Component)raidSlider).transform); val5.transform.SetParent(((Component)raidSlider).transform); val6.transform.SetParent(((Component)raidSlider).transform); fillRt = val3.GetComponent(); raidSlider.fillRect = fillRt; sliderFillImage = val3.GetComponent(); fillRt.anchoredPosition3D = new Vector3(0f, 0f, 0f); fillRt.anchoredPosition = new Vector2(0f, 0f); fillRt.offsetMax = new Vector2(0f, -7.5f); fillRt.offsetMin = new Vector2(0f, 7.5f); fillRt.pivot = new Vector2(0.5f, 0.5f); fillRt.sizeDelta = new Vector2(0f, -15f); handleRt = val4.GetComponent(); raidSlider.handleRect = handleRt; handleGunImage = val4.GetComponent(); handleGunImage.overrideSprite = m1911Sprite; handleRt.anchoredPosition3D = new Vector3(25f, 0f, 0f); handleRt.anchoredPosition = new Vector2(25f, 0f); handleRt.offsetMax = new Vector2(50f, 12.5f); handleRt.offsetMin = new Vector2(0f, -12.5f); handleRt.sizeDelta = new Vector2(50f, 25f); RectTransform component2 = val5.GetComponent(); component2.anchoredPosition = new Vector2(-350f, 0f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.anchorMin = new Vector2(0.5f, 0.5f); component2.offsetMax = new Vector2(-325f, 25f); component2.offsetMin = new Vector2(-375f, -25f); component2.sizeDelta = new Vector2(50f, 50f); homeImage = val5.GetComponent(); homeImage.overrideSprite = homeSprite; RectTransform component3 = val6.GetComponent(); component3.anchoredPosition = new Vector2(0f, 30f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.offsetMax = new Vector2(300f, 55f); component3.offsetMin = new Vector2(-300f, 5f); component3.sizeDelta = new Vector2(600f, 50f); raidText = val6.GetComponent(); ((TMP_Text)raidText).fontSize = 20f; ((TMP_Text)raidText).alignment = (TextAlignmentOptions)258; ((TMP_Text)raidText).horizontalAlignment = (HorizontalAlignmentOptions)2; } raidSlider.value = 1f; ((Graphic)sliderFillImage).color = Color.white; ((TMP_Text)raidText).text = "The police are raiding " + property.PropertyName + "!"; NACops.coros.Add(MelonCoroutines.Start(FadeUI(4f, 2.5f, fadeIn: true))); float originalDistance = Vector3.Distance(((NPC)currentRaidOfficers[0].officer).CenterPoint, currentRaidOfficers[0].targetProperty.NPCSpawnPoint.position); while (true) { yield return NACops.Wait05; if (!NACops.registered) { yield break; } if (officersReady || !raidActive) { break; } fillRt.anchoredPosition = new Vector2(0f, 0f); handleRt.anchoredPosition = new Vector2(25f, 0f); float num = 0f; float num2 = 0f; if (distancesToProperty.Count > 0) { num2 = originalDistance * (float)distancesToProperty.Count; foreach (float value in distancesToProperty.Values) { num += value; } } float num3 = Mathf.Clamp01(num / num2); if (num3 < 0.05f) { raidSlider.value = 0f; ((Graphic)sliderFillImage).color = Color.red; DebugModule.Log("Detected all arrived", "RaidNotification"); NACops.coros.Add(MelonCoroutines.Start(HighlightHomeIcon(homeImage))); NACops.coros.Add(MelonCoroutines.Start(FadeScaleIcon(handleGunImage))); break; } ((Graphic)sliderFillImage).color = new Color(1f, num3, num3); raidSlider.value = num3; } NACops.coros.Add(MelonCoroutines.Start(FadeUI(2f, 2.5f, fadeIn: false))); distancesToProperty.Clear(); } public static IEnumerator HighlightHomeIcon(Image image) { float dur = 2f; float current = 0f; float xOrig = ((Graphic)image).rectTransform.sizeDelta.x; float yOrig = ((Graphic)image).rectTransform.sizeDelta.y; Color origColor = ((Graphic)image).color; while (current < dur) { current += Time.deltaTime; float num = current / dur; ((Graphic)image).color = new Color(Mathf.SmoothStep(origColor.r, 1f, num), Mathf.SmoothStep(origColor.g, 0f, num), Mathf.SmoothStep(origColor.b, 0f, num), Mathf.SmoothStep(origColor.a, 0f, num)); ((Graphic)image).rectTransform.sizeDelta = new Vector2(Mathf.SmoothStep(xOrig, xOrig * 1.5f, num), Mathf.SmoothStep(yOrig, yOrig * 1.5f, num)); yield return null; } yield return NACops.Wait5; if (NACops.registered) { ((Graphic)image).rectTransform.sizeDelta = new Vector2(xOrig, yOrig); ((Graphic)image).color = origColor; } } public static IEnumerator FadeScaleIcon(Image image) { float dur = 1f; float current = 0f; float xOrig = ((Graphic)image).rectTransform.sizeDelta.x; float yOrig = ((Graphic)image).rectTransform.sizeDelta.y; Color origColor = ((Graphic)image).color; while (current < dur) { current += Time.deltaTime; float num = current / dur; ((Graphic)image).color = SetAlpha(((Graphic)image).color, Mathf.SmoothStep(1f, 0f, num)); ((Graphic)image).rectTransform.sizeDelta = new Vector2(Mathf.SmoothStep(xOrig, 0f, num), Mathf.SmoothStep(yOrig, 0f, num)); yield return null; } yield return NACops.Wait5; if (NACops.registered) { ((Graphic)image).rectTransform.sizeDelta = new Vector2(xOrig, yOrig); ((Graphic)image).color = origColor; } } public static Color SetAlpha(Color c, float a) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) return new Color(c.r, c.g, c.b, a); } public static IEnumerator FadeUI(float delayUntilStart, float durInOut, bool fadeIn) { yield return (object)new WaitForSeconds(delayUntilStart); float current = 0f; if (fadeIn) { notificationGroup.alpha = 0f; ((Component)raidSlider).gameObject.SetActive(true); } while (current < durInOut) { current += Time.deltaTime; float num = current / durInOut; if (fadeIn) { notificationGroup.alpha = Mathf.SmoothStep(0f, 1f, num); } else { notificationGroup.alpha = Mathf.SmoothStep(1f, 0f, num); } yield return null; } if (fadeIn) { notificationGroup.alpha = 1f; } else { notificationGroup.alpha = 0f; } yield return NACops.Wait01; if (!fadeIn) { ((Component)raidSlider).gameObject.SetActive(false); notificationGroup.alpha = 1f; } } public static void SetRaidSprite() { ItemInstance defaultInstance = new Func(Registry.GetItem)("m1911").GetDefaultInstance(1); IntegerItemInstance val = (IntegerItemInstance)(object)((defaultInstance is IntegerItemInstance) ? defaultInstance : null); if (val != null) { m1911Sprite = ((BaseItemInstance)val).Icon; } RectTransform iconContainer = Property.Properties[0].PoI.IconContainer; Transform val2 = null; for (int i = 0; i < ((Transform)iconContainer).childCount; i++) { Transform child = ((Transform)iconContainer).GetChild(i); if (((Object)child).name == "Owned") { if (child.childCount > 0) { val2 = child.GetChild(0); } if ((Object)(object)val2 != (Object)null) { homeSprite = ((Component)val2).GetComponent().sprite; break; } } } if ((Object)(object)homeSprite == (Object)null) { DebugModule.Log("Warning: Home sprite not assigned!", "SetRaidSprite"); } } } [HarmonyPatch(typeof(Customer), "SampleOffered")] public static class Customer_SampleOffered_Patch { public static bool Prefix(Customer __instance) { NACops.coros.Add(MelonCoroutines.Start(PreSampleOffered(__instance))); return true; } private static IEnumerator PreSampleOffered(Customer customer) { if (!NACops.currentConfig.SnitchingSamples) { yield break; } yield return NACops.Wait5; if (NACops.registered) { var (num, num2) = ThresholdUtils.Evaluate(NACops.thresholdConfig.SnitchProbability, NetworkSingleton.Instance.ElapsedDays); if (NACops.currentConfig.DebugMode || !(Random.Range(num, num2) < 0.5f)) { DebugModule.Log("Snitching Samples", "PreSampleOffered"); NACops.coros.Add(MelonCoroutines.Start(BaseUtility.LateInvestigation(Player.Local))); NACops.coros.Add(MelonCoroutines.Start(BaseUtility.GiveFalseCharges(1, Player.Local))); } } } } public static class AvatarUtility { public static readonly List skinColors = new List { new Color(0.729412f, 0.596078f, 0.541176f), new Color(0.7768f, 0.5931f, 0.4442f), new Color(0.364705f, 0.298039f, 0.270588f), new Color(0.454902f, 0.372549f, 0.337255f), new Color(0.7768f, 0.5931f, 0.4442f) }; public static readonly List randomFaceLayers = new List { "Avatar/Layers/Face/Face_SmugPout", "Avatar/Layers/Face/Face_SlightSmile", "Avatar/Layers/Face/Face_Neutral", "Avatar/Layers/Face/Face_NeutralPout" }; public static readonly List randomMaleHairLayers = new List { "Avatar/Hair/Balding/Balding", "Avatar/Hair/BuzzCut/BuzzCut", "Avatar/Hair/Peaked/Peaked" }; public static readonly List randomFacialHairLayers = new List { "Avatar/Layers/Face/FacialHair_Swirl", "Avatar/Layers/Face/FacialHair_Goatee" }; public static readonly List randomFemaleHairLayers = new List { "Avatar/Hair/MidFringe/MidFringe", "Avatar/Hair/LowBun/LowBun", "Avatar/Hair/DoubleTopKnot/DoubleTopKnot" }; public static readonly List randomHairColors = new List { new Color(0.141176f, 0.109803f, 0.066666f), new Color(0.666666f, 0.533333f, 0.4f), new Color(0.50196f, 0.501965f, 0.5019607f), new Color(0.294117f, 0.196078f, 0.121568f), new Color(0.6071f, 0.3886f, 0.087f), new Color(0.0804f, 0.0699f, 0.0624f), new Color(0.1278f, 0.1278f, 0.1278f) }; public static Dictionary> PIColorPalettes = new Dictionary> { { 0, new List { new Color(0.396f, 0.396f, 0.396f), new Color(0.326f, 0.578f, 0.896f), new Color(0.151f, 0.151f, 0.151f), new Color(0.613f, 0.493f, 0.344f), new Color(0.613f, 0.493f, 0.344f) } }, { 1, new List { new Color(0.2588f, 0.3647f, 0.549f), new Color(0.7137f, 0.2941f, 0.1568f), Color.black, new Color(0.1372f, 0.1058f, 0.0823f), new Color(0.1372f, 0.1058f, 0.0823f) } }, { 2, new List { new Color(0.258f, 0.364f, 0.549f), new Color(0.326f, 0.578f, 0.896f), Color.black, new Color(0.121f, 0.094f, 0.078f), new Color(0.772f, 0.772f, 0.772f) } }, { 3, new List { new Color(0.615f, 0.478f, 0.313f), Color.black, Color.black, new Color(0.396f, 0.396f, 0.396f), new Color(0.772f, 0.772f, 0.772f) } } }; public static Dictionary instancedSettings = new Dictionary(); public static List maleVOs = new List(); public static List femaleVOs = new List(); public static void SetRandomAvatar(PoliceOfficer offc, ref AvatarSettings createdSettings) { AvatarSettings val = ScriptableObject.CreateInstance(); List accessorySettings = ((NPC)offc).Avatar.CurrentSettings.AccessorySettings; List bodyLayerSettings = ((NPC)offc).Avatar.CurrentSettings.BodyLayerSettings; List faceLayerSettings = SetRandomLook(val); val.AccessorySettings = new List(accessorySettings); val.BodyLayerSettings = new List(bodyLayerSettings); val.FaceLayerSettings = faceLayerSettings; val.FaceLayerSettings = faceLayerSettings; ((NPC)offc).Avatar.LoadAvatarSettings(val); int instanceID = ((Object)((Component)((Component)offc).transform.root).gameObject).GetInstanceID(); if (instancedSettings.ContainsKey(instanceID)) { if ((Object)(object)instancedSettings[instanceID] != (Object)null) { Object.DestroyImmediate((Object)(object)instancedSettings[instanceID]); } instancedSettings[instanceID] = val; } else { instancedSettings.Add(((Object)((Component)((Component)offc).transform.root).gameObject).GetInstanceID(), val); } createdSettings = val; } public static List SetRandomLook(AvatarSettings newSettings) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_0101: 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_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) List list = new List(); for (int i = 0; i < 6; i++) { list.Add(new LayerSetting { layerPath = "", layerTint = Color.white }); } LayerSetting value = list[0]; value.layerPath = randomFaceLayers[Random.Range(0, randomFaceLayers.Count)]; value.layerTint = new Color(0f, 0f, 0f, 1f); list[0] = value; newSettings.Gender = Random.Range(0, 2); if (Random.Range(0f, 1f) > 0.6f && newSettings.Gender < 0.5f) { LayerSetting value2 = list[1]; value2.layerPath = randomFacialHairLayers[Random.Range(0, randomFacialHairLayers.Count)]; value2.layerTint = new Color(0f, 0f, 0f, 1f); list[1] = value2; } LayerSetting value3 = list[3]; value3.layerPath = "Avatar/Layers/Face/EyeShadow"; value3.layerTint = new Color(0f, 0f, 0f, 0.96f); list[3] = value3; if (Random.Range(0f, 1f) > 0.3f) { LayerSetting value4 = list[4]; string text = ""; text = ((!(Random.Range(0f, 1f) > 0.5f)) ? "Avatar/Layers/Face/Freckles" : "Avatar/Layers/Face/OldPersonWrinkles"); value4.layerPath = text; value4.layerTint = new Color(0f, 0f, 0f, 0.55f); list[4] = value4; } newSettings.UseCombinedLayer = false; newSettings.EyebrowScale = Random.Range(1f, 1.1f); newSettings.EyebrowThickness = Random.Range(1f, 1.4f); newSettings.EyebrowRestingHeight = Random.Range(-1f, -1.4f); newSettings.EyeBallTint = new Color(1f, 1f, 1f); newSettings.EyeballMaterialIdentifier = "Default"; newSettings.Height = Random.Range(0.96f, 1.08f); newSettings.HairColor = randomHairColors[Random.Range(0, randomHairColors.Count)]; if (newSettings.Gender < 0.5f) { newSettings.HairPath = randomMaleHairLayers[Random.Range(0, randomMaleHairLayers.Count)]; } else { newSettings.HairPath = randomFemaleHairLayers[Random.Range(0, randomFemaleHairLayers.Count)]; } newSettings.Weight = Random.Range(0.3f, 0.7f); newSettings.PupilDilation = 0.55f; newSettings.RightEyeLidColor = new Color(0.4118f, 0.3216f, 0.2471f); newSettings.LeftEyeLidColor = new Color(0.4118f, 0.3216f, 0.2471f); newSettings.RightEyeRestingState = new EyeLidConfiguration { bottomLidOpen = 0.2719f, topLidOpen = 0.4313f }; newSettings.LeftEyeRestingState = new EyeLidConfiguration { bottomLidOpen = 0.2719f, topLidOpen = 0.4313f }; newSettings.SkinColor = skinColors[Random.Range(0, skinColors.Count)]; return list; } public static IEnumerator GenerateImpostor(PoliceOfficer offc, AvatarSettings settings) { ((Behaviour)((NPC)offc).Movement.Agent).enabled = false; ((Behaviour)((NPC)offc).Movement).enabled = false; Vector3 origPos = ((Component)offc).transform.position; Quaternion origRot = ((Component)offc).transform.rotation; ((Component)offc).transform.SetPositionAndRotation(RuntimeImpostor.targetPosition, Quaternion.Euler(RuntimeImpostor.targetRotationEuler)); ((NPC)offc).Avatar.Animation.SetGrounded(true); yield return NACops.Wait1; ((Behaviour)((NPC)offc).Avatar.Animation).enabled = false; ((NPC)offc).Avatar.Impostor.DisableImpostor(); ((Component)((NPC)offc).Avatar.BodyContainer).gameObject.SetActive(true); yield return NACops.Wait01; Texture2D impostorTexture = RuntimeImpostor.CreateImpostor(offc); ((NPC)offc).Avatar.Impostor.EnableImpostor(); ((Component)offc).transform.SetPositionAndRotation(origPos, origRot); ((Behaviour)((NPC)offc).Avatar.Animation).enabled = true; ((Behaviour)((NPC)offc).Movement.Agent).enabled = true; ((Behaviour)((NPC)offc).Movement).enabled = true; settings.ImpostorTexture = impostorTexture; ((NPC)offc).Avatar.Impostor.SetAvatarSettings(settings); ((NPC)offc).Avatar.Animation.PlayStandUpAnimation(); } public static IEnumerator PIAvatar(PoliceOfficer offc) { AvatarSettings val = ScriptableObject.CreateInstance(); _ = ((NPC)offc).Avatar.CurrentSettings.AccessorySettings; _ = ((NPC)offc).Avatar.CurrentSettings.BodyLayerSettings; List list = new List(); for (int i = 0; i < 6; i++) { list.Add(new LayerSetting { layerPath = "", layerTint = Color.white }); } List list2 = new List(); for (int j = 0; j < 9; j++) { list2.Add(new AccessorySetting { path = "", color = Color.white }); } List list3 = PIColorPalettes[Random.Range(0, PIColorPalettes.Count)]; val.FaceLayerSettings = SetRandomLook(val); bool flag = false; if (val.Gender > 0.5f && Random.Range(0f, 1f) > 0.3f) { flag = true; } else { LayerSetting value = list[2]; value.layerPath = "Avatar/Layers/Bottom/Jeans"; value.layerTint = list3[0]; list[2] = value; } if (Random.Range(0f, 1f) > 0.5f) { LayerSetting value2 = list[3]; value2.layerPath = "Avatar/Layers/Top/RolledButtonUp"; value2.layerTint = list3[1]; list[3] = value2; } else { LayerSetting value3 = list[3]; value3.layerPath = "Avatar/Layers/Top/FlannelButtonUp"; value3.layerTint = list3[1]; list[3] = value3; } AccessorySetting val2 = list2[0]; val2.path = "Avatar/Accessories/Feet/Sneakers/Sneakers"; val2.color = list3[2]; list2[0] = val2; if (Random.Range(0f, 1f) > 0.3f && !flag) { AccessorySetting val3 = list2[2]; val3.path = "Avatar/Accessories/Chest/Blazer/Blazer"; val3.color = list3[3]; list2[2] = val3; } if (Random.Range(0f, 1f) > 0.75f && val.HairPath != "Avatar/Hair/DoubleTopKnot/DoubleTopKnot") { AccessorySetting val4 = list2[3]; val4.path = "Avatar/Accessories/Head/Cap/Cap"; val4.color = list3[4]; list2[3] = val4; } else if (Random.Range(0f, 1f) > 0.9f && val.Gender < 0.5f) { AccessorySetting val5 = list2[3]; val5.path = "Avatar/Accessories/Head/Beanie/Beanie"; val5.color = list3[4]; list2[3] = val5; val.HairPath = ""; } if (flag) { AccessorySetting val6 = list2[4]; val6.path = "Avatar/Accessories/Bottom/MediumSkirt/MediumSkirt"; val6.color = list3[0]; list2[4] = val6; } if (Random.Range(0f, 1f) > 0.8f) { AccessorySetting val7 = list2[5]; val7.path = "Avatar/Accessories/Head/LegendSunglasses/LegendSunglasses"; val7.color = new Color(0.7f, 0.717f, 0.76f); list2[5] = val7; } val.AccessorySettings = list2; val.BodyLayerSettings = list; ((NPC)offc).Avatar.LoadAvatarSettings(val); ((NPC)offc).NPCData.BasicInfo.FirstName = ((val.Gender < 0.5f) ? PrivateInvestigator.randomMaleNames[Random.Range(0, PrivateInvestigator.randomMaleNames.Count)] : PrivateInvestigator.randomFemaleNames[Random.Range(0, PrivateInvestigator.randomFemaleNames.Count)]); int instanceID = ((Object)((Component)((Component)offc).transform.root).gameObject).GetInstanceID(); if (instancedSettings.ContainsKey(instanceID)) { if ((Object)(object)instancedSettings[instanceID] != (Object)null) { Object.DestroyImmediate((Object)(object)instancedSettings[instanceID]); } instancedSettings[instanceID] = val; } else { instancedSettings.Add(((Object)((Component)((Component)offc).transform.root).gameObject).GetInstanceID(), val); } yield return GenerateImpostor(offc, val); } public static IEnumerator SetRaiderAvatar(PoliceOfficer offc) { AvatarSettings val = ScriptableObject.CreateInstance(); _ = ((NPC)offc).Avatar.CurrentSettings.AccessorySettings; _ = ((NPC)offc).Avatar.CurrentSettings.BodyLayerSettings; List list = new List(); for (int i = 0; i < 6; i++) { list.Add(new LayerSetting { layerPath = "", layerTint = Color.white }); } List list2 = new List(); for (int j = 0; j < 9; j++) { list2.Add(new AccessorySetting { path = "", color = Color.white }); } LayerSetting value = list[2]; value.layerPath = "Avatar/Layers/Bottom/Jeans"; value.layerTint = new Color(0.063f, 0.102f, 0.141f); list[2] = value; LayerSetting value2 = list[3]; value2.layerPath = "Avatar/Layers/Top/RolledButtonUp"; value2.layerTint = new Color(0.012f, 0.161f, 0.31f); list[3] = value2; LayerSetting value3 = list[4]; value3.layerPath = "Avatar/Layers/Accessories/FingerlessGloves"; value3.layerTint = new Color(0.29f, 0.313f, 0.349f); list[4] = value3; AccessorySetting val2 = list2[0]; val2.path = "Avatar/Accessories/Feet/CombatBoots/CombatBoots"; val2.color = new Color(0.47f, 0.462f, 0.4f); list2[0] = val2; AccessorySetting val3 = list2[1]; val3.path = "Avatar/Accessories/Waist/PoliceBelt/PoliceBelt"; val3.color = new Color(0.063f, 0.102f, 0.141f); list2[1] = val3; AccessorySetting val4 = list2[2]; val4.path = "Avatar/Accessories/Chest/BulletproofVest/BulletproofVest_Police"; val4.color = new Color(0.063f, 0.102f, 0.141f); list2[2] = val4; AccessorySetting val5 = list2[3]; val5.path = "Avatar/Accessories/Head/PoliceCap/PoliceCap"; val5.color = new Color(0.29f, 0.313f, 0.349f); list2[3] = val5; if (Random.Range(0f, 1f) > 0.5f) { AccessorySetting val6 = list2[5]; val6.path = "Avatar/Accessories/Head/LegendSunglasses/LegendSunglasses"; val6.color = new Color(0.7f, 0.717f, 0.76f); list2[5] = val6; } val.FaceLayerSettings = SetRandomLook(val); val.AccessorySettings = list2; val.BodyLayerSettings = list; ((NPC)offc).Avatar.LoadAvatarSettings(val); yield return null; } public static void SetupVODatabaseRefs() { VODatabase[] array = Resources.FindObjectsOfTypeAll(); foreach (VODatabase val in array) { if (!maleVOs.Contains(val) && !femaleVOs.Contains(val)) { if (((Object)val).name == "Tyler VO" || ((Object)val).name == "Hippie VO" || ((Object)val).name == "Redneck VO") { maleVOs.Add(val); } if (((Object)val).name == "Female1 VO" || ((Object)val).name == "Female2 VO" || ((Object)val).name == "Timid VO") { femaleVOs.Add(val); } } } DebugModule.Log("Finished settting up VODatabase refs", "SetupVODatabaseRefs"); } public static void SetVOEmitter(NPC npc) { if (maleVOs.Count == 0 || femaleVOs.Count == 0) { maleVOs.Clear(); femaleVOs.Clear(); SetupVODatabaseRefs(); } if (npc.Avatar.CurrentSettings.Gender < 0.5f) { npc.VoiceOverEmitter.SetDatabase(maleVOs[Random.Range(0, maleVOs.Count)], true); npc.VoiceOverEmitter.SetDefaultPitch(Random.Range(0.9f, 0.98f)); } else { npc.VoiceOverEmitter.SetDatabase(femaleVOs[Random.Range(0, femaleVOs.Count)], true); npc.VoiceOverEmitter.SetDefaultPitch(Random.Range(1.15f, 1.4f)); } } } public static class BaseUtility { public static List GUIDInUse = new List(); public static IEnumerator AttemptWarp(PoliceOfficer offc, Transform target) { _ = Vector3.zero; int maxWarpAttempts = 10; Vector3 val2 = default(Vector3); for (int i = 0; i < maxWarpAttempts; i++) { yield return NACops.Wait05; if (!NACops.registered) { break; } float num = Random.Range(8f, 30f); float num2 = Random.Range(8f, 30f); num *= ((Random.Range(0f, 1f) > 0.5f) ? 1f : (-1f)); num2 *= ((Random.Range(0f, 1f) > 0.5f) ? 1f : (-1f)); Vector3 val = target.position + new Vector3(num, 0f, num2); ((NPC)offc).Movement.GetClosestReachablePoint(val, ref val2); if (val2 != Vector3.zero && !Player.Local.IsPointVisibleToPlayer(val2, 30f, 5f)) { DebugModule.Log("Warp succeeded", "AttemptWarp"); ((NPC)offc).Movement.Warp(val2); break; } } } public static bool IsStationNearby(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(((Component)PoliceStation.GetClosestPoliceStation(pos)).transform.position, pos) < 20f; } public static IEnumerator GiveFalseCharges(int severity, Player player) { if (NACops.currentConfig.CorruptCops) { switch (severity) { case 1: player.CrimeData.AddCrime((Crime)new DrugTrafficking(), 1); player.CrimeData.AddCrime((Crime)new AttemptingToSell(), 1); player.CrimeData.AddCrime((Crime)new Evading(), 1); break; case 2: player.CrimeData.AddCrime((Crime)new FailureToComply(), 10); player.CrimeData.AddCrime((Crime)new Evading(), 1); break; case 3: player.CrimeData.AddCrime((Crime)new PossessingHighSeverityDrug(), 60); break; } yield return null; } } public static IEnumerator LateInvestigation(Player player) { yield return NACops.Wait1; if (NACops.registered && Singleton.InstanceExists && PoliceStation.PoliceStations.Count != 0 && ((NPCEnterableBuilding)PoliceStation.GetClosestPoliceStation(((Component)player).transform.position)).OccupantCount >= 2) { try { Singleton.Instance.PoliceCalled(player, (Crime)new DrugTrafficking()); } catch (NullReferenceException ex) { MelonLogger.Error("Failed to invoke PoliceCalled status " + ex); } yield return NACops.Wait5; if (NACops.registered) { player.CrimeData.SetPursuitLevel((EPursuitLevel)1); yield return null; } } } public static bool CanProceed(PoliceOfficer officer, Player player, float minDist, bool ignoreVehicle = false) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!ignoreVehicle && ((NPC)officer).IsInVehicle) { return false; } if (((NPC)officer).isInBuilding) { return false; } if (((NPC)officer).Health.IsDead || ((NPC)officer).Health.IsKnockedOut) { return false; } if ((Object)(object)player.CurrentProperty != (Object)null) { return false; } if ((int)player.CrimeData.CurrentPursuitLevel != 0) { return false; } if (!ignoreVehicle && Object.op_Implicit((Object)(object)((NPC)officer).Behaviour.activeBehaviour) && (Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.VehiclePatrolBehaviour) { return false; } if (Object.op_Implicit((Object)(object)((NPC)officer).Behaviour.activeBehaviour) && (Object)(object)((NPC)officer).Behaviour.activeBehaviour == (Object)(object)officer.CheckpointBehaviour) { return false; } if (GUIDInUse.Contains(((NPC)officer).BakedGUID)) { return false; } if (NACops.currentDrugApprehender.Contains(officer)) { return false; } if ((Object)(object)officer == (Object)(object)CopInitHelper.investigator || (Object)(object)officer == (Object)(object)CopInitHelper.buyBustCop) { return false; } if (IsStationNearby(player.CenterPointTransform.position)) { return false; } if (player.CrimeData.BodySearchPending) { return false; } if (Vector3.Distance(((NPC)officer).CenterPoint, player.CenterPointTransform.position) > minDist) { return false; } return true; } } [HarmonyPatch(typeof(PoliceOfficer), "GetNameAddress")] public static class PoliceOfficer_GetNameAddress_Patch { [HarmonyPostfix] public static void Postfix(PoliceOfficer __instance, ref string __result) { if (NACops.currentConfig.PrivateInvestigator && (Object)(object)__instance == (Object)(object)CopInitHelper.investigator) { __result = ((NPC)__instance).NPCData.BasicInfo.FirstName; } } } [HarmonyPatch(typeof(PursuitBehaviour), "OnCurrentWeaponChanged")] public static class PursuitBehaviour_OnCurrentWeaponChanged_Patch { [HarmonyPrefix] public static bool Prefix(PursuitBehaviour __instance, AvatarWeapon weapon) { if (!NACops.currentConfig.PrivateInvestigator) { return true; } if ((Object)(object)__instance.officer.belt == (Object)null) { return false; } return true; } } [HarmonyPatch(typeof(VisionCone), "SetSightableStateEnabled")] public static class VisionCone_SetSightableStateEnabled_Patch { [HarmonyPrefix] public static bool Prefix(VisionCone __instance, ISightable sightable, EVisualState state, ref bool enabled) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)((Component)((Component)__instance).transform.root).gameObject).GetInstanceID(); if (PrivateInvestigator.investigatorActive && instanceID == CopInitHelper.investigatorID) { if (PrivateInvestigator.PIdisabledVisualStates.Contains(state)) { enabled = false; } return true; } if (RaidPropertyEvent.raidActive && RaidPropertyEvent.raidOfficerObjIDs.Contains(instanceID)) { if (RaidPropertyEvent.raiderDisabledVisualStates.Contains(state)) { enabled = false; } return true; } Player val = default(Player); if ((int)state == 2 && ((Component)sightable.NetworkObject).TryGetComponent(ref val) && ((val.CrimeData.MinsSinceLastArrested < 60 && NetworkSingleton.Instance.IsHardCurfewActive) || (Object)(object)val.CurrentProperty != (Object)null)) { enabled = false; } return true; } } [Serializable] public class MinMaxThreshold { public int MinOf { get; set; } public float Min { get; set; } public float Max { get; set; } public MinMaxThreshold(int minOf, float min, float max) { MinOf = minOf; Min = min; Max = max; } } public static class ThresholdUtils { public static (float min, float max) Evaluate(List thresholds, int value) { MinMaxThreshold minMaxThreshold = thresholds[0]; foreach (MinMaxThreshold threshold in thresholds) { if (value >= threshold.MinOf) { minMaxThreshold = threshold; continue; } break; } return (min: minMaxThreshold.Min, max: minMaxThreshold.Max); } } [Serializable] public class ThresholdMappings { public List LethalCopFrequency = new List { new MinMaxThreshold(0, 30f, 60f), new MinMaxThreshold(5, 20f, 60f), new MinMaxThreshold(10, 20f, 50f), new MinMaxThreshold(20, 15f, 40f), new MinMaxThreshold(30, 10f, 30f), new MinMaxThreshold(40, 10f, 20f), new MinMaxThreshold(50, 8f, 18f) }; public List LethalCopRange = new List { new MinMaxThreshold(0, 1f, 3f), new MinMaxThreshold(8000, 1f, 5f), new MinMaxThreshold(30000, 2f, 6f), new MinMaxThreshold(100000, 3f, 8f), new MinMaxThreshold(300000, 4f, 10f), new MinMaxThreshold(600000, 9f, 14f), new MinMaxThreshold(1000000, 10f, 15f) }; public List NearbyCrazyFrequency = new List { new MinMaxThreshold(0, 120f, 400f), new MinMaxThreshold(5, 120f, 350f), new MinMaxThreshold(10, 100f, 200f), new MinMaxThreshold(20, 80f, 100f), new MinMaxThreshold(30, 60f, 100f), new MinMaxThreshold(40, 50f, 80f), new MinMaxThreshold(50, 30f, 80f) }; public List NearbyCrazyRange = new List { new MinMaxThreshold(0, 10f, 20f), new MinMaxThreshold(8000, 10f, 25f), new MinMaxThreshold(30000, 10f, 30f), new MinMaxThreshold(100000, 20f, 35f), new MinMaxThreshold(300000, 20f, 40f), new MinMaxThreshold(500000, 25f, 40f) }; public List PIFrequency = new List { new MinMaxThreshold(0, 600f, 1200f), new MinMaxThreshold(9000, 500f, 1000f), new MinMaxThreshold(30000, 450f, 800f), new MinMaxThreshold(50000, 400f, 800f), new MinMaxThreshold(80000, 300f, 600f), new MinMaxThreshold(300000, 300f, 550f), new MinMaxThreshold(500000, 300f, 550f), new MinMaxThreshold(900000, 300f, 500f), new MinMaxThreshold(1500000, 300f, 500f), new MinMaxThreshold(8000000, 300f, 400f) }; public List SnitchProbability = new List { new MinMaxThreshold(0, 0f, 0.53f), new MinMaxThreshold(5, 0f, 0.65f), new MinMaxThreshold(10, 0f, 0.7f), new MinMaxThreshold(20, 0f, 0.75f), new MinMaxThreshold(30, 0f, 0.85f), new MinMaxThreshold(40, 0f, 0.9f), new MinMaxThreshold(50, 0.05f, 0.95f), new MinMaxThreshold(60, 0.1f, 1f), new MinMaxThreshold(70, 0.15f, 1f), new MinMaxThreshold(80, 0.2f, 1f), new MinMaxThreshold(90, 0.25f, 1f) }; public List BuyBustProbability = new List { new MinMaxThreshold(0, 0f, 1f), new MinMaxThreshold(5, 0f, 0.9f), new MinMaxThreshold(10, 0f, 0.8f), new MinMaxThreshold(15, 0f, 0.75f), new MinMaxThreshold(20, 0f, 0.65f), new MinMaxThreshold(25, 0f, 0.75f), new MinMaxThreshold(30, 0f, 0.6f), new MinMaxThreshold(40, 0f, 0.55f), new MinMaxThreshold(50, 0f, 0.49f) }; } [HarmonyPatch(typeof(PropertyDoorController), "CanPlayerAccess")] public static class PropertyDoorController_CanPlayerAccess_Patch { [HarmonyPostfix] public static void Postfix(PropertyDoorController __instance, ref EDoorSide side, ref bool __result, ref string reason) { if (reason != null && NACops.registered && NACops.officerConfig != null && NACops.officerConfig.CanEnterBuildings && __instance.Property.IsOwned && reason == "Police are nearby!") { __result = true; } } } public static class RuntimeImpostor { private static Vector3 cameraPosition = new Vector3(-1.95f, 501f, 0f); private static Vector3 cameraRotationEuler = new Vector3(0f, 90f, 0f); public static Vector3 targetPosition = new Vector3(0f, 501f, 0f); public static Vector3 targetRotationEuler = new Vector3(0f, 0f, 0f); private static Vector3 impostorLightPos = new Vector3(-5f, 504f, 0f); private static Vector3 impostorLightRot = new Vector3(0f, 0f, 90f); public static Dictionary createdTextures = new Dictionary(); public static Texture2D CreateImpostor(PoliceOfficer officer) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_014b: Expected O, but got Unknown Texture2D val = null; GameObject val2 = new GameObject("TempLight"); val2.transform.SetPositionAndRotation(impostorLightPos, Quaternion.Euler(impostorLightRot)); Light obj = val2.AddComponent(); obj.range = 20f; obj.intensity = 2.2f; GameObject val3 = new GameObject("TempCamera"); val3.transform.SetPositionAndRotation(cameraPosition, Quaternion.Euler(cameraRotationEuler)); Camera val4 = val3.AddComponent(); ((Behaviour)val4).enabled = false; ((Component)val4).tag = "Untagged"; val4.cullingMask = 2049; val4.clearFlags = (CameraClearFlags)2; val4.backgroundColor = new Color(0f, 0f, 0f, 0f); val4.targetTexture = RenderTexture.GetTemporary(64, 64, 24, (RenderTextureFormat)0); val4.Render(); RenderTexture active = RenderTexture.active; RenderTexture.active = val4.targetTexture; val = new Texture2D(((Texture)val4.targetTexture).width, ((Texture)val4.targetTexture).height, (TextureFormat)5, false); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)val4.targetTexture).width, (float)((Texture)val4.targetTexture).height), 0, 0); val.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(val4.targetTexture); val4.targetTexture = null; Object.Destroy((Object)val3); Object.Destroy((Object)val2); createdTextures.Add(((Object)((Component)((Component)officer).transform.root).gameObject).GetInstanceID(), val); return val; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }