Decompiled source of UnderNewManagement v1.0.2

Proprietor.dll

Decompiled an hour 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 System.Text.Json;
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;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
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("Proprietor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Proprietor")]
[assembly: AssemblyTitle("Proprietor")]
[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 Proprietor
{
	internal static class Dialogs
	{
		private sealed class SellLogic : IDialogLogic
		{
			private readonly bool viaStaff;

			public SellLogic(bool viaStaff)
			{
				this.viaStaff = viaStaff;
			}

			public bool IsDialogShown(DialogPreset preset, Citizen saysTo, SideJob jobRef)
			{
				return Returnable((Human)(object)saysTo, viaStaff) != null;
			}

			public ForceSuccess ShouldDialogSucceedOverride(DialogController instance, DialogOption dialog, Citizen saysTo, NewNode where, Actor saidBy)
			{
				if (Returnable((Human)(object)saysTo, viaStaff) != null)
				{
					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)
			{
				if (!success)
				{
					return;
				}
				try
				{
					Company val = Returnable((Human)(object)saysTo, viaStaff);
					if (val != null)
					{
						Store.Sell(val, out var message);
						Plugin.Message(message);
						Plugin.Logger.LogInfo((object)message);
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)("Selling failed: " + ex));
				}
			}
		}

		private sealed class BuyLogic : IDialogLogic
		{
			private readonly bool viaStaff;

			public BuyLogic(bool viaStaff)
			{
				this.viaStaff = viaStaff;
			}

			public bool IsDialogShown(DialogPreset preset, Citizen saysTo, SideJob jobRef)
			{
				return ForSale((Human)(object)saysTo, viaStaff) != null;
			}

			public ForceSuccess ShouldDialogSucceedOverride(DialogController instance, DialogOption dialog, Citizen saysTo, NewNode where, Actor saidBy)
			{
				Company val = ForSale((Human)(object)saysTo, viaStaff);
				if (val != null && GameplayController.Instance.money >= Store.Price(val))
				{
					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_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Expected O, but got Unknown
				if (!success)
				{
					return;
				}
				try
				{
					Company val = ForSale((Human)(object)saysTo, viaStaff);
					if (val != null)
					{
						int num = Store.Price(val);
						Store.Buy(val, num);
						if (val.director.passcode != null)
						{
							GameplayController.Instance.AddPasscode(val.director.passcode, false);
						}
						Plugin.Message($"You now own {val.name}. Log in to its cruncher as {val.shortName}_Admin.");
						ManualLogSource logger = Plugin.Logger;
						bool flag = default(bool);
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(62, 6, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Bought ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(val.name);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (company ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val.companyID);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") for ¢");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": regulars ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(Store.Regulars(val), "0.#");
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("land value ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(((Object)(object)val.address != (Object)null) ? val.address.normalizedLandValue : 0f, "0.00");
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", menu factor ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(Store.MenuFactor(val), "0.00");
						}
						logger.LogInfo(val2);
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)("Buying failed: " + ex));
				}
			}
		}

		public const string BuyName = "Proprietor_Buy";

		public const string SellName = "Proprietor_Sell";

		public const string StaffBuyName = "Proprietor_BuyViaStaff";

		public const string StaffSellName = "Proprietor_SellViaStaff";

		public static void Register()
		{
			Lib.Dialogs.Builder("Proprietor_Buy").SetText("I'd like to buy your business.").SetDialogLogic((IDialogLogic)(object)new BuyLogic(viaStaff: false))
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.cost = 1;
					p.ranking = 5;
				})
				.AddResponse("You've got yourself a deal. I'll stay on and keep the place running for you. The office cruncher's yours too.", true, true)
				.AddResponse("Come back when you've got the money.", false, true)
				.CreateAndRegister();
			Lib.Dialogs.Builder("Proprietor_BuyViaStaff").SetText("I'd like to buy this business. Can you get the owner on the phone?").SetDialogLogic((IDialogLogic)(object)new BuyLogic(viaStaff: true))
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.cost = 1;
					p.ranking = 5;
				})
				.AddResponse("Hang on, I'll call the boss... They say you've got a deal. They'll stay on and run the place for you.", true, true)
				.AddResponse("The boss says come back when you've got the money.", false, true)
				.CreateAndRegister();
			Lib.Dialogs.Builder("Proprietor_SellViaStaff").SetText("Can you call the manager? I want to sell the business back to them.").SetDialogLogic((IDialogLogic)(object)new SellLogic(viaStaff: true))
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.ranking = 4;
				})
				.AddResponse("One moment... They'll take it back. The money's on its way to you.", true, true)
				.CreateAndRegister();
			Lib.Dialogs.Builder("Proprietor_Sell").SetText("I'd like to sell the business back to you.").SetDialogLogic((IDialogLogic)(object)new SellLogic(viaStaff: false))
				.ModifyDialogOptions((Action<DialogPreset>)delegate(DialogPreset p)
				{
					p.ranking = 4;
				})
				.AddResponse("If that's what you want. Here's your money; I'll take it from here.", true, true)
				.CreateAndRegister();
		}

		public static Company SellerCompany(Human h)
		{
			if ((Object)(object)h == (Object)null || ((Actor)h).isPlayer)
			{
				return null;
			}
			Occupation job = h.job;
			Company val = ((job != null) ? job.employer : null);
			if (val != null && (Object)(object)val.director != (Object)null && val.director.humanID == h.humanID)
			{
				return val;
			}
			return null;
		}

		public static Company StaffOnShift(Human h)
		{
			if ((Object)(object)h == (Object)null || ((Actor)h).isPlayer || !((Actor)h).isAtWork)
			{
				return null;
			}
			Occupation job = h.job;
			Company val = ((job != null) ? job.employer : null);
			if (val == null || (Object)(object)val.address == (Object)null || (Object)(object)val.director == (Object)null || val.director.humanID == h.humanID)
			{
				return null;
			}
			NewGameLocation currentGameLocation = ((Actor)h).currentGameLocation;
			NewAddress val2 = ((currentGameLocation != null) ? currentGameLocation.thisAsAddress : null);
			if (!((Object)(object)val2 != (Object)null) || !(((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)val.address).Pointer))
			{
				return null;
			}
			return val;
		}

		public static Company ForSale(Human h, bool viaStaff)
		{
			Company val = (viaStaff ? StaffOnShift(h) : SellerCompany(h));
			if (val == null || !Store.Sellable(val))
			{
				return null;
			}
			return val;
		}

		public static Company Returnable(Human h, bool viaStaff)
		{
			Company val = (viaStaff ? StaffOnShift(h) : ManagedForPlayer(h));
			if (val == null || Store.Get(val) == null)
			{
				return null;
			}
			return val;
		}

		public static Company ManagedForPlayer(Human h)
		{
			if ((Object)(object)h == (Object)null || ((Actor)h).isPlayer)
			{
				return null;
			}
			Occupation job = h.job;
			Company val = ((job != null) ? job.employer : null);
			if (val == null || !((Object)(object)val.director != (Object)null) || val.director.humanID != h.humanID || Store.Get(val) == null)
			{
				return null;
			}
			return val;
		}
	}
	[HarmonyPatch(typeof(DialogPreset), "GetCost")]
	internal static class CostPatch
	{
		private static void Postfix(DialogPreset __instance, Actor talkingTo, ref int __result)
		{
			if ((SoCustomComparison)(object)__instance == (SoCustomComparison)null)
			{
				return;
			}
			string name = ((Object)__instance).name;
			if (name != "Proprietor_Buy" && name != "Proprietor_BuyViaStaff")
			{
				return;
			}
			try
			{
				Company val = Dialogs.ForSale((talkingTo != null) ? ((Il2CppObjectBase)talkingTo).TryCast<Human>() : null, name == "Proprietor_BuyViaStaff");
				if (val != null)
				{
					__result = Store.Price(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Price lookup failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	internal static class LedgerApp
	{
		private enum RowKind
		{
			Till,
			Item,
			Business,
			Back
		}

		private sealed class Row
		{
			public RowKind Kind;

			public string Item;

			public int Price;

			public int CompanyId;
		}

		public const string AppName = "BusinessLedger";

		public const string Marker = "\u200b";

		private const string Currency = "¢";

		private static CruncherAppPreset preset;

		private static readonly Dictionary<IntPtr, Row> rows = new Dictionary<IntPtr, Row>();

		private static readonly Dictionary<IntPtr, int> viewing = new Dictionary<IntPtr, int>();

		private static readonly Dictionary<IntPtr, List<CruncherAppPreset>> originals = new Dictionary<IntPtr, List<CruncherAppPreset>>();

		private static bool AtHome(ComputerController cc)
		{
			object obj;
			if (cc == null)
			{
				obj = null;
			}
			else
			{
				InteractableController ic = cc.ic;
				if (ic == null)
				{
					obj = null;
				}
				else
				{
					Interactable interactable = ic.interactable;
					if (interactable == null)
					{
						obj = null;
					}
					else
					{
						NewNode node = interactable.node;
						if (node == null)
						{
							obj = null;
						}
						else
						{
							NewGameLocation gameLocation = node.gameLocation;
							obj = ((gameLocation != null) ? gameLocation.thisAsAddress : null);
						}
					}
				}
			}
			NewAddress val = (NewAddress)obj;
			if ((Object)(object)val == (Object)null || (Object)(object)Player.Instance == (Object)null)
			{
				return false;
			}
			Enumerator<NewAddress> enumerator = Player.Instance.apartmentsOwned.GetEnumerator();
			while (enumerator.MoveNext())
			{
				NewAddress current = enumerator.Current;
				if ((Object)(object)current != (Object)null && ((Il2CppObjectBase)current).Pointer == ((Il2CppObjectBase)val).Pointer)
				{
					return true;
				}
			}
			return false;
		}

		private static Company Shown(ComputerController cc)
		{
			Company val = CompanyAt(cc);
			if (Store.Get(val) != null)
			{
				return val;
			}
			if (!AtHome(cc) || !viewing.TryGetValue(((Il2CppObjectBase)cc).Pointer, out var value))
			{
				return null;
			}
			return Store.FindCompany(value);
		}

		private static bool IsLedger(ComputerController cc)
		{
			if ((SoCustomComparison)(object)preset != (SoCustomComparison)null && (Object)(object)cc != (Object)null && (SoCustomComparison)(object)cc.currentApp != (SoCustomComparison)null)
			{
				return ((Il2CppObjectBase)cc.currentApp).Pointer == ((Il2CppObjectBase)preset).Pointer;
			}
			return false;
		}

		private static Company CompanyAt(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;
			}
			NewAddress thisAsAddress = gameLocation.thisAsAddress;
			if (thisAsAddress == null)
			{
				return null;
			}
			return thisAsAddress.company;
		}

		[HarmonyPatch(typeof(DesktopApp), "UpdateIcons")]
		[HarmonyPrefix]
		private static void Install(DesktopApp __instance)
		{
			try
			{
				ComputerController controller = ((CruncherAppContent)__instance).controller;
				object obj;
				if (controller == null)
				{
					obj = null;
				}
				else
				{
					InteractableController ic = controller.ic;
					if (ic == null)
					{
						obj = null;
					}
					else
					{
						Interactable interactable = ic.interactable;
						if (interactable == null)
						{
							obj = null;
						}
						else
						{
							InteractablePreset obj2 = interactable.preset;
							obj = ((obj2 != null) ? obj2.additionalApps : null);
						}
					}
				}
				List<CruncherAppPreset> val = (List<CruncherAppPreset>)obj;
				if (val == null)
				{
					return;
				}
				if ((SoCustomComparison)(object)preset == (SoCustomComparison)null)
				{
					Create();
				}
				if ((SoCustomComparison)(object)preset == (SoCustomComparison)null)
				{
					return;
				}
				if (!originals.TryGetValue(((Il2CppObjectBase)val).Pointer, out var value))
				{
					value = new List<CruncherAppPreset>();
					Enumerator<CruncherAppPreset> enumerator = val.GetEnumerator();
					while (enumerator.MoveNext())
					{
						CruncherAppPreset current = enumerator.Current;
						if ((SoCustomComparison)(object)current != (SoCustomComparison)null && ((Il2CppObjectBase)current).Pointer != ((Il2CppObjectBase)preset).Pointer)
						{
							value.Add(current);
						}
					}
					originals[((Il2CppObjectBase)val).Pointer] = value;
				}
				ComputerController controller2 = ((CruncherAppContent)__instance).controller;
				bool flag = Store.Get(CompanyAt(controller2)) != null;
				bool flag2 = !flag && Store.Owned.Count > 0 && AtHome(controller2);
				val.Clear();
				bool flag3 = false;
				foreach (CruncherAppPreset item in value)
				{
					if (flag && !flag3 && IsWizcards(item))
					{
						val.Add(preset);
						flag3 = true;
					}
					else
					{
						val.Add(item);
					}
				}
				if ((flag || flag2) && !flag3)
				{
					val.Add(preset);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't set up the Business Ledger: " + ex));
			}
		}

		private static bool IsWizcards(CruncherAppPreset app)
		{
			Enumerator<GameObject> enumerator = app.appContent.GetEnumerator();
			while (enumerator.MoveNext())
			{
				GameObject current = enumerator.Current;
				if ((Object)(object)current != (Object)null && (Object)(object)current.GetComponent<WizcardsApp>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private static void Create()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			CruncherAppPreset val = null;
			foreach (CruncherAppPreset item in Resources.FindObjectsOfTypeAll<CruncherAppPreset>())
			{
				if ((SoCustomComparison)(object)item != (SoCustomComparison)null && ((Object)item).name != "BusinessLedger" && IsSalesRecords(item))
				{
					val = item;
					break;
				}
			}
			if (!((SoCustomComparison)(object)val == (SoCustomComparison)null))
			{
				preset = Object.Instantiate<CruncherAppPreset>(val);
				((Object)preset).name = "BusinessLedger";
				preset.alwaysInstalled = true;
				preset.companyOnly = false;
				preset.salesRecordsOnly = false;
				preset.onlyIfOwner = false;
				preset.onlyIfResidential = false;
				preset.onlyIfCorporateSabotageSkill = false;
				preset.installationConditions = new List<AppAccess>();
				preset.onlyInAddresses = new List<AddressPreset>();
				Object.DontDestroyOnLoad((Object)(object)preset);
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Business Ledger program created from '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)val).name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'");
				}
				logger.LogInfo(val2);
			}
		}

		private static bool IsSalesRecords(CruncherAppPreset app)
		{
			Enumerator<GameObject> enumerator = app.appContent.GetEnumerator();
			while (enumerator.MoveNext())
			{
				GameObject current = enumerator.Current;
				if ((Object)(object)current != (Object)null && (Object)(object)current.GetComponent<SalesRecordsApp>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(DesktopIconController), "Setup")]
		[HarmonyPostfix]
		private static void IconName(DesktopIconController __instance, CruncherAppPreset newApp)
		{
			if ((SoCustomComparison)(object)preset != (SoCustomComparison)null && (SoCustomComparison)(object)newApp != (SoCustomComparison)null && ((Il2CppObjectBase)newApp).Pointer == ((Il2CppObjectBase)preset).Pointer)
			{
				((TMP_Text)__instance.iconText).text = "Business Ledger";
			}
		}

		[HarmonyPatch(typeof(SalesRecordsApp), "UpdateEntries")]
		[HarmonyPrefix]
		private static bool Entries(SalesRecordsApp __instance)
		{
			if (!IsLedger(((CruncherAppContent)__instance).controller))
			{
				return true;
			}
			try
			{
				Fill(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Business Ledger couldn't list: " + ex));
			}
			return false;
		}

		private static void Fill(SalesRecordsApp app)
		{
			ComputerController controller = ((CruncherAppContent)app).controller;
			bool flag = AtHome(controller) && Store.Get(CompanyAt(controller)) == null;
			Company val = Shown(controller);
			Business business = Store.Get(val);
			rows.Clear();
			List<OSMultiOption> val2 = new List<OSMultiOption>();
			if (business == null && flag)
			{
				((TMP_Text)app.titleText).text = "MY BUSINESSES";
				foreach (Business item in Store.Owned.Values.OrderBy((Business x) => x.Name))
				{
					val2.Add(Option(Summary(item), new Row
					{
						Kind = RowKind.Business,
						CompanyId = item.CompanyId
					}));
				}
				if (val2.Count == 0)
				{
					val2.Add(Option("You don't own any businesses.", null));
				}
				app.list.UpdateElements(val2);
				app.UpdateSelected();
				return;
			}
			((TMP_Text)app.titleText).text = ((val != null) ? val.name.ToUpperInvariant() : "BUSINESS LEDGER");
			if (business == null)
			{
				val2.Add(Option("You don't own this business.", null));
				app.list.UpdateElements(val2);
				return;
			}
			if (flag)
			{
				val2.Add(Option("< ALL BUSINESSES\nBack to the list", new Row
				{
					Kind = RowKind.Back
				}));
			}
			float now = SessionData.Instance.gameTime;
			List<Sale> list = business.Sales.Where((Sale s) => now - s.Time <= 24f).ToList();
			int num = val.companyRoster?.Count ?? 0;
			int num2 = business.Transfers.Sum((Transfer t) => t.Amount);
			val2.Add(Option($"TILL: {"¢"}{business.Till}" + ((num2 > 0) ? $"\n{"¢"}{num2} on its way to you" : "") + $"\n24 hours: {list.Count} customers, {"¢"}{list.Sum((Sale s) => s.Total)}\n" + $"Turned away: {business.TurnedAway}\nWages: {"¢"}{num * Plugin.WagePerStaff.Value}/day", new Row
			{
				Kind = RowKind.Till,
				CompanyId = business.CompanyId
			}));
			foreach (KeyValuePair<InteractablePreset, int> item2 in Store.Menu(val))
			{
				string name = ((Object)item2.Key).name;
				int value;
				int num3 = (business.Stock.TryGetValue(name, out value) ? value : 0);
				List<Order> list2 = business.Orders.Where((Order o) => o.Item == name).ToList();
				string text = $"{Store.ItemName(name)}: {((num3 > 0) ? (num3 + " in stock") : "OUT OF STOCK")}\nPrice {"¢"}{item2.Value}\nCost {"¢"}{Store.UnitCost(item2.Value)}";
				foreach (Order item3 in list2)
				{
					int num4 = Store.DaysUntil(item3.Arrives);
					text += $"\n+{item3.Quantity} due {((num4 <= 0) ? "today" : ((num4 == 1) ? "tomorrow" : $"in {num4} days"))}";
				}
				val2.Add(Option(text, new Row
				{
					Kind = RowKind.Item,
					Item = name,
					Price = item2.Value,
					CompanyId = business.CompanyId
				}));
			}
			foreach (Sale item4 in business.Sales.Take(40))
			{
				string text2 = SessionData.Instance.TimeAndDate(item4.Time, false, true, true) + "  " + item4.Customer;
				string text3 = string.Join("\n", item4.Items.Select((SaleItem i) => "<align=\"left\">" + Store.ItemName(i.Item) + "  <align=\"right\">¢" + i.Price));
				val2.Add(Option(text2 + "\n" + text3, null));
			}
			app.list.UpdateElements(val2);
			app.UpdateSelected();
		}

		private static string Summary(Business b)
		{
			float now = SessionData.Instance.gameTime;
			List<Sale> list = b.Sales.Where((Sale s) => now - s.Time <= 24f).ToList();
			int num = b.Stock.Count((KeyValuePair<string, int> kv) => kv.Value <= Plugin.LowStock.Value);
			return $"{b.Name}\nTill {"¢"}{b.Till}\n24h: {list.Count} sales, {"¢"}{list.Sum((Sale s) => s.Total)}\n" + ((num > 0) ? $"LOW STOCK: {num} item{((num == 1) ? "" : "s")}" : "Stock OK") + ((b.Orders.Count > 0) ? $"\nOrders due: {b.Orders.Count}" : "");
		}

		private static OSMultiOption Option(string text, Row row)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			OSMultiOption val = new OSMultiOption("\u200b" + text, (Human)null);
			if (row != null)
			{
				rows[((Il2CppObjectBase)val).Pointer] = row;
			}
			return val;
		}

		private static Row Selected(SalesRecordsApp app)
		{
			ComputerOSMultiSelect list = app.list;
			object obj;
			if (list == null)
			{
				obj = null;
			}
			else
			{
				ComputerOSMultiSelectElement selected = list.selected;
				obj = ((selected != null) ? selected.option : null);
			}
			OSMultiOption val = (OSMultiOption)obj;
			if (val == null || !rows.TryGetValue(((Il2CppObjectBase)val).Pointer, out var value))
			{
				return null;
			}
			return value;
		}

		[HarmonyPatch(typeof(ComputerOSMultiSelectElement), "Setup")]
		[HarmonyPostfix]
		private static void RowText(ComputerOSMultiSelectElement __instance, OSMultiOption newOpt)
		{
			string text = ((newOpt != null) ? newOpt.text : null);
			if (text != null && text.StartsWith("\u200b"))
			{
				int num = text.IndexOf('\n');
				((TMP_Text)__instance.elementText).text = ((num < 0) ? text : text.Substring(0, num)).Substring("\u200b".Length);
				if ((Object)(object)__instance.elementText2 != (Object)null)
				{
					((TMP_Text)__instance.elementText2).text = ((num < 0) ? "" : text.Substring(num + 1));
				}
			}
		}

		[HarmonyPatch(typeof(SalesRecordsApp), "UpdateSelected")]
		[HarmonyPostfix]
		private static void ActionButton(SalesRecordsApp __instance)
		{
			if (!IsLedger(((CruncherAppContent)__instance).controller) || (Object)(object)__instance.printButton == (Object)null)
			{
				return;
			}
			try
			{
				Row row = Selected(__instance);
				Business business = ((row != null) ? Store.Get(Store.FindCompany(row.CompanyId)) : null);
				bool flag = Store.Get(CompanyAt(((CruncherAppContent)__instance).controller)) == null;
				string text;
				switch (row?.Kind)
				{
				case RowKind.Back:
					text = "BACK";
					break;
				case RowKind.Business:
					text = "OPEN";
					break;
				case RowKind.Till:
					if (business != null && flag)
					{
						text = $"TRANSFER {"¢"}{Store.TransferNet(business.Till)}";
						break;
					}
					if (business != null)
					{
						text = $"COLLECT {"¢"}{Math.Max(0, business.Till)}";
						break;
					}
					goto default;
				case RowKind.Item:
					if (business != null)
					{
						text = $"ORDER {Plugin.OrderSize.Value} - {"¢"}{Store.UnitCost(row.Price) * Plugin.OrderSize.Value}";
						break;
					}
					goto default;
				default:
					text = null;
					break;
				}
				string text2 = text;
				((Component)__instance.printButton).gameObject.SetActive(text2 != null);
				TextMeshProUGUI val = ((text2 != null) ? Label(__instance) : null);
				if ((Object)(object)val != (Object)null)
				{
					((TMP_Text)val).text = text2;
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Business Ledger button failed: " + ex.Message));
			}
		}

		private static TextMeshProUGUI Label(SalesRecordsApp app)
		{
			TextMeshProUGUI componentInChildren = ((Component)app.printButton).GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			ComputerAutoTextController component = ((Component)componentInChildren).GetComponent<ComputerAutoTextController>();
			if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
			{
				((Behaviour)component).enabled = false;
				Widen(app.printButton, 2.5f);
				((TMP_Text)componentInChildren).fontSizeMax = ((TMP_Text)componentInChildren).fontSize;
				((TMP_Text)componentInChildren).fontSizeMin = ((TMP_Text)componentInChildren).fontSize * 0.6f;
				((TMP_Text)componentInChildren).enableAutoSizing = true;
				((TMP_Text)componentInChildren).enableWordWrapping = false;
				((TMP_Text)componentInChildren).overflowMode = (TextOverflowModes)3;
				((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)514;
			}
			return componentInChildren;
		}

		private static void Widen(RectTransform rect, float factor)
		{
			//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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0054: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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)
			//IL_0114: 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)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Rect rect2 = rect.rect;
				float width = ((Rect)(ref rect2)).width;
				float num = width * (factor - 1f);
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 6, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Button] width ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(width);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", anchors ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector2>(rect.anchorMin);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("-");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector2>(rect.anchorMax);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", pivot ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector2>(rect.pivot);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", pos ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector2>(rect.anchoredPosition);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", size ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector2>(rect.sizeDelta);
				}
				logger.LogInfo(val);
				LayoutElement component = ((Component)rect).GetComponent<LayoutElement>();
				if ((Object)(object)component != (Object)null)
				{
					if (component.preferredWidth > 0f)
					{
						component.preferredWidth = width * factor;
					}
					if (component.minWidth > 0f)
					{
						component.minWidth = width * factor;
					}
				}
				rect.sizeDelta = new Vector2(rect.sizeDelta.x + num, rect.sizeDelta.y);
				rect.anchoredPosition = new Vector2(rect.anchoredPosition.x - num * (1f - rect.pivot.x), rect.anchoredPosition.y);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't widen the button: " + ex.Message));
			}
		}

		private static void LogHierarchy(Transform t, int depth)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			List<string> list = new List<string>();
			foreach (Component component in ((Component)t).GetComponents<Component>())
			{
				list.Add(((MemberInfo)((Object)component).GetIl2CppType()).Name);
			}
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(12, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Button] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(new string(' ', depth * 2));
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)t).name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
			}
			logger.LogInfo(val);
			for (int i = 0; i < t.childCount; i++)
			{
				LogHierarchy(t.GetChild(i), depth + 1);
			}
		}

		[HarmonyPatch(typeof(SalesRecordsApp), "OnPrintEntry")]
		[HarmonyPrefix]
		private static bool Action(SalesRecordsApp __instance)
		{
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			if (!IsLedger(((CruncherAppContent)__instance).controller))
			{
				return true;
			}
			try
			{
				Row row = Selected(__instance);
				if (row == null)
				{
					return false;
				}
				ComputerController controller = ((CruncherAppContent)__instance).controller;
				if (row.Kind == RowKind.Business || row.Kind == RowKind.Back)
				{
					if (row.Kind == RowKind.Business)
					{
						viewing[((Il2CppObjectBase)controller).Pointer] = row.CompanyId;
					}
					else
					{
						viewing.Remove(((Il2CppObjectBase)controller).Pointer);
					}
					Sound(controller, AudioControls.Instance.computerPrint);
					__instance.list.page = 0;
					Fill(__instance);
					__instance.OnChangePage();
					return false;
				}
				Business business = Store.Get(Store.FindCompany(row.CompanyId));
				if (business == null)
				{
					return false;
				}
				bool flag = Store.Get(CompanyAt(controller)) == null;
				bool flag2 = default(bool);
				if (row.Kind == RowKind.Till)
				{
					if (business.Till <= 0)
					{
						Plugin.Message("The till is empty.", good: false);
						Sound(controller, AudioControls.Instance.computerInvalidPasscode);
						return false;
					}
					if (flag)
					{
						string text = Store.Transfer(business);
						Plugin.Message(text);
						ManualLogSource logger = Plugin.Logger;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(2, 2, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(business.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						}
						logger.LogInfo(val);
					}
					else
					{
						GameplayController.Instance.AddMoney(business.Till, true, "proprietor_collect");
						ManualLogSource logger2 = Plugin.Logger;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(13, 2, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(business.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": collected ¢");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(business.Till);
						}
						logger2.LogInfo(val);
						business.Till = 0;
					}
					Sound(controller, AudioControls.Instance.computerPrint);
				}
				else
				{
					string message;
					bool flag3 = Store.PlaceOrder(business, row.Item, row.Price, out message);
					Plugin.Message(message, flag3);
					ManualLogSource logger3 = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(2, 2, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(business.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message);
					}
					logger3.LogInfo(val);
					Sound(controller, flag3 ? AudioControls.Instance.computerPrint : AudioControls.Instance.computerInvalidPasscode);
				}
				int page = __instance.list.page;
				Fill(__instance);
				if (page != __instance.list.page)
				{
					__instance.list.NextPage(page - __instance.list.page);
				}
				__instance.OnChangePage();
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Business Ledger action failed: " + ex));
			}
			return false;
		}

		private static void Sound(ComputerController cc, AudioEvent e)
		{
			//IL_0026: 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)
			try
			{
				AudioController.Instance.PlayWorldOneShot(e, (Actor)(object)Player.Instance, cc.ic.interactable.node, cc.ic.interactable.wPos, (Interactable)null, (List<FMODParam>)null, 1f, (List<NewNode>)null, false, (SoundMaterialOverride)null, false);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ComputerOSMultiSelect), "SpawnList")]
	internal static class LedgerListPatch
	{
		private static bool Prefix(ComputerOSMultiSelect __instance)
		{
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			List<OSMultiOption> allOptions = __instance.allOptions;
			if (allOptions != null && allOptions.Count != 0)
			{
				OSMultiOption obj = allOptions[0];
				if (((obj != null) ? obj.text : null) != null && allOptions[0].text.StartsWith("\u200b"))
				{
					try
					{
						Enumerator<ComputerOSMultiSelectElement> enumerator = __instance.options.GetEnumerator();
						while (enumerator.MoveNext())
						{
							ComputerOSMultiSelectElement current = enumerator.Current;
							if ((Object)(object)current != (Object)null)
							{
								Object.Destroy((Object)(object)((Component)current).gameObject);
							}
						}
						__instance.options.Clear();
						int num = (__instance.usePages ? (__instance.page * __instance.maxPerPage) : 0);
						int num2 = (__instance.usePages ? (num + __instance.maxPerPage) : allOptions.Count);
						float num3 = 0f;
						for (int i = num; i < num2 && i < allOptions.Count; i++)
						{
							ComputerOSMultiSelectElement component = Object.Instantiate<GameObject>(__instance.elementPrefab, (Transform)(object)__instance.elementParent).GetComponent<ComputerOSMultiSelectElement>();
							component.Setup(allOptions[i], __instance);
							component.rect.anchoredPosition = new Vector2(0f, num3);
							num3 -= component.rect.sizeDelta.y;
							__instance.options.Add(component);
						}
					}
					catch (Exception ex)
					{
						Plugin.Logger.LogError((object)("Business Ledger couldn't draw its list: " + ex.Message));
					}
					return false;
				}
			}
			return true;
		}
	}
	[BepInPlugin("sodmods.proprietor", "Under New Management", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		public const string Guid = "sodmods.proprietor";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<int> BasePrice;

		internal static ConfigEntry<int> PricePerRegular;

		internal static ConfigEntry<int> StartingStock;

		internal static ConfigEntry<int> OrderSize;

		internal static ConfigEntry<int> WagePerStaff;

		internal static ConfigEntry<int> MinDeliveryDays;

		internal static ConfigEntry<int> MaxDeliveryDays;

		internal static ConfigEntry<float> WholesaleShare;

		internal static ConfigEntry<float> TransferFee;

		internal static ConfigEntry<float> TransferHour;

		internal static ConfigEntry<float> TypicalMenuPrice;

		internal static ConfigEntry<float> SellBackShare;

		internal static ConfigEntry<int> LowStock;

		internal static ConfigEntry<bool> LogEachSale;

		internal static ConfigEntry<bool> ProbeShops;

		internal static ConfigEntry<int> TestStock;

		internal static ConfigEntry<float> TestDeliveryHours;

		public override void Load()
		{
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			BasePrice = ((BasePlugin)this).Config.Bind<int>("Buying", "BasePrice", 1500, "Price of a business before its size is counted, in crows.");
			PricePerRegular = ((BasePlugin)this).Config.Bind<int>("Buying", "PricePerRegular", 12, "Added to the price for each regular customer (citizens whose favourite place it is; a regular for meals counts fully, for snacks or coffee 0.6, for drinks 0.8).");
			TypicalMenuPrice = ((BasePlugin)this).Config.Bind<float>("Buying", "TypicalMenuPrice", 4f, "Average menu price of an ordinary diner. Businesses with pricier menus cost more to buy (and less if cheaper).");
			SellBackShare = ((BasePlugin)this).Config.Bind<float>("Buying", "SellBackShare", 0.6f, "Selling a business back to its manager returns this share of what you paid (0.6 = 60%), plus whatever is in the till.");
			StartingStock = ((BasePlugin)this).Config.Bind<int>("Stock", "StartingStock", 20, "How many of each menu item a business has when you buy it.");
			OrderSize = ((BasePlugin)this).Config.Bind<int>("Stock", "OrderSize", 10, "How many of an item one order brings.");
			WholesaleShare = ((BasePlugin)this).Config.Bind<float>("Stock", "WholesaleShare", 0.3f, "What stock costs you, as a share of its menu price (0.3 = 30%).");
			MinDeliveryDays = ((BasePlugin)this).Config.Bind<int>("Stock", "MinDeliveryDays", 2, "Fewest in-game days an order takes to arrive.");
			MaxDeliveryDays = ((BasePlugin)this).Config.Bind<int>("Stock", "MaxDeliveryDays", 6, "Most in-game days an order takes to arrive.");
			LowStock = ((BasePlugin)this).Config.Bind<int>("Stock", "LowStockWarning", 5, "The home ledger warns about items with this many or fewer left.");
			TransferFee = ((BasePlugin)this).Config.Bind<float>("Remote", "TransferFee", 0.1f, "Share of the till a courier keeps when you send it home from your apartment's cruncher (0.1 = 10%). 0 = free.");
			TransferHour = ((BasePlugin)this).Config.Bind<float>("Remote", "TransferArrivalHour", 8f, "Hour of the next morning the courier arrives with the money.");
			WagePerStaff = ((BasePlugin)this).Config.Bind<int>("Running", "WagePerStaff", 8, "Paid out of the till every in-game day, per job at the business.");
			LogEachSale = ((BasePlugin)this).Config.Bind<bool>("Debug", "LogEachSale", false, "Write every sale at a business to the log.");
			ProbeShops = ((BasePlugin)this).Config.Bind<bool>("Debug", "ProbeShops", false, "Research: log the game's shopping goals and what citizens do inside businesses you own.");
			TestStock = ((BasePlugin)this).Config.Bind<int>("Debug", "TestStock", -1, "Testing: when a save loads, set every item at your businesses to this many in stock. -1 = off.");
			TestDeliveryHours = ((BasePlugin)this).Config.Bind<float>("Debug", "TestDeliveryHours", -1f, "Testing: orders arrive this many in-game hours after you place them (orders already on the way are brought forward when a save loads). -1 = off.");
			Lib.SaveGame.OnAfterLoad += delegate(object? _, SaveGameArgs args)
			{
				Store.Load(args);
			};
			Lib.SaveGame.OnAfterSave += delegate(object? _, SaveGameArgs args)
			{
				Store.Save(args);
			};
			Lib.SaveGame.OnBeforeNewGame += delegate
			{
				Store.Clear();
			};
			Dialogs.Register();
			new Harmony("sodmods.proprietor").PatchAll(typeof(Plugin).Assembly);
			((BasePlugin)this).Log.LogInfo((object)"Under New Management loaded");
		}

		internal static void Message(string text, bool good = true)
		{
			//IL_001d: 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)
			try
			{
				Lib.GameMessage.Broadcast(text, (GameMessageType)0, (Icon)17, (Color?)(good ? InterfaceControls.Instance.messageGreen : InterfaceControls.Instance.messageRed), 0f);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Couldn't show message: " + ex.Message));
			}
		}
	}
	internal static class ShopProbe
	{
		public static void DumpGoals()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ProbeShops.Value)
			{
				return;
			}
			try
			{
				bool flag = default(bool);
				foreach (AIGoalPreset item in from g in (IEnumerable<AIGoalPreset>)Resources.FindObjectsOfTypeAll<AIGoalPreset>()
					where (SoCustomComparison)(object)g != (SoCustomComparison)null && ((int)g.locationOption == 6 || (int)g.locationOption == 3)
					orderby ((Object)g).name
					select g)
				{
					ManualLogSource logger = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(35, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Probe] goal '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)item).name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' location=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<LocationOption>(item.locationOption);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" category=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<CompanyCategory>(item.desireCategory);
					}
					logger.LogInfo(val);
				}
				foreach (Business value in Store.Owned.Values)
				{
					Company val2 = Store.FindCompany(value.CompanyId);
					if (val2 == null)
					{
						continue;
					}
					List<string> list = new List<string>();
					Enumerator<CompanyCategory> enumerator3 = val2.preset.companyCategories.GetEnumerator();
					while (enumerator3.MoveNext())
					{
						list.Add(((object)enumerator3.Current/*cast due to .constrained prefix*/).ToString());
					}
					List<string> list2 = new List<string>();
					Enumerator<InteractablePreset, int> enumerator4 = val2.prices.GetEnumerator();
					while (enumerator4.MoveNext())
					{
						KeyValuePair<InteractablePreset, int> current3 = enumerator4.Current;
						if ((SoCustomComparison)(object)current3.Key != (SoCustomComparison)null)
						{
							DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(3, 3);
							defaultInterpolatedStringHandler.AppendFormatted(((Object)current3.Key).name);
							defaultInterpolatedStringHandler.AppendLiteral("=");
							defaultInterpolatedStringHandler.AppendFormatted(current3.Value);
							defaultInterpolatedStringHandler.AppendLiteral("(");
							RetailItemPreset retailItem = current3.Key.retailItem;
							defaultInterpolatedStringHandler.AppendFormatted((retailItem != null) ? new CompanyCategory?(retailItem.desireCategory) : ((CompanyCategory?)null));
							defaultInterpolatedStringHandler.AppendLiteral(")");
							list2.Add(defaultInterpolatedStringHandler.ToStringAndClear());
						}
					}
					ManualLogSource logger2 = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(69, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Probe] ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(val2.address.favouredCustomers.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" regular customers (citizens whose favourite place this is)");
					}
					logger2.LogInfo(val);
					ManualLogSource logger3 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(56, 5, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Probe] ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": preset '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)val2.preset).name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' categories [");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("records sales=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(val2.preset.recordSalesData);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", menu: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list2));
					}
					logger3.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Probe failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ActionController), "ExecuteAction")]
	internal static class ShopActionProbe
	{
		private static readonly HashSet<string> seen = new HashSet<string>();

		private static void Prefix(AIActionPreset action, Interactable what, NewNode where, Actor who)
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			if (!Plugin.ProbeShops.Value || (SoCustomComparison)(object)action == (SoCustomComparison)null || (Object)(object)who == (Object)null || who.isPlayer)
			{
				return;
			}
			try
			{
				object obj;
				if (where == null)
				{
					obj = null;
				}
				else
				{
					NewGameLocation gameLocation = where.gameLocation;
					if (gameLocation == null)
					{
						obj = null;
					}
					else
					{
						NewAddress thisAsAddress = gameLocation.thisAsAddress;
						obj = ((thisAsAddress != null) ? thisAsAddress.company : null);
					}
				}
				Company val = (Company)obj;
				Business business = Store.Get(val);
				if (business == null)
				{
					return;
				}
				Human val2 = ((Il2CppObjectBase)who).TryCast<Human>();
				object obj2;
				if (val2 == null)
				{
					obj2 = null;
				}
				else
				{
					Occupation job = val2.job;
					obj2 = ((job != null) ? job.employer : null);
				}
				bool flag = obj2 != null && val2.job.employer.companyID == val.companyID;
				string item = $"{((val2 != null) ? new int?(val2.humanID) : ((int?)null))}|{((Object)action).name}|{Mathf.FloorToInt(SessionData.Instance.gameTime)}";
				if (!seen.Add(item))
				{
					return;
				}
				object obj3;
				if (val2 == null)
				{
					obj3 = null;
				}
				else
				{
					NewAIController ai = ((Actor)val2).ai;
					if (ai == null)
					{
						obj3 = null;
					}
					else
					{
						NewAIGoal currentGoal = ai.currentGoal;
						if (currentGoal == null)
						{
							obj3 = null;
						}
						else
						{
							AIGoalPreset preset = currentGoal.preset;
							obj3 = ((preset != null) ? ((Object)preset).name : null);
						}
					}
				}
				string text = (string)obj3;
				ManualLogSource logger = Plugin.Logger;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(34, 6, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Probe] ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(business.Name);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(flag ? "staff" : "visitor");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((val2 != null) ? val2.GetCitizenName() : null);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("did '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)action).name);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' on '");
					object obj4;
					if (what == null)
					{
						obj4 = null;
					}
					else
					{
						InteractablePreset preset2 = what.preset;
						obj4 = ((preset2 != null) ? ((Object)preset2).name : null);
					}
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((string)obj4);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' (goal '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("')");
				}
				logger.LogInfo(val3);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class PurchasePatch
	{
		private static Human buyer;

		private static Company company;

		private static Business business;

		private static Vector3 where;

		private static Sale sale;

		private static bool anyHidden;

		[HarmonyPatch(typeof(ActionController), "TakeConsumable")]
		[HarmonyPrefix]
		private static void Start(Interactable what, NewNode where, Actor who)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			End();
			try
			{
				if ((Object)(object)who == (Object)null || who.isPlayer)
				{
					return;
				}
				Human val = ((Il2CppObjectBase)who).TryCast<Human>();
				if ((Object)(object)val == (Object)null || what == null || (SoCustomComparison)(object)what.preset == (SoCustomComparison)null || (SoCustomComparison)(object)what.preset.menuOverride != (SoCustomComparison)null)
				{
					return;
				}
				object obj;
				if (where == null)
				{
					obj = null;
				}
				else
				{
					NewGameLocation gameLocation = where.gameLocation;
					if (gameLocation == null)
					{
						obj = null;
					}
					else
					{
						NewAddress thisAsAddress = gameLocation.thisAsAddress;
						obj = ((thisAsAddress != null) ? thisAsAddress.company : null);
					}
				}
				Company val2 = (Company)obj;
				if (val2 != null)
				{
					Begin(val, val2, what.wPos);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Purchase tracking failed: " + ex.Message));
			}
		}

		internal static void Begin(Human human, Company c, Vector3 position)
		{
			//IL_001c: 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)
			End();
			buyer = human;
			company = c;
			business = Store.Get(c);
			where = position;
		}

		[HarmonyPatch(typeof(ActionController), "TakeConsumable")]
		[HarmonyFinalizer]
		internal static void Finish()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			try
			{
				if (business != null && sale == null && anyHidden)
				{
					business.TurnedAway++;
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(business.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						Human obj = buyer;
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((obj != null) ? obj.GetCitizenName() : null);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" left, nothing they wanted was in stock");
					}
					logger.LogInfo(val);
				}
			}
			catch
			{
			}
			End();
		}

		private static void End()
		{
			buyer = null;
			company = null;
			business = null;
			sale = null;
			anyHidden = false;
		}

		[HarmonyPatch(typeof(Human), "PickConsumable")]
		[HarmonyPrefix]
		private static void HideOutOfStock(Human __instance, ref List<InteractablePreset> ignore)
		{
			if (business == null || (Object)(object)buyer == (Object)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)buyer).Pointer)
			{
				return;
			}
			try
			{
				List<InteractablePreset> val = null;
				Enumerator<InteractablePreset, int> enumerator = company.prices.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<InteractablePreset, int> current = enumerator.Current;
					if ((SoCustomComparison)(object)current.Key == (SoCustomComparison)null || (business.Stock.TryGetValue(((Object)current.Key).name, out var value) && value > 0))
					{
						continue;
					}
					if (val == null)
					{
						val = new List<InteractablePreset>();
						if (ignore != null)
						{
							Enumerator<InteractablePreset> enumerator2 = ignore.GetEnumerator();
							while (enumerator2.MoveNext())
							{
								InteractablePreset current2 = enumerator2.Current;
								val.Add(current2);
							}
						}
					}
					val.Add(current.Key);
				}
				if (val != null)
				{
					ignore = val;
					anyHidden = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Stock check failed: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(Human), "PickConsumable")]
		[HarmonyPostfix]
		private static void Picked(Human __instance, InteractablePreset __result)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			if ((Object)(object)buyer == (Object)null || (SoCustomComparison)(object)__result == (SoCustomComparison)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)buyer).Pointer)
			{
				return;
			}
			try
			{
				int num = (company.prices.ContainsKey(__result) ? company.prices[__result] : 0);
				Ledger.Count(company, where, num);
				if (business == null)
				{
					return;
				}
				if (sale == null)
				{
					sale = new Sale
					{
						Time = SessionData.Instance.gameTime,
						Customer = buyer.GetCitizenName()
					};
					Store.RecordSale(business, sale);
				}
				sale.Items.Add(new SaleItem
				{
					Item = ((Object)__result).name,
					Price = num
				});
				business.Till += num;
				business.TotalTaken += num;
				if (business.Stock.TryGetValue(((Object)__result).name, out var value))
				{
					business.Stock[((Object)__result).name] = Math.Max(0, value - 1);
				}
				if (Plugin.LogEachSale.Value)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(16, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(business.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(sale.Customer);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" bought ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)__result).name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" for ¢");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					}
					logger.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't record a sale: " + ex.Message));
			}
		}
	}
	internal static class Ledger
	{
		private static int hour = -1;

		private static int count;

		private static int money;

		public static void Count(Company company, Vector3 where, int price)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			int num = Mathf.FloorToInt(SessionData.Instance.gameTime);
			if (num != hour)
			{
				if (hour >= 0)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Ledger] Hour ending ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SessionData.Instance.GameTimeToClock24String((float)num, false));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" items sold city-wide, ¢");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(money);
					}
					logger.LogInfo(val);
				}
				hour = num;
				count = (money = 0);
			}
			count++;
			money += price;
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class TickPatch
	{
		private static float next;

		private static void Postfix()
		{
			if (Time.unscaledTime < next)
			{
				return;
			}
			next = Time.unscaledTime + 0.5f;
			try
			{
				if ((Object)(object)SessionData.Instance != (Object)null && SessionData.Instance.startedGame)
				{
					Store.Tick();
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Business tick failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	internal static class OwnerAccessPatch
	{
		[HarmonyPatch(typeof(Human), "IsTrespassing")]
		[HarmonyPostfix]
		private static void General(Human __instance, NewRoom room, ref int trespassEscalation, ref bool __result)
		{
			if (((Actor)__instance).isPlayer)
			{
				Clear(__instance, room, ref trespassEscalation, ref __result);
			}
		}

		[HarmonyPatch(typeof(Player), "IsTrespassing")]
		[HarmonyPostfix]
		private static void PlayerCheck(Player __instance, NewRoom room, ref int trespassEscalation, ref bool __result)
		{
			Clear((Human)(object)__instance, room, ref trespassEscalation, ref __result);
		}

		private static void Clear(Human who, NewRoom room, ref int trespassEscalation, ref bool result)
		{
			if (((Actor)who).inAirVent)
			{
				return;
			}
			object c;
			if (room == null)
			{
				c = null;
			}
			else
			{
				NewGameLocation gameLocation = room.gameLocation;
				if (gameLocation == null)
				{
					c = null;
				}
				else
				{
					NewAddress thisAsAddress = gameLocation.thisAsAddress;
					c = ((thisAsAddress != null) ? thisAsAddress.company : null);
				}
			}
			if (Store.Get((Company)c) != null)
			{
				result = false;
				trespassEscalation = 0;
			}
		}
	}
	[HarmonyPatch(typeof(NewAIController), "IsMuggingValid")]
	internal static class NoMuggingAtHomePatch
	{
		private static void Postfix(Human target, ref bool __result)
		{
			if (!__result || (Object)(object)target == (Object)null || !((Actor)target).isPlayer)
			{
				return;
			}
			NewRoom currentRoom = ((Actor)target).currentRoom;
			object c;
			if (currentRoom == null)
			{
				c = null;
			}
			else
			{
				NewGameLocation gameLocation = currentRoom.gameLocation;
				if (gameLocation == null)
				{
					c = null;
				}
				else
				{
					NewAddress thisAsAddress = gameLocation.thisAsAddress;
					c = ((thisAsAddress != null) ? thisAsAddress.company : null);
				}
			}
			if (Store.Get((Company)c) != null)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(UpgradeEffectController), "GetUpgradeEffect")]
	internal static class NoLoiteringPatch
	{
		private static void Postfix(Effect effect, ref float __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)effect != 69 || __result >= 1f)
			{
				return;
			}
			try
			{
				Player instance = Player.Instance;
				object c;
				if (instance == null)
				{
					c = null;
				}
				else
				{
					NewGameLocation currentGameLocation = ((Actor)instance).currentGameLocation;
					if (currentGameLocation == null)
					{
						c = null;
					}
					else
					{
						NewAddress thisAsAddress = currentGameLocation.thisAsAddress;
						c = ((thisAsAddress != null) ? thisAsAddress.company : null);
					}
				}
				if (Store.Get((Company)c) != null)
				{
					__result = 1f;
				}
			}
			catch
			{
			}
		}
	}
	public class Sale
	{
		public float Time { get; set; }

		public string Customer { get; set; }

		public List<SaleItem> Items { get; set; } = new List<SaleItem>();

		public int Total => Items.Sum((SaleItem i) => i.Price);
	}
	public class SaleItem
	{
		public string Item { get; set; }

		public int Price { get; set; }
	}
	public class Transfer
	{
		public int Amount { get; set; }

		public float Arrives { get; set; }
	}
	public class Order
	{
		public string Item { get; set; }

		public int Quantity { get; set; }

		public float Arrives { get; set; }
	}
	public class Business
	{
		public int CompanyId { get; set; }

		public string Name { get; set; }

		public int PricePaid { get; set; }

		public float BoughtAt { get; set; }

		public int Till { get; set; }

		public int TotalTaken { get; set; }

		public int TurnedAway { get; set; }

		public Dictionary<string, int> Stock { get; set; } = new Dictionary<string, int>();

		public List<Order> Orders { get; set; } = new List<Order>();

		public List<Transfer> Transfers { get; set; } = new List<Transfer>();

		public List<Sale> Sales { get; set; } = new List<Sale>();
	}
	internal static class Store
	{
		private const string FileName = "proprietor.json";

		private const int MaxSales = 150;

		public static Dictionary<int, Business> Owned = new Dictionary<int, Business>();

		private static int lastDay = -1;

		private static readonly (CompanyCategory Category, float Weight)[] CustomerCategories = new(CompanyCategory, float)[4]
		{
			((CompanyCategory)0, 1f),
			((CompanyCategory)1, 0.6f),
			((CompanyCategory)2, 0.6f),
			((CompanyCategory)6, 0.8f)
		};

		private const string Currency = "¢";

		public static Business Get(Company c)
		{
			if (c == null || !Owned.TryGetValue(c.companyID, out var value))
			{
				return null;
			}
			return value;
		}

		public static void Clear()
		{
			Owned = new Dictionary<int, Business>();
			lastDay = -1;
		}

		public static void Load(SaveGameArgs args)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			Clear();
			try
			{
				string saveGameDataPath = Lib.SaveGame.GetSaveGameDataPath(args, "proprietor.json");
				if (File.Exists(saveGameDataPath))
				{
					Owned = JsonSerializer.Deserialize<List<Business>>(File.ReadAllText(saveGameDataPath)).ToDictionary((Business b) => b.CompanyId);
				}
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Save loaded: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Owned.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" business(es) owned");
				}
				logger.LogInfo(val);
				foreach (Business value in Owned.Values)
				{
					GiveKeys(FindCompany(value.CompanyId), message: false);
				}
				ShopProbe.DumpGoals();
				if (Plugin.TestStock.Value >= 0)
				{
					foreach (Business value2 in Owned.Values)
					{
						foreach (string item in value2.Stock.Keys.ToList())
						{
							value2.Stock[item] = Plugin.TestStock.Value;
						}
						ManualLogSource logger2 = Plugin.Logger;
						val = new BepInExInfoLogInterpolatedStringHandler(33, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Test: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value2.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" stock set to ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Plugin.TestStock.Value);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" of each item");
						}
						logger2.LogInfo(val);
					}
				}
				if (!(Plugin.TestDeliveryHours.Value >= 0f))
				{
					return;
				}
				float num = SessionData.Instance.gameTime + Plugin.TestDeliveryHours.Value;
				foreach (Business value3 in Owned.Values)
				{
					foreach (Order order in value3.Orders)
					{
						if (order.Arrives > num)
						{
							order.Arrives = num;
						}
					}
				}
				ManualLogSource logger3 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Test: orders on the way now arrive within ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Plugin.TestDeliveryHours.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" hours");
				}
				logger3.LogInfo(val);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't load owned businesses: " + ex));
			}
		}

		public static void Save(SaveGameArgs args)
		{
			try
			{
				string saveGameDataPath = Lib.SaveGame.GetSaveGameDataPath(args, "proprietor.json");
				if (Owned.Count == 0)
				{
					if (File.Exists(saveGameDataPath))
					{
						File.Delete(saveGameDataPath);
					}
				}
				else
				{
					File.WriteAllText(saveGameDataPath, JsonSerializer.Serialize(Owned.Values.ToList(), new JsonSerializerOptions
					{
						WriteIndented = true
					}));
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't save owned businesses: " + ex));
			}
		}

		public static bool Sellable(Company c)
		{
			if (c != null && (Object)(object)c.director != (Object)null && !((Actor)c.director).isPlayer && c.prices != null && c.prices.Count > 0 && (Object)(object)c.address != (Object)null && !Owned.ContainsKey(c.companyID))
			{
				return HasCustomers(c);
			}
			return false;
		}

		public static bool HasCustomers(Company c)
		{
			//IL_0029: 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: Unknown result type (might be due to invalid IL or missing references)
			CompanyPreset preset = c.preset;
			List<CompanyCategory> val = ((preset != null) ? preset.companyCategories : null);
			if (val == null)
			{
				return false;
			}
			(CompanyCategory, float)[] customerCategories = CustomerCategories;
			for (int i = 0; i < customerCategories.Length; i++)
			{
				CompanyCategory item = customerCategories[i].Item1;
				if (val.Contains(item))
				{
					return true;
				}
			}
			return false;
		}

		public static float Regulars(Company c)
		{
			//IL_0050: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			NewAddress address = c.address;
			if ((Object)(object)address == (Object)null)
			{
				return 0f;
			}
			float num = 0f;
			Enumerator<Human> enumerator = address.favouredCustomers.GetEnumerator();
			NewAddress val2 = default(NewAddress);
			while (enumerator.MoveNext())
			{
				Human current = enumerator.Current;
				if ((Object)(object)current == (Object)null)
				{
					continue;
				}
				(CompanyCategory, float)[] customerCategories = CustomerCategories;
				for (int i = 0; i < customerCategories.Length; i++)
				{
					var (val, num2) = customerCategories[i];
					if (current.favouritePlaces.TryGetValue(val, ref val2) && (Object)(object)val2 != (Object)null && ((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)address).Pointer)
					{
						num += num2;
					}
				}
			}
			return num;
		}

		public static int Price(Company c)
		{
			NewAddress address = c.address;
			float num = Mathf.Clamp01((address != null) ? address.normalizedLandValue : 0.5f);
			float num2 = ((float)Plugin.BasePrice.Value + (float)Plugin.PricePerRegular.Value * Regulars(c)) * (0.7f + 0.8f * num) * MenuFactor(c);
			return Mathf.Max(50, Mathf.RoundToInt(num2 / 50f) * 50);
		}

		public static float MenuFactor(Company c)
		{
			List<KeyValuePair<InteractablePreset, int>> list = Menu(c);
			if (list.Count == 0)
			{
				return 1f;
			}
			return Mathf.Clamp(Mathf.Sqrt((float)list.Average((KeyValuePair<InteractablePreset, int> kv) => kv.Value) / Plugin.TypicalMenuPrice.Value), 0.7f, 2f);
		}

		public static Business Buy(Company c, int price)
		{
			Business business = new Business
			{
				CompanyId = c.companyID,
				Name = c.name,
				PricePaid = price,
				BoughtAt = SessionData.Instance.gameTime
			};
			foreach (KeyValuePair<InteractablePreset, int> item in Menu(c))
			{
				business.Stock[((Object)item.Key).name] = Plugin.StartingStock.Value;
			}
			Owned[c.companyID] = business;
			GiveKeys(c, message: true);
			return business;
		}

		public static int Sell(Company c, out string message)
		{
			Business business = Get(c);
			int num = Mathf.RoundToInt((float)business.PricePaid * Plugin.SellBackShare.Value);
			int num2 = Math.Max(0, num + business.Till + business.Transfers.Sum((Transfer t) => t.Amount));
			Owned.Remove(business.CompanyId);
			if (num2 > 0)
			{
				GameplayController.Instance.AddMoney(num2, true, "proprietor_sell");
			}
			message = $"You sold {business.Name} for {"¢"}{num2}" + ((num2 > num) ? $" ({"¢"}{num} for the business, plus {"¢"}{num2 - num} from the till)" : ((num2 < num) ? $" ({"¢"}{num} for the business, less {"¢"}{num - num2} the till owed)" : ""));
			return num2;
		}

		public static void GiveKeys(Company c, bool message)
		{
			try
			{
				if ((Object)(object)((c != null) ? c.address : null) != (Object)null && (Object)(object)Player.Instance != (Object)null)
				{
					((Actor)Player.Instance).AddToKeyring(c.address, message);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't hand over the keys: " + ex.Message));
			}
		}

		public static List<KeyValuePair<InteractablePreset, int>> Menu(Company c)
		{
			List<KeyValuePair<InteractablePreset, int>> list = new List<KeyValuePair<InteractablePreset, int>>();
			Enumerator<InteractablePreset, int> enumerator = c.prices.GetEnumerator();
			while (enumerator.MoveNext())
			{
				KeyValuePair<InteractablePreset, int> current = enumerator.Current;
				if ((SoCustomComparison)(object)current.Key != (SoCustomComparison)null)
				{
					list.Add(new KeyValuePair<InteractablePreset, int>(current.Key, current.Value));
				}
			}
			return list.OrderBy((KeyValuePair<InteractablePreset, int> kv) => ItemName(((Object)kv.Key).name)).ToList();
		}

		public static string ItemName(string preset)
		{
			return Strings.Get("evidence.names", preset, (Casing)0, false, false, false, (Human)null);
		}

		public static int UnitCost(int price)
		{
			return Mathf.Max(1, Mathf.CeilToInt((float)price * Plugin.WholesaleShare.Value));
		}

		public static void RecordSale(Business b, Sale sale)
		{
			b.Sales.Insert(0, sale);
			if (b.Sales.Count > 150)
			{
				b.Sales.RemoveAt(b.Sales.Count - 1);
			}
		}

		public static bool PlaceOrder(Business b, string item, int price, out string message)
		{
			int value = Plugin.OrderSize.Value;
			int num = UnitCost(price) * value;
			int num2 = Math.Min(b.Till, num);
			int num3 = num - num2;
			if (num3 > GameplayController.Instance.money)
			{
				message = $"Not enough money: the order costs ¢{num}";
				return false;
			}
			b.Till -= num2;
			if (num3 > 0)
			{
				GameplayController.Instance.AddMoney(-num3, true, "proprietor_order");
			}
			int num4 = Random.Range(Plugin.MinDeliveryDays.Value, Plugin.MaxDeliveryDays.Value + 1);
			float arrives = TodayMidnight() + (float)num4 * 24f + Random.Range(7f, 11f);
			if (Plugin.TestDeliveryHours.Value >= 0f)
			{
				arrives = SessionData.Instance.gameTime + Plugin.TestDeliveryHours.Value;
				num4 = 0;
			}
			b.Orders.Add(new Order
			{
				Item = item,
				Quantity = value,
				Arrives = arrives
			});
			message = $"Ordered {value} {ItemName(item)} for ¢{num}" + ((num3 > 0) ? $" (¢{num3} from your wallet)" : "") + ((num4 > 0) ? $", arriving in {num4} days" : ", arriving soon (test setting)");
			return true;
		}

		public static int TransferNet(int till)
		{
			return Math.Max(0, till - Mathf.RoundToInt((float)Math.Max(0, till) * Plugin.TransferFee.Value));
		}

		public static string Transfer(Business b)
		{
			int num = TransferNet(b.Till);
			int num2 = b.Till - num;
			b.Transfers.Add(new Transfer
			{
				Amount = num,
				Arrives = TodayMidnight() + 24f + Plugin.TransferHour.Value
			});
			b.Till = 0;
			return $"Courier booked: {"¢"}{num} arrives tomorrow morning" + ((num2 > 0) ? $" ({"¢"}{num2} fee)" : "");
		}

		public static void Tick()
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected O, but got Unknown
			if (Owned.Count == 0 || (Object)(object)SessionData.Instance == (Object)null)
			{
				return;
			}
			float now = SessionData.Instance.gameTime;
			bool flag = default(bool);
			foreach (Business value2 in Owned.Values)
			{
				BepInExInfoLogInterpolatedStringHandler val;
				foreach (Transfer item in value2.Transfers.Where((Transfer t) => t.Arrives <= now).ToList())
				{
					GameplayController.Instance.AddMoney(item.Amount, true, "proprietor_transfer");
					value2.Transfers.Remove(item);
					Plugin.Message($"{value2.Name}: courier delivered {"¢"}{item.Amount}");
					ManualLogSource logger = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value2.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": transfer of ¢");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item.Amount);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" delivered");
					}
					logger.LogInfo(val);
				}
				List<Order> list = value2.Orders.Where((Order o) => o.Arrives <= now).ToList();
				if (list.Count == 0)
				{
					continue;
				}
				foreach (Order item2 in list)
				{
					value2.Stock[item2.Item] = (value2.Stock.TryGetValue(item2.Item, out var value) ? value : 0) + item2.Quantity;
					value2.Orders.Remove(item2);
				}
				string text = string.Join(", ", list.Select((Order o) => o.Quantity + " " + ItemName(o.Item)));
				Plugin.Message(value2.Name + ": delivery arrived (" + text + ")");
				ManualLogSource logger2 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(21, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value2.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": delivery arrived (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
				}
				logger2.LogInfo(val);
			}
			int num = DayNumber();
			if (lastDay < 0)
			{
				lastDay = num;
			}
			else if (num != lastDay)
			{
				for (int num2 = lastDay; num2 < num; num2++)
				{
					PayWages();
				}
				lastDay = num;
			}
		}

		private static void PayWages()
		{
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			bool flag = default(bool);
			foreach (Business value in Owned.Values)
			{
				Company obj = FindCompany(value.CompanyId);
				int valueOrDefault = ((obj == null) ? ((int?)null) : obj.companyRoster?.Count).GetValueOrDefault();
				int num = valueOrDefault * Plugin.WagePerStaff.Value;
				int num2 = Math.Min(Math.Max(0, value.Till), num);
				int num3 = Math.Min(num - num2, Math.Max(0, GameplayController.Instance.money));
				int num4 = num - num2 - num3;
				value.Till -= num2 + num4;
				if (num3 > 0)
				{
					GameplayController.Instance.AddMoney(-num3, false, "proprietor_wages");
				}
				string text = ((num3 > 0) ? $" (¢{num3} from your wallet)" : "");
				if (num4 > 0)
				{
					text += $", ¢{num4} owed from the till";
				}
				Plugin.Message($"{value.Name}: paid ¢{num} in wages{text}. Till: ¢{value.Till}", num4 == 0);
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(60, 7, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": wages ¢");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(valueOrDefault);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" staff: till ¢");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", wallet ¢");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num3);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", unpaid ¢");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num4);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; till now ¢");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(value.Till);
				}
				logger.LogInfo(val);
			}
		}

		public static float TodayMidnight()
		{
			return SessionData.Instance.gameTime - SessionData.Instance.decimalClock;
		}

		public static int DayNumber()
		{
			return Mathf.RoundToInt(TodayMidnight() / 24f);
		}

		public static int DaysUntil(float time)
		{
			return Mathf.FloorToInt((time - TodayMidnight()) / 24f);
		}

		public static Company FindCompany(int id)
		{
			Enumerator<Company> enumerator = CityData.Instance.companyDirectory.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Company current = enumerator.Current;
				if (current != null && current.companyID == id)
				{
					return current;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ActionController), "ExecuteAction")]
	internal static class SupermarketPatch
	{
		private static readonly Dictionary<int, float> lastBought = new Dictionary<int, float>();

		private static void Postfix(AIActionPreset action, Interactable what, NewNode where, Actor who)
		{
			//IL_00c7: 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)
			if ((SoCustomComparison)(object)action == (SoCustomComparison)null || (Object)(object)who == (Object)null || who.isPlayer || ((Object)action).name != "ShopForGroceries")
			{
				return;
			}
			try
			{
				object obj;
				if (where == null)
				{
					obj = null;
				}
				else
				{
					NewGameLocation gameLocation = where.gameLocation;
					if (gameLocation == null)
					{
						obj = null;
					}
					else
					{
						NewAddress thisAsAddress = gameLocation.thisAsAddress;
						obj = ((thisAsAddress != null) ? thisAsAddress.company : null);
					}
				}
				Company val = (Company)obj;
				if (Store.Get(val) == null)
				{
					return;
				}
				Human val2 = ((Il2CppObjectBase)who).TryCast<Human>();
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				float gameTime = SessionData.Instance.gameTime;
				if (lastBought.TryGetValue(val2.humanID, out var value) && gameTime - value < 1f)
				{
					return;
				}
				lastBought[val2.humanID] = gameTime;
				PurchasePatch.Begin(val2, val, (what != null) ? what.wPos : ((Component)val2).transform.position);
				try
				{
					Dictionary<InteractablePreset, int> prices = val.prices;
					List<InteractablePreset> val3 = new List<InteractablePreset>();
					int num = Random.Range(1, 4);
					int num2 = default(int);
					for (int i = 0; i < num; i++)
					{
						InteractablePreset val4 = val2.PickConsumable(ref prices, ref num2, val3);
						if (!((SoCustomComparison)(object)val4 == (SoCustomComparison)null))
						{
							val3.Add(val4);
							continue;
						}
						break;
					}
				}
				finally
				{
					PurchasePatch.Finish();
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Supermarket purchase failed: " + ex.Message));
			}
		}
	}
}