Decompiled source of PinObjectiveLeads v1.0.0

SoDPinObjectiveLeads.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SoDPinObjectiveLeads")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SoDPinObjectiveLeads")]
[assembly: AssemblyTitle("SoDPinObjectiveLeads")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 SoDPinObjectiveLeads
{
	[BepInPlugin("sm3gm.sod.pinobjectiveleads", "Pin Objective Leads", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public const string GUID = "sm3gm.sod.pinobjectiveleads";

		public const string VER = "1.0.0";

		internal static ManualLogSource L;

		internal static ConfigEntry<bool> PinAddresses;

		internal static ConfigEntry<bool> PinPhones;

		internal static ConfigEntry<bool> IncludeMurder;

		internal static ConfigEntry<bool> IncludeSideJobs;

		internal static ConfigEntry<bool> PinSightings;

		public override void Load()
		{
			L = ((BasePlugin)this).Log;
			PinAddresses = ((BasePlugin)this).Config.Bind<bool>("Pin", "Addresses", true, "When a HUD objective names a place (Fry Boulevard, an apartment), pin it on that case board so it is clickable and you can autotravel.");
			PinPhones = ((BasePlugin)this).Config.Bind<bool>("Pin", "Phones", true, "When a HUD objective is a call or a phone at a place, pin that number on the case board.");
			PinSightings = ((BasePlugin)this).Config.Bind<bool>("Pin", "Sightings", true, "When you ask someone \"Have you seen...\" and they name a place (where they saw the person, or where the person lives or works), pin it on the case board.");
			IncludeMurder = ((BasePlugin)this).Config.Bind<bool>("Cases", "Murder", true, "Also pin from murder-case objectives.");
			IncludeSideJobs = ((BasePlugin)this).Config.Bind<bool>("Cases", "SideJobs", true, "Also pin from sidejob objectives.");
			Harmony.CreateAndPatchAll(typeof(AddObjectivePatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(CleanUpWords), (string)null);
			Harmony.CreateAndPatchAll(typeof(SightingProbe), (string)null);
			((BasePlugin)this).AddComponent<ScanBehaviour>();
			L.LogInfo((object)("=== SoDPinObjectiveLeads 1.0.0 starting addr=" + PinAddresses.Value + " phone=" + PinPhones.Value + " murder=" + IncludeMurder.Value + " sidejob=" + IncludeSideJobs.Value + " ==="));
		}
	}
	public class ScanBehaviour : MonoBehaviour
	{
		private float _acc;

		public ScanBehaviour(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			_acc += Time.unscaledDeltaTime;
			if (!(_acc < 1f))
			{
				_acc = 0f;
				Pinner.ScanActiveCases();
			}
		}
	}
	[HarmonyPatch(typeof(Strings), "GetContainedValue")]
	public static class CleanUpWords
	{
		internal static NewGameLocation? Heard;

		private static float armedUntil = -1f;

		private static void Postfix(string withinScope, string newValue, Object inputObject)
		{
			try
			{
				string text = (withinScope ?? "").ToLowerInvariant();
				string text2 = (newValue ?? "").ToLowerInvariant();
				if (text == "killer" && text2 == "cleanupreward")
				{
					armedUntil = Time.unscaledTime + 30f;
				}
				else if (!(Time.unscaledTime > armedUntil) && inputObject != null && !(text2 != "name"))
				{
					NewAddress val = ((Il2CppObjectBase)inputObject).TryCast<NewAddress>();
					if (!((Object)(object)val == (Object)null))
					{
						armedUntil = -1f;
						Heard = (NewGameLocation?)(object)val;
						Plugin.L.LogInfo((object)("[PIN] clean-up call names " + ((Object)val).name));
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Case), "AddObjective")]
	public static class AddObjectivePatch
	{
		private static void Postfix(Case __instance)
		{
			try
			{
				Pinner.PinFromCase(__instance);
			}
			catch (Exception ex)
			{
				Plugin.L.LogInfo((object)("[PIN] AddObjective: " + ex.Message));
			}
		}
	}
	internal static class Pinner
	{
		private static readonly HashSet<string> Once = new HashSet<string>();

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

		private static int _lastActive = -1;

		private static string? _toldCleanUp;

		private static void LogSig(Case c, string sig, string msg)
		{
			string key = ((c.name != null) ? c.name : "?");
			if (!LastSig.TryGetValue(key, out var value) || !(value == sig))
			{
				LastSig[key] = sig;
				Plugin.L.LogInfo((object)("[PIN] " + msg));
			}
		}

		internal static void ScanActiveCases()
		{
			try
			{
				CasePanelController instance = CasePanelController.Instance;
				if (!((Object)(object)instance == (Object)null) && instance.activeCases != null)
				{
					List<Case> activeCases = instance.activeCases;
					if (activeCases.Count != _lastActive)
					{
						_lastActive = activeCases.Count;
						Plugin.L.LogInfo((object)("[PIN] active cases=" + activeCases.Count));
					}
					for (int i = 0; i < activeCases.Count; i++)
					{
						PinFromCase(activeCases[i]);
					}
					CleanUpCall(instance);
					Sightings(instance);
				}
			}
			catch
			{
			}
		}

		private static void CleanUpCall(CasePanelController panel)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			MurderController instance = MurderController.Instance;
			if ((Object)(object)instance == (Object)null || !Plugin.IncludeMurder.Value)
			{
				return;
			}
			PhoneCall coverUpCall = instance.coverUpCall;
			if (coverUpCall == null)
			{
				return;
			}
			CallState state = coverUpCall.state;
			if ((int)state != 3 && (int)state != 4)
			{
				return;
			}
			NewGameLocation heard = CleanUpWords.Heard;
			if ((Object)(object)heard == (Object)null)
			{
				return;
			}
			Case val = instance.currentActiveCase;
			if (val == null && panel.activeCases != null)
			{
				for (int i = 0; i < panel.activeCases.Count; i++)
				{
					if (panel.activeCases[i] != null && (int)panel.activeCases[i].caseType == 1)
					{
						val = panel.activeCases[i];
						break;
					}
				}
			}
			if ((Object)(object)heard == (Object)null || val == null)
			{
				return;
			}
			if (Once.Contains(val.name + ":loc:" + ((Object)heard).name))
			{
				if (_toldCleanUp != ((Object)heard).name)
				{
					_toldCleanUp = ((Object)heard).name;
					Plugin.L.LogInfo((object)("[PIN] clean-up call place " + ((Object)heard).name + " was already pinned to " + val.name));
				}
			}
			else
			{
				PinNamedLocation(panel, val, heard, "clean-up call");
			}
		}

		private static void Sightings(CasePanelController panel)
		{
			if (SightingProbe.Heard.Count == 0)
			{
				return;
			}
			try
			{
				if ((Object)(object)InteractionController.Instance != (Object)null && InteractionController.Instance.dialogMode)
				{
					return;
				}
			}
			catch
			{
			}
			Case activeCase = panel.activeCase;
			if (activeCase == null)
			{
				return;
			}
			List<NewGameLocation> list;
			lock (SightingProbe.Heard)
			{
				list = new List<NewGameLocation>(SightingProbe.Heard);
				SightingProbe.Heard.Clear();
			}
			foreach (NewGameLocation item in list)
			{
				PinNamedLocation(panel, activeCase, item, "sighting");
			}
		}

		internal static void PinFromCase(Case c)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (c == null)
			{
				return;
			}
			string text = "?";
			try
			{
				text = ((object)c.caseType/*cast due to .constrained prefix*/).ToString();
			}
			catch
			{
			}
			if (!CaseWanted(c))
			{
				LogSig(c, "unwanted:" + text, "case=" + c.name + " type=" + text + " skipped: type not wanted or disabled in config");
				return;
			}
			CasePanelController instance = CasePanelController.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			List<Objective> currentActiveObjectives = c.currentActiveObjectives;
			if (currentActiveObjectives == null)
			{
				LogSig(c, "nullobjs", "case=" + c.name + " type=" + text + " currentActiveObjectives is null");
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			for (int i = 0; i < currentActiveObjectives.Count; i++)
			{
				Objective val = currentActiveObjectives[i];
				if (val == null || val.isComplete || val.isCancelled)
				{
					continue;
				}
				List<ObjectiveTrigger> list = new List<ObjectiveTrigger>();
				try
				{
					if (val.queueElement != null && val.queueElement.triggers != null)
					{
						Enumerator<ObjectiveTrigger> enumerator = val.queueElement.triggers.GetEnumerator();
						while (enumerator.MoveNext())
						{
							ObjectiveTrigger current = enumerator.Current;
							list.Add(current);
						}
					}
				}
				catch
				{
				}
				try
				{
					if (val.appliedProgress != null)
					{
						Enumerator<ObjectiveTrigger> enumerator = val.appliedProgress.GetEnumerator();
						while (enumerator.MoveNext())
						{
							ObjectiveTrigger current2 = enumerator.Current;
							list.Add(current2);
						}
					}
				}
				catch
				{
				}
				try
				{
					if (val.objectiveAddOn != null)
					{
						list.Add(val.objectiveAddOn);
					}
				}
				catch
				{
				}
				for (int j = 0; j < list.Count; j++)
				{
					ObjectiveTrigger val2 = list[j];
					if (val2 != null)
					{
						num2++;
						NewGameLocation val3 = LocationFromTrigger(val2);
						if ((Object)(object)val3 != (Object)null)
						{
							num3++;
						}
						if (IsNamed(val3))
						{
							num4++;
						}
						bool flag = IsPhoneTrigger(val2);
						if (flag)
						{
							num5++;
						}
						if (Plugin.PinAddresses.Value && PinNamedLocation(instance, c, val3, "obj"))
						{
							num++;
						}
						if (Plugin.PinPhones.Value && flag && PinPhonesAt(instance, c, val3, val2))
						{
							num++;
						}
					}
				}
			}
			LogSig(c, currentActiveObjectives.Count + "/" + num2 + "/" + num3 + "/" + num4 + "/" + num5, "case=" + c.name + " type=" + text + " objs=" + currentActiveObjectives.Count + " triggers=" + num2 + " withLocation=" + num3 + " named=" + num4 + " phoneTriggers=" + num5);
			if (num <= 0)
			{
				return;
			}
			Plugin.L.LogInfo((object)("[PIN] relock after " + num + " pins case=" + c.name));
			try
			{
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
			}
			catch
			{
			}
		}

		private static bool AlreadyPinned(Evidence ev, DataKey key)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<DataKey> val = new List<DataKey>();
				val.Add(key);
				return (Object)(object)ev.GetPinned(val) != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static bool CaseWanted(Case c)
		{
			//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_0009: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			try
			{
				CaseType caseType = c.caseType;
				if ((int)caseType == 1)
				{
					return Plugin.IncludeMurder.Value;
				}
				if ((int)caseType == 2)
				{
					return Plugin.IncludeSideJobs.Value;
				}
				return true;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsPhoneTrigger(ObjectiveTrigger t)
		{
			//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_000a: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			try
			{
				ObjectiveTriggerType triggerType = t.triggerType;
				return (int)triggerType == 14 || (int)triggerType == 20 || (int)triggerType == 31 || (int)triggerType == 52;
			}
			catch
			{
				return false;
			}
		}

		private static NewGameLocation LocationFromTrigger(ObjectiveTrigger t)
		{
			try
			{
				if ((Object)(object)t.gameLocation != (Object)null)
				{
					return t.gameLocation;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)t.room != (Object)null && (Object)(object)t.room.gameLocation != (Object)null)
				{
					return t.room.gameLocation;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)t.door != (Object)null && t.door.wall != null && t.door.wall.node != null)
				{
					return t.door.wall.node.gameLocation;
				}
			}
			catch
			{
			}
			try
			{
				if (t.node != null && (Object)(object)t.node.gameLocation != (Object)null)
				{
					return t.node.gameLocation;
				}
			}
			catch
			{
			}
			try
			{
				if (t.interactable != null && t.interactable.node != null)
				{
					return t.interactable.node.gameLocation;
				}
			}
			catch
			{
			}
			try
			{
				if (t.addressID > 0)
				{
					CityData instance = CityData.Instance;
					NewAddress result = default(NewAddress);
					if ((Object)(object)instance != (Object)null && instance.addressDictionary != null && instance.addressDictionary.TryGetValue(t.addressID, ref result))
					{
						return (NewGameLocation)(object)result;
					}
				}
			}
			catch
			{
			}
			try
			{
				if (t.streetID > 0)
				{
					List<StreetController> val = (((Object)(object)CityData.Instance != (Object)null) ? CityData.Instance.streetDirectory : null);
					if (val != null)
					{
						for (int i = 0; i < val.Count; i++)
						{
							StreetController val2 = val[i];
							if ((Object)(object)val2 != (Object)null && val2.streetID == t.streetID)
							{
								return (NewGameLocation)(object)val2;
							}
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static bool IsNamed(NewGameLocation loc)
		{
			if ((Object)(object)loc == (Object)null)
			{
				return false;
			}
			try
			{
				string name = ((Object)loc).name;
				if (string.IsNullOrEmpty(name))
				{
					return false;
				}
				string text = name.ToLowerInvariant();
				return text != "unknown" && !text.Contains("unknown");
			}
			catch
			{
				return false;
			}
		}

		private static bool PinNamedLocation(CasePanelController panel, Case c, NewGameLocation loc, string why)
		{
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			if (!IsNamed(loc))
			{
				return false;
			}
			string text = c.name + ":loc:" + ((Object)loc).name;
			if (IsAnswer(c, loc))
			{
				if (Once.Add(text + ":answer"))
				{
					Plugin.L.LogInfo((object)("[PIN] not pinned, it is an answer: " + ((Object)loc).name + " (" + why + ") case=" + c.name));
				}
				return false;
			}
			if (Once.Contains(text))
			{
				return false;
			}
			try
			{
				EvidenceLocation evidenceEntry = loc.evidenceEntry;
				if (evidenceEntry == null)
				{
					return false;
				}
				try
				{
					((Evidence)evidenceEntry).AddDiscovery((Discovery)7);
				}
				catch
				{
				}
				try
				{
					((Evidence)evidenceEntry).AddDiscovery((Discovery)0);
				}
				catch
				{
				}
				try
				{
					((Evidence)evidenceEntry).AddOrSetCustomName((DataKey)0, ((Object)loc).name);
				}
				catch
				{
				}
				try
				{
					((Evidence)evidenceEntry).AddOrSetCustomName((DataKey)14, ((Object)loc).name);
				}
				catch
				{
				}
				List<DataKey> val = new List<DataKey>();
				val.Add((DataKey)14);
				val.Add((DataKey)0);
				val.Add((DataKey)36);
				bool flag = false;
				try
				{
					flag = (Object)(object)((Evidence)evidenceEntry).GetPinned(val) != (Object)null;
				}
				catch
				{
				}
				if (!flag)
				{
					flag = AlreadyPinned((Evidence)(object)evidenceEntry, (DataKey)14);
				}
				if (flag)
				{
					Once.Add(text);
					Plugin.L.LogInfo((object)("[PIN] location already pinned, skipped " + ((Object)loc).name + " (" + why + ") case=" + c.name));
					return false;
				}
				panel.PinToCasePanel(c, (Evidence)(object)evidenceEntry, val, true, Vector2.zero, false);
				Once.Add(text);
				Plugin.L.LogInfo((object)("[PIN] location " + ((Object)loc).name + " (" + why + ") case=" + c.name));
				return true;
			}
			catch (Exception ex)
			{
				Plugin.L.LogInfo((object)("[PIN] loc " + why + ": " + ex.Message));
				return false;
			}
		}

		private static bool IsAnswer(Case c, NewGameLocation loc)
		{
			try
			{
				SideJob val = ((c != null) ? c.job : null);
				if (val == null || (Object)(object)loc == (Object)null)
				{
					return false;
				}
				Human purp = val.purp;
				if ((Object)(object)purp != (Object)null)
				{
					if (Same((NewGameLocation)(object)purp.home))
					{
						return true;
					}
					try
					{
						Occupation job = purp.job;
						object x;
						if (job == null)
						{
							x = null;
						}
						else
						{
							Company employer = job.employer;
							x = ((employer != null) ? employer.address : null);
						}
						if (Same((NewGameLocation)x))
						{
							return true;
						}
					}
					catch
					{
					}
				}
				if (val.activeJobItems != null)
				{
					Enumerator<JobTag, Interactable> enumerator = val.activeJobItems.GetEnumerator();
					while (enumerator.MoveNext())
					{
						KeyValuePair<JobTag, Interactable> current = enumerator.Current;
						try
						{
							Interactable value = current.Value;
							if (value != null)
							{
								NewNode obj2 = value.node ?? value.spawnNode;
								if (Same((obj2 != null) ? obj2.gameLocation : null))
								{
									return true;
								}
							}
						}
						catch
						{
						}
					}
				}
			}
			catch
			{
			}
			return false;
			bool Same(NewGameLocation val2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					return ((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)loc).Pointer;
				}
				return false;
			}
		}

		private static bool PinPhonesAt(CasePanelController panel, Case c, NewGameLocation loc, ObjectiveTrigger t)
		{
			int num = 0;
			try
			{
				Evidence evidence = t.evidence;
				EvidenceTelephone val = ((evidence != null) ? ((Il2CppObjectBase)evidence).TryCast<EvidenceTelephone>() : null);
				if (val != null && val.telephone != null && PinTelephone(panel, c, val.telephone, "trigger"))
				{
					num++;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)loc != (Object)null && loc.telephones != null)
				{
					int num2 = loc.telephones.Count;
					if (num2 > 2)
					{
						num2 = 2;
					}
					for (int i = 0; i < num2; i++)
					{
						if (PinTelephone(panel, c, loc.telephones[i], "loc"))
						{
							num++;
						}
					}
				}
			}
			catch
			{
			}
			return num > 0;
		}

		private static bool PinTelephone(CasePanelController panel, Case c, Telephone tel, string why)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (tel == null)
			{
				return false;
			}
			string item = c.name + ":phone:" + tel.number;
			if (Once.Contains(item))
			{
				return false;
			}
			try
			{
				if (tel.telephoneEntry == null)
				{
					tel.CreateEvidence();
				}
				EvidenceTelephone telephoneEntry = tel.telephoneEntry;
				if (telephoneEntry == null)
				{
					return false;
				}
				try
				{
					((Evidence)telephoneEntry).AddDiscovery((Discovery)6);
				}
				catch
				{
				}
				if (AlreadyPinned((Evidence)(object)telephoneEntry, (DataKey)33))
				{
					Once.Add(item);
					Plugin.L.LogInfo((object)("[PIN] phone already pinned, skipped " + tel.numberString + " (" + why + ") case=" + c.name));
					return false;
				}
				panel.PinToCasePanel(c, (Evidence)(object)telephoneEntry, (DataKey)33, true, Vector2.zero, false);
				Once.Add(item);
				Plugin.L.LogInfo((object)("[PIN] phone " + tel.numberString + " (" + why + ") case=" + c.name));
				return true;
			}
			catch (Exception ex)
			{
				Plugin.L.LogInfo((object)("[PIN] phone " + why + ": " + ex.Message));
				return false;
			}
		}
	}
	[HarmonyPatch]
	public static class SightingProbe
	{
		internal static float ArmedUntil = -1f;

		private static Human? asked;

		private static string? seenAt;

		private static int words;

		private static readonly HashSet<string> Seen = new HashSet<string>();

		internal static readonly List<NewGameLocation> Heard = new List<NewGameLocation>();

		[HarmonyPatch(typeof(Human), "RevealSighting", new Type[]
		{
			typeof(Human),
			typeof(bool),
			typeof(bool),
			typeof(SpeechController),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void Ask(Human __instance, Human prospectCitizen, bool allowCalls, bool allowSounds)
		{
			try
			{
				Arm();
				asked = prospectCitizen;
				seenAt = null;
				Find($"[SIGHT] ask: {Name(__instance)} about {Name(prospectCitizen)} (calls={allowCalls}, sounds={allowSounds})");
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Human), "RevealSighting", new Type[]
		{
			typeof(Human),
			typeof(Sighting),
			typeof(SpeechController)
		})]
		[HarmonyPrefix]
		private static void Reveal(Human __instance, Human prospectCitizen, Sighting sighting)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Arm();
				asked = prospectCitizen;
				seenAt = null;
				try
				{
					NewNode? obj = Node(sighting.node);
					object obj2;
					if (obj == null)
					{
						obj2 = null;
					}
					else
					{
						NewGameLocation gameLocation = obj.gameLocation;
						obj2 = ((gameLocation != null) ? ((Object)gameLocation).name : null);
					}
					seenAt = (string?)obj2;
				}
				catch
				{
				}
				if (sighting == null)
				{
					Find("[SIGHT] " + Name(__instance) + " about " + Name(prospectCitizen) + ": no sighting");
					return;
				}
				float num = 0f;
				try
				{
					num = SessionData.Instance.gameTime - sighting.time;
				}
				catch
				{
				}
				Find($"[SIGHT] {Name(__instance)} saw {Name(prospectCitizen)} {num:0.00} h ago, mov={sighting.mov} run={sighting.run} phone={sighting.phone} poi={sighting.poi} sound={sighting.sound} exp={sighting.exp}" + " | at " + Where(sighting.node) + " | heading " + Where(sighting.dest));
			}
			catch (Exception ex)
			{
				Plugin.L.LogInfo((object)("[SIGHT] reveal: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(Strings), "GetContainedValue")]
		[HarmonyPostfix]
		private static void Word(string withinScope, string newValue, Object inputObject)
		{
			if (Time.unscaledTime > ArmedUntil || words++ > 40)
			{
				return;
			}
			try
			{
				string text = "-";
				if (inputObject != null)
				{
					NewGameLocation val = ((Il2CppObjectBase)inputObject).TryCast<NewGameLocation>();
					Human val2 = ((Il2CppObjectBase)inputObject).TryCast<Human>();
					text = (((Object)(object)val != (Object)null) ? ("location " + Describe(val)) : (((Object)(object)val2 != (Object)null) ? ("person " + Name(val2)) : ((MemberInfo)inputObject.GetIl2CppType()).Name));
				}
				Find("[SIGHT] word " + withinScope + "." + newValue + " -> " + text);
				Truth((inputObject != null) ? ((Il2CppObjectBase)inputObject).TryCast<NewGameLocation>() : null);
				NewGameLocation val3 = ((inputObject != null) ? ((Il2CppObjectBase)inputObject).TryCast<NewGameLocation>() : null);
				if (!((Object)(object)val3 != (Object)null) || !Plugin.PinSightings.Value)
				{
					return;
				}
				lock (Heard)
				{
					if (!Heard.Contains(val3))
					{
						Heard.Add(val3);
					}
				}
			}
			catch
			{
			}
		}

		private static void Truth(NewGameLocation? said)
		{
			if ((Object)(object)said == (Object)null || (Object)(object)asked == (Object)null)
			{
				return;
			}
			string name = ((Object)said).name;
			string text = "";
			string text2 = "";
			try
			{
				text = (((Object)(object)asked.home != (Object)null) ? ((Object)asked.home).name : "");
			}
			catch
			{
			}
			try
			{
				Occupation job = asked.job;
				Company val = ((job != null) ? job.employer : null);
				if (val != null)
				{
					text2 = (((Object)(object)val.placeOfBusiness != (Object)null) ? ((Object)val.placeOfBusiness).name : (((Object)(object)val.address != (Object)null) ? ((Object)val.address).name : ""));
				}
			}
			catch
			{
			}
			bool flag = false;
			try
			{
				flag = (Object)(object)said.thisAsStreet != (Object)null;
			}
			catch
			{
			}
			string text3 = ((flag && seenAt != null) ? ((name == seenAt) ? "true (where the sighting was)" : ("WRONG: the sighting was on " + seenAt)) : ((name == text) ? "true (their home)" : ((name == text2) ? "true (their workplace)" : ((!flag) ? ("WRONG: home is " + text + ", work is " + text2) : "no sighting to compare"))));
			Find("[SIGHT] check: says '" + name + "' about " + Name(asked) + ": " + text3);
		}

		private static NewNode? Node(Vector3 node)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Vector3, NewNode> nodeMap = PathFinder.Instance.nodeMap;
			NewNode val = null;
			if (nodeMap.TryGetValue(node, ref val) && val != null)
			{
				return val;
			}
			if (nodeMap.TryGetValue(CityData.Instance.RealPosToNode(node), ref val) && val != null)
			{
				return val;
			}
			return null;
		}

		private static void Arm()
		{
			ArmedUntil = Time.unscaledTime + 3f;
			words = 0;
		}

		private static string Name(Human h)
		{
			if ((Object)(object)h == (Object)null)
			{
				return "?";
			}
			try
			{
				return h.GetCitizenName();
			}
			catch
			{
				return ((Object)h).name;
			}
		}

		private static string Where(Vector3 node)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00a7: 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_0034: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (node == Vector3.zero)
			{
				return "nowhere";
			}
			try
			{
				Dictionary<Vector3, NewNode> nodeMap = PathFinder.Instance.nodeMap;
				NewNode val = null;
				if (!nodeMap.TryGetValue(node, ref val) || val == null)
				{
					Vector3 val2 = CityData.Instance.RealPosToNode(node);
					if (!nodeMap.TryGetValue(val2, ref val) || val == null)
					{
						return $"{node} (no node)";
					}
				}
				NewGameLocation gameLocation = val.gameLocation;
				string text = "";
				try
				{
					if ((Object)(object)val.room != (Object)null)
					{
						text = ", room " + val.room.name;
					}
				}
				catch
				{
				}
				string arg = Describe(gameLocation);
				string arg2 = text;
				Vector3Int nodeCoord = val.nodeCoord;
				return $"{arg}{arg2} floor {((Vector3Int)(ref nodeCoord)).z}";
			}
			catch (Exception ex)
			{
				return $"{node} ({ex.Message})";
			}
		}

		private static string Describe(NewGameLocation loc)
		{
			if ((Object)(object)loc == (Object)null)
			{
				return "no location";
			}
			string text = "place";
			try
			{
				if ((Object)(object)loc.thisAsAddress != (Object)null)
				{
					text = "address";
				}
				else if ((Object)(object)loc.thisAsStreet != (Object)null)
				{
					text = "street";
				}
			}
			catch
			{
			}
			string text2 = "";
			try
			{
				if ((Object)(object)loc.building != (Object)null)
				{
					text2 = " in " + ((Object)loc.building).name;
				}
			}
			catch
			{
			}
			bool flag = false;
			try
			{
				flag = loc.evidenceEntry != null;
			}
			catch
			{
			}
			return text + " '" + ((Object)loc).name + "'" + text2 + (flag ? "" : " (no evidence)");
		}

		private static void Find(string line)
		{
			Plugin.L.LogInfo((object)line);
			Seen.Add(line);
		}
	}
}