Decompiled source of DetectiveLicense v1.2.0

DetectiveLicense.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using ProtectorateShared;
using SOD.Common;
using SOD.Common.Helpers;
using SOD.Common.Helpers.DialogObjects;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DetectiveLicense")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+0a93c4585cf6d92cd2cc95ba73fb5bdf1b3f6c08")]
[assembly: AssemblyProduct("DetectiveLicense")]
[assembly: AssemblyTitle("DetectiveLicense")]
[assembly: AssemblyVersion("1.2.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 ProtectorateShared
{
	internal static class CredentialsCard
	{
		private const string RootName = "ProtectorateCredentials";

		private const string HeaderName = "00_Header";

		public static void Refresh(string sectionKey, string title, Func<List<string>> lines)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			MainMenuController instance = MainMenuController.Instance;
			RectTransform val = ((instance != null) ? instance.mainMenuContainer : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool num = instance.mainMenuActive && (Object)(object)SessionData.Instance != (Object)null && SessionData.Instance.startedGame && instance.currentComponent != null && (int)instance.currentComponent.component == 1;
			Transform val2 = ((Transform)val).Find("ProtectorateCredentials");
			if (!num)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2).gameObject.SetActive(false);
				}
				return;
			}
			if (val2 == null)
			{
				val2 = CreateRoot((Transform)(object)val, instance);
			}
			Transform val3 = val2.Find(sectionKey) ?? ((TMP_Text)CreateText(val2, sectionKey, instance, 17f)).transform;
			List<string> list = lines();
			TextMeshProUGUI component = ((Component)val3).GetComponent<TextMeshProUGUI>();
			if (list.Count == 0)
			{
				((Component)val3).gameObject.SetActive(false);
			}
			else
			{
				((TMP_Text)component).text = "<b><color=#E8B04B>" + title + "</color></b>\n" + string.Join("\n", list);
				((Component)val3).gameObject.SetActive(true);
			}
			bool active = false;
			List<string> list2 = new List<string>();
			for (int i = 0; i < val2.childCount; i++)
			{
				list2.Add(((Object)val2.GetChild(i)).name);
			}
			list2.Sort(StringComparer.Ordinal);
			for (int j = 0; j < list2.Count; j++)
			{
				Transform val4 = val2.Find(list2[j]);
				val4.SetSiblingIndex(j);
				if (list2[j] != "00_Header" && ((Component)val4).gameObject.activeSelf)
				{
					active = true;
				}
			}
			val2.SetAsLastSibling();
			((Component)val2).gameObject.SetActive(active);
		}

		private static Transform CreateRoot(Transform container, MainMenuController menu)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00b0: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ProtectorateCredentials");
			RectTransform obj = val.AddComponent<RectTransform>();
			((Transform)obj).SetParent(container, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 0f);
			obj.pivot = val2;
			Vector2 anchorMin = (obj.anchorMax = val2);
			obj.anchorMin = anchorMin;
			obj.anchoredPosition = new Vector2(-48f, 48f);
			Image obj2 = val.AddComponent<Image>();
			((Graphic)obj2).color = new Color(0.08f, 0.07f, 0.11f, 0.82f);
			((Graphic)obj2).raycastTarget = false;
			VerticalLayoutGroup obj3 = val.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj3).padding = new RectOffset
			{
				left = 20,
				right = 20,
				top = 14,
				bottom = 16
			};
			((HorizontalOrVerticalLayoutGroup)obj3).spacing = 10f;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
			ContentSizeFitter obj4 = val.AddComponent<ContentSizeFitter>();
			obj4.horizontalFit = (FitMode)2;
			obj4.verticalFit = (FitMode)2;
			TextMeshProUGUI obj5 = CreateText(val.transform, "00_Header", menu, 20f);
			((TMP_Text)obj5).text = "<b>CREDENTIALS</b>";
			((Graphic)obj5).color = new Color(0.95f, 0.93f, 0.88f, 1f);
			return val.transform;
		}

		private static TextMeshProUGUI CreateText(Transform parent, string name, MainMenuController menu, float size)
		{
			//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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			((Transform)val.AddComponent<RectTransform>()).SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)menu.buildText != (Object)null)
			{
				((TMP_Text)val2).font = ((TMP_Text)menu.buildText).font;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = new Color(0.86f, 0.84f, 0.8f, 1f);
			((Graphic)val2).raycastTarget = false;
			((TMP_Text)val2).enableWordWrapping = false;
			((TMP_Text)val2).richText = true;
			val.AddComponent<LayoutElement>().minWidth = 300f;
			return val2;
		}

		public static string Hours(float hours)
		{
			hours = Mathf.Max(0f, hours);
			int num = Mathf.FloorToInt(hours);
			int value = Mathf.FloorToInt((hours - (float)num) * 60f);
			if (num > 0)
			{
				return $"{num}h {value:00}m";
			}
			return $"{value}m";
		}
	}
	[HarmonyPatch]
	internal static class DialogGuard
	{
		private static ManualLogSource log;

		private static readonly PropertyInfo ResponseInfo = typeof(DialogObject).GetProperty("ResponseInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static ManualLogSource Log => log ?? (log = Logger.CreateLogSource("DialogGuard"));

		[HarmonyPatch(typeof(DialogController), "Start")]
		[HarmonyPrefix]
		internal static void Protect()
		{
			foreach (DialogObject knownModDialog in Lib.Dialogs.KnownModDialogs)
			{
				try
				{
					Keep((Object)(object)knownModDialog.Preset);
					object? obj = ResponseInfo?.GetValue(knownModDialog);
					Keep((Object)((obj is Object) ? obj : null));
				}
				catch (Exception ex)
				{
					Log.LogError((object)ex.Message);
				}
			}
		}

		private static void Keep(Object o)
		{
			//IL_000b: 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)
			if (o != (Object)null)
			{
				o.hideFlags = (HideFlags)(o.hideFlags | 0x20);
			}
		}

		[HarmonyPatch(typeof(EvidenceWitness), "GetDialogOptions", new Type[] { typeof(List<DataKey>) })]
		[HarmonyPostfix]
		private static void DropDead(List<DialogOption> __result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (__result == null)
			{
				return;
			}
			bool flag = default(bool);
			for (int num = __result.Count - 1; num >= 0; num--)
			{
				DialogOption obj = __result[num];
				DialogPreset val = ((obj != null) ? obj.preset : null);
				if (val != null && !((SoCustomComparison)(object)val != (SoCustomComparison)null))
				{
					ManualLogSource obj2 = Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(52, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipped a destroyed dialog option (msgID ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(val.msgID);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ranking ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val.ranking);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
					}
					obj2.LogWarning(val2);
					__result.RemoveAt(num);
				}
			}
		}
	}
}
namespace DetectiveLicense
{
	[HarmonyPatch]
	internal static class Credentials
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(MainMenuController), "SetMenuComponent", new Type[] { typeof(Component) })]
		private static void OnMenuComponent()
		{
			Refresh();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MainMenuController), "EnableMainMenu")]
		private static void OnMenu()
		{
			Refresh();
		}

		private static void Refresh()
		{
			try
			{
				CredentialsCard.Refresh("10_Detective", "Detective", Lines);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Credentials card: " + ex));
			}
		}

		private static List<string> Lines()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			if (Plugin.Licensed)
			{
				list.Add("Private investigator's license");
			}
			float gameTime = SessionData.Instance.gameTime;
			Dictionary<NewAddress, Vector2> guestPasses = GameplayController.Instance.guestPasses;
			foreach (NewAddress item in CaseLocations.Get())
			{
				if (guestPasses.ContainsKey(item))
				{
					float x = guestPasses[item].x;
					if (x > gameTime)
					{
						list.Add($"Crime scene permit: {((Object)item).name} ({CredentialsCard.Hours(x - gameTime)} left)");
					}
				}
			}
			return list;
		}
	}
	internal static class Dialogs
	{
		private sealed class PermitLogic : IDialogLogic
		{
			public bool IsDialogShown(DialogPreset preset, Citizen saysTo, SideJob jobRef)
			{
				if (!Plugin.Licensed)
				{
					return IsCityHallDesk(saysTo);
				}
				return false;
			}

			public ForceSuccess ShouldDialogSucceedOverride(DialogController instance, DialogOption dialog, Citizen saysTo, NewNode where, Actor saidBy)
			{
				if (CaseLocations.Get().Count > 0)
				{
					return (ForceSuccess)1;
				}
				return (ForceSuccess)2;
			}

			public void OnDialogExecute(DialogController instance, Citizen saysTo, Interactable saysToInteractable, NewNode where, Actor saidBy, bool success, NewRoom roomRef, SideJob jobRef)
			{
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Expected O, but got Unknown
				if (success)
				{
					float value = Plugin.PermitHours.Value;
					int num = CaseLocations.IssuePermit(value);
					Lib.GameMessage.Broadcast($"Crime scene permit: {num} location{((num == 1) ? "" : "s")}, {value:0.#} hours", (GameMessageType)0, (Icon)2, (Color?)InterfaceControls.Instance.messageGreen, 0f);
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Permit issued for ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" case location(s), ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(value);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" hours");
					}
					logger.LogInfo(val);
				}
			}
		}

		private sealed class RecordsLogic : IDialogLogic
		{
			public bool IsDialogShown(DialogPreset preset, Citizen saysTo, SideJob jobRef)
			{
				return IsCityHallDesk(saysTo);
			}

			public ForceSuccess ShouldDialogSucceedOverride(DialogController instance, DialogOption dialog, Citizen saysTo, NewNode where, Actor saidBy)
			{
				if (Plugin.Licensed)
				{
					return (ForceSuccess)1;
				}
				return (ForceSuccess)2;
			}

			public void OnDialogExecute(DialogController instance, Citizen saysTo, Interactable saysToInteractable, NewNode where, Actor saidBy, bool success, NewRoom roomRef, SideJob jobRef)
			{
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Expected O, but got Unknown
				if (!success)
				{
					return;
				}
				Human val = Records.DeskLogin((Human)(object)saysTo);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"Records: no lobby desk login found");
					return;
				}
				GameplayController.Instance.AddPasscode(val.passcode, false);
				Lib.GameMessage.Broadcast($"Public records: log in at a lobby desk as {val.GetInitialledName()} ({Plugin.PrintCost.Value} crows per printout)", (GameMessageType)0, (Icon)2, (Color?)InterfaceControls.Instance.messageGreen, 0f);
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(30, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Records login given: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(val.GetCitizenName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (asked ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Human)saysTo).GetCitizenName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
				}
				logger.LogInfo(val2);
			}
		}

		private sealed class LicenseLogic : IDialogLogic
		{
			public bool IsDialogShown(DialogPreset preset, Citizen saysTo, SideJob jobRef)
			{
				if (!Plugin.Licensed)
				{
					return IsCityHallDesk(saysTo);
				}
				return false;
			}

			public ForceSuccess ShouldDialogSucceedOverride(DialogController instance, DialogOption dialog, Citizen saysTo, NewNode where, Actor saidBy)
			{
				return (ForceSuccess)1;
			}

			public void OnDialogExecute(DialogController instance, Citizen saysTo, Interactable saysToInteractable, NewNode where, Actor saidBy, bool success, NewRoom roomRef, SideJob jobRef)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if (success)
				{
					Plugin.Licensed = true;
					CaseLocations.Invalidate();
					Lib.GameMessage.Broadcast("Private investigator's license acquired", (GameMessageType)0, (Icon)13, (Color?)InterfaceControls.Instance.messageGreen, 0f);
					Plugin.Logger.LogInfo((object)"License acquired");
				}
			}
		}

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

		public static void Register()
		{
			Lib.Dialogs.Builder("DetectiveLicense_Permit").SetText("I need a crime scene permit.").SetDialogLogic((IDialogLogic)(object)new PermitLogic())
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.cost = Plugin.PermitCost.Value;
					p.ranking = 6;
				})
				.AddResponse("Here's your permit. Don't touch anything you don't need to.", true, true)
				.AddResponse("There aren't any open murder cases right now, Detective.", false, true)
				.CreateAndRegister();
			Lib.Dialogs.Builder("DetectiveLicense_License").SetText("I'd like a private investigator's license.").SetDialogLogic((IDialogLogic)(object)new LicenseLogic())
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.cost = Plugin.LicenseCost.Value;
					p.ranking = 5;
				})
				.AddResponse("All in order. Welcome to the profession, Detective.", true, true)
				.CreateAndRegister();
			Lib.Dialogs.Builder("DetectiveLicense_Records").SetText("I need to check the public records.").SetDialogLogic((IDialogLogic)(object)new RecordsLogic())
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.ranking = 4;
				})
				.AddResponse("Use the terminal at the desk, my login's fine. Printouts are charged per page.", true, true)
				.AddResponse("Records access is for licensed investigators only. You can apply for a license here.", false, true)
				.CreateAndRegister();
		}

		internal static bool IsCityHallDesk(Citizen citizen)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			if ((Object)(object)citizen == (Object)null)
			{
				return false;
			}
			Occupation job = ((Human)citizen).job;
			object obj;
			if (job == null)
			{
				obj = null;
			}
			else
			{
				Company employer = job.employer;
				if (employer == null)
				{
					obj = null;
				}
				else
				{
					NewGameLocation placeOfBusiness = employer.placeOfBusiness;
					obj = ((placeOfBusiness != null) ? placeOfBusiness.building : null);
				}
			}
			NewBuilding val = (NewBuilding)obj;
			if ((SoCustomComparison)(object)((val != null) ? val.preset : null) == (SoCustomComparison)null || ((SoCustomComparison)val.preset).presetName != "CityHall")
			{
				return false;
			}
			if (LoggedStaff.Add(((Human)citizen).humanID))
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(30, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("City Hall staff: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Human)citizen).GetCitizenName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" job=");
					OccupationPreset preset = job.preset;
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>((preset != null) ? ((Object)preset).name : null);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" atWork=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(((Actor)citizen).isAtWork);
				}
				logger.LogDebug(val2);
			}
			if (!((Actor)citizen).isAtWork)
			{
				return false;
			}
			string value = Plugin.DeskJobs.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return true;
			}
			OccupationPreset preset2 = job.preset;
			string jobName = ((preset2 != null) ? ((Object)preset2).name : null);
			if (jobName != null)
			{
				return value.Split(',').Any((string j) => j.Trim().Equals(jobName, StringComparison.OrdinalIgnoreCase));
			}
			return false;
		}
	}
	[BepInPlugin("sodmods.detectivelicense", "Detective License", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		public const string Guid = "sodmods.detectivelicense";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<int> PermitCost;

		internal static ConfigEntry<float> PermitHours;

		internal static ConfigEntry<int> LicenseCost;

		internal static ConfigEntry<float> LookAroundBonus;

		internal static ConfigEntry<float> TrustAuthorityBonus;

		internal static ConfigEntry<float> DistrustAuthorityBonus;

		internal static ConfigEntry<string> DeskJobs;

		internal static ConfigEntry<int> PrintCost;

		internal static bool Licensed;

		public override void Load()
		{
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			PermitCost = ((BasePlugin)this).Config.Bind<int>("Permit", "Cost", 100, "Price of a crime scene permit, in crows.");
			PermitHours = ((BasePlugin)this).Config.Bind<float>("Permit", "Hours", 4f, "How many in-game hours a permit lasts (1 in-game hour is about 6.5 real minutes).");
			LicenseCost = ((BasePlugin)this).Config.Bind<int>("License", "Cost", 1500, "Price of a private investigator's license, in crows.");
			LookAroundBonus = ((BasePlugin)this).Config.Bind<float>("License", "LookAroundBonus", 0.3f, "Added to the chance a resident lets you look around, for licensed investigators (0.3 = +30%).");
			TrustAuthorityBonus = ((BasePlugin)this).Config.Bind<float>("License", "TrustAuthorityBonus", 0.2f, "Extra chance on top of LookAroundBonus for residents who trust authority.");
			DistrustAuthorityBonus = ((BasePlugin)this).Config.Bind<float>("License", "DistrustAuthorityBonus", -0.25f, "Change on top of LookAroundBonus for residents who distrust authority (negative = the license helps less).");
			PrintCost = ((BasePlugin)this).Config.Bind<int>("Records", "PrintCost", 50, "Price of each citizen file printed at the City Hall lobby computers (license holders only), in crows.");
			DeskJobs = ((BasePlugin)this).Config.Bind<string>("CityHall", "DeskJobs", "", "Comma-separated job names at City Hall who sell permits and licenses (e.g. Receptionist). Empty = any City Hall employee at work.");
			Lib.SaveGame.OnAfterLoad += delegate(object? _, SaveGameArgs args)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				Licensed = SaveData.Load(args);
				ManualLogSource log = ((BasePlugin)this).Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Save loaded: licensed = ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Licensed);
				}
				log.LogInfo(val);
			};
			Lib.SaveGame.OnAfterSave += delegate(object? _, SaveGameArgs args)
			{
				SaveData.Save(args, Licensed);
			};
			Lib.SaveGame.OnBeforeNewGame += delegate
			{
				Licensed = false;
			};
			Dialogs.Register();
			DialogGuard.Protect();
			new Harmony("sodmods.detectivelicense").PatchAll(typeof(Plugin).Assembly);
			((BasePlugin)this).Log.LogInfo((object)"Detective License loaded");
		}
	}
	internal static class SaveData
	{
		private const string FileName = "detectivelicense.txt";

		public static bool Load(SaveGameArgs args)
		{
			try
			{
				string saveGameDataPath = Lib.SaveGame.GetSaveGameDataPath(args, "detectivelicense.txt");
				return File.Exists(saveGameDataPath) && File.ReadAllText(saveGameDataPath).Trim() == "licensed";
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Failed to load license state: " + ex));
				return false;
			}
		}

		public static void Save(SaveGameArgs args, bool licensed)
		{
			try
			{
				string saveGameDataPath = Lib.SaveGame.GetSaveGameDataPath(args, "detectivelicense.txt");
				if (licensed)
				{
					File.WriteAllText(saveGameDataPath, "licensed");
				}
				else if (File.Exists(saveGameDataPath))
				{
					File.Delete(saveGameDataPath);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Failed to save license state: " + ex));
			}
		}
	}
	internal static class CaseLocations
	{
		private static readonly HashSet<int> cachedIds = new HashSet<int>();

		private static float cachedAt = -10f;

		private static bool LogMurders;

		public static List<NewAddress> Get()
		{
			List<NewAddress> list = new List<NewAddress>();
			MurderController instance = MurderController.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return list;
			}
			Collect(instance.activeMurders, list);
			Collect(instance.inactiveMurders, list);
			return list;
		}

		private static void Collect(List<Murder> murders, List<NewAddress> into)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if (murders == null)
			{
				return;
			}
			bool flag = default(bool);
			for (int i = 0; i < murders.Count; i++)
			{
				Murder val = murders[i];
				if (val == null || (int)val.state == 9)
				{
					continue;
				}
				Human victim = val.victim;
				Death val2 = ((victim != null) ? victim.death : null);
				if (val2 == null || !val2.isDead || !val2.reported)
				{
					continue;
				}
				if (LogMurders)
				{
					ManualLogSource logger = Plugin.Logger;
					BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(60, 5, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Open case: victim ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(val.victim.GetCitizenName());
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", state ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<MurderState>(val.state);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", ");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("location '");
						NewGameLocation location = val.location;
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((location != null) ? ((Object)location).name : null);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' (address: ");
						NewGameLocation location2 = val.location;
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>((Object)(object)((location2 != null) ? location2.thisAsAddress : null) != (Object)null);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("), home '");
						NewAddress home = val.victim.home;
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((home != null) ? ((Object)home).name : null);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("'");
					}
					logger.LogDebug(val3);
				}
				NewGameLocation location3 = val.location;
				Add((location3 != null) ? location3.thisAsAddress : null, into);
				Add(val.victim.home, into);
			}
		}

		private static void Add(NewAddress address, List<NewAddress> into)
		{
			if ((Object)(object)address != (Object)null && !into.Contains(address))
			{
				into.Add(address);
			}
		}

		public static bool Covers(NewAddress address)
		{
			if ((Object)(object)address == (Object)null)
			{
				return false;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - cachedAt > 2f)
			{
				cachedAt = unscaledTime;
				cachedIds.Clear();
				foreach (NewAddress item in Get())
				{
					cachedIds.Add(item.id);
				}
			}
			return cachedIds.Contains(address.id);
		}

		public static void Invalidate()
		{
			cachedAt = -10f;
		}

		public static int IssuePermit(float hours)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			LogMurders = true;
			List<NewAddress> list = Get();
			LogMurders = false;
			bool flag = default(bool);
			foreach (NewAddress item in list)
			{
				GameplayController.Instance.AddGuestPass(item, hours);
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(35, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Permit covers '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)item).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (id ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item.id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", building '");
					NewBuilding building = ((NewGameLocation)item).building;
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((building != null) ? ((Object)building).name : null);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("')");
				}
				logger.LogInfo(val);
			}
			return list.Count;
		}
	}
	[HarmonyPatch(typeof(Human), "IsTrespassing")]
	internal static class LicensedCaseAccessPatch
	{
		private static void Postfix(Human __instance, NewRoom room, ref int trespassEscalation, ref bool __result)
		{
			if (__result && Plugin.Licensed && ((Actor)__instance).isPlayer && !((Actor)__instance).inAirVent)
			{
				object address;
				if (room == null)
				{
					address = null;
				}
				else
				{
					NewGameLocation gameLocation = room.gameLocation;
					address = ((gameLocation != null) ? gameLocation.thisAsAddress : null);
				}
				if (CaseLocations.Covers((NewAddress)address))
				{
					__result = false;
					trespassEscalation = 0;
				}
			}
		}
	}
	[HarmonyPatch(typeof(UpgradeEffectController), "GetUpgradeEffect")]
	internal static class UpgradeEffectPatch
	{
		private static void Postfix(Effect effect, ref float __result)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			if (!Plugin.Licensed)
			{
				return;
			}
			if ((int)effect == 61)
			{
				__result = Math.Max(__result, 1f);
			}
			else
			{
				if ((int)effect != 64)
				{
					return;
				}
				if ((Object)(object)LookAroundTarget.Current != (Object)null)
				{
					float num = LookAroundTarget.Bonus(LookAroundTarget.Current);
					__result += num;
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(49, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LookAround] bonus +");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "P0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" applied for ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(LookAroundTarget.Current.GetCitizenName());
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (modifier now ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(__result, "0.00");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
					}
					logger.LogDebug(val);
				}
				else
				{
					Plugin.Logger.LogDebug((object)"[LookAround] guestPassIssueModifier read with no current target (bonus not applied)");
				}
			}
		}
	}
	[HarmonyPatch(typeof(DialogController), "ExecuteDialog")]
	internal static class LookAroundTarget
	{
		internal static Human Current;

		private static void Prefix(DialogOption dialog, Interactable saysTo)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			Current = null;
			if ((SoCustomComparison)(object)((dialog != null) ? dialog.preset : null) != (SoCustomComparison)null && (int)dialog.preset.specialCase == 10)
			{
				object current;
				if (saysTo == null)
				{
					current = null;
				}
				else
				{
					Actor isActor = saysTo.isActor;
					current = ((isActor != null) ? ((Il2CppObjectBase)isActor).TryCast<Human>() : null);
				}
				Current = (Human)current;
				DialogPreset preset = dialog.preset;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(88, 7, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LookAround] asking ");
					Human current2 = Current;
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((current2 != null) ? current2.GetCitizenName() : null);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": baseChance=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(preset.baseChance, "0.00");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("useSuccessTest=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(preset.useSuccessTest);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" traitRules=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int?>(preset.modifySuccessChanceTraits?.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("trust=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(HasTrait(Current, "Principle-TrustOfAuthority"));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" distrust=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(HasTrait(Current, "Principle-DistrustOfAuthority"));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("licensed=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Plugin.Licensed);
				}
				logger.LogDebug(val);
			}
		}

		private static void Postfix(DialogOption dialog, bool __result)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if ((SoCustomComparison)(object)((dialog != null) ? dialog.preset : null) != (SoCustomComparison)null && (int)dialog.preset.specialCase == 10)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(21, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LookAround] result: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(__result ? "SUCCESS" : "refused");
				}
				logger.LogDebug(val);
			}
		}

		private static void Finalizer()
		{
			Current = null;
		}

		internal static float Bonus(Human resident)
		{
			float num = Plugin.LookAroundBonus.Value;
			if (HasTrait(resident, "Principle-TrustOfAuthority"))
			{
				num += Plugin.TrustAuthorityBonus.Value;
			}
			if (HasTrait(resident, "Principle-DistrustOfAuthority"))
			{
				num += Plugin.DistrustAuthorityBonus.Value;
			}
			return num;
		}

		private static bool HasTrait(Human human, string traitName)
		{
			List<Trait> val = ((human != null) ? human.characterTraits : null);
			if (val == null)
			{
				return false;
			}
			for (int i = 0; i < val.Count; i++)
			{
				Trait obj = val[i];
				if ((SoCustomComparison)(object)((obj != null) ? obj.trait : null) != (SoCustomComparison)null && ((Object)val[i].trait).name == traitName)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class Records
	{
		private const string LobbyPreset = "CityHallLobby";

		private const string DatabaseAppName = "GovDatabase";

		internal static bool IsLobby(NewAddress address)
		{
			if ((SoCustomComparison)(object)((address != null) ? address.addressPreset : null) != (SoCustomComparison)null)
			{
				return ((Object)address.addressPreset).name == "CityHallLobby";
			}
			return false;
		}

		private static NewAddress AddressOf(ComputerController cc)
		{
			if (cc == null)
			{
				return null;
			}
			InteractableController ic = cc.ic;
			if (ic == null)
			{
				return null;
			}
			Interactable interactable = ic.interactable;
			if (interactable == null)
			{
				return null;
			}
			NewNode node = interactable.node;
			if (node == null)
			{
				return null;
			}
			NewGameLocation gameLocation = node.gameLocation;
			if (gameLocation == null)
			{
				return null;
			}
			return gameLocation.thisAsAddress;
		}

		internal static Human DeskLogin(Human clerk)
		{
			List<Human> list = new List<Human>();
			object obj;
			if (clerk == null)
			{
				obj = null;
			}
			else
			{
				Occupation job = clerk.job;
				if (job == null)
				{
					obj = null;
				}
				else
				{
					Company employer = job.employer;
					if (employer == null)
					{
						obj = null;
					}
					else
					{
						NewGameLocation placeOfBusiness = employer.placeOfBusiness;
						obj = ((placeOfBusiness != null) ? placeOfBusiness.building : null);
					}
				}
			}
			NewBuilding val = (NewBuilding)obj;
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Enumerator<int, NewFloor> enumerator = val.floors.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Enumerator<NewAddress> enumerator2 = enumerator.Current.Value.addresses.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					NewAddress current = enumerator2.Current;
					if (!IsLobby(current))
					{
						continue;
					}
					Enumerator<NewRoom> enumerator3 = ((NewGameLocation)current).rooms.GetEnumerator();
					while (enumerator3.MoveNext())
					{
						Enumerator<NewNode> enumerator4 = enumerator3.Current.nodes.GetEnumerator();
						while (enumerator4.MoveNext())
						{
							Enumerator<Interactable> enumerator5 = enumerator4.Current.interactables.GetEnumerator();
							while (enumerator5.MoveNext())
							{
								Interactable current2 = enumerator5.Current;
								if ((SoCustomComparison)(object)((current2 != null) ? current2.preset : null) == (SoCustomComparison)null || !current2.preset.isComputer || current2.furnitureParent == null)
								{
									continue;
								}
								Enumerator<OwnerKey, int> enumerator6 = current2.furnitureParent.ownerMap.GetEnumerator();
								while (enumerator6.MoveNext())
								{
									KeyValuePair<OwnerKey, int> current3 = enumerator6.Current;
									Human h = current3.Key.human;
									if (!((Object)(object)h == (Object)null) && h.passcode != null)
									{
										if (h.humanID == clerk.humanID)
										{
											return h;
										}
										if (!list.Exists((Human o) => o.humanID == h.humanID))
										{
											list.Add(h);
										}
									}
								}
							}
						}
					}
				}
			}
			if (list.Count <= 0)
			{
				return null;
			}
			return list[0];
		}

		[HarmonyPatch(typeof(DesktopApp), "UpdateIcons")]
		[HarmonyPrefix]
		private static void Install(DesktopApp __instance)
		{
			try
			{
				NewAddress val = AddressOf(((CruncherAppContent)__instance).controller);
				if (!IsLobby(val))
				{
					return;
				}
				Enumerator<CruncherAppPreset> enumerator = ((CruncherAppContent)__instance).controller.ic.interactable.preset.additionalApps.GetEnumerator();
				while (enumerator.MoveNext())
				{
					CruncherAppPreset current = enumerator.Current;
					if (!((SoCustomComparison)(object)current == (SoCustomComparison)null) && !(((Object)current).name != "GovDatabase"))
					{
						List<AddressPreset> onlyInAddresses = current.onlyInAddresses;
						bool flag = onlyInAddresses.Contains(val.addressPreset);
						if (Plugin.Licensed && !flag)
						{
							onlyInAddresses.Add(val.addressPreset);
						}
						else if (!Plugin.Licensed && flag)
						{
							onlyInAddresses.Remove(val.addressPreset);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Records install failed: " + ex));
			}
		}

		[HarmonyPatch(typeof(DatabaseApp), "OnPrintEntry")]
		[HarmonyPrefix]
		private static bool BeforePrint(DatabaseApp __instance, out bool __state)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			__state = false;
			ComputerController controller = ((CruncherAppContent)__instance).controller;
			if (!IsLobby(AddressOf(controller)))
			{
				return true;
			}
			int value = Plugin.PrintCost.Value;
			__state = value > 0 && controller.printedDocument == null && controller.printTimer <= 0f;
			if (__state && GameplayController.Instance.money < value)
			{
				__state = false;
				AudioController.Instance.PlayWorldOneShot(AudioControls.Instance.computerInvalidPasscode, (Actor)(object)Player.Instance, controller.ic.interactable.node, controller.ic.interactable.wPos, (Interactable)null, (List<FMODParam>)null, 1f, (List<NewNode>)null, false, (SoundMaterialOverride)null, false);
				Lib.GameMessage.Broadcast($"Records printout: {value} crows", (GameMessageType)0, (Icon)17, (Color?)InterfaceControls.Instance.messageRed, 0f);
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(DatabaseApp), "OnPrintEntry")]
		[HarmonyPostfix]
		private static void AfterPrint(DatabaseApp __instance, bool __state)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			if (__state && ((CruncherAppContent)__instance).controller.printedDocument != null)
			{
				int value = Plugin.PrintCost.Value;
				GameplayController.Instance.AddMoney(-value, true, "public records");
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Records printout: charged ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(value);
				}
				logger.LogInfo(val);
			}
		}
	}
}