Decompiled source of TML Heat v1.0.0

Mods/TMLHeat.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using HarmonyLib;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Doors;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.Employees;
using Il2CppScheduleOne.EntityFramework;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Messaging;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Police;
using Il2CppScheduleOne.Property;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using S1API.Console;
using S1API.Entities;
using S1API.GameTime;
using S1API.Internal.Abstraction;
using S1API.Law;
using S1API.Leveling;
using S1API.Lifecycle;
using S1API.Messaging;
using S1API.Money;
using S1API.PhoneApp;
using S1API.Property;
using S1API.Saveables;
using S1API.UI;
using S1API.Utils;
using TMLHeat;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "TML Heat", "1.0.0", "ThatMaddLadd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TMLHeat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2211298c4493628c0d830ce9e794ecaff23ac061")]
[assembly: AssemblyProduct("TMLHeat")]
[assembly: AssemblyTitle("TMLHeat")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 TMLHeat
{
	internal static class Compat
	{
		public static T? As<T>(this Object? value) where T : Il2CppObjectBase
		{
			if (value == null)
			{
				return default(T);
			}
			return ((Il2CppObjectBase)value).TryCast<T>();
		}
	}
	internal static class Json
	{
		private static readonly JsonSerializerOptions Options = new JsonSerializerOptions
		{
			IncludeFields = true
		};

		public static string Write<T>(T value)
		{
			return JsonSerializer.Serialize(value, Options);
		}

		public static T? Read<T>(string json) where T : class
		{
			try
			{
				return JsonSerializer.Deserialize<T>(json, Options);
			}
			catch (Exception ex) when (((ex is JsonException || ex is NotSupportedException) ? 1 : 0) != 0)
			{
				return null;
			}
		}
	}
	public sealed class Core : MelonMod
	{
		internal static Instance Log { get; private set; }

		public override void OnInitializeMelon()
		{
			Log = ((MelonBase)this).LoggerInstance;
			Settings.Load();
			Lang.Load(Settings.Language);
			GameLifecycle.OnPreLoad += Heat.Detach;
			GameLifecycle.OnLoadComplete += Heat.Attach;
			TimeManager.OnHourPass = (Action)Delegate.Combine(TimeManager.OnHourPass, new Action(Heat.OnHour));
			TimeManager.OnDayPass = (Action)Delegate.Combine(TimeManager.OnDayPass, new Action(Heat.OnDay));
			LevelManager.OnRankUp += delegate
			{
				Heat.CheckUnlock(force: false);
			};
		}

		public override void OnUpdate()
		{
			Sync.Update();
		}

		internal static void Debug(string message)
		{
			if (Settings.DebugLogs)
			{
				Log.Msg(message);
			}
		}
	}
	internal static class Heat
	{
		public const float Max = 100f;

		private const float WarningReset = 10f;

		private const float DealProximity = 8f;

		private const int HistoryDays = 7;

		private static readonly Random Rng = new Random();

		private static readonly HashSet<NPC> Hooked = new HashSet<NPC>();

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

		private static bool _bribeOffered;

		private static bool _forceSting;

		private const int LoyaltyBonusDays = 3;

		private const float TurfEvidenceWeight = 0.25f;

		private const int PatrolSize = 2;

		private static HeatData? Data => HeatSave.Instance?.Data;

		private static bool IsHost => !Sync.IsClient;

		private static int Today => TimeManager.ElapsedDays;

		public static bool Active
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.Unlocked ?? false;
				}
				return Sync.Mirror.Unlocked;
			}
		}

		public static float Value
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.Heat ?? 0f;
				}
				return Sync.Mirror.Heat;
			}
		}

		public static int Trust
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.Trust ?? 0;
				}
				return Sync.Mirror.Trust;
			}
		}

		public static int EvidenceCount
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.Evidence.Count ?? 0;
				}
				return Sync.Mirror.Evidence;
			}
		}

		public static int SnitchingCount
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.SnitchingEmployees.Count ?? 0;
				}
				return Sync.Mirror.Snitching;
			}
		}

		public static int DetainedCount
		{
			get
			{
				if (!Sync.IsClient)
				{
					return Data?.Detained.Count ?? 0;
				}
				return Sync.Mirror.Detained;
			}
		}

		public static bool FavourPending
		{
			get
			{
				if (!Sync.IsClient)
				{
					HeatData? data = Data;
					if (data == null)
					{
						return false;
					}
					return data.FavourDay >= 0;
				}
				return Sync.Mirror.FavourPending;
			}
		}

		public static bool TipOffReady
		{
			get
			{
				if (!Sync.IsClient)
				{
					if (Data != null)
					{
						return Today - Data.LastTipOffDay >= 1;
					}
					return false;
				}
				return Sync.Mirror.TipOffReady;
			}
		}

		public static IReadOnlyList<Informant> Informants
		{
			get
			{
				object obj;
				if (!Sync.IsClient)
				{
					obj = Data?.Informants;
					if (obj == null)
					{
						return new List<Informant>();
					}
				}
				else
				{
					obj = Sync.Mirror.Informants;
				}
				return (IReadOnlyList<Informant>)obj;
			}
		}

		public static IReadOnlyList<ArrestedDealer> HeldDealers
		{
			get
			{
				object obj;
				if (!Sync.IsClient)
				{
					obj = Data?.ArrestedDealers;
					if (obj == null)
					{
						return new List<ArrestedDealer>();
					}
				}
				else
				{
					obj = Sync.Mirror.Arrested;
				}
				return (IReadOnlyList<ArrestedDealer>)obj;
			}
		}

		public static IReadOnlyList<float> History
		{
			get
			{
				object obj;
				if (!Sync.IsClient)
				{
					obj = Data?.History;
					if (obj == null)
					{
						return new List<float>();
					}
				}
				else
				{
					obj = Sync.Mirror.History;
				}
				return (IReadOnlyList<float>)obj;
			}
		}

		public static Raid? KnownRaid
		{
			get
			{
				if (!Sync.IsClient)
				{
					Raid raid = Data?.Raid;
					if (raid == null || !raid.Warned)
					{
						return null;
					}
					return raid;
				}
				return Sync.Mirror.Raid;
			}
		}

		public static float PersonalValue
		{
			get
			{
				Dictionary<string, float> dictionary = (Sync.IsClient ? Sync.Mirror.PlayerHeat : Data?.PlayerHeat);
				if (dictionary == null || !dictionary.TryGetValue(Sync.LocalCode, out var value))
				{
					return 0f;
				}
				return value;
			}
		}

		public static PursuitLevel WantedLevel
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				Player local = Player.Local;
				if (local == null)
				{
					return (PursuitLevel)0;
				}
				return LawManager.GetWantedLevel(local);
			}
		}

		public static float BribeCost => Settings.BribeCostPerLevel * (float)WantedLevel;

		public static float CleanupCost => Settings.CleanerCost * (float)EvidenceCount;

		public static event Action? Changed;

		public static void NotifyChanged()
		{
			Sync.MarkDirty();
			Heat.Changed?.Invoke();
		}

		public static void Detach()
		{
			HeatSave.Instance?.Reset();
			Hooked.Clear();
			LastWitnessed.Clear();
			_bribeOffered = false;
			_forceSting = false;
		}

		public static void HookNpcs()
		{
			int count = Hooked.Count;
			foreach (NPC npc in NPC.All.ToList())
			{
				if (npc is Vance || npc is SwatOfficer || npc.ID.StartsWith("officer") || !Hooked.Add(npc))
				{
					continue;
				}
				npc.OnNoticedDrugDealing += delegate(Player? player)
				{
					OnWitnessed(npc, player);
				};
				if (npc.Customer.IsCustomer)
				{
					npc.Customer.OnDealCompleted += delegate
					{
						OnCustomerDeal(npc);
					};
				}
				if (npc.Dealer.IsDealer)
				{
					HookDealer(npc);
				}
			}
			if (Hooked.Count > count)
			{
				Core.Debug($"Hooked {Hooked.Count - count} NPCs ({Hooked.Count} total).");
			}
		}

		public static void Attach()
		{
			HookNpcs();
			Vance.Refresh();
			HeatApp.ApplyVisibility();
			if (IsHost)
			{
				Raids.Stage();
				CheckUnlock(force: false);
				RestoreHeld();
			}
			Core.Debug(Status());
			NotifyChanged();
		}

		public static void CheckUnlock(bool force)
		{
			//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)
			if (!IsHost)
			{
				return;
			}
			HeatData data = Data;
			if (data != null && !data.Unlocked)
			{
				FullRank val = default(FullRank);
				((FullRank)(ref val))..ctor((Rank)Settings.UnlockRank, Settings.UnlockTier);
				if (force || Settings.UnlockAtStart || !(LevelManager.CurrentRank < val))
				{
					data.Unlocked = true;
					Vance.Notify(Strings.Intro, "", "");
					HeatApp.ApplyVisibility();
					Core.Debug("TML Heat unlocked.");
					NotifyChanged();
				}
			}
		}

		public static void OnHour()
		{
			HeatApp.ApplyVisibility();
			HookNpcs();
			if (!Active)
			{
				return;
			}
			Player local = Player.Local;
			if (local != null)
			{
				CheckBribeOffer(local);
				HeatData data = Data;
				if (data != null && IsHost)
				{
					CheckEvidence(data);
					CheckEmployees(data);
					CheckRaid(data);
					CheckInvestigations(data);
					CheckPatrols(data);
					NotifyChanged();
				}
			}
		}

		public static void OnDay()
		{
			if (!IsHost)
			{
				return;
			}
			HeatData data = Data;
			if (data == null || !data.Unlocked)
			{
				return;
			}
			data.History.Add(data.Heat);
			if (data.History.Count > 7)
			{
				data.History.RemoveAt(0);
			}
			Add(0f - Settings.HeatDecayPerDay);
			foreach (string item in data.PlayerHeat.Keys.ToList())
			{
				AddPersonal(item, 0f - Settings.HeatDecayPerDay);
			}
			data.Evidence.RemoveAll((Evidence e) => Today - e.Day >= Settings.EvidenceLifetimeDays);
			data.Informants.RemoveAll((Informant i) => Today - i.Since >= Settings.InformantQuietDays);
			Add(Settings.InformantHeatPerDay * (float)data.Informants.Count);
			foreach (NPC item2 in NPC.All.ToList())
			{
				if (item2.Customer.IsCustomer && item2.Relationship.IsUnlocked && item2.Relationship.Normalized < Settings.SnitchRelationship && Roll(Settings.SnitchChancePerDay))
				{
					AddInformant(item2);
				}
			}
			ReleaseDetained(data);
			CheckDealers(data);
			CheckUndercover(data);
			CheckFavour(data);
			CheckBetrayal(data);
			ScheduleRaid(data, force: false);
			Core.Debug("New day. " + Status());
			NotifyChanged();
		}

		public static void HandleRequest(string playerCode, string action, string arg)
		{
			if (Active)
			{
				string text = Apply(action, arg, playerCode);
				if (text.Length > 0)
				{
					Vance.Notify(text, playerCode, "");
				}
				Core.Debug($"Handled '{action}' from {playerCode}.");
			}
		}

		public static void ApplyEffect(string effect)
		{
			Player local = Player.Local;
			if (local == null)
			{
				return;
			}
			string[] array = effect.Split(':', 3);
			switch (array[0])
			{
			case "clear":
				LawManager.ClearWantedLevel(local);
				break;
			case "sting":
			case "wanted":
				local.CrimeData.RecordLastKnownPosition(true);
				LawManager.SetWantedLevel(local, (PursuitLevel)2);
				break;
			case "investigate":
				TryInvestigate(local);
				break;
			case "arrest":
			{
				Player local2 = Player.Local;
				if (local2 != null)
				{
					local2.Arrest_Server();
				}
				break;
			}
			case "raid":
			{
				if (array.Length == 3 && int.TryParse(array[1], out var result))
				{
					PropertyWrapper currentProperty = local.CurrentProperty;
					if (((currentProperty != null) ? ((BaseProperty)currentProperty).PropertyName : null) == array[2])
					{
						Hud.Countdown(array[2], result);
					}
				}
				break;
			}
			}
		}

		public static Snapshot Snapshot(List<SyncMessage> messages)
		{
			HeatData heatData = Data ?? new HeatData();
			Snapshot obj = new Snapshot
			{
				Unlocked = heatData.Unlocked,
				Heat = heatData.Heat,
				Trust = heatData.Trust,
				Evidence = heatData.Evidence.Count,
				Snitching = heatData.SnitchingEmployees.Count,
				Detained = heatData.Detained.Count,
				FavourPending = (heatData.FavourDay >= 0),
				TipOffReady = (Today - heatData.LastTipOffDay >= 1),
				Informants = heatData.Informants,
				Arrested = heatData.ArrestedDealers,
				PlayerHeat = heatData.PlayerHeat,
				History = heatData.History
			};
			Raid raid = heatData.Raid;
			obj.Raid = ((raid != null && raid.Warned) ? raid : null);
			obj.Messages = messages;
			return obj;
		}

		public static string Status()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			if (Sync.IsClient)
			{
				return $"Client | {(Active ? "Unlocked" : "Locked")} | Crew heat {Value:0.#} | Your heat {PersonalValue:0.#} | Trust {Trust} | Wanted {WantedLevel}";
			}
			HeatData data = Data;
			if (data == null)
			{
				return "No save loaded.";
			}
			Raid raid = data.Raid;
			string value = ((raid != null) ? $"{raid.Property} day {raid.Day} at {raid.Time:0000}{(raid.Warned ? " (warned)" : "")}" : "none");
			return $"{(data.Unlocked ? "Unlocked" : "Locked")} | Crew heat {data.Heat:0.#} | Your heat {PersonalValue:0.#} | Trust {data.Trust} | Wanted {WantedLevel} | Evidence {data.Evidence.Count} | Informants {List<Informant>(data.Informants, (Informant i) => i.Name)} | Snitching staff {data.SnitchingEmployees.Count} | Detained {List<DetainedEmployee>(data.Detained, (DetainedEmployee d) => $"{d.Name} (day {d.ReleaseDay})")} | Held dealers {List<ArrestedDealer>(data.ArrestedDealers, (ArrestedDealer a) => a.Name + (a.Seized ? " (seized)" : ""))} | Undercover {data.Undercover?.Name ?? "none"} | Favour {((data.FavourDay >= 0) ? "pending" : "none")} | Betray streak {data.BetrayStreak} | Raid {value}{(Raids.Running ? " (in progress)" : "")} | Day {Today} {TimeManager.CurrentTime:0000}";
			static string List<T>(IEnumerable<T> items, Func<T, string> name) where T : notnull
			{
				if (!items.Any())
				{
					return "none";
				}
				return string.Join(", ", items.Select(name));
			}
		}

		public static void SetHeat(float value)
		{
			HeatData data = Data;
			if (data != null)
			{
				data.Heat = Math.Clamp(value, 0f, 100f);
				CheckWarnings(data);
				NotifyChanged();
			}
		}

		public static void SetPersonalHeat(float value)
		{
			HeatData data = Data;
			if (data != null)
			{
				data.PlayerHeat[Sync.LocalCode] = Math.Clamp(value, 0f, 100f);
				NotifyChanged();
			}
		}

		public static void SetTrust(int value)
		{
			HeatData data = Data;
			if (data != null)
			{
				data.Trust = Math.Max(0, value);
				NotifyChanged();
			}
		}

		public static void ForceInformant(string npcId)
		{
			NPC val = (NPC)((npcId.Length > 0) ? ((object)NPC.Get(npcId)) : ((object)RandomNpc((NPC n) => n.Customer.IsCustomer && Informants.All((Informant i) => i.NpcId != n.ID))));
			if (val == null)
			{
				Core.Log.Warning((npcId.Length > 0) ? ("No NPC with id '" + npcId + "'.") : "No customers left to turn.");
				return;
			}
			AddInformant(val);
			NotifyChanged();
		}

		public static void ForceWitness(string npcId)
		{
			NPC val = (NPC)((npcId.Length > 0) ? ((object)NPC.Get(npcId)) : ((object)RandomNpc((NPC n) => !n.ID.StartsWith("officer") && !(n is Vance) && !(n is SwatOfficer))));
			if (val != null)
			{
				Player local = Player.Local;
				if (local != null)
				{
					LastWitnessed.Remove(val.ID);
					OnWitnessed(val, local);
					return;
				}
			}
			Core.Log.Warning("No NPC with id '" + npcId + "'.");
		}

		public static void ForcePlayerDeal()
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			Player local = Player.Local;
			if (local != null)
			{
				RecordDeal(Settings.DealHeat, ((object)local.CurrentRegion/*cast due to .constrained prefix*/).ToString(), local.Name, Sync.LocalCode, local.Position);
			}
		}

		public static void ForceDealerDeal()
		{
			NPC val = RandomNpc((NPC n) => n.Dealer.IsDealer && n.Dealer.IsRecruited()) ?? RandomNpc((NPC n) => n.Dealer.IsDealer);
			if (val == null)
			{
				Core.Log.Warning("No dealers found.");
			}
			else
			{
				OnDealerDeal(val, forced: true);
			}
		}

		public static void AddEvidence(int count)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			Player local = Player.Local;
			if (local != null)
			{
				for (int i = 0; i < count; i++)
				{
					data.Evidence.Add(NewEvidence(((object)local.CurrentRegion/*cast due to .constrained prefix*/).ToString(), Sync.LocalCode, local.Position));
				}
				NotifyChanged();
			}
		}

		public static void FindEvidenceNow()
		{
			HeatData data = Data;
			if (data == null || data.Evidence.Count == 0)
			{
				Core.Log.Warning("No evidence to find.");
				return;
			}
			FoundEvidence(data, data.Evidence[0]);
			NotifyChanged();
		}

		public static void CheckEmployeesNow()
		{
			HeatData data = Data;
			if (data != null)
			{
				CheckEmployees(data);
			}
			NotifyChanged();
		}

		public static void ForceRaid(string propertyName)
		{
			HeatData data = Data;
			if (data != null)
			{
				object obj;
				if (propertyName.Length <= 0)
				{
					Player local = Player.Local;
					PropertyWrapper val = ((local != null) ? local.CurrentProperty : null);
					obj = ((val != null) ? FindProperty(((BaseProperty)val).PropertyName) : RandomOwnedProperty());
				}
				else
				{
					obj = FindProperty(propertyName);
				}
				Property val2 = (Property)obj;
				if ((Object)(object)val2 == (Object)null)
				{
					Core.Log.Warning((propertyName.Length > 0) ? ("You don't own a property called '" + propertyName + "'.") : "You don't own any properties to raid.");
					return;
				}
				data.Raid = null;
				Raids.Start(val2);
				NotifyChanged();
			}
		}

		public static void ScheduleRaidNow()
		{
			HeatData data = Data;
			if (data != null)
			{
				data.Raid = null;
				ScheduleRaid(data, force: true);
				NotifyChanged();
			}
		}

		public static void ForceInvestigation()
		{
			Player local = Player.Local;
			if (local != null)
			{
				Investigate(local);
			}
		}

		public static void ForceBribeOffer()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			Player local = Player.Local;
			if (local != null)
			{
				if ((int)LawManager.GetWantedLevel(local) < 2)
				{
					local.CrimeData.RecordLastKnownPosition(true);
					LawManager.SetWantedLevel(local, (PursuitLevel)2);
				}
				_bribeOffered = false;
				CheckBribeOffer(local);
			}
		}

		public static void SetWanted(int level)
		{
			Player local = Player.Local;
			if (local != null)
			{
				local.CrimeData.RecordLastKnownPosition(true);
				LawManager.SetWantedLevel(local, (PursuitLevel)Math.Clamp(level, 0, 4));
			}
		}

		public static void ArmSting()
		{
			_forceSting = true;
		}

		public static void ResetSave()
		{
			HeatSave.Instance?.Reset();
			_bribeOffered = false;
			NotifyChanged();
		}

		internal static void FinishRaid(Property property, bool pursued)
		{
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			Add(0f - Settings.RaidHeatRelief);
			int num = Detain(data, property);
			string propertyName = property.PropertyName;
			if (pursued)
			{
				Vance.Notify(Strings.RaidInside(propertyName, num), "", "");
			}
			else
			{
				float onlineBalance = Money.GetOnlineBalance();
				float num2 = Math.Min(onlineBalance, Settings.RaidFineBase + onlineBalance * Settings.RaidFinePercent);
				if (num2 > 0f)
				{
					Money.CreateOnlineTransaction(Strings.SeizureTitle, 0f - num2, 1f, propertyName);
				}
				Vance.Notify(Strings.RaidSeized(propertyName, num2, num), "", "");
			}
			Core.Debug($"Raid on {propertyName} finished. Pursued {pursued}, detained {num}.");
			NotifyChanged();
		}

		private static void OnCustomerDeal(NPC customer)
		{
			//IL_0019: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !IsHost)
			{
				return;
			}
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			Player val = NearestPlayer(customer.Position, 8f);
			if (!((Object)(object)val == (Object)null))
			{
				RecordDeal(Settings.DealHeat, RegionOf(((Component)val).transform.position), val.PlayerCode, val.PlayerCode, ((Component)val).transform.position);
				if (data.Undercover?.NpcId == customer.ID)
				{
					BurnUndercover(data, val.PlayerCode);
				}
			}
		}

		private static void HookDealer(NPC npc)
		{
			Dealer val = ((Object?)(object)NPCManager.GetNPC(npc.ID)).As<Dealer>();
			if (val != null)
			{
				val.OnCompleteDeal += DelegateSupport.ConvertDelegate<Action>((Delegate)(Action)delegate
				{
					OnDealerDeal(npc, forced: false);
				});
			}
		}

		private static void OnDealerDeal(NPC npc, bool forced)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (Active && IsHost && (forced || npc.Dealer.IsRecruited()))
			{
				RecordDeal(Settings.DealerDealHeat, Strings.DealerTurf(npc.FullName), npc.FullName, npc.ID, npc.Position);
			}
		}

		private static void RecordDeal(float heat, string location, string who, string source, Vector3 position)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			HeatData data = Data;
			if (data != null)
			{
				Add(heat);
				AddPersonal(source, heat);
				data.Evidence.Add(NewEvidence(location, source, position));
				Core.Debug($"{who} completed a deal in {location}, heat {Value:0.#}.");
				NotifyChanged();
			}
		}

		private static Evidence NewEvidence(string region, string source, Vector3 position)
		{
			//IL_001f: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			return new Evidence
			{
				Region = region,
				Source = source,
				Day = Today,
				X = position.x,
				Y = position.y,
				Z = position.z
			};
		}

		private static void OnWitnessed(NPC npc, Player? player)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !IsHost || player == null)
			{
				return;
			}
			int num = Today * 24 + TimeManager.CurrentTime / 100;
			if (!LastWitnessed.TryGetValue(npc.ID, out var value) || value != num)
			{
				LastWitnessed[npc.ID] = num;
				Add(Settings.WitnessHeat);
				Player? obj = NearestPlayer(player.Position, 1f);
				AddPersonal(((obj != null) ? obj.PlayerCode : null) ?? "", Settings.WitnessHeat);
				Core.Debug($"{npc.FullName} saw {player.Name} deal, heat {Value:0.#}.");
				if (Roll(Settings.WitnessInformantChance))
				{
					AddInformant(npc);
				}
				NotifyChanged();
			}
		}

		private static void AddInformant(NPC npc)
		{
			HeatData data = Data;
			if (data != null && !data.Informants.Any((Informant i) => i.NpcId == npc.ID))
			{
				data.Informants.Add(new Informant
				{
					NpcId = npc.ID,
					Name = npc.FullName,
					Since = Today
				});
				Core.Debug(npc.FullName + " (" + npc.ID + ") is now an informant.");
				Vance.Notify(Strings.InformantTip(npc.FullName, Settings.PayOffCost), "", "", "payoff:" + npc.ID, "ignore");
			}
		}

		private static void CheckEvidence(HeatData data)
		{
			float num = Math.Min(1f, (float)LawManager.ActiveOfficerCount / 4f);
			foreach (Evidence item in data.Evidence)
			{
				float num2 = 1f - (float)(Today - item.Day) / (float)Settings.EvidenceLifetimeDays;
				if (Roll(Settings.EvidenceFindChance * num2 * num))
				{
					FoundEvidence(data, item);
					break;
				}
			}
		}

		private static void FoundEvidence(HeatData data, Evidence evidence)
		{
			data.Evidence.Remove(evidence);
			Add(Settings.EvidenceHeat);
			AddPersonal(evidence.Source, Settings.EvidenceHeat);
			Core.Debug($"Police found evidence in {evidence.Region}, heat {Value:0.#}.");
			Vance.Notify(Strings.EvidenceFound(evidence.Region), "", "");
		}

		private static void ScheduleRaid(HeatData data, bool force)
		{
			if (data.Raid != null || Raids.Running || (!force && (data.Heat < Settings.RaidThreshold || !Roll(Settings.RaidChancePerDay))))
			{
				return;
			}
			Property val = RandomOwnedProperty();
			if (!((Object)(object)val == (Object)null))
			{
				Raid raid = (data.Raid = new Raid
				{
					Property = val.PropertyName,
					Day = Today,
					Time = (force ? Math.Min(2359, TimeManager.CurrentTime + 100) : (Rng.Next(9, 21) * 100)),
					Warned = (data.Trust >= Settings.RaidWarningTrust)
				});
				Core.Debug($"Raid scheduled on {raid.Property} at {raid.Time:0000}, warned {raid.Warned}.");
				if (raid.Warned)
				{
					Vance.Notify(Strings.RaidWarning(raid.Property, raid.Time), "", "");
				}
			}
		}

		private static void CheckRaid(HeatData data)
		{
			Raid raid = data.Raid;
			if (raid != null && !Raids.Running && (Today != raid.Day || TimeManager.CurrentTime >= raid.Time))
			{
				data.Raid = null;
				Property val = FindProperty(raid.Property);
				if (val != null)
				{
					Raids.Start(val);
				}
			}
		}

		private static void CheckInvestigations(HeatData data)
		{
			float investigationThreshold = Settings.InvestigationThreshold;
			Enumerator<Player> enumerator = Player.PlayerList.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Player current = enumerator.Current;
				if (!((Object)(object)current == (Object)null) && data.PlayerHeat.TryGetValue(current.PlayerCode, out var value) && !(value < investigationThreshold) && Roll(Settings.InvestigationChance * Pressure(value, investigationThreshold)))
				{
					Vance.Notify("", current.PlayerCode, "investigate");
				}
			}
		}

		private static void TryInvestigate(Player player)
		{
			if (!LawManager.IsPlayerWanted(player) && !player.IsSleeping && !player.IsArrested && player.CurrentProperty == null)
			{
				Investigate(player);
			}
		}

		private static void Investigate(Player player)
		{
			player.CrimeData.RecordLastKnownPosition(true);
			LawManager.SetWantedLevel(player, (PursuitLevel)1);
			Core.Debug("Police started an investigation.");
		}

		private static void CheckBribeOffer(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001a: Invalid comparison between Unknown and I4
			PursuitLevel wantedLevel = LawManager.GetWantedLevel(player);
			if ((int)wantedLevel == 0)
			{
				_bribeOffered = false;
			}
			else if (!_bribeOffered && (int)wantedLevel >= 2)
			{
				_bribeOffered = true;
				Vance.Send(Strings.BribeOffer(BribeCost), Vance.Reply("bribe"), Vance.Reply("ignore"));
			}
		}

		private static bool Sting(HeatData data, string playerCode)
		{
			float num = Math.Max(Settings.StingChanceMin, Settings.StingChance - (float)data.Trust * Settings.StingTrustReduction);
			if (!_forceSting && !Roll(num))
			{
				data.Trust++;
				Core.Debug($"Bribe paid, trust {data.Trust}.");
				return false;
			}
			_forceSting = false;
			data.Trust = 0;
			Add(Settings.StingHeat);
			AddPersonal(playerCode, Settings.StingHeat);
			Vance.Notify("", playerCode, "sting");
			Core.Debug($"Bribe was a sting ({num:P0} chance).");
			NotifyChanged();
			return true;
		}

		private static void CheckWarnings(HeatData data)
		{
			int num = Settings.WarningLevels.Where((int level) => data.Heat >= (float)level).DefaultIfEmpty(0).Max();
			if (num > data.LastWarning)
			{
				data.LastWarning = num;
				Vance.Notify(Strings.Warning(num), "", "");
			}
			else if (data.Heat < (float)data.LastWarning - 10f)
			{
				data.LastWarning = num;
			}
		}

		private static Player? NearestPlayer(Vector3 position, float range)
		{
			//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)
			Player result = null;
			float num = range;
			Enumerator<Player> enumerator = Player.PlayerList.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Player current = enumerator.Current;
				if (!((Object)(object)current == (Object)null))
				{
					float num2 = Vector3.Distance(((Component)current).transform.position, position);
					if (!(num2 > num))
					{
						num = num2;
						result = current;
					}
				}
			}
			return result;
		}

		private static string RegionOf(Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			Player? obj = Player.All.OrderBy((Player p) => Vector3.Distance(p.Position, position)).FirstOrDefault();
			return ((obj != null) ? ((object)obj.CurrentRegion/*cast due to .constrained prefix*/).ToString() : null) ?? "";
		}

		private static Property? FindProperty(string name)
		{
			Enumerator<Property> enumerator = Property.OwnedProperties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property current = enumerator.Current;
				if ((Object)(object)current != (Object)null && current.PropertyName == name)
				{
					return current;
				}
			}
			return null;
		}

		private static Property? RandomOwnedProperty()
		{
			List<Property> ownedProperties = Property.OwnedProperties;
			if (ownedProperties.Count != 0)
			{
				return ownedProperties[Rng.Next(ownedProperties.Count)];
			}
			return null;
		}

		private static NPC? RandomNpc(Func<NPC, bool> filter)
		{
			return (from _ in NPC.All.Where(filter)
				orderby Rng.Next()
				select _).FirstOrDefault();
		}

		private static bool TryPay(float cost)
		{
			if (Money.GetCashBalance() < cost)
			{
				return false;
			}
			Money.ChangeCashBalance(0f - cost, true, true);
			return true;
		}

		private static void Add(float amount)
		{
			HeatData data = Data;
			if (data != null)
			{
				data.Heat = Math.Clamp(data.Heat + amount, 0f, 100f);
				CheckWarnings(data);
			}
		}

		private static void AddPersonal(string playerCode, float amount)
		{
			if (playerCode.Length != 0)
			{
				HeatData data = Data;
				if (data != null)
				{
					data.PlayerHeat.TryGetValue(playerCode, out var value);
					data.PlayerHeat[playerCode] = Math.Clamp(value + amount, 0f, 100f);
				}
			}
		}

		private static float Pressure(float heat, float threshold)
		{
			return (heat - threshold + 1f) / (100f - threshold + 1f);
		}

		private static bool Roll(float chance)
		{
			return Rng.NextDouble() < (double)chance;
		}

		public static bool IsDealerHeld(string npcId)
		{
			if (IsHost)
			{
				return Data?.ArrestedDealers.Any((ArrestedDealer d) => d.NpcId == npcId) ?? false;
			}
			return false;
		}

		public static void ReleaseAll()
		{
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			foreach (DetainedEmployee item in data.Detained.ToList())
			{
				ReleaseEmployee(data, item);
			}
			foreach (ArrestedDealer item2 in data.ArrestedDealers.ToList())
			{
				FreeDealer(data, item2);
			}
			NotifyChanged();
		}

		public static void ArrestDealerNow(string npcId)
		{
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			Dealer val = ((npcId.Length > 0) ? FindDealer(npcId) : ((IEnumerable<Dealer>)Dealer.AllPlayerDealers.ToArray()).FirstOrDefault((Func<Dealer, bool>)((Dealer d) => (Object)(object)d != (Object)null && data.ArrestedDealers.All((ArrestedDealer a) => a.NpcId != ((NPC)d).ID))));
			if ((Object)(object)val == (Object)null)
			{
				Core.Log.Warning((npcId.Length > 0) ? ("No dealer with id '" + npcId + "'.") : "No recruited dealers to arrest.");
				return;
			}
			ArrestDealer(data, val);
			NotifyChanged();
		}

		public static void SeizeHeldNow()
		{
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			foreach (ArrestedDealer item in data.ArrestedDealers.Where((ArrestedDealer d) => !d.Seized).ToList())
			{
				SeizeDealer(data, item);
			}
			NotifyChanged();
		}

		private static void RestoreHeld()
		{
			HeatData data = Data;
			if (data == null)
			{
				return;
			}
			foreach (DetainedEmployee item in data.Detained)
			{
				Employee val = FindEmployee(item.NpcId);
				if (val != null)
				{
					SetDetained(val, detained: true);
				}
			}
			foreach (ArrestedDealer arrestedDealer in data.ArrestedDealers)
			{
				Dealer? obj = FindDealer(arrestedDealer.NpcId);
				if (obj != null)
				{
					((NPC)obj).SetVisible(false, true);
				}
			}
		}

		private static void CheckEmployees(HeatData data)
		{
			Enumerator<Property> enumerator = Property.OwnedProperties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property current = enumerator.Current;
				if ((Object)(object)current == (Object)null)
				{
					continue;
				}
				Enumerator<Employee> enumerator2 = current.Employees.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					Employee employee = enumerator2.Current;
					if ((Object)(object)employee == (Object)null || data.Detained.Any((DetainedEmployee d) => d.NpcId == ((NPC)employee).ID))
					{
						continue;
					}
					EmployeeHome home = employee.GetHome();
					if (home == null)
					{
						continue;
					}
					float num = Loyalty(data, ((NPC)employee).ID);
					bool flag = data.SnitchingEmployees.Contains(((NPC)employee).ID);
					if (home.GetCashSum() > 0f)
					{
						if (flag)
						{
							data.SnitchingEmployees.Remove(((NPC)employee).ID);
						}
					}
					else if (!Roll(num))
					{
						Add(Settings.EmployeeSnitchHeat);
						Core.Debug($"{((NPC)employee).FullName}'s locker is empty, heat {Value:0.#} (loyalty {num:P0}).");
						if (!flag)
						{
							data.SnitchingEmployees.Add(((NPC)employee).ID);
							Vance.Notify(Strings.EmployeeSnitch(((NPC)employee).FullName, current.PropertyName), "", "");
						}
					}
				}
			}
		}

		private static int Detain(HeatData data, Property property)
		{
			int releaseDay = Today + Rng.Next(Settings.DetainMinDays, Settings.DetainMaxDays + 1);
			int num = 0;
			Enumerator<Employee> enumerator = property.Employees.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Employee employee = enumerator.Current;
				if (!((Object)(object)employee == (Object)null) && !data.Detained.Any((DetainedEmployee d) => d.NpcId == ((NPC)employee).ID))
				{
					data.Detained.Add(new DetainedEmployee
					{
						NpcId = ((NPC)employee).ID,
						Name = ((NPC)employee).FullName,
						ReleaseDay = releaseDay
					});
					data.SnitchingEmployees.Remove(((NPC)employee).ID);
					SetDetained(employee, detained: true);
					num++;
				}
			}
			return num;
		}

		private static void ReleaseDetained(HeatData data)
		{
			foreach (DetainedEmployee item in data.Detained.Where((DetainedEmployee d) => d.ReleaseDay <= Today).ToList())
			{
				ReleaseEmployee(data, item);
			}
		}

		private static void ReleaseEmployee(HeatData data, DetainedEmployee entry)
		{
			data.Detained.Remove(entry);
			Employee val = FindEmployee(entry.NpcId);
			if (val != null)
			{
				SetDetained(val, detained: false);
			}
			ReturnFromCustody(data, entry.NpcId, entry.Name);
		}

		private static void SetDetained(Employee employee, bool detained)
		{
			employee.SetWaitOutside(detained);
			((NPC)employee).SetVisible(!detained, true);
		}

		private static void CheckDealers(HeatData data)
		{
			foreach (ArrestedDealer item in data.ArrestedDealers.ToList())
			{
				if (!item.Seized && item.Day < Today)
				{
					SeizeDealer(data, item);
				}
				if (item.ReleaseDay <= Today)
				{
					FreeDealer(data, item);
				}
			}
			Enumerator<Dealer> enumerator2 = Dealer.AllPlayerDealers.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				Dealer current2 = enumerator2.Current;
				if ((Object)(object)current2 != (Object)null && current2.IsRecruited)
				{
					Loyalty(data, ((NPC)current2).ID);
				}
			}
			if (data.Heat < Settings.DealerArrestThreshold)
			{
				return;
			}
			float num = Pressure(data.Heat, Settings.DealerArrestThreshold);
			foreach (Dealer dealer in Dealer.AllPlayerDealers.ToArray())
			{
				if (!((Object)(object)dealer == (Object)null) && dealer.IsRecruited && !data.ArrestedDealers.Any((ArrestedDealer a) => a.NpcId == ((NPC)dealer).ID))
				{
					int num2 = data.Evidence.Count((Evidence e) => e.Source == ((NPC)dealer).ID);
					if (Roll(Settings.DealerArrestChance * num * (1f + (float)num2 * 0.25f)))
					{
						ArrestDealer(data, dealer);
					}
				}
			}
		}

		private static void ArrestDealer(HeatData data, Dealer dealer)
		{
			int num = Today + Rng.Next(Settings.DetainMinDays, Settings.DetainMaxDays + 1);
			data.ArrestedDealers.Add(new ArrestedDealer
			{
				NpcId = ((NPC)dealer).ID,
				Name = ((NPC)dealer).FullName,
				Day = Today,
				ReleaseDay = num
			});
			((NPC)dealer).SetVisible(false, true);
			Core.Debug($"{((NPC)dealer).FullName} was arrested until day {num}.");
			Vance.Notify(Strings.DealerArrested(((NPC)dealer).FullName, Settings.BailCost), "", "", "bail:" + ((NPC)dealer).ID, "ignore");
		}

		private static void SeizeDealer(HeatData data, ArrestedDealer entry)
		{
			entry.Seized = true;
			Dealer val = FindDealer(entry.NpcId);
			if (val != null)
			{
				val.SetCash(0f);
				Enumerator<ItemSlot> enumerator = val.ItemSlots.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ItemSlot current = enumerator.Current;
					if (current != null)
					{
						current.ClearStoredInstance(false);
					}
				}
			}
			Vance.Notify(Strings.DealerSeized(entry.Name), "", "");
			Core.Debug(entry.Name + "'s cash and product were seized.");
		}

		private static void FreeDealer(HeatData data, ArrestedDealer entry)
		{
			data.ArrestedDealers.Remove(entry);
			Dealer? obj = FindDealer(entry.NpcId);
			if (obj != null)
			{
				((NPC)obj).SetVisible(true, true);
			}
			if (entry.Seized)
			{
				ReturnFromCustody(data, entry.NpcId, entry.Name);
			}
		}

		private static void ReturnFromCustody(HeatData data, string npcId, string name)
		{
			float num = Loyalty(data, npcId);
			if (Roll(Settings.ReleaseInformantChance * (1f - num)))
			{
				NPC val = NPC.Get(npcId);
				if (val != null)
				{
					Vance.Notify(Strings.StaffTurned(name), "", "");
					AddInformant(val);
					return;
				}
			}
			data.StaffSince[npcId] = data.StaffSince[npcId] - 3;
			Vance.Notify(Strings.StaffLoyal(name), "", "");
		}

		private static float Loyalty(HeatData data, string npcId)
		{
			if (!data.StaffSince.TryGetValue(npcId, out var value))
			{
				value = (data.StaffSince[npcId] = Today);
			}
			return Math.Min(1f, (float)(Today - value) / (float)Settings.LoyaltyDays) * Settings.MaxLoyalty;
		}

		private static Employee? FindEmployee(string id)
		{
			return ((Object?)(object)NPCManager.GetNPC(id)).As<Employee>();
		}

		private static Dealer? FindDealer(string id)
		{
			return ((Object?)(object)NPCManager.GetNPC(id)).As<Dealer>();
		}

		public static string PayOff(string npcId)
		{
			return Perform("payoff", npcId);
		}

		public static string LoseFile()
		{
			return Perform("losefile", "");
		}

		public static string MakeItGoAway()
		{
			return Perform("bribe", "");
		}

		public static string CallCleaner()
		{
			return Perform("cleaner", "");
		}

		public static string DoFavour()
		{
			return Perform("favour", "");
		}

		public static string DeclineFavour()
		{
			return Perform("decline", "");
		}

		public static string TipOff()
		{
			return Perform("tipoff", "");
		}

		public static string Bail(string npcId)
		{
			return Perform("bail", npcId);
		}

		public static void AskFavourNow()
		{
			HeatData data = Data;
			if (data != null)
			{
				data.FavourDay = -1;
				AskFavour(data);
				NotifyChanged();
			}
		}

		public static void BetrayNow()
		{
			HeatData data = Data;
			if (data != null)
			{
				Betray(data);
			}
			NotifyChanged();
		}

		private static string Perform(string action, string arg)
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			string text;
			switch (action)
			{
			case "payoff":
				if (Informants.All((Informant i) => i.NpcId != arg))
				{
					text = Strings.AlreadyQuiet;
					break;
				}
				goto default;
			case "losefile":
				if (Value <= 0f)
				{
					text = Strings.FileClean;
					break;
				}
				goto default;
			case "bribe":
				if ((int)WantedLevel == 0)
				{
					text = Strings.NotWanted;
					break;
				}
				goto default;
			case "cleaner":
				if (EvidenceCount == 0)
				{
					text = Strings.NothingToClean;
					break;
				}
				goto default;
			case "favour":
			case "decline":
				if (!FavourPending)
				{
					text = Strings.FavourNone;
					break;
				}
				goto default;
			case "tipoff":
				if (!TipOffReady)
				{
					text = Strings.TipOffCooldown;
					break;
				}
				goto default;
			case "bail":
				if (HeldDealers.All((ArrestedDealer d) => d.NpcId != arg || d.Seized))
				{
					text = Strings.DealerNotHeld;
					break;
				}
				goto default;
			default:
				text = null;
				break;
			}
			string text2 = text;
			if (text2 != null)
			{
				return text2;
			}
			float cost = action switch
			{
				"payoff" => Settings.PayOffCost, 
				"losefile" => Settings.LoseFileCost, 
				"bribe" => BribeCost, 
				"cleaner" => CleanupCost, 
				"favour" => Settings.FavourCost, 
				"tipoff" => Settings.TipOffCost, 
				"bail" => Settings.BailCost, 
				_ => 0f, 
			};
			if (!TryPay(cost))
			{
				return Strings.NotEnoughCash(cost);
			}
			if (!Sync.IsClient)
			{
				return Apply(action, arg, Sync.LocalCode);
			}
			Sync.Request(action, arg);
			return Strings.RequestSent;
		}

		private static string Apply(string action, string arg, string playerCode)
		{
			HeatData data = Data;
			if (data == null)
			{
				return "";
			}
			string result;
			switch (action)
			{
			case "payoff":
			{
				Informant informant = data.Informants.FirstOrDefault((Informant i) => i.NpcId == arg);
				if (informant == null)
				{
					return Strings.AlreadyQuiet;
				}
				data.Informants.Remove(informant);
				result = Strings.PaidOff(informant.Name);
				break;
			}
			case "losefile":
				if (Sting(data, playerCode))
				{
					return Strings.Sting;
				}
				Add(0f - Settings.LoseFileHeat);
				AddPersonal(playerCode, 0f - Settings.LoseFileHeat);
				result = Strings.FileLost;
				break;
			case "bribe":
				if (Sting(data, playerCode))
				{
					return Strings.Sting;
				}
				Vance.Notify("", playerCode, "clear");
				result = Strings.Cleared;
				break;
			case "cleaner":
				data.Evidence.Clear();
				result = Strings.Cleaned;
				break;
			case "favour":
				data.FavourDay = -1;
				data.Trust += Settings.FavourTrust;
				result = Strings.FavourThanks;
				break;
			case "decline":
				data.FavourDay = -1;
				data.Trust = Math.Max(0, data.Trust - 1);
				result = Strings.FavourDeclined;
				break;
			case "tipoff":
				if (Sting(data, playerCode))
				{
					return Strings.Sting;
				}
				data.LastTipOffDay = Today;
				Add(0f - Settings.TipOffHeat);
				result = Strings.TipOffDone;
				break;
			case "bail":
			{
				ArrestedDealer arrestedDealer = data.ArrestedDealers.FirstOrDefault((ArrestedDealer d) => d.NpcId == arg && !d.Seized);
				if (arrestedDealer == null)
				{
					return Strings.DealerNotHeld;
				}
				FreeDealer(data, arrestedDealer);
				result = Strings.DealerBailed(arrestedDealer.Name);
				break;
			}
			default:
				return "";
			}
			Core.Debug($"{action} done for {playerCode}. {Status()}");
			NotifyChanged();
			return result;
		}

		private static void CheckFavour(HeatData data)
		{
			if (data.FavourDay >= 0 && data.FavourDay < Today)
			{
				data.FavourDay = -1;
				data.Trust = Math.Max(0, data.Trust - 1);
				Core.Debug("Vance's favour went unanswered.");
			}
			if (data.FavourDay < 0 && Roll(Settings.FavourChance))
			{
				AskFavour(data);
			}
		}

		private static void AskFavour(HeatData data)
		{
			data.FavourDay = Today;
			Vance.Notify(Strings.FavourAsk(Settings.FavourCost), "", "", "favour", "decline");
		}

		private static void CheckBetrayal(HeatData data)
		{
			data.BetrayStreak = ((data.Trust <= Settings.BetrayTrust && data.Heat >= Settings.BetrayHeat) ? (data.BetrayStreak + 1) : 0);
			if (data.BetrayStreak >= Settings.BetrayDays)
			{
				Betray(data);
			}
		}

		private static void Betray(HeatData data)
		{
			data.BetrayStreak = 0;
			data.Trust = 0;
			data.Raid = null;
			ScheduleRaid(data, force: true);
			Vance.Notify(Strings.Betrayal, "", "");
			Core.Debug("Vance sold you out.");
		}

		public static bool IsNervous(string npcId)
		{
			if (IsHost)
			{
				HeatData data = Data;
				if (data != null && data.Unlocked && !(data.Heat < Settings.NervousThreshold))
				{
					return StableRoll(npcId, Today) < (double)(Settings.NervousChance * Pressure(data.Heat, Settings.NervousThreshold));
				}
			}
			return false;
		}

		public static int NervousCount()
		{
			return NPC.All.Count((NPC n) => n.Customer.IsCustomer && IsNervous(n.ID));
		}

		public static void ForceUndercover(string npcId)
		{
			HeatData data = Data;
			if (data != null)
			{
				NPC val = (NPC)((npcId.Length > 0) ? ((object)NPC.Get(npcId)) : ((object)RandomNpc((NPC n) => n.Customer.IsCustomer && n.Relationship.IsUnlocked)));
				if (val == null)
				{
					Core.Log.Warning((npcId.Length > 0) ? ("No NPC with id '" + npcId + "'.") : "No unlocked customers to plant.");
					return;
				}
				PlantUndercover(data, val);
				NotifyChanged();
			}
		}

		public static void StartPatrolNow()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			HeatData data = Data;
			if (data != null)
			{
				Player local = Player.Local;
				if (local != null && !SendPatrol((data.Evidence.Count > 0) ? EvidencePosition(data.Evidence[Rng.Next(data.Evidence.Count)]) : local.Position))
				{
					Core.Log.Warning("No patrol could be started.");
				}
			}
		}

		private static void CheckPatrols(HeatData data)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!(data.Heat < Settings.PatrolThreshold) && data.Evidence.Count != 0 && Roll(Settings.PatrolChance * Pressure(data.Heat, Settings.PatrolThreshold)))
			{
				SendPatrol(EvidencePosition(data.Evidence[Rng.Next(data.Evidence.Count)]));
			}
		}

		private static bool SendPatrol(Vector3 spot)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			FootPatrolRoute val = (from r in LawManager.GetAllFootPatrolRoutes()
				orderby Vector3.Distance(r.Position, spot)
				select r).FirstOrDefault();
			if (val == null || LawManager.StartFootPatrol(val, 2) == null)
			{
				return false;
			}
			Core.Debug("Sent a patrol to " + val.RouteName + ".");
			return true;
		}

		private static void CheckUndercover(HeatData data)
		{
			Undercover undercover = data.Undercover;
			if (undercover != null && Today - undercover.Since >= Settings.UndercoverDays)
			{
				data.Undercover = null;
			}
			if (data.Undercover == null && !(data.Heat < Settings.UndercoverThreshold) && Roll(Settings.UndercoverChance))
			{
				NPC val = RandomNpc((NPC n) => n.Customer.IsCustomer && n.Relationship.IsUnlocked);
				if (val != null)
				{
					PlantUndercover(data, val);
				}
			}
		}

		private static void PlantUndercover(HeatData data, NPC npc)
		{
			data.Undercover = new Undercover
			{
				NpcId = npc.ID,
				Name = npc.FullName,
				Since = Today,
				Warned = (data.Trust >= Settings.UndercoverWarnTrust)
			};
			Core.Debug($"{npc.FullName} ({npc.ID}) is now undercover, warned {data.Undercover.Warned}.");
			if (data.Undercover.Warned)
			{
				Vance.Notify(Strings.UndercoverWarning(npc.FullName), "", "");
			}
		}

		private static void BurnUndercover(HeatData data, string playerCode)
		{
			string name = data.Undercover.Name;
			data.Undercover = null;
			Add(Settings.UndercoverHeat);
			AddPersonal(playerCode, Settings.UndercoverHeat);
			Vance.Notify("", playerCode, "wanted");
			Vance.Notify(Strings.UndercoverBurned(name), "", "");
			Core.Debug("Sold to undercover officer " + name + ".");
			NotifyChanged();
		}

		private static Vector3 EvidencePosition(Evidence evidence)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(evidence.X, evidence.Y, evidence.Z);
		}

		private static double StableRoll(string id, int day)
		{
			int num = day * 7919;
			foreach (char c in id)
			{
				num = num * 31 + c;
			}
			return (double)((num & 0x7FFFFFFF) % 10000) / 10000.0;
		}
	}
	public class HeatApp : PhoneApp
	{
		private static readonly Color Background = new Color(0.08f, 0.08f, 0.09f);

		private static readonly Color Accent = new Color(0.78f, 0.3f, 0.14f);

		private static readonly Color Subtle = new Color(0.62f, 0.62f, 0.66f);

		private static readonly Color BarBack = new Color(0.2f, 0.2f, 0.22f);

		private static readonly Color Cool = new Color(0.3f, 0.62f, 0.85f);

		private static readonly Color Hot = new Color(0.92f, 0.26f, 0.12f);

		private static Sprite? _icon;

		private static Transform? _iconRoot;

		private RectTransform? _status;

		private RectTransform? _actions;

		private string _note = "";

		protected override string AppName => "TMLHeat";

		protected override string AppTitle => Strings.AppTitle;

		protected override string IconLabel => Strings.AppTitle;

		protected override string IconFileName => "TMLHeat.png";

		protected override void OnCreated()
		{
			((PhoneApp)this).OnCreated();
			if ((Object)(object)_icon == (Object)null)
			{
				_icon = BuildIcon();
			}
			((PhoneApp)this).SetIconSprite(_icon);
		}

		protected override void OnCreatedUI(GameObject container)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			GameObject val = UIFactory.Panel("Root", container.transform, Background, (Vector2?)null, (Vector2?)null, true);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)obj).padding = new RectOffset(36, 36, 28, 28);
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 36f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true;
			_status = Column("Status", val.transform);
			_actions = Column("Actions", val.transform);
			Heat.Changed += Refresh;
			Refresh();
		}

		protected override void OnDestroyed()
		{
			Heat.Changed -= Refresh;
			((PhoneApp)this).OnDestroyed();
		}

		protected override void OnPhoneClosed()
		{
			_note = "";
		}

		private void Refresh()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_status == (Object)null || (Object)(object)_actions == (Object)null)
			{
				return;
			}
			UIFactory.ClearChildren((Transform)(object)_status);
			UIFactory.ClearChildren((Transform)(object)_actions);
			Label((Transform)(object)_status, Strings.AppTitle, 26, (FontStyle)1, Color.white);
			Label((Transform)(object)_status, Strings.HeatLine(Heat.Value), 18, (FontStyle)0, Color.white);
			Bar((Transform)(object)_status, Heat.Value / 100f);
			Label((Transform)(object)_status, Strings.PersonalLine(Heat.PersonalValue), 15, (FontStyle)0, Color.white);
			Bar((Transform)(object)_status, Heat.PersonalValue / 100f);
			Label((Transform)(object)_status, Strings.HistoryLine, 13, (FontStyle)0, Subtle);
			HistoryChart((Transform)(object)_status, Heat.History.Append(Heat.Value).ToList());
			Label((Transform)(object)_status, Strings.InformantsLine(Heat.Informants.Count), 15, (FontStyle)0, Subtle);
			Label((Transform)(object)_status, Strings.EvidenceLine(Heat.EvidenceCount), 15, (FontStyle)0, Subtle);
			Label((Transform)(object)_status, Strings.TrustLine(Heat.Trust), 15, (FontStyle)0, Subtle);
			if (Heat.SnitchingCount > 0)
			{
				Label((Transform)(object)_status, Strings.SnitchingLine(Heat.SnitchingCount), 15, (FontStyle)0, Hot);
			}
			if (Heat.DetainedCount > 0)
			{
				Label((Transform)(object)_status, Strings.DetainedLine(Heat.DetainedCount), 15, (FontStyle)0, Subtle);
			}
			if (Heat.HeldDealers.Count > 0)
			{
				Label((Transform)(object)_status, Strings.HeldLine(Heat.HeldDealers.Count), 15, (FontStyle)0, Hot);
			}
			if ((int)Heat.WantedLevel != 0)
			{
				Label((Transform)(object)_status, Strings.WantedLine(((object)Heat.WantedLevel/*cast due to .constrained prefix*/).ToString()), 15, (FontStyle)1, Hot);
			}
			Raid knownRaid = Heat.KnownRaid;
			if (knownRaid != null)
			{
				Label((Transform)(object)_status, Strings.RaidLine(knownRaid), 15, (FontStyle)1, Hot);
			}
			if (Sync.IsClient)
			{
				Label((Transform)(object)_status, Strings.SyncedLine, 13, (FontStyle)2, Subtle);
			}
			Label((Transform)(object)_actions, Strings.VanceTitle, 26, (FontStyle)1, Color.white);
			Label((Transform)(object)_actions, Strings.CashLine(Money.GetCashBalance()), 15, (FontStyle)0, Subtle);
			if ((int)Heat.WantedLevel != 0)
			{
				Action(Strings.GoAwayButton(Heat.BribeCost), Heat.MakeItGoAway);
			}
			Action(Strings.LoseFileButton(Settings.LoseFileCost), Heat.LoseFile);
			if (Heat.EvidenceCount > 0)
			{
				Action(Strings.CleanerButton(Heat.CleanupCost), Heat.CallCleaner);
			}
			if (Heat.TipOffReady)
			{
				Action(Strings.TipOffButton(Settings.TipOffCost), Heat.TipOff);
			}
			if (Heat.FavourPending)
			{
				Action(Strings.FavourButton(Settings.FavourCost), Heat.DoFavour);
			}
			foreach (ArrestedDealer item in Heat.HeldDealers.Where((ArrestedDealer d) => !d.Seized))
			{
				string id = item.NpcId;
				Action(Strings.BailButton(item.Name, Settings.BailCost), () => Heat.Bail(id));
			}
			foreach (Informant informant in Heat.Informants)
			{
				string id2 = informant.NpcId;
				Action(Strings.PayOffButton(informant.Name, Settings.PayOffCost), () => Heat.PayOff(id2));
			}
			if (_note.Length > 0)
			{
				Label((Transform)(object)_actions, _note, 15, (FontStyle)2, Color.white);
			}
			UIFactory.FitContentHeight(_status);
			UIFactory.FitContentHeight(_actions);
		}

		private void Action(string label, Func<string> action)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			var (go, val, _) = UIFactory.RoundedButtonWithLabel("Action", label, (Transform)(object)_actions, Accent, 300f, 42f, 16, Color.white);
			Size(go, 42f);
			ButtonUtils.AddListener(val, (Action)delegate
			{
				_note = action();
				Refresh();
			});
		}

		private static RectTransform Column(string name, Transform parent)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00e4: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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)
			ScrollRect val2 = default(ScrollRect);
			RectTransform val = UIFactory.ScrollableVerticalList(name, parent, ref val2);
			val2.horizontal = false;
			val2.vertical = true;
			LayoutElement val3 = ((Component)val2).gameObject.GetComponent<LayoutElement>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = ((Component)val2).gameObject.AddComponent<LayoutElement>();
			}
			val3.flexibleWidth = 1f;
			val3.flexibleHeight = 1f;
			VerticalLayoutGroup val4 = ((Component)val).GetComponent<VerticalLayoutGroup>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val).gameObject.AddComponent<VerticalLayoutGroup>();
			}
			((HorizontalOrVerticalLayoutGroup)val4).spacing = 10f;
			((LayoutGroup)val4).padding = new RectOffset(0, 14, 0, 14);
			((LayoutGroup)val4).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)val4).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val4).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val4).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val4).childForceExpandHeight = false;
			ContentSizeFitter val5 = ((Component)val).GetComponent<ContentSizeFitter>();
			if ((Object)(object)val5 == (Object)null)
			{
				val5 = ((Component)val).gameObject.AddComponent<ContentSizeFitter>();
			}
			val5.horizontalFit = (FitMode)0;
			val5.verticalFit = (FitMode)2;
			val.anchorMin = new Vector2(0f, 1f);
			val.anchorMax = new Vector2(1f, 1f);
			val.pivot = new Vector2(0.5f, 1f);
			val.offsetMin = new Vector2(0f, val.offsetMin.y);
			val.offsetMax = new Vector2(0f, val.offsetMax.y);
			return val;
		}

		private static void Label(Transform parent, string text, int size, FontStyle style, Color color)
		{
			//IL_0009: 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)
			((Graphic)UIFactory.Text("Label", text, parent, size, (TextAnchor)3, style)).color = color;
		}

		private static void Bar(Transform parent, float fill)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = UIFactory.Panel("Bar", parent, BarBack, (Vector2?)null, (Vector2?)null, false);
			Size(val, 12f);
			if (!(fill <= 0f))
			{
				RectTransform component = UIFactory.Panel("Fill", val.transform, Color.Lerp(Cool, Hot, fill), (Vector2?)null, (Vector2?)null, false).GetComponent<RectTransform>();
				component.anchorMin = Vector2.zero;
				component.anchorMax = new Vector2(Mathf.Clamp01(fill), 1f);
				component.offsetMin = Vector2.zero;
				component.offsetMax = Vector2.zero;
			}
		}

		private static void HistoryChart(Transform parent, List<float> values)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00fb: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("History");
			val.AddComponent<RectTransform>();
			val.transform.SetParent(parent, false);
			Size(val, 48f);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)6;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true;
			foreach (float value in values)
			{
				GameObject val2 = UIFactory.Panel("Day", val.transform, BarBack, (Vector2?)null, (Vector2?)null, false);
				float num = Mathf.Clamp01(value / 100f);
				if (!(num <= 0f))
				{
					RectTransform component = UIFactory.Panel("Fill", val2.transform, Color.Lerp(Cool, Hot, num), (Vector2?)null, (Vector2?)null, false).GetComponent<RectTransform>();
					component.anchorMin = Vector2.zero;
					component.anchorMax = new Vector2(1f, num);
					component.offsetMin = Vector2.zero;
					component.offsetMax = Vector2.zero;
				}
			}
		}

		internal static void ApplyVisibility()
		{
			if ((Object)(object)_iconRoot == (Object)null)
			{
				_iconRoot = ((IEnumerable<Transform>)Resources.FindObjectsOfTypeAll<Transform>()).FirstOrDefault((Func<Transform, bool>)delegate(Transform t)
				{
					//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)
					if (((Object)t).name == "AppIcons")
					{
						Scene scene = ((Component)t).gameObject.scene;
						return ((Scene)(ref scene)).IsValid();
					}
					return false;
				});
			}
			Transform val = (((Object)(object)_iconRoot == (Object)null) ? null : _iconRoot.Find("TMLHeat"));
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(Heat.Active);
			}
		}

		private static void Size(GameObject go, float height)
		{
			LayoutElement val = go.GetComponent<LayoutElement>();
			if ((Object)(object)val == (Object)null)
			{
				val = go.AddComponent<LayoutElement>();
			}
			val.minHeight = height;
			val.preferredHeight = height;
		}

		private static Sprite BuildIcon()
		{
			//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_0018: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(128, 128)
			{
				hideFlags = (HideFlags)32
			};
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.17f, 0.18f, 0.21f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.09f, 0.09f, 0.11f);
			Color val4 = default(Color);
			((Color)(ref val4))..ctor(0.93f, 0.93f, 0.95f);
			Color val5 = default(Color);
			((Color)(ref val5))..ctor(0.9f, 0.22f, 0.12f);
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float u = ((float)j + 0.5f) / 128f;
					float num = ((float)i + 0.5f) / 128f;
					Color val6 = Color.Lerp(val3, val2, num);
					val6 = Color.Lerp(val6, val4, Cover(Thermometer(u, num, 0.105f, 0.17f), 128));
					val6 = Color.Lerp(val6, val3, Cover(Thermometer(u, num, 0.06f, 0.125f), 128));
					float num2 = Mathf.Max(Thermometer(u, num, 0.06f, 0.125f), num - 0.6f);
					val6 = Color.Lerp(val6, val5, Cover(num2 + 0.012f, 128));
					val6 = Color.Lerp(val6, val4, Cover(Ticks(u, num), 128));
					val.SetPixel(j, i, val6);
				}
			}
			val.Apply();
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f));
			((Object)obj).hideFlags = (HideFlags)32;
			return obj;
		}

		private static float Thermometer(float u, float v, float tube, float bulb)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float num = Mathf.Abs(u - 0.44f) - tube;
			float num2 = Mathf.Max(0.3f - v, v - 0.8f);
			float num3;
			Vector2 val;
			if (!(num2 > 0f))
			{
				num3 = num;
			}
			else
			{
				val = new Vector2(Mathf.Max(num, 0f), num2);
				num3 = ((Vector2)(ref val)).magnitude + Mathf.Min(Mathf.Max(num, num2), 0f);
			}
			float num4 = num3;
			if (v > 0.8f)
			{
				val = new Vector2(u - 0.44f, v - 0.8f);
				num4 = ((Vector2)(ref val)).magnitude - tube;
			}
			val = new Vector2(u - 0.44f, v - 0.25f);
			float num5 = ((Vector2)(ref val)).magnitude - bulb;
			return Mathf.Min(num4, num5);
		}

		private static float Ticks(float u, float v)
		{
			float num = float.MaxValue;
			for (int i = 0; i < 4; i++)
			{
				float num2 = Mathf.Abs(v - (0.48f + (float)i * 0.09f)) - 0.012f;
				float num3 = Mathf.Abs(u - 0.66f) - 0.05f;
				num = Mathf.Min(num, Mathf.Max(num3, num2));
			}
			return num;
		}

		private static float Cover(float distance, int size)
		{
			return Mathf.Clamp01(0.5f - distance * (float)size);
		}
	}
	public class HeatCommand : BaseConsoleCommand
	{
		private static readonly Dictionary<string, string> Help = new Dictionary<string, string>
		{
			["status"] = "show everything",
			["set <n>"] = "set heat (triggers warnings)",
			["add <n>"] = "add heat",
			["trust <n>"] = "set Vance's trust",
			["unlock"] = "unlock now",
			["deal"] = "simulate one of your deals",
			["dealerdeal"] = "simulate a dealer's deal",
			["witness [npcId]"] = "someone sees you deal",
			["informant [npcId]"] = "turn someone into an informant",
			["evidence [n]"] = "leave evidence where you stand",
			["findevidence"] = "police find the oldest evidence",
			["employees"] = "check lockers now",
			["wanted <0-4>"] = "set your wanted level",
			["bribeoffer"] = "get wanted and receive Vance's bribe offer",
			["sting"] = "the next bribe will be a sting",
			["investigate"] = "start an investigation",
			["schedule"] = "schedule a raid for next hour",
			["raid [property]"] = "raid now (your current property if inside)",
			["countdown"] = "preview the raid countdown",
			["release"] = "release detained staff and dealers",
			["personal <n>"] = "set your own heat",
			["favour"] = "Vance asks for a favour now",
			["betray"] = "Vance sells you out now",
			["arrestdealer [npcId]"] = "arrest one of your dealers",
			["seize"] = "seize held dealers' cash and product now",
			["undercover [npcId]"] = "plant an undercover officer",
			["patrol"] = "send a patrol to your evidence",
			["nervous"] = "count customers too nervous to order",
			["lang <en|es>"] = "switch language until restart",
			["hour"] = "run hourly checks",
			["day"] = "run daily checks",
			["sync"] = "co-op sync status",
			["reset"] = "clear TML Heat data for this save",
			["debug on|off"] = "log heat events"
		};

		public override string CommandWord => "heat";

		public override string CommandDescription => "TML Heat tools. Type 'heat help' for options.";

		public override string ExampleUsage => "heat set 80";

		public override void ExecuteCommand(List<string> args)
		{
			string text = ((args.Count > 0) ? args[0].ToLowerInvariant() : "status");
			string text2 = ((args.Count > 1) ? string.Join(" ", args.Skip(1)) : "");
			if (text == "help")
			{
				foreach (var (value, value2) in Help)
				{
					Core.Log.Msg($"heat {value,-18} {value2}");
				}
				return;
			}
			if (text == "sync")
			{
				Core.Log.Msg(Sync.Status);
				return;
			}
			if (HeatSave.Instance == null || Player.Local == null)
			{
				Core.Log.Warning("Load a save first.");
				return;
			}
			if (Sync.IsClient && text != "status" && text != "countdown" && text != "wanted" && text != "debug")
			{
				Core.Log.Warning("Only the host can change TML Heat. Run this on the host.");
				return;
			}
			switch (text)
			{
			case "set":
				Heat.SetHeat(Number(text2));
				break;
			case "add":
				Heat.SetHeat(Heat.Value + Number(text2));
				break;
			case "trust":
				Heat.SetTrust((int)Number(text2));
				break;
			case "unlock":
				Heat.CheckUnlock(force: true);
				break;
			case "deal":
				Heat.ForcePlayerDeal();
				break;
			case "dealerdeal":
				Heat.ForceDealerDeal();
				break;
			case "witness":
				Heat.ForceWitness(text2);
				break;
			case "informant":
				Heat.ForceInformant(text2);
				break;
			case "evidence":
				Heat.AddEvidence(Math.Max(1, (int)Number(text2)));
				break;
			case "findevidence":
				Heat.FindEvidenceNow();
				break;
			case "employees":
				Heat.CheckEmployeesNow();
				break;
			case "wanted":
				Heat.SetWanted((int)Number(text2));
				break;
			case "bribeoffer":
				Heat.ForceBribeOffer();
				break;
			case "sting":
				Heat.ArmSting();
				Core.Log.Msg("The next bribe will be a sting.");
				break;
			case "investigate":
				Heat.ForceInvestigation();
				break;
			case "schedule":
				Heat.ScheduleRaidNow();
				break;
			case "raid":
				Heat.ForceRaid(text2);
				break;
			case "countdown":
				Hud.Countdown("Test", Settings.RaidCountdown);
				break;
			case "release":
				Heat.ReleaseAll();
				break;
			case "personal":
				Heat.SetPersonalHeat(Number(text2));
				break;
			case "favour":
				Heat.AskFavourNow();
				break;
			case "betray":
				Heat.BetrayNow();
				break;
			case "arrestdealer":
				Heat.ArrestDealerNow(text2);
				break;
			case "seize":
				Heat.SeizeHeldNow();
				break;
			case "undercover":
				Heat.ForceUndercover(text2);
				break;
			case "patrol":
				Heat.StartPatrolNow();
				break;
			case "nervous":
				Core.Log.Msg($"{Heat.NervousCount()} customers are too nervous to order today.");
				break;
			case "lang":
				Lang.Load((text2.Length > 0) ? text2.ToLowerInvariant() : "en");
				Heat.NotifyChanged();
				break;
			case "hour":
				Heat.OnHour();
				break;
			case "day":
				Heat.OnDay();
				break;
			case "reset":
				Heat.ResetSave();
				break;
			case "debug":
				Settings.DebugLogs = text2 != "off";
				Core.Log.Msg("Debug logs " + (Settings.DebugLogs ? "on" : "off"));
				break;
			default:
				Core.Log.Warning("Unknown option '" + text + "'. Type 'heat help'.");
				return;
			case "status":
				break;
			}
			Core.Log.Msg(Heat.Status());
		}

		private static float Number(string text)
		{
			if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return 0f;
			}
			return result;
		}
	}
	public class HeatSave : Saveable
	{
		[SaveableField("tmlheat")]
		private HeatData _data = new HeatData();

		internal static HeatSave? Instance { get; private set; }

		internal HeatData Data => _data;

		public HeatSave()
		{
			Instance = this;
		}

		internal void Reset()
		{
			_data = new HeatData();
		}

		protected override void OnLoaded()
		{
			if (_data == null)
			{
				_data = new HeatData();
			}
			Heat.NotifyChanged();
		}
	}
	public class HeatData
	{
		public float Heat;

		public int Trust;

		public bool Unlocked;

		public List<Evidence> Evidence = new List<Evidence>();

		public List<Informant> Informants = new List<Informant>();

		public Raid? Raid;

		public int LastWarning;

		public List<string> SnitchingEmployees = new List<string>();

		public List<DetainedEmployee> Detained = new List<DetainedEmployee>();

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

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

		public Dictionary<string, int> StaffSince = new Dictionary<string, int>();

		public List<ArrestedDealer> ArrestedDealers = new List<ArrestedDealer>();

		public Undercover? Undercover;

		public int FavourDay = -1;

		public int LastTipOffDay = -99;

		public int BetrayStreak;
	}
	public class Evidence
	{
		public string Region = "";

		public string Source = "";

		public int Day;

		public float X;

		public float Y;

		public float Z;
	}
	public class Informant
	{
		public string NpcId = "";

		public string Name = "";

		public int Since;
	}
	public class Raid
	{
		public string Property = "";

		public int Day;

		public int Time;

		public bool Warned;
	}
	public class DetainedEmployee
	{
		public string NpcId = "";

		public string Name = "";

		public int ReleaseDay;
	}
	public class ArrestedDealer
	{
		public string NpcId = "";

		public string Name = "";

		public int Day;

		public int ReleaseDay;

		public bool Seized;
	}
	public class Undercover
	{
		public string NpcId = "";

		public string Name = "";

		public int Since;

		public bool Warned;
	}
	public class Snapshot
	{
		public bool Unlocked;

		public float Heat;

		public int Trust;

		public int Evidence;

		public int Snitching;

		public int Detained;

		public bool FavourPending;

		public bool TipOffReady;

		public List<Informant> Informants = new List<Informant>();

		public List<ArrestedDealer> Arrested = new List<ArrestedDealer>();

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

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

		public Raid? Raid;

		public List<SyncMessage> Messages = new List<SyncMessage>();
	}
	public class SyncMessage
	{
		public int Id;

		public string Target = "";

		public string Text = "";

		public string Effect = "";

		public string[] Replies = Array.Empty<string>();
	}
	internal static class Hud
	{
		private static readonly Color Banner = new Color(0.08f, 0.08f, 0.09f, 0.7f);

		private static GameObject? _root;

		private static Text? _label;

		private static int _run;

		public static void Countdown(string property, int seconds)
		{
			MelonCoroutines.Start(Run(property, seconds, ++_run));
		}

		private static IEnumerator Run(string property, int seconds, int run)
		{
			Ensure();
			_root.SetActive(true);
			int remaining = seconds;
			while (remaining > 0 && run == _run)
			{
				_label.text = Strings.RaidCountdown(property, remaining);
				yield return (object)new WaitForSeconds(1f);
				remaining--;
			}
			if (run == _run)
			{
				_label.text = Strings.RaidBreach;
				yield return (object)new WaitForSeconds(1.5f);
				if (run == _run)
				{
					_root.SetActive(false);
				}
			}
		}

		private static void Ensure()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_005d: 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_0085: 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_00e7: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root != (Object)null))
			{
				_root = new GameObject("TMLHeatHud");
				Object.DontDestroyOnLoad((Object)(object)_root);
				Canvas obj = _root.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 500;
				CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
				obj2.uiScaleMode = (ScaleMode)1;
				obj2.referenceResolution = new Vector2(1920f, 1080f);
				GameObject val = UIFactory.Panel("Banner", _root.transform, Banner, (Vector2?)new Vector2(0.38f, 0.91f), (Vector2?)new Vector2(0.62f, 0.95f), false);
				Stretch(val.GetComponent<RectTransform>());
				_label = UIFactory.Text("Label", "", val.transform, 20, (TextAnchor)4, (FontStyle)0);
				((Graphic)_label).color = new Color(1f, 0.55f, 0.5f);
				RectTransform component = ((Component)_label).GetComponent<RectTransform>();
				component.anchorMin = Vector2.zero;
				component.anchorMax = Vector2.one;
				Stretch(component);
			}
		}

		private static void Stretch(RectTransform rect)
		{
			//IL_0001: 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)
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
		}
	}
	internal static class Lang
	{
		private const string Fallback = "en";

		private static Dictionary<string, string> _fallback = new Dictionary<string, string>();

		private static Dictionary<string, string> _active = new Dictionary<string, string>();

		public static string Folder => Path.Combine(MelonEnvironment.UserDataDirectory, "TMLHeat", "lang");

		public static bool Exists(string language)
		{
			if (!File.Exists(Path.Combine(Folder, language + ".json")))
			{
				return Embedded(language) != null;
			}
			return true;
		}

		public static void Load(string language)
		{
			Directory.CreateDirectory(Folder);
			string[] array = new string[2] { "en", "es" };
			for (int i = 0; i < array.Length; i++)
			{
				Export(array[i]);
			}
			_fallback = Read("en");
			_active = ((language == "en") ? _fallback : Read(language));
			if (_active.Count == 0)
			{
				Core.Log.Warning("No translations found for '" + language + "'. Using English.");
				_active = _fallback;
			}
		}

		public static string T(string key)
		{
			if (!_active.TryGetValue(key, out string value))
			{
				if (!_fallback.TryGetValue(key, out string value2))
				{
					return key;
				}
				return value2;
			}
			return value;
		}

		public static string T(string key, params object[] args)
		{
			return string.Format(CultureInfo.InvariantCulture, T(key), args);
		}

		private static Dictionary<string, string> Read(string language)
		{
			Dictionary<string, string> dictionary = Parse(Embedded(language)) ?? new Dictionary<string, string>();
			string text = Path.Combine(Folder, language + ".json");
			if (!File.Exists(text))
			{
				return dictionary;
			}
			Dictionary<string, string> dictionary2 = Parse(File.ReadAllText(text));
			if (dictionary2 == null)
			{
				Core.Log.Warning(text + " isn't valid JSON. Using the built-in text.");
				return dictionary;
			}
			foreach (KeyValuePair<string, string> item in dictionary2)
			{
				item.Deconstruct(out var key, out var value);
				string key2 = key;
				string value2 = value;
				dictionary[key2] = value2;
			}
			return dictionary;
		}

		private static void Export(string language)
		{
			string path = Path.Combine(Folder, language + ".json");
			if (!File.Exists(path))
			{
				string text = Embedded(language);
				if (text != null)
				{
					File.WriteAllText(path, text);
				}
			}
		}

		private static string? Embedded(string language)
		{
			using Stream stream = typeof(Lang).Assembly.GetManifestResourceStream("TMLHeat.lang." + language + ".json");
			if (stream == null)
			{
				return null;
			}
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		private static Dictionary<string, string>? Parse(string? json)
		{
			if (string.IsNullOrEmpty(json))
			{
				return null;
			}
			return Json.Read<Dictionary<string, string>>(json);
		}
	}
	[HarmonyPatch(typeof(Customer), "ShouldTryGenerateDeal")]
	internal static class NervousCustomerPatch
	{
		private static bool Prefix(Customer __instance, ref bool __result)
		{
			NPC component = ((Component)__instance).GetComponent<NPC>();
			if ((Object)(object)component == (Object)null || !Heat.IsNervous(component.ID))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Dealer), "ShouldAcceptContract")]
	internal static class HeldDealerPatch
	{
		private static bool Prefix(Dealer __instance, ref bool __result)
		{
			if (!Heat.IsDealerHeld(((NPC)__instance).ID))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	internal static class Raids
	{
		public static readonly Vector3 Staging = new Vector3(-50f, 1.06f, 70f);

		private const float SightRange = 16f;

		private const float ArrestRange = 2.2f;

		private const float ChaseRefresh = 0.5f;

		private const float RetargetDelay = 2.5f;

		private const int MaxWaypoints = 16;

		private const string SpeedControl = "tmlheat_raid";

		private const float RaidSpeed = 0.85f;

		private const float StageTimeout = 30f;

		private const float MinimumSweep = 20f;

		private static readonly Random Rng = new Random();

		private static readonly List<SwatOfficer> Squad = new List<SwatOfficer>();

		private static readonly List<(DoorController Door, bool Openable)> Doors = new List<(DoorController, bool)>();

		public static bool Running { get; private set; }

		public static void Start(Property property)
		{
			if (!Running)
			{
				Running = true;
				MelonCoroutines.Start(Guarded(property));
			}
		}

		private static IEnumerator Guarded(Property property)
		{
			try
			{
				IEnumerator run = Run(property);
				while (run.MoveNext())
				{
					yield return run.Current;
				}
			}
			finally
			{
				if (Squad.Count > 0 || Doors.Count > 0)
				{
					Withdraw();
				}
				Running = false;
			}
		}

		public static void Stage()
		{
			MelonCoroutines.Start(StageWhenSpawned());
		}

		private static IEnumerator StageWhenSpawned()
		{
			float deadline = Time.realtimeSinceStartup + 30f;
			while (Time.realtimeSinceStartup < deadline && !NPC.All.OfType<SwatOfficer>().All(Spawned))
			{
				yield return (object)new WaitForSeconds(1f);
			}
			if (Running)
			{
				yield break;
			}
			foreach (SwatOfficer item in NPC.All.OfType<SwatOfficer>().Where(Spawned))
			{
				Deploy(item, deployed: false, "");
			}
			Core.Debug($"Staged {NPC.All.OfType<SwatOfficer>().Count(Spawned)} SWAT officers.");
			Heat.HookNpcs();
		}

		private static IEnumerator Run(Property property)
		{
			string name = property.PropertyName;
			Core.Debug($"Raid on {name} in {Settings.RaidCountdown}s.");
			Vance.Notify("", "", $"raid:{Settings.RaidCountdown}:{name}");
			yield return (object)new WaitForSeconds((float)Settings.RaidCountdown);
			Breach(property);
			List<Vector3> waypoints = Waypoints(property);
			HashSet<string> spotted = new HashSet<string>();
			HashSet<string> arrested = new HashSet<string>();
			Dictionary<SwatOfficer, float> nextMove = new Dictionary<SwatOfficer, float>();
			float end = Time.time + (float)Settings.RaidDuration;
			int visited = 0;
			float diagnoseAt = Time.time + 1.5f;
			float minimumEnd = Time.time + 20f;
			while (Time.time < end && Squad.Count > 0)
			{
				List<Player> list = Targets(property, arrested);
				foreach (SwatOfficer officer in Squad)
				{
					var (player, num) = (from p in list
						select (p: p, Vector3.Distance(((NPC)officer).Position, ((Component)p).transform.position)) into t
						where t.Item2 <= 16f
						orderby t.Item2
						select t).FirstOrDefault();
					float value;
					if ((Object)(object)player != (Object)null)
					{
						spotted.Add(player.PlayerCode);
						if (num <= 2.2f && arrested.Add(player.PlayerCode))
						{
							Safely(delegate
							{
								//IL_001b: Unknown result type (might be due to invalid IL or missing references)
								((NPC)officer).Movement.FacePoint(((Component)player).transform.position);
							});
							Vance.Notify("", player.PlayerCode, "arrest");
							Core.Debug($"{((NPC)officer).FullName} arrested {player.PlayerCode} in {name}.");
						}
						else
						{
							Reach(officer, ((Component)player).transform.position);
							nextMove[officer] = Time.time + 0.5f;
						}
					}
					else if (visited < waypoints.Count && !Moving(officer) && (!nextMove.TryGetValue(officer, out value) || !(Time.time < value)))
					{
						Reach(officer, waypoints[visited++]);
						nextMove[officer] = Time.time + 2.5f;
					}
				}
				if (diagnoseAt > 0f && Time.time >= diagnoseAt)
				{
					diagnoseAt = 0f;
					Diagnose(property, waypoints);
				}
				if (list.Count == 0 && visited >= waypoints.Count && Time.time >= minimumEnd && !Squad.Any(Moving) && nextMove.Values.All((float t) => Time.time >= t))
				{
					break;
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			foreach (string item in spotted.Except(arrested))
			{
				Vance.Notify("", item, "wanted");
			}
			Withdraw();
			Heat.FinishRaid(property, spotted.Count > 0);
		}

		private static void Breach(Property property)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Vector3 entrance = property.SpawnPoint.position;
			string gun = GunPath();
			List<SwatOfficer> list = (from o in NPC.All.OfType<SwatOfficer>().Where(Spawned)
				orderby ((NPC)o).ID
				select o).Take(Settings.RaidOfficers).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				float angle = (float)num * (float)Math.PI * 2f / (float)list.Count;
				Deploy(list[num], deployed: true, gun);
				SwatOfficer officer = list[num];
				Safely(delegate
				{
					//IL_0016: 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_0040: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					Live(officer).Movement.Warp(entrance + new Vector3(Mathf.Cos(angle), 0f, Mathf.Sin(angle)) * 1.5f);
				});
				Squad.Add(list[num]);
			}
			if (Squad.Count == 0)
			{
				Core.Log.Warning("No SWAT officers were available for the raid.");
			}
			foreach (DoorController item in Object.FindObjectsOfType<DoorController>())
			{
				if (!((Object)(object)item == (Object)null) && Near(property, ((Component)item).transform))
				{
					Doors.Add((item, item.OpenableByNPCs));
					item.OpenableByNPCs = true;
					item.SetIsOpen_Server(true, (EDoorSide)1, false);
				}
			}
			Core.Debug($"Breached {property.PropertyName} with {Squad.Count} officers, {Doors.Count} doors opened.");
		}

		private static void Diagnose(Property property, List<Vector3> waypoints)
		{
			if (!Settings.DebugLogs)
			{
				return;
			}
			Core.Debug($"Raid waypoints: {waypoints.Count}. Players inside: {Targets(property, new HashSet<string>()).Count}.");
			foreach (SwatOfficer item in Squad)
			{
				NPC? obj = Live(item);
				NavMeshAgent val = ((obj != null) ? obj.Movement._agent : null);
				Core.Debug(((Object)(object)val == (Object)null) ? (((NPC)item).FullName + ": no agent.") : $"{((NPC)item).FullName}: enabled {((Behaviour)val).enabled}, on navmesh {val.isOnNavMesh}, stopped {val.isOnNavMesh && val.isStopped}, path {val.hasPath}, speed {val.speed:0.0}, moving {Moving(item)}.");
			}
		}

		private static void Deploy(SwatOfficer officer, bool deployed, string gun)
		{
			NPC npc = Live(officer);
			if (npc == null)
			{
				return;
			}
			MSGConversation mSGConversation = npc.MSGConversation;
			if (mSGConversation != null && mSGConversation.uiCreated)
			{
				mSGConversation.SetEntryVisibility(false);
			}
			if (deployed)
			{
				Safely(delegate
				{
					npc.Movement.SetAgentEnabled(true);
				});
				if (gun.Length > 0)
				{
					npc.SetEquippable_Networked_Return((NetworkConnection)null, gun);
				}
				npc.SendEquippableMessage_Networked((NetworkConnection)null, "Raise");
				((NPC)officer).Movement.AddSpeedControl("tmlheat_raid", 60, 0.85f);
			}
			else
			{
				npc.SendEquippableMessage_Networked((NetworkConnection)null, "Lower");
				npc.SetEquippable_Networked_Return((NetworkConnection)null, "");
				((NPC)officer).Movement.RemoveSpeedControl("tmlheat_raid");
				Safely(delegate
				{
					npc.Movement.Stop();
				});
			}
			npc.SetVisible(deployed, true);
		}

		private static NPC? Live(SwatOfficer officer)
		{
			if (!((Object)(object)((NPC)officer).gameObject == (Object)null))
			{
				return ((NPC)officer).gameObject.GetComponent<NPC>();
			}
			return null;
		}

		private static bool Moving(SwatOfficer officer)
		{
			try
			{
				NPC? obj = Live(officer);
				return obj != null && obj.Movement.IsMoving;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static void Reach(SwatOfficer officer, Vector3 target)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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)
			NPC npc = Live(officer);
			if (npc == null)
			{
				return;
			}
			List<Vector3> list = new List<Vector3> { target };
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(target, ref val, 3f, -1))
			{
				list.Add(((NavMeshHit)(ref val)).position);
			}
			list.AddRange(from d in Doors
				where (Object)(object)d.Door != (Object)null
				select ((Component)d.Door).transform.position into p
				orderby Vector3.Distance(p, target)
				select p);
			foreach (Vector3 point in list)
			{
				bool reachable = false;
				Safely(delegate
				{
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					reachable = npc.Movement.CanGetTo(point, 2.2f);
				});
				if (reachable)
				{
					Go(officer, point);
					return;
				}
			}
			Core.Debug($"{((NPC)officer).FullName} can't find a route towards {target}.");
			Go(officer, target);
		}

		private static void Go(SwatOfficer officer, Vector3 destination)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			Safely(delegate
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				NPC? obj = Live(officer);
				if (obj != null)
				{
					obj.Movement.SetDestination(destination);
				}
			});
		}

		private static void Safely(Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				Core.Debug("Raid officer action failed: " + ex.Message);
			}
		}

		private static bool Spawned(SwatOfficer officer)
		{
			NPC val = Live(officer);
			if (val != null)
			{
				return ((NetworkBehaviour)val).IsSpawned;
			}
			return false;
		}

		private static string GunPath()
		{
			Enumerator<PoliceOfficer> enumerator = PoliceOfficer.Officers.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PoliceOfficer current = enumerator.Current;
				if ((Object)(object)current != (Object)null && (Object)(object)current.GunPrefab != (Object)null)
				{
					return current.GunPrefab.AssetPath;
				}
			}
			return "";
		}

		private static List<Player> Targets(Property property, HashSet<string> arrested)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			List<Player> list = new List<Player>();
			Enumerator<Player> enumerator = Player.PlayerList.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Player current = enumerator.Current;
				if ((Object)(object)current != (Object)null && !arrested.Contains(current.PlayerCode) && property.DoBoundsContainPoint(((Component)current).transform.position))
				{
					list.Add(current);
				}
			}
			return list;
		}

		private static List<Vector3> Waypoints(Property property)
		{
			//IL_001b: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			if ((Object)(object)property.InteriorSpawnPoint != (Object)null)
			{
				list.Add(property.InteriorSpawnPoint.position);
			}
			if ((Object)(object)property.NPCSpawnPoint != (Object)null)
			{
				list.Add(property.NPCSpawnPoint.position);
			}
			foreach (Transform item in (Il2CppArrayBase<Transform>)(object)property.EmployeeIdlePoints)
			{
				if ((Object)(object)item != (Object)null)
				{
					list.Add(item.position);
				}
			}
			Enumerator<BuildableItem> enumerator2 = property.BuildableItems.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				BuildableItem current2 = enumerator2.Current;
				if ((Object)(object)current2 != (Object)null)
				{
					list.Add(((Component)current2).transform.position);
				}
			}
			IEnumerable<Vector3> second = (from _ in ((IEnumerable<Vector3>)list).Where((Func<Vector3, bool>)property.DoBoundsContainPoint)
				orderby Rng.Next()
				select _).Take(16);
			return (from d in Doors
				where (Object)(object)d.Door != (Object)null
				select ((Component)d.Door).transform.position).Concat(second).ToList();
		}

		private static bool Near(Property property, Transform door)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = door.position;
			if (!property.DoBoundsContainPoint(position) && !property.DoBoundsContainPoint(position + door.forward * 1.5f) && !property.DoBoundsContainPoint(position - door.forward * 1.5f) && !property.DoBoundsContainPoint(position + door.right * 1.5f))
			{
				return property.DoBoundsContainPoint(position - door.right * 1.5f);
			}
			return true;
		}

		private static void Withdraw()
		{
			fore