Decompiled source of Shop Prestige v1.3.3

BepInEx/plugins/ShopPrestige/ShopPrestige.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CC;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pathfinding;
using PhoneOverhaul.API;
using ShopPrestige.Ui;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Shop Prestige")]
[assembly: AssemblyDescription("The better your shop is decorated, the more it attracts.")]
[assembly: AssemblyCompany("Dimwit's")]
[assembly: AssemblyProduct("Shop Prestige")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Dimwit's")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace ShopPrestige
{
	internal static class Art
	{
		private static readonly Dictionary<string, Sprite?> Cache = new Dictionary<string, Sprite>();

		private static readonly string[] TierFiles = new string[4] { "tier_1_hole_in_the_wall", "tier_2_neighborhood_shop", "tier_3_destination_store", "tier_4_collectors_paradise" };

		public static Sprite? Tier(int tier)
		{
			return Get(TierFiles[Math.Max(0, Math.Min(tier, TierFiles.Length - 1))]);
		}

		public static void Preload()
		{
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location) ?? "", "art");
				if (Directory.Exists(path))
				{
					string[] files = Directory.GetFiles(path, "*.png");
					for (int i = 0; i < files.Length; i++)
					{
						Get(Path.GetFileNameWithoutExtension(files[i]));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't preload the icons: " + ex.Message));
			}
		}

		public static Sprite? Get(string name)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (Cache.TryGetValue(name, out Sprite value))
			{
				return value;
			}
			Sprite val = null;
			try
			{
				string path = Path.Combine(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location) ?? "", "art"), name + ".png");
				if (File.Exists(path))
				{
					Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, true)
					{
						filterMode = (FilterMode)2,
						wrapMode = (TextureWrapMode)1,
						name = "ShopPrestige_" + name
					};
					if (ImageConversion.LoadImage(val2, File.ReadAllBytes(path)))
					{
						Object.DontDestroyOnLoad((Object)(object)val2);
						val = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f);
						((Object)val).name = "ShopPrestige_" + name;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't load art/" + name + ".png: " + ex.Message));
			}
			Cache[name] = val;
			return val;
		}
	}
	internal static class CapPatches
	{
		public static void Apply(Harmony harmony)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(CustomerCapTranspiler), "Transpiler", (Type[])null, (Type[])null));
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CustomerManager), "EvaluateMaxCustomerCount", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo methodInfo = AccessTools.Method("FurnitureOverhaul.CustomerCountFix:Evaluate", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo2 = AccessTools.Method("DecoBonusOverlay.Overlay:DrawReadings", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method("DecoBonusOverlay.DecoReading:get_IsCapped", (Type[])null, (Type[])null);
			if (methodInfo2 != null && methodInfo3 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(OverlayTranspilers), "CapLabel", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(OverlayTranspilers), "CapCheck", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
	}
	internal static class BonusMath
	{
		public static float ApplyCap(float raw)
		{
			Perf.CountCapCall();
			Perf.Mark start = Perf.Start();
			raw += Finishes.Total();
			raw += Themes.Extra();
			raw += Guards.Prestige();
			raw += Outside.Total(raw);
			Prestige.Capture(raw);
			Perf.Stop("the customer-limit recalculation", start);
			if (Plugin.DeferToWeeklyTraffic)
			{
				return 0f;
			}
			float value = Plugin.DecoBonusCap.Value;
			if (raw <= 0f)
			{
				return 0f;
			}
			if (!Plugin.SoftCapEnabled.Value)
			{
				return Mathf.Min(raw, value);
			}
			float num = Mathf.Min(Plugin.SoftCapStart.Value, value);
			if (raw <= num)
			{
				return raw;
			}
			float num2 = value - num;
			if (!(num2 <= 0f))
			{
				return num + num2 * (1f - Mathf.Exp((0f - (raw - num)) / num2));
			}
			return value;
		}

		public static float EffectiveCount(int count, float falloff)
		{
			if (count <= 0)
			{
				return 0f;
			}
			if (!(falloff >= 1f))
			{
				return (1f - Mathf.Pow(falloff, (float)count)) / (1f - falloff);
			}
			return count;
		}

		public static float DecoCount(int count)
		{
			return EffectiveCount(count, Plugin.DuplicateFalloff.Value);
		}

		public static float FurnitureCount(int count)
		{
			return EffectiveCount(count, Plugin.FalloffAppliesToFurniture.Value ? Plugin.DuplicateFalloff.Value : 1f);
		}

		public static int GetBaseCustomerCap()
		{
			if (!Plugin.DeferToWeeklyTraffic)
			{
				return Plugin.BaseCustomerCap.Value;
			}
			return 30;
		}

		public static float GetDecoBonusCap()
		{
			return Plugin.DecoBonusCap.Value;
		}

		public static float GetCappedThreshold()
		{
			if (!Plugin.SoftCapEnabled.Value)
			{
				return Plugin.DecoBonusCap.Value;
			}
			return Plugin.DecoBonusCap.Value - 0.5f;
		}

		public static float ResetCardTotal(float runningTotal)
		{
			if (!Plugin.FixDisplayCaseSnowball.Value)
			{
				return runningTotal;
			}
			return 0f;
		}
	}
	internal static class OverlayTranspilers
	{
		public static IEnumerable<CodeInstruction> CapLabel(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			return ReplaceTwenty(instructions, original, AccessTools.Method(typeof(BonusMath), "GetDecoBonusCap", (Type[])null, (Type[])null));
		}

		public static IEnumerable<CodeInstruction> CapCheck(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			return ReplaceTwenty(instructions, original, AccessTools.Method(typeof(BonusMath), "GetCappedThreshold", (Type[])null, (Type[])null));
		}

		private static IEnumerable<CodeInstruction> ReplaceTwenty(IEnumerable<CodeInstruction> instructions, MethodBase original, MethodInfo getter)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			foreach (CodeInstruction item in list)
			{
				if (item.opcode == OpCodes.Ldc_R4 && (float)item.operand == 20f)
				{
					item.opcode = OpCodes.Call;
					item.operand = getter;
					num++;
				}
			}
			string text = original.DeclaringType.FullName + "." + original.Name;
			if (num == 1)
			{
				Plugin.Log.LogInfo((object)("Pointed " + text + " at the configured cap."));
			}
			else
			{
				Plugin.Log.LogWarning((object)(text + ": expected 1 cap constant, replaced " + num + ". The overlay may have changed."));
			}
			return list;
		}
	}
	internal static class CustomerCapTranspiler
	{
		private static readonly HashSet<string> Reported = new HashSet<string>();

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Expected O, but got Unknown
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0430: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Mathf), "Clamp", new Type[3]
			{
				typeof(int),
				typeof(int),
				typeof(int)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(List<int>), "get_Item", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(KeyValuePair<int, int>), "get_Value", (Type[])null, (Type[])null);
			MethodInfo[] array = new MethodInfo[2]
			{
				AccessTools.Method(typeof(BonusMath), "DecoCount", (Type[])null, (Type[])null),
				AccessTools.Method(typeof(BonusMath), "FurnitureCount", (Type[])null, (Type[])null)
			};
			MethodInfo methodInfo4 = AccessTools.Method(typeof(BonusMath), "ResetCardTotal", (Type[])null, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (num == 0 && i > 0 && i + 3 < list.Count && IsLdcR4(list[i], 20f) && (list[i + 1].opcode == OpCodes.Ble_Un_S || list[i + 1].opcode == OpCodes.Ble_Un) && IsLdcR4(list[i + 2], 20f) && IsStloc(list[i + 3]))
				{
					list[i].opcode = OpCodes.Call;
					list[i].operand = AccessTools.Method(typeof(BonusMath), "ApplyCap", (Type[])null, (Type[])null);
					list[i + 1].opcode = list[i + 3].opcode;
					list[i + 1].operand = list[i + 3].operand;
					list[i + 2].opcode = OpCodes.Nop;
					list[i + 2].operand = null;
					list[i + 3].opcode = OpCodes.Nop;
					list[i + 3].operand = null;
					num++;
					i += 3;
				}
				else if (num2 == 0 && IsLdcI4(list[i], 30) && i + 1 < list.Count && CodeInstructionExtensions.Calls(list[i + 1], methodInfo))
				{
					list[i].opcode = OpCodes.Call;
					list[i].operand = AccessTools.Method(typeof(BonusMath), "GetBaseCustomerCap", (Type[])null, (Type[])null);
					num2++;
				}
				else if (num3 < array.Length && i > 0 && i + 1 < list.Count && list[i].opcode == OpCodes.Conv_R4 && list[i + 1].opcode == OpCodes.Mul && (CodeInstructionExtensions.Calls(list[i - 1], methodInfo2) || CodeInstructionExtensions.Calls(list[i - 1], methodInfo3)))
				{
					list[i].opcode = OpCodes.Call;
					list[i].operand = array[num3];
					num3++;
				}
				else
				{
					if (num4 != 0 || i + 2 >= list.Count || !IsLdloc(list[i]) || !IsLdcR4(list[i + 1], 50000f) || !(list[i + 2].opcode == OpCodes.Div))
					{
						continue;
					}
					CodeInstruction val = list[i];
					for (int j = i + 3; j < list.Count && j < i + 12; j++)
					{
						if (IsStloc(list[j]))
						{
							list.InsertRange(j + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
							{
								new CodeInstruction(val.opcode, val.operand),
								new CodeInstruction(OpCodes.Call, (object)methodInfo4),
								StoreFor(val)
							});
							num4++;
							break;
						}
					}
				}
			}
			string text = original.DeclaringType.FullName + "." + original.Name;
			if (!Reported.Add(text + num + num2 + num3 + num4))
			{
				return list;
			}
			if (num == 1 && num2 == 1 && num3 == 2 && num4 == 1)
			{
				Plugin.Log.LogInfo((object)("Patched customer caps, Prestige capture and the display-case fix in " + text + "."));
			}
			if (num != 1)
			{
				Plugin.Log.LogWarning((object)(text + ": decoration cap not found, so Prestige can't be read there. The code may have changed."));
			}
			if (num2 != 1)
			{
				Plugin.Log.LogWarning((object)(text + ": base customer limit not found. The code may have changed."));
			}
			if (num3 != 2)
			{
				Plugin.Log.LogWarning((object)(text + ": expected 2 per-type counts for duplicate falloff, found " + num3 + ". The code may have changed."));
			}
			if (num4 != 1)
			{
				Plugin.Log.LogWarning((object)(text + ": display-case card total not found, so the display-case fix is off there. The code may have changed."));
			}
			return list;
		}

		private static CodeInstruction StoreFor(CodeInstruction load)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			if (!(load.opcode == OpCodes.Ldloc_0))
			{
				if (!(load.opcode == OpCodes.Ldloc_1))
				{
					if (!(load.opcode == OpCodes.Ldloc_2))
					{
						if (!(load.opcode == OpCodes.Ldloc_3))
						{
							return new CodeInstruction((load.opcode == OpCodes.Ldloc_S) ? OpCodes.Stloc_S : OpCodes.Stloc, load.operand);
						}
						return new CodeInstruction(OpCodes.Stloc_3, (object)null);
					}
					return new CodeInstruction(OpCodes.Stloc_2, (object)null);
				}
				return new CodeInstruction(OpCodes.Stloc_1, (object)null);
			}
			return new CodeInstruction(OpCodes.Stloc_0, (object)null);
		}

		private static bool IsLdcR4(CodeInstruction c, float value)
		{
			if (c.opcode == OpCodes.Ldc_R4)
			{
				return (float)c.operand == value;
			}
			return false;
		}

		private static bool IsLdcI4(CodeInstruction c, int value)
		{
			if (c.opcode == OpCodes.Ldc_I4_S || c.opcode == OpCodes.Ldc_I4)
			{
				return Convert.ToInt32(c.operand) == value;
			}
			return false;
		}

		private static bool IsStloc(CodeInstruction c)
		{
			if (!(c.opcode == OpCodes.Stloc_S) && !(c.opcode == OpCodes.Stloc) && !(c.opcode == OpCodes.Stloc_0) && !(c.opcode == OpCodes.Stloc_1) && !(c.opcode == OpCodes.Stloc_2))
			{
				return c.opcode == OpCodes.Stloc_3;
			}
			return true;
		}

		private static bool IsLdloc(CodeInstruction c)
		{
			if (!(c.opcode == OpCodes.Ldloc_S) && !(c.opcode == OpCodes.Ldloc) && !(c.opcode == OpCodes.Ldloc_0) && !(c.opcode == OpCodes.Ldloc_1) && !(c.opcode == OpCodes.Ldloc_2))
			{
				return c.opcode == OpCodes.Ldloc_3;
			}
			return true;
		}
	}
	public sealed class DisplayFilterRule
	{
		public bool Enabled;

		public string Element = "";

		public string Set = "";

		public string Rarity = "";

		public string Border = "";

		public string Monster = "";

		public int Foil;

		public int Graded;

		public double MinimumValue;

		public double MaximumValue;

		public bool NoDuplicates;

		private const char Sep = '|';

		public bool IsDefault
		{
			get
			{
				if (!Enabled && Element.Length == 0 && Set.Length == 0 && Rarity.Length == 0 && Border.Length == 0 && Monster.Length == 0 && Foil == 0 && Graded == 0 && MinimumValue == 0.0 && MaximumValue == 0.0)
				{
					return !NoDuplicates;
				}
				return false;
			}
		}

		public string Reject(CardFilterFacts card, IEnumerable<string> existing)
		{
			if (!Enabled)
			{
				return "";
			}
			if (Element.Length > 0 && Element != card.Element)
			{
				return "only " + Element + " cards";
			}
			if (Set.Length > 0 && Set != card.Set)
			{
				return "only " + Set + " cards";
			}
			if (Rarity.Length > 0 && Rarity != card.Rarity)
			{
				return "only " + Rarity + " cards";
			}
			if (Border.Length > 0 && Border != card.Border)
			{
				return "only " + Border + " border cards";
			}
			if (Monster.Length > 0 && Monster != card.Monster)
			{
				return "only " + ((card.MonsterWanted.Length > 0) ? card.MonsterWanted : "one monster") + " cards";
			}
			if (Foil == 1 && !card.Foil)
			{
				return "only foil cards";
			}
			if (Foil == 2 && card.Foil)
			{
				return "only non-foil cards";
			}
			if (Graded == 1 && !card.Graded)
			{
				return "only graded cards";
			}
			if (Graded == 2 && card.Graded)
			{
				return "only ungraded cards";
			}
			if ((MinimumValue > 0.0 || MaximumValue > 0.0) && (double.IsNaN(card.Value) || double.IsInfinity(card.Value)))
			{
				return "this card's value isn't known";
			}
			if (card.Value < MinimumValue)
			{
				return "only cards worth " + MinimumValue.ToString("N0", CultureInfo.InvariantCulture) + " or more";
			}
			if (MaximumValue > 0.0 && card.Value > MaximumValue)
			{
				return "only cards worth up to " + MaximumValue.ToString("N0", CultureInfo.InvariantCulture);
			}
			if (NoDuplicates && existing.Any((string identity) => identity == card.Identity))
			{
				return "that card is already in this case";
			}
			return "";
		}

		public void Clear()
		{
			Enabled = false;
			Element = (Set = (Rarity = (Border = (Monster = ""))));
			Foil = (Graded = 0);
			MinimumValue = (MaximumValue = 0.0);
			NoDuplicates = false;
		}

		public string Write()
		{
			return string.Join('|'.ToString(), "1", Enabled ? "1" : "0", Clean(Element), Clean(Set), Clean(Rarity), Clean(Border), Clean(Monster), Foil.ToString(CultureInfo.InvariantCulture), Graded.ToString(CultureInfo.InvariantCulture), MinimumValue.ToString("R", CultureInfo.InvariantCulture), MaximumValue.ToString("R", CultureInfo.InvariantCulture), NoDuplicates ? "1" : "0");
		}

		public static DisplayFilterRule? Read(string? line)
		{
			string[] array = (line ?? "").Split('|');
			if (array.Length != 12 || array[0] != "1")
			{
				return null;
			}
			if (!int.TryParse(array[7], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 0 || result > 2)
			{
				return null;
			}
			if (!int.TryParse(array[8], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || result2 < 0 || result2 > 2)
			{
				return null;
			}
			if (!double.TryParse(array[9], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !double.TryParse(array[10], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4))
			{
				return null;
			}
			if (result3 < 0.0 || result4 < 0.0 || double.IsNaN(result3) || double.IsNaN(result4) || double.IsInfinity(result3) || double.IsInfinity(result4) || (result4 > 0.0 && result4 < result3))
			{
				return null;
			}
			return new DisplayFilterRule
			{
				Enabled = (array[1] == "1"),
				Element = array[2],
				Set = array[3],
				Rarity = array[4],
				Border = array[5],
				Monster = array[6],
				Foil = result,
				Graded = result2,
				MinimumValue = result3,
				MaximumValue = result4,
				NoDuplicates = (array[11] == "1")
			};
		}

		private static string Clean(string s)
		{
			return (s ?? "").Replace('|'.ToString(), "").Replace("\n", "").Replace("\r", "");
		}
	}
	public sealed class CardFilterFacts
	{
		public string Element = "";

		public string Set = "";

		public string Rarity = "";

		public string Border = "";

		public string Monster = "";

		public string Identity = "";

		public string MonsterWanted = "";

		public bool Foil;

		public bool Graded;

		public double Value;
	}
	internal static class DisplayFilters
	{
		[Serializable]
		private sealed class SaveData
		{
			public string[] cases = Array.Empty<string>();

			public string[] rules = Array.Empty<string>();
		}

		private static readonly Dictionary<CardShelf, DisplayFilterRule> Live = new Dictionary<CardShelf, DisplayFilterRule>();

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

		private static float _nextNotice;

		internal static bool Ready { get; private set; }

		internal static void Apply(Harmony harmony)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(InteractableCardCompartment), "OnMouseButtonUp", (Type[])null, (Type[])null) ?? throw new MissingMethodException("InteractableCardCompartment.OnMouseButtonUp");
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(DisplayFilters), "BeforePlace", (Type[])null, (Type[])null))
			{
				priority = 800
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CardShelf), "OnStartMoveObject", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.Method(typeof(DisplayFilters), "BeforeMove", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CardShelf), "BoxUpObject", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(DisplayFilters), "AfterBox", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CardShelf), "OnDestroyed", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.Method(typeof(DisplayFilters), "Destroyed", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Ready = true;
		}

		private static string Key(CardShelf s)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)s).transform.position;
			return ((object)Unsafe.As<EObjectType, EObjectType>(ref ((InteractableObject)s).m_ObjectType)/*cast due to .constrained prefix*/).ToString() + "/" + position.x.ToString("F2", CultureInfo.InvariantCulture) + "/" + position.y.ToString("F2", CultureInfo.InvariantCulture) + "/" + position.z.ToString("F2", CultureInfo.InvariantCulture);
		}

		internal static DisplayFilterRule Get(CardShelf shelf)
		{
			if (Live.TryGetValue(shelf, out DisplayFilterRule value))
			{
				return value;
			}
			string key = Key(shelf);
			if (Pending.TryGetValue(key, out value))
			{
				Pending.Remove(key);
			}
			else
			{
				value = new DisplayFilterRule();
			}
			Live[shelf] = value;
			return value;
		}

		private static void BeforeMove(CardShelf __instance)
		{
			if (__instance.m_ItemNotForSale)
			{
				Get(__instance);
			}
		}

		private static void AfterBox(CardShelf __instance)
		{
			if (((InteractableObject)__instance).GetIsBoxedUp())
			{
				Live.Remove(__instance);
			}
		}

		private static void Destroyed(CardShelf __instance)
		{
			Live.Remove(__instance);
		}

		internal static IEnumerable<CardData> Cards(CardShelf shelf)
		{
			foreach (InteractableCardCompartment cardCompartment in shelf.GetCardCompartmentList())
			{
				foreach (InteractableCard3d storedCard in cardCompartment.m_StoredCardList)
				{
					object obj;
					if (!((Object)(object)storedCard != (Object)null))
					{
						obj = null;
					}
					else
					{
						Card3dUIGroup card3dUI = storedCard.m_Card3dUI;
						if (card3dUI == null)
						{
							obj = null;
						}
						else
						{
							CardUI cardUI = card3dUI.m_CardUI;
							obj = ((cardUI != null) ? cardUI.GetCardData() : null);
						}
					}
					CardData val = (CardData)obj;
					if (val != null)
					{
						yield return val;
					}
				}
			}
		}

		internal static CardFilterFacts Facts(CardData card, DisplayFilterRule rule)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			CardFilterFacts cardFilterFacts = new CardFilterFacts();
			EElementIndex? val = Themes.Element(card);
			cardFilterFacts.Element = (val.HasValue ? ((object)val.GetValueOrDefault()/*cast due to .constrained prefix*/).ToString() : null) ?? "";
			cardFilterFacts.Set = ((object)Unsafe.As<ECardExpansionType, ECardExpansionType>(ref card.expansionType)/*cast due to .constrained prefix*/).ToString();
			cardFilterFacts.Rarity = ((object)Themes.Rarity(card)/*cast due to .constrained prefix*/).ToString();
			cardFilterFacts.Border = ((object)Themes.Border(card)/*cast due to .constrained prefix*/).ToString();
			cardFilterFacts.Monster = ((object)Unsafe.As<EMonsterType, EMonsterType>(ref card.monsterType)/*cast due to .constrained prefix*/).ToString();
			cardFilterFacts.MonsterWanted = ((rule.Monster.Length > 0 && Enum.TryParse<EMonsterType>(rule.Monster, out EMonsterType result)) ? Themes.MonsterName(result) : "");
			cardFilterFacts.Identity = Themes.Identity(card);
			cardFilterFacts.Foil = card.isFoil;
			cardFilterFacts.Graded = card.cardGrade > 0;
			cardFilterFacts.Value = CPlayerData.GetCardMarketPrice(card);
			return cardFilterFacts;
		}

		private static bool BeforePlace(InteractableCardCompartment __instance)
		{
			try
			{
				CardShelf cardShelf = __instance.GetCardShelf();
				if (!Ready || (Object)(object)cardShelf == (Object)null || !cardShelf.m_ItemNotForSale || __instance.m_StoredCardList.Count != 0)
				{
					return true;
				}
				if (!Live.TryGetValue(cardShelf, out DisplayFilterRule value) && !Pending.ContainsKey(Key(cardShelf)))
				{
					return true;
				}
				value = Get(cardShelf);
				if (!value.Enabled)
				{
					return true;
				}
				InteractableCard3d currentHoldCard = InteractionPlayerController.GetCurrentHoldCard();
				if ((Object)(object)currentHoldCard == (Object)null || currentHoldCard.IsDisplayedOnShelf())
				{
					return true;
				}
				Card3dUIGroup card3dUI = currentHoldCard.m_Card3dUI;
				object obj;
				if (card3dUI == null)
				{
					obj = null;
				}
				else
				{
					CardUI cardUI = card3dUI.m_CardUI;
					obj = ((cardUI != null) ? cardUI.GetCardData() : null);
				}
				CardData val = (CardData)obj;
				if (val == null)
				{
					return true;
				}
				string text = value.Reject(Facts(val, value), Cards(cardShelf).Select(Themes.Identity));
				if (text.Length == 0)
				{
					return true;
				}
				Notice("This case takes " + text + ".");
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Display filter couldn't check a card, so it was let through: " + ex.Message));
				return true;
			}
		}

		internal static void Notice(string message)
		{
			if (!(Time.unscaledTime < _nextNotice))
			{
				_nextNotice = Time.unscaledTime + 1f;
				Toast.Show("src_card_displays", message);
			}
		}

		private static string PathFor(int slot)
		{
			return Path.Combine(Application.persistentDataPath, "ShopPrestige", "DisplayFilters_" + slot + ".json");
		}

		public static void Save(int slot)
		{
			try
			{
				List<string> list = new List<string>();
				List<string> list2 = new List<string>();
				ShelfManager val = Object.FindObjectOfType<ShelfManager>();
				foreach (CardShelf item in ((Object)(object)val != (Object)null) ? val.m_CardShelfList : new List<CardShelf>())
				{
					if (!((Object)(object)item == (Object)null) && item.m_ItemNotForSale && !((InteractableObject)item).GetIsBoxedUp() && !((InteractableObject)item).GetIsMovingObject())
					{
						DisplayFilterRule displayFilterRule = Get(item);
						if (!displayFilterRule.IsDefault)
						{
							list.Add(Key(item));
							list2.Add(displayFilterRule.Write());
						}
					}
				}
				foreach (KeyValuePair<string, DisplayFilterRule> item2 in Pending)
				{
					if (!item2.Value.IsDefault && !list.Contains(item2.Key))
					{
						list.Add(item2.Key);
						list2.Add(item2.Value.Write());
					}
				}
				string path = PathFor(slot);
				if (list.Count != 0 || File.Exists(path))
				{
					Directory.CreateDirectory(Path.GetDirectoryName(path));
					File.WriteAllText(path, JsonUtility.ToJson((object)new SaveData
					{
						cases = list.ToArray(),
						rules = list2.ToArray()
					}));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't save display filters: " + ex.Message));
			}
		}

		public static void Load(int slot)
		{
			Reset();
			try
			{
				string path = PathFor(slot);
				if (!File.Exists(path))
				{
					return;
				}
				SaveData saveData = JsonUtility.FromJson<SaveData>(File.ReadAllText(path));
				if (saveData?.cases == null || saveData.rules == null)
				{
					return;
				}
				int num = 0;
				for (int i = 0; i < saveData.cases.Length && i < saveData.rules.Length; i++)
				{
					DisplayFilterRule displayFilterRule = DisplayFilterRule.Read(saveData.rules[i]);
					if (displayFilterRule == null || string.IsNullOrEmpty(saveData.cases[i]))
					{
						num++;
					}
					else
					{
						Pending[saveData.cases[i]] = displayFilterRule;
					}
				}
				Plugin.Log.LogInfo((object)($"Display filters: {Pending.Count} case(s) with filters in save slot {slot}" + ((num > 0) ? $" ({num} damaged line(s) skipped)." : ".")));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't load display filters (cases keep no filters): " + ex.Message));
			}
		}

		public static void Reset()
		{
			Live.Clear();
			Pending.Clear();
		}
	}
	internal static class Effects
	{
		private static readonly FieldRef<CustomerManager, float> MaxMoney = AccessTools.FieldRefAccess<CustomerManager, float>("m_CustomerMaxMoney");

		private static readonly Dictionary<ConfigEntry<string>, (string Raw, float[] Values)> Parsed = new Dictionary<ConfigEntry<string>, (string, float[])>();

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

		public static float VanillaWallet { get; private set; } = -1f;

		public static float Wallet { get; private set; } = -1f;

		private static float Score => Math.Max(0f, Prestige.Active);

		public static void Apply(Harmony harmony)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CustomerManager), "EvaluateMaxCustomerCount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Effects), "WalletPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CustomerManager), "GetCustomerMaxMoney", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Effects), "RichOddsTranspiler", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CustomerManager), "GetCustomerBuyItemChance", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.Method(typeof(Effects), "PriceTolerancePrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static float[] Values(ConfigEntry<string> entry)
		{
			string value = entry.Value;
			if (Parsed.TryGetValue(entry, out (string, float[]) value2) && (object)value2.Item1 == value)
			{
				return value2.Item2;
			}
			float[] array = ParseValues(entry, value);
			Parsed[entry] = (value, array);
			return array;
		}

		private static float[] ParseValues(ConfigEntry<string> entry, string raw)
		{
			float[] array = Parse(raw);
			if (array.Length != 4 || array.Any(float.IsNaN))
			{
				array = Parse((string)((ConfigEntryBase)entry).DefaultValue);
			}
			return array;
			static float[] Parse(string s)
			{
				float result;
				return (from p in s.Split(',')
					select (!float.TryParse(p.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? float.NaN : result).ToArray();
			}
		}

		public static float At(float[] values, float score)
		{
			float[] array = Prestige.Thresholds();
			if (score <= array[0])
			{
				return values[0];
			}
			for (int i = 1; i < array.Length; i++)
			{
				if (score < array[i])
				{
					float num = Math.Max(0.001f, array[i] - array[i - 1]);
					return Mathf.Lerp(values[i - 1], values[i], (score - array[i - 1]) / num);
				}
			}
			return values[array.Length - 1];
		}

		public static float Step(float value)
		{
			float num = Math.Max(0.01f, Plugin.BonusStep.Value);
			return Mathf.Floor(value / num + 0.0001f) * num;
		}

		public static float WalletPercent(float score)
		{
			if (!Plugin.WalletEnabled.Value)
			{
				return 0f;
			}
			return Step(At(Values(Plugin.WalletBonus), score));
		}

		public static float WalletLimit(float score)
		{
			return At(Values(Plugin.WalletLimit), score);
		}

		public static float RichPercent(float score)
		{
			if (!Plugin.RichOddsEnabled.Value)
			{
				return 4.7f;
			}
			return At(Values(Plugin.RichChance), score);
		}

		public static float VeryRichPercent(float score)
		{
			if (!Plugin.RichOddsEnabled.Value)
			{
				return 0.3f;
			}
			return At(Values(Plugin.VeryRichChance), score);
		}

		public static float TolerancePoints(float score)
		{
			if (!Plugin.PriceToleranceEnabled.Value)
			{
				return 0f;
			}
			return Step(At(Values(Plugin.PriceTolerance), score));
		}

		private static void WalletPostfix(CustomerManager __instance)
		{
			try
			{
				float num = MaxMoney.Invoke(__instance);
				float num2 = Math.Max(num, Math.Min(num * (1f + WalletPercent(Score) / 100f), WalletLimit(Score)));
				MaxMoney.Invoke(__instance) = num2;
				if (Math.Abs(num2 - Wallet) > 0.5f)
				{
					Plugin.Log.LogInfo((object)$"Wallet ceiling {num:N0} -> {num2:N0} (Prestige {Score:0.0}).");
				}
				VanillaWallet = num;
				Wallet = num2;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Wallet ceiling not changed: " + ex.Message));
			}
		}

		public static void RefreshWallet()
		{
			if (!(VanillaWallet < 0f))
			{
				CustomerManager val = Object.FindObjectOfType<CustomerManager>();
				if (!((Object)(object)val == (Object)null) && !(Math.Abs(MaxMoney.Invoke(val) - Wallet) > 0.5f))
				{
					MaxMoney.Invoke(val) = VanillaWallet;
					WalletPostfix(val);
				}
			}
		}

		public static int VeryRichPerMille()
		{
			return Mathf.Clamp(Mathf.RoundToInt(VeryRichPercent(Score) * 10f), 0, 1000);
		}

		public static int RichPerMille()
		{
			return Mathf.Clamp(VeryRichPerMille() + Mathf.RoundToInt(RichPercent(Score) * 10f), 0, 1000);
		}

		private static IEnumerable<CodeInstruction> RichOddsTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			int num2 = 0;
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (IsBranch(list[i + 1]))
				{
					if (num == 0 && IsLdcI4(list[i], 3))
					{
						list[i].opcode = OpCodes.Call;
						list[i].operand = AccessTools.Method(typeof(Effects), "VeryRichPerMille", (Type[])null, (Type[])null);
						num++;
					}
					else if (num == 1 && num2 == 0 && IsLdcI4(list[i], 50))
					{
						list[i].opcode = OpCodes.Call;
						list[i].operand = AccessTools.Method(typeof(Effects), "RichPerMille", (Type[])null, (Type[])null);
						num2++;
					}
				}
			}
			if (Reported.Add($"{num}{num2}"))
			{
				if (num == 1 && num2 == 1)
				{
					Plugin.Log.LogInfo((object)"Patched rich customer odds.");
				}
				else
				{
					Plugin.Log.LogWarning((object)"Rich customer odds not found in GetCustomerMaxMoney, so they stay the game's. The code may have changed.");
				}
			}
			return list;
		}

		private static void PriceTolerancePrefix(ref float currentPrice, float marketPrice)
		{
			if (!(marketPrice <= 0f))
			{
				float num = TolerancePoints(Score) + Wealthy.ExtraTolerance() + Whales.ExtraTolerance();
				if (num > 0f)
				{
					currentPrice -= marketPrice * num / 100f;
				}
			}
		}

		private static bool IsBranch(CodeInstruction c)
		{
			if (!(c.opcode == OpCodes.Bge) && !(c.opcode == OpCodes.Bge_S) && !(c.opcode == OpCodes.Blt) && !(c.opcode == OpCodes.Blt_S) && !(c.opcode == OpCodes.Bge_Un) && !(c.opcode == OpCodes.Bge_Un_S) && !(c.opcode == OpCodes.Blt_Un))
			{
				return c.opcode == OpCodes.Blt_Un_S;
			}
			return true;
		}

		private static bool IsLdcI4(CodeInstruction c, int value)
		{
			if (value != 3 || !(c.opcode == OpCodes.Ldc_I4_3))
			{
				if (c.opcode == OpCodes.Ldc_I4_S || c.opcode == OpCodes.Ldc_I4)
				{
					return Convert.ToInt32(c.operand) == value;
				}
				return false;
			}
			return true;
		}
	}
	internal enum Surface
	{
		Wall,
		Floor,
		Ceiling
	}
	internal sealed class Area
	{
		public string Name = "";

		public Func<Surface, int> Equipped = (Surface _) => 0;

		public Action<Surface, int> Equip = delegate
		{
		};
	}
	internal sealed class Finish
	{
		public Surface Surface;

		public int Index;

		public string Name = "";

		public float Price;

		public int Tier;

		public float Prestige;

		public bool Owned;

		public Sprite? Icon;
	}
	internal static class Finishes
	{
		public static readonly string[] TierNames = new string[5] { "Basic", "Standard", "Quality", "Premium", "Luxury" };

		private static readonly float[] Prices = new float[5] { 0f, 1000f, 2500f, 5000f, 10000f };

		private static readonly float[] Base = new float[5] { 0f, 0.1f, 0.25f, 0.5f, 1f };

		private const float TopTierMax = 1.5f;

		public static readonly string[] SurfaceNames = new string[3] { "Walls", "Floors", "Ceilings" };

		private static readonly string[] SurfaceWords = new string[3] { "wall", "floor", "ceiling" };

		private static Dictionary<(Surface, int), float>? _custom;

		private static bool _looked;

		private static FieldInfo? _shopCUnlocked;

		private static MethodInfo? _shopCEffective;

		private static MethodInfo? _shopCEquip;

		private static MethodInfo? _upEffective;

		private static MethodInfo? _upEquip;

		private static MethodInfo? _upOwned;

		private static float _total;

		private static float _totalUntil;

		public static int TierOfPrice(float price)
		{
			int result = 0;
			for (int i = 0; i < Prices.Length; i++)
			{
				if (price >= Prices[i] - 0.5f)
				{
					result = i;
				}
			}
			return result;
		}

		public static float BaseOf(int tier)
		{
			if (tier != 0)
			{
				return Base[tier];
			}
			return Math.Min(0f, Plugin.CheapestFinishPrestige.Value);
		}

		public static (float Min, float Max) Range(int tier)
		{
			return (Min: (tier > 0) ? BaseOf(tier - 1) : BaseOf(0), Max: (tier < Base.Length - 1) ? BaseOf(tier + 1) : (BaseOf(Base.Length - 1) * 1.5f));
		}

		public static float PrestigeOf(Surface surface, int index, float price)
		{
			int tier = TierOfPrice(price);
			float result = BaseOf(tier);
			if (Custom().TryGetValue((surface, index), out var value))
			{
				(float Min, float Max) tuple = Range(tier);
				float item = tuple.Min;
				float item2 = tuple.Max;
				result = Mathf.Clamp(value, item, item2);
			}
			return result;
		}

		private static Dictionary<(Surface, int), float> Custom()
		{
			if (_custom != null)
			{
				return _custom;
			}
			_custom = new Dictionary<(Surface, int), float>();
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location) ?? "", "finish-prestige.txt");
				if (!File.Exists(path))
				{
					return _custom;
				}
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Split('#')[0].Trim();
					int num = text.IndexOf('=');
					if (num < 0)
					{
						continue;
					}
					string[] array2 = text.Substring(0, num).Trim().Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length == 2 && int.TryParse(array2[1], out var result) && float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						int num2 = Array.IndexOf(SurfaceWords, array2[0].ToLowerInvariant());
						if (num2 >= 0 && result >= 1)
						{
							_custom[((Surface)num2, result - 1)] = result2;
						}
					}
				}
				Plugin.Log.LogInfo((object)$"Read {_custom.Count} finish Prestige values from finish-prestige.txt.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't read finish-prestige.txt: " + ex.Message));
			}
			return _custom;
		}

		private static List<ShopDecoData> List(Surface surface)
		{
			ShelfData_ScriptableObject objectData_SO = CSingleton<InventoryBase>.Instance.m_ObjectData_SO;
			return surface switch
			{
				Surface.Wall => objectData_SO.m_WallDecoDataList, 
				Surface.Floor => objectData_SO.m_FloorDecoDataList, 
				_ => objectData_SO.m_CeilingDecoDataList, 
			};
		}

		public static bool IsOwned(Surface surface, int index)
		{
			if (index == 0)
			{
				return true;
			}
			try
			{
				return surface switch
				{
					Surface.Wall => CPlayerData.IsDecoWallUnlocked(index), 
					Surface.Floor => CPlayerData.IsDecoFloorUnlocked(index), 
					_ => CPlayerData.IsDecoCeilingUnlocked(index), 
				};
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static Finish? Get(Surface surface, int index)
		{
			List<ShopDecoData> list = List(surface);
			if (index < 0 || index >= list.Count || list[index] == null)
			{
				return null;
			}
			ShopDecoData val = list[index];
			string text;
			try
			{
				text = val.GetName();
			}
			catch (Exception)
			{
				text = val.name;
			}
			if (string.IsNullOrWhiteSpace(text) || text.StartsWith("Missing", StringComparison.OrdinalIgnoreCase))
			{
				text = $"{SurfaceWords[(int)surface]} {index + 1}";
			}
			return new Finish
			{
				Surface = surface,
				Index = index,
				Name = text,
				Price = val.price,
				Tier = TierOfPrice(val.price),
				Prestige = PrestigeOf(surface, index, val.price),
				Owned = IsOwned(surface, index),
				Icon = val.icon
			};
		}

		public static List<Finish> All(Surface surface)
		{
			List<Finish> list = new List<Finish>();
			int count = List(surface).Count;
			for (int i = 0; i < count; i++)
			{
				Finish finish = Get(surface, i);
				if (finish != null)
				{
					list.Add(finish);
				}
			}
			return (from f in list
				orderby f.Prestige descending, f.Price descending, f.Name
				select f).ToList();
		}

		private static void Look()
		{
			if (!_looked)
			{
				_looked = true;
				_shopCUnlocked = AccessTools.Field(AccessTools.TypeByName("ShopLotC.ShopCState"), "Unlocked");
				_shopCEffective = AccessTools.Method("ShopLotC.ShopCMaterials:EffectiveIndexForCategory", (Type[])null, (Type[])null);
				_shopCEquip = AccessTools.Method("ShopLotC.ShopCMaterials:EquipForCategory", (Type[])null, (Type[])null);
				_upOwned = AccessTools.PropertyGetter(AccessTools.TypeByName("Upstairs.UpState"), "AnyOwned");
				_upEffective = AccessTools.Method("Upstairs.UpMaterials:EffectiveIndexForCategory", (Type[])null, (Type[])null);
				_upEquip = AccessTools.Method("Upstairs.UpMaterials:EquipForCategory", (Type[])null, (Type[])null);
			}
		}

		public static List<Area> Areas()
		{
			Look();
			List<Area> list = new List<Area>
			{
				new Area
				{
					Name = "Shop A",
					Equipped = (Surface s) => s switch
					{
						Surface.Wall => CPlayerData.m_EquippedWallDecoIndex, 
						Surface.Floor => CPlayerData.m_EquippedFloorDecoIndex, 
						_ => CPlayerData.m_EquippedCeilingDecoIndex, 
					},
					Equip = delegate(Surface s, int i)
					{
						EquipVanilla(s, i, lotB: false);
					}
				}
			};
			if (CPlayerData.m_IsWarehouseRoomUnlocked)
			{
				list.Add(new Area
				{
					Name = "Shop B",
					Equipped = (Surface s) => s switch
					{
						Surface.Wall => CPlayerData.m_EquippedWallDecoIndexB, 
						Surface.Floor => CPlayerData.m_EquippedFloorDecoIndexB, 
						_ => CPlayerData.m_EquippedCeilingDecoIndexB, 
					},
					Equip = delegate(Surface s, int i)
					{
						EquipVanilla(s, i, lotB: true);
					}
				});
			}
			try
			{
				object obj = _shopCUnlocked?.GetValue(null);
				if (obj is bool && (bool)obj && _shopCEffective != null && _shopCEquip != null)
				{
					list.Add(new Area
					{
						Name = "Shop C",
						Equipped = (Surface s) => (int)_shopCEffective.Invoke(null, new object[1] { (int)s }),
						Equip = delegate(Surface s, int i)
						{
							_shopCEquip.Invoke(null, new object[2]
							{
								(int)s,
								i
							});
						}
					});
				}
				obj = _upOwned?.Invoke(null, null);
				if (obj is bool && (bool)obj && _upEffective != null && _upEquip != null)
				{
					list.Add(new Area
					{
						Name = "Upstairs",
						Equipped = (Surface s) => (int)_upEffective.Invoke(null, new object[1] { (int)s }),
						Equip = delegate(Surface s, int i)
						{
							_upEquip.Invoke(null, new object[2]
							{
								(int)s,
								i
							});
						}
					});
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't read Shop C or Upstairs finishes: " + (ex.InnerException ?? ex).Message));
			}
			return list;
		}

		private static void EquipVanilla(Surface surface, int index, bool lotB)
		{
			switch (surface)
			{
			case Surface.Wall:
				ShopCustomizationManager.ChangeWallMaterial(index, lotB);
				if (lotB)
				{
					CPlayerData.m_EquippedWallDecoIndexB = index;
				}
				else
				{
					CPlayerData.m_EquippedWallDecoIndex = index;
				}
				break;
			case Surface.Floor:
				ShopCustomizationManager.ChangeFloorMaterial(index, lotB);
				if (lotB)
				{
					CPlayerData.m_EquippedFloorDecoIndexB = index;
				}
				else
				{
					CPlayerData.m_EquippedFloorDecoIndex = index;
				}
				break;
			default:
				ShopCustomizationManager.ChangeCeilingMaterial(index, lotB);
				if (lotB)
				{
					CPlayerData.m_EquippedCeilingDecoIndexB = index;
				}
				else
				{
					CPlayerData.m_EquippedCeilingDecoIndex = index;
				}
				break;
			}
		}

		public static float Total(List<Source>? sources = null)
		{
			if (sources == null && Time.unscaledTime < _totalUntil)
			{
				return _total;
			}
			float num = 0f;
			try
			{
				if ((Object)(object)CSingleton<InventoryBase>.Instance == (Object)null)
				{
					return 0f;
				}
				foreach (Area item in Areas())
				{
					float num2 = 0f;
					List<string> list = new List<string>();
					foreach (Surface value in Enum.GetValues(typeof(Surface)))
					{
						Finish finish = Get(value, item.Equipped(value));
						if (finish != null)
						{
							num2 += finish.Prestige;
							list.Add(finish.Name);
						}
					}
					num += num2;
					sources?.Add(new Source
					{
						Name = item.Name + ": " + string.Join(", ", list),
						Kind = "Finishes",
						Count = 3,
						Points = num2
					});
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't count finishes: " + ex.Message));
			}
			_total = num;
			_totalUntil = Time.unscaledTime + 1f;
			return num;
		}

		public static void Invalidate()
		{
			_totalUntil = 0f;
		}

		public static string? Buy(Finish f)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			if (f.Owned)
			{
				return "You already own it.";
			}
			if (CPlayerData.m_CoinAmountDouble < (double)f.Price)
			{
				return "Not enough money.";
			}
			CPlayerData.m_GameReportDataCollect.upgradeCost -= f.Price;
			CPlayerData.m_GameReportDataCollectPermanent.upgradeCost -= f.Price;
			PriceChangeManager.AddTransaction(0f - f.Price, (ETransactionType)10, (int)f.Surface, f.Index, (CardData)null);
			CEventManager.QueueEvent((CEvent)new CEventPlayer_ReduceCoin(f.Price, false));
			switch (f.Surface)
			{
			case Surface.Wall:
				CPlayerData.SetUnlockDecoWall(f.Index, true);
				break;
			case Surface.Floor:
				CPlayerData.SetUnlockDecoFloor(f.Index, true);
				break;
			default:
				CPlayerData.SetUnlockDecoCeiling(f.Index, true);
				break;
			}
			try
			{
				SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f);
			}
			catch (Exception)
			{
			}
			Plugin.Log.LogInfo((object)$"Bought {SurfaceWords[(int)f.Surface]} \"{f.Name}\" for {f.Price:N0}.");
			return null;
		}

		public static string? Equip(Area area, Finish f)
		{
			if (!f.Owned)
			{
				return "Buy it first.";
			}
			try
			{
				area.Equip(f.Surface, f.Index);
			}
			catch (Exception ex)
			{
				return "Couldn't equip it: " + (ex.InnerException ?? ex).Message;
			}
			Recount();
			Plugin.Log.LogInfo((object)("Equipped " + SurfaceWords[(int)f.Surface] + " \"" + f.Name + "\" in " + area.Name + "."));
			return null;
		}

		public static void Recount()
		{
			try
			{
				Prestige.Invalidate();
				if (Plugin.DeferToWeeklyTraffic)
				{
					if (Prestige.GameReady())
					{
						Breakdown breakdown = Prestige.Calculate();
						if (breakdown != null)
						{
							Prestige.Capture(breakdown.Total);
							Effects.RefreshWallet();
						}
					}
				}
				else
				{
					CustomerManager val = Object.FindObjectOfType<CustomerManager>();
					if ((Object)(object)val != (Object)null)
					{
						AccessTools.Method(typeof(CustomerManager), "EvaluateMaxCustomerCount", (Type[])null, (Type[])null)?.Invoke(val, null);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't recalculate the customer limit: " + (ex.InnerException ?? ex).Message));
			}
		}
	}
	internal sealed class GuardBody : MonoBehaviour
	{
		private static bool _apparelLogged;

		private Animator? _anim;

		private Seeker? _seeker;

		private Path? _path;

		private int _waypoint;

		private float _nextRepath;

		private float _returnStarted;

		private Vector3 _postPosition;

		private Vector3 _lastPosition;

		private Quaternion _postRotation;

		private Quaternion _facing;

		private Customer? _target;

		private bool _returning;

		public bool IsHome
		{
			get
			{
				if ((Object)(object)_target == (Object)null)
				{
					return !_returning;
				}
				return false;
			}
		}

		public static GuardBody? Create(Transform parent, int index)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			CustomerManager instance = CSingleton<CustomerManager>.Instance;
			Customer val = (((Object)(object)instance != (Object)null) ? instance.m_CustomerPrefab : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = new GameObject("ShopPrestigeGuardHolder");
			val2.SetActive(false);
			try
			{
				GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, val2.transform);
				((Object)val3).name = "ShopPrestigeGuard" + (index + 1);
				Customer component = val3.GetComponent<Customer>();
				CharacterCustomization characterCustom = component.m_CharacterCustom;
				Animator anim = component.m_Anim;
				Seeker seeker = component.m_Seeker;
				if ((Object)(object)component.m_InteractCollider != (Object)null)
				{
					component.m_InteractCollider.SetActive(false);
				}
				Object.DestroyImmediate((Object)(object)component);
				List<string> list = new List<string>();
				MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val4 in componentsInChildren)
				{
					string text = ((object)val4).GetType().Namespace ?? "";
					if (!(val4 is CharacterCustomization) && !(text == "CC") && !text.StartsWith("Pathfinding") && !(val4 is Seeker))
					{
						((Behaviour)val4).enabled = false;
						list.Add(((object)val4).GetType().Name);
					}
				}
				Rigidbody[] componentsInChildren2 = val3.GetComponentsInChildren<Rigidbody>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].isKinematic = true;
				}
				Collider[] componentsInChildren3 = val3.GetComponentsInChildren<Collider>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					componentsInChildren3[i].enabled = false;
				}
				if (list.Count > 0 && index == 0)
				{
					Plugin.Log.LogInfo((object)("Guard character: switched off " + string.Join(", ", list.Distinct())));
				}
				GuardBody guardBody = val3.AddComponent<GuardBody>();
				guardBody._anim = anim;
				if ((Object)(object)anim != (Object)null)
				{
					anim.applyRootMotion = false;
				}
				guardBody._seeker = seeker;
				val3.transform.SetParent(parent, false);
				val3.SetActive(true);
				if ((Object)(object)characterCustom != (Object)null)
				{
					Dress(characterCustom, index);
				}
				return guardBody;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't make a guard character: " + ex));
				return null;
			}
			finally
			{
				Object.Destroy((Object)(object)val2);
			}
		}

		private static void Dress(CharacterCustomization custom, int index)
		{
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = (((Object)(object)custom.Presets != (Object)null) ? (from p in custom.Presets.Presets
				select p.CharacterName into n
				where n?.StartsWith("Male") ?? false
				select n).ToList() : new List<string>());
			custom.CharacterName = ((list.Count > 0) ? list[(index * 5 + 2) % list.Count] : "ShopPrestigeGuard");
			custom.Initialize();
			if (!_apparelLogged)
			{
				_apparelLogged = true;
				for (int num = 0; num < custom.ApparelTables.Count; num++)
				{
					List<Apparel> list2 = custom.ApparelTables[num]?.Items;
					if (list2 != null)
					{
						Plugin.Log.LogInfo((object)($"Outfit slot {num}: " + string.Join(", ", list2.Select((Apparel i) => i.Name))));
					}
				}
			}
			CC_CharacterData data = custom.StoredCharacterData;
			int slot;
			for (slot = 0; slot < custom.ApparelTables.Count; slot++)
			{
				List<Apparel> list3 = custom.ApparelTables[slot]?.Items;
				if (list3 != null && data != null && slot < data.ApparelNames.Count)
				{
					int num2 = list3.FindIndex((Apparel i) => i.Name == data.ApparelNames[slot]);
					if (num2 >= 0)
					{
						custom.setApparel(num2, slot, Darkest(list3[num2]));
					}
				}
			}
			for (int num3 = 0; num3 < custom.ApparelTables.Count; num3++)
			{
				List<Apparel> list4 = custom.ApparelTables[num3]?.Items;
				if (list4 == null)
				{
					continue;
				}
				int num4 = list4.FindIndex((Apparel i) => i.Name != null && i.Name.IndexOf("BlackSunglasses", StringComparison.OrdinalIgnoreCase) >= 0);
				if (num4 < 0)
				{
					num4 = list4.FindIndex((Apparel i) => i.Name != null && i.Name.IndexOf("Sunglasses", StringComparison.OrdinalIgnoreCase) >= 0);
				}
				if (num4 >= 0)
				{
					custom.setApparel(num4, num3, Darkest(list4[num4]));
					if (index == 0)
					{
						Plugin.Log.LogInfo((object)$"Guards wear \"{list4[num4].Name}\" (outfit slot {num3}).");
					}
					return;
				}
			}
			if (index == 0)
			{
				Plugin.Log.LogWarning((object)"No sunglasses found in the game's outfit tables; guards go without.");
			}
		}

		private static int Darkest(Apparel item)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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)
			if (item.Materials == null || item.Materials.Count <= 1)
			{
				return 0;
			}
			int result = 0;
			float num = float.MaxValue;
			for (int i = 0; i < item.Materials.Count; i++)
			{
				List<CC_Apparel_Material_Definition> materialDefinitions = item.Materials[i].MaterialDefinitions;
				if (materialDefinitions != null && materialDefinitions.Count != 0)
				{
					float num2 = materialDefinitions.Average((CC_Apparel_Material_Definition d) => Light(d.MainTint) + Light(d.TintR) + Light(d.TintG) + Light(d.TintB));
					if (num2 < num)
					{
						num = num2;
						result = i;
					}
				}
			}
			return result;
		}

		private static float Light(Color c)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return 0.2126f * c.r + 0.7152f * c.g + 0.0722f * c.b;
		}

		public void Teleport((Vector3 Position, Quaternion Rotation) post)
		{
			//IL_0002: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			(_postPosition, _postRotation) = post;
			((Component)this).transform.SetPositionAndRotation(post.Position, post.Rotation);
			_facing = post.Rotation;
			_lastPosition = post.Position;
			_path = null;
			_returning = false;
		}

		public void SetPost((Vector3 Position, Quaternion Rotation) post)
		{
			//IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = post.Position - _postPosition;
			bool num = ((Vector3)(ref val)).sqrMagnitude > 0.0001f;
			(_postPosition, _postRotation) = post;
			if (num && IsHome)
			{
				Teleport(post);
			}
		}

		public void Follow(Customer? customer)
		{
			if (!((Object)(object)customer == (Object)(object)_target))
			{
				if ((Object)(object)customer == (Object)null && (Object)(object)_target != (Object)null)
				{
					_returning = true;
					_returnStarted = Time.time;
					_nextRepath = 0f;
				}
				_target = customer;
				if ((Object)(object)customer != (Object)null)
				{
					_returning = false;
					_nextRepath = 0f;
				}
			}
		}

		private void Update()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			float num = Math.Max(Time.deltaTime, 0.0001f);
			Vector3? val = null;
			float num2 = 0.15f;
			Vector3 val2;
			if ((Object)(object)_target != (Object)null)
			{
				Vector3 value = ((Component)_target).transform.position - ((Component)_target).transform.forward * Plugin.GuardFollowDistance.Value;
				val = value;
				num2 = 0.35f;
				val2 = ((Component)_target).transform.position - ((Component)this).transform.position;
				if (((Vector3)(ref val2)).sqrMagnitude <= Plugin.GuardFollowDistance.Value * Plugin.GuardFollowDistance.Value * 1.1f)
				{
					val = null;
					_path = null;
				}
			}
			else if (_returning)
			{
				val = _postPosition;
				val2 = ((Component)this).transform.position - _postPosition;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.05f || Time.time - _returnStarted > 25f)
				{
					Teleport((Position: _postPosition, Rotation: _postRotation));
					val = null;
				}
			}
			if (val.HasValue && (Object)(object)_seeker != (Object)null && Time.time >= _nextRepath && _seeker.IsDone())
			{
				_nextRepath = Time.time + 0.8f;
				_seeker.StartPath(((Component)this).transform.position, val.Value, new OnPathDelegate(OnPathComplete));
			}
			if (val.HasValue && _path != null && _path.vectorPath.Count > 0)
			{
				while (_waypoint < _path.vectorPath.Count - 1 && Vector3.Distance(((Component)this).transform.position, _path.vectorPath[_waypoint]) < 0.1f)
				{
					_waypoint++;
				}
				Vector3 val3 = _path.vectorPath[_waypoint];
				if (_waypoint == _path.vectorPath.Count - 1 && Vector3.Distance(((Component)this).transform.position, val3) < num2)
				{
					_path = null;
				}
				else
				{
					((Component)this).transform.position = Vector3.MoveTowards(((Component)this).transform.position, val3, Plugin.GuardWalkSpeed.Value * num);
					Vector3 val4 = val3 - ((Component)this).transform.position;
					val4.y = 0f;
					if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f)
					{
						_facing = Quaternion.LookRotation(val4, Vector3.up);
					}
				}
			}
			else if ((Object)(object)_target != (Object)null)
			{
				Vector3 val5 = ((Component)_target).transform.position - ((Component)this).transform.position;
				val5.y = 0f;
				if (((Vector3)(ref val5)).sqrMagnitude > 0.0001f)
				{
					_facing = Quaternion.LookRotation(val5, Vector3.up);
				}
			}
			else if (!_returning)
			{
				_facing = _postRotation;
			}
			((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, _facing, Math.Min(1f, num * 6f));
			val2 = ((Component)this).transform.position - _lastPosition;
			float num3 = ((Vector3)(ref val2)).magnitude / num;
			_lastPosition = ((Component)this).transform.position;
			if ((Object)(object)_anim != (Object)null)
			{
				_anim.SetFloat("MoveSpeed", num3);
			}
		}

		private void OnPathComplete(Path p)
		{
			p.Claim((object)this);
			if (!p.error)
			{
				Path? path = _path;
				if (path != null)
				{
					path.Release((object)this, false);
				}
				_path = p;
				_waypoint = 0;
			}
			else
			{
				p.Release((object)this, false);
			}
		}

		private void OnDestroy()
		{
			Path? path = _path;
			if (path != null)
			{
				path.Release((object)this, false);
			}
			_path = null;
		}
	}
	internal static class Guards
	{
		[Serializable]
		private sealed class SaveData
		{
			public int guards;
		}

		private static readonly FieldRef<Customer, bool> InsideShop = AccessTools.FieldRefAccess<Customer, bool>("m_IsInsideShop");

		private static readonly FieldRef<CustomerManager, float> MaxMoney = AccessTools.FieldRefAccess<CustomerManager, float>("m_CustomerMaxMoney");

		private static readonly List<GuardBody> Bodies = new List<GuardBody>();

		private static GameObject? _parent;

		private static float _nextLook;

		private static bool _bodiesFailed;

		private static bool _ready;

		private static float _nextReadyCheck;

		private static float _nextPosts;

		public static int Count { get; private set; }

		public static Customer? Following { get; private set; }

		public static int Max => Mathf.Clamp(Plugin.MaxGuards.Value, 0, 2);

		public static bool Unlocked => CPlayerData.m_ShopLevel + 1 >= Plugin.GuardUnlockLevel.Value;

		public static float Wages
		{
			get
			{
				if (!Plugin.GuardsEnabled.Value)
				{
					return 0f;
				}
				return (float)Count * Plugin.GuardWage.Value;
			}
		}

		public static int OnDutyBodies => Bodies.Count((GuardBody b) => (Object)(object)b != (Object)null);

		public static void Apply(Harmony harmony)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Guards), "SalaryPostfix", (Type[])null, (Type[])null));
			val.after = new string[1] { "com.qolmods.staffoverhaul" };
			HarmonyMethod val2 = val;
			harmony.Patch((MethodBase)AccessTools.Method(typeof(WorkerManager), "GetTotalSalaryCost", (Type[])null, (Type[])null), (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CGameData), "SaveGameData", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Guards), "AfterSave", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CSaveLoad), "Load", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Guards), "AfterLoad", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CSaveLoad), "LoadBackup", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Guards), "AfterLoad", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CPlayerData), "CreateDefaultData", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Guards), "AfterNewGame", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static float Prestige()
		{
			return PrestigeFor(Count);
		}

		public static float PrestigeFor(int count)
		{
			if (!Plugin.GuardsEnabled.Value)
			{
				return 0f;
			}
			float num = 0f;
			for (int i = 0; i < count; i++)
			{
				num += Plugin.GuardPrestige.Value * Mathf.Pow(Plugin.DuplicateFalloff.Value, (float)i);
			}
			return num;
		}

		private static void SalaryPostfix(WorkerManager __instance, ref float __result)
		{
			float wages = Wages;
			if (wages > 0f)
			{
				__result += wages;
				__instance.m_TotalSalaryCost = __result;
			}
		}

		public static string Hire()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			if (!Plugin.GuardsEnabled.Value)
			{
				return "Guards are off in the settings.";
			}
			if (!Unlocked)
			{
				return $"Guards unlock at shop level {Plugin.GuardUnlockLevel.Value}.";
			}
			if (Count >= Max)
			{
				return "You already have every guard you can hire.";
			}
			if (LightManager.GetHasDayEnded())
			{
				return "The day has ended. Hire guards once the next day starts.";
			}
			int value = Plugin.GuardHireCost.Value;
			if (CPlayerData.m_CoinAmountDouble < (double)value)
			{
				return "Not enough money.";
			}
			PriceChangeManager.AddTransaction(0f - (float)value, (ETransactionType)8, 0, 0, (CardData)null);
			CEventManager.QueueEvent((CEvent)new CEventPlayer_ReduceCoin((float)value, false));
			CPlayerData.m_GameReportDataCollect.employeeCost -= value;
			CPlayerData.m_GameReportDataCollectPermanent.employeeCost -= value;
			Count++;
			try
			{
				SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f);
			}
			catch (Exception)
			{
			}
			Finishes.Recount();
			Plugin.Log.LogInfo((object)$"Hired guard {Count} for {value:N0}.");
			return $"Hired guard {Count}. He takes his post at the door.";
		}

		public static string Dismiss()
		{
			if (Count <= 0)
			{
				return "No guards to dismiss.";
			}
			Count--;
			Finishes.Recount();
			Plugin.Log.LogInfo((object)$"Dismissed a guard ({Count} left).");
			return "Guard dismissed. No refund.";
		}

		private static string PathFor(int slot)
		{
			return Path.Combine(Application.persistentDataPath, "ShopPrestige", "Guards_" + slot + ".json");
		}

		private static void AfterSave(int saveSlotIndex)
		{
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(PathFor(saveSlotIndex)));
				File.WriteAllText(PathFor(saveSlotIndex), JsonUtility.ToJson((object)new SaveData
				{
					guards = Count
				}));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't save guards: " + ex.Message));
			}
			Outside.Save(saveSlotIndex);
			DisplayFilters.Save(saveSlotIndex);
		}

		private static void AfterLoad(int slotIndex, bool __result)
		{
			if (!__result)
			{
				return;
			}
			ShopPrestige.Prestige.Invalidate();
			Perf.QuietWhileLoading();
			Art.Preload();
			Count = 0;
			Outside.Load(slotIndex);
			DisplayFilters.Load(slotIndex);
			try
			{
				string path = PathFor(slotIndex);
				if (File.Exists(path))
				{
					Count = Mathf.Clamp(JsonUtility.FromJson<SaveData>(File.ReadAllText(path))?.guards ?? 0, 0, 2);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't load guards: " + ex.Message));
			}
			if (Count > 0)
			{
				Plugin.Log.LogInfo((object)$"{Count} guard(s) on the payroll in save slot {slotIndex}.");
			}
		}

		private static void AfterNewGame()
		{
			Count = 0;
			Outside.Reset();
			DisplayFilters.Reset();
			ShopPrestige.Prestige.Invalidate();
			Perf.QuietWhileLoading();
			Art.Preload();
		}

		public static void Update()
		{
			try
			{
				int num = ((Plugin.GuardsEnabled.Value && Count > 0 && Prestige_GameReady() && !LightManager.GetHasDayEnded()) ? Math.Min(Count, Max) : 0);
				Bodies.RemoveAll((GuardBody b) => (Object)(object)b == (Object)null);
				while (Bodies.Count > num)
				{
					GuardBody guardBody = Bodies[Bodies.Count - 1];
					Bodies.RemoveAt(Bodies.Count - 1);
					Object.Destroy((Object)(object)((Component)guardBody).gameObject);
				}
				if (num == 0)
				{
					Following = null;
					return;
				}
				CustomerManager instance = CSingleton<CustomerManager>.Instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_ShopEntranceLocationPoint == (Object)null)
				{
					return;
				}
				while (Bodies.Count < num && !_bodiesFailed)
				{
					GuardBody guardBody2 = GuardBody.Create(Parent(), Bodies.Count);
					if ((Object)(object)guardBody2 == (Object)null)
					{
						_bodiesFailed = true;
						Plugin.Log.LogWarning((object)"Guards can't be shown (no character could be made). They still add Prestige and are paid.");
						break;
					}
					Bodies.Add(guardBody2);
					guardBody2.Teleport(Post(instance, Bodies.Count - 1));
				}
				if (Time.unscaledTime >= _nextPosts)
				{
					_nextPosts = Time.unscaledTime + 2f;
					for (int num2 = 0; num2 < Bodies.Count; num2++)
					{
						Bodies[num2].SetPost(Post(instance, num2));
					}
				}
				PickTarget(instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Guards update failed: " + ex));
				_bodiesFailed = true;
			}
		}

		private static bool Prestige_GameReady()
		{
			if (Time.unscaledTime >= _nextReadyCheck)
			{
				_nextReadyCheck = Time.unscaledTime + 1f;
				_ready = ShopPrestige.Prestige.GameReady();
			}
			return _ready;
		}

		private static Transform Parent()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)_parent == (Object)null)
			{
				_parent = new GameObject("ShopPrestigeGuards");
			}
			return _parent.transform;
		}

		public static (Vector3 Position, Quaternion Rotation) Post(CustomerManager manager, int index)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			Vector3 door = manager.m_ShopEntranceLocationPoint.position;
			List<Vector3> list = (from t in manager.m_ShopLocationPointList ?? new List<Transform>()
				where (Object)(object)t != (Object)null && Math.Abs(t.position.y - door.y) < 1.5f
				select t.position).OrderBy(delegate(Vector3 p)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: 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_000c: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val4 = p - door;
				return ((Vector3)(ref val4)).sqrMagnitude;
			}).Take(4).ToList();
			Vector3 val = list.Aggregate(Vector3.zero, (Vector3 sum, Vector3 p) => sum + p);
			int count = list.Count;
			Vector3 val2 = ((count > 0) ? (door - val / (float)count) : manager.m_ShopEntranceLocationPoint.forward);
			val2.y = 0f;
			val2 = ((Math.Abs(val2.x) >= Math.Abs(val2.z)) ? new Vector3((float)Math.Sign(val2.x), 0f, 0f) : new Vector3(0f, 0f, (float)Math.Sign(val2.z)));
			if (val2 == Vector3.zero)
			{
				val2 = Vector3.forward;
			}
			Vector3 val3 = Vector3.Cross(Vector3.up, val2) * ((index == 0) ? (-1f) : 1f);
			return (Position: door - val2 * Plugin.GuardInsideOffset.Value + val3 * Plugin.GuardSideOffset.Value, Rotation: Quaternion.LookRotation(val2, Vector3.up));
		}

		private static void PickTarget(CustomerManager manager)
		{
			GuardBody follower = ((Bodies.Count >= 2) ? Bodies[1] : Bodies[0]);
			if ((Object)(object)Following != (Object)null && !StillShopping(Following))
			{
				Following = null;
			}
			if ((Object)(object)Following == (Object)null && follower.IsHome && Time.time >= _nextLook)
			{
				_nextLook = Time.time + 1f;
				Following = (from c in Candidates(manager)
					orderby c.m_MaxMoney descending
					select c).FirstOrDefault();
				if ((Object)(object)Following != (Object)null)
				{
					Plugin.Log.LogInfo((object)$"A guard is following a wealthy customer with {Following.m_MaxMoney:N0} to spend.");
				}
			}
			follower.Follow(Following);
			foreach (GuardBody item in Bodies.Where((GuardBody b) => (Object)(object)b != (Object)(object)follower))
			{
				item.Follow(null);
			}
		}

		private static IEnumerable<Customer> Candidates(CustomerManager manager)
		{
			return Wealthy.InShop();
		}

		private static bool StillShopping(Customer c)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			if ((Object)(object)c != (Object)null && c.m_IsActive && ((Component)c).gameObject.activeInHierarchy && InsideShop.Invoke(c))
			{
				return (int)c.m_CurrentState != 7;
			}
			return false;
		}
	}
	internal static class HudLine
	{
		private const float Gap = 2f;

		private static GameUIScreen? _screen;

		private static TextMeshProUGUI? _text;

		private static float _next;

		private static float _nextLive;

		private static float _live = -1f;

		private static bool _failed;

		public static void Update()
		{
			if (_failed || Time.unscaledTime < _next)
			{
				return;
			}
			_next = Time.unscaledTime + 0.5f;
			try
			{
				if (!Plugin.HudLineEnabled.Value)
				{
					if ((Object)(object)_text != (Object)null)
					{
						((Component)_text).gameObject.SetActive(false);
					}
				}
				else
				{
					if (!Prestige.GameReady())
					{
						return;
					}
					if ((Object)(object)_screen == (Object)null)
					{
						_text = null;
						_screen = Object.FindObjectOfType<GameUIScreen>();
						if ((Object)(object)_screen == (Object)null || (Object)(object)_screen.m_ShopLevelText == (Object)null || (Object)(object)_screen.m_ShopExpBar == (Object)null)
						{
							return;
						}
					}
					if ((Object)(object)_text == (Object)null)
					{
						_text = Make(_screen.m_ShopLevelText, ((Graphic)_screen.m_ShopExpBar).rectTransform);
					}
					Place(((TMP_Text)_text).rectTransform, ((Graphic)_screen.m_ShopExpBar).rectTransform);
					((Component)_text).gameObject.SetActive(true);
					((TMP_Text)_text).text = Line();
				}
			}
			catch (Exception ex)
			{
				_failed = true;
				Plugin.Log.LogWarning((object)("The Prestige line under the shop level is turned off: " + ex.Message));
			}
		}

		private static string Line()
		{
			float num = Prestige.Active;
			if (num < 0f)
			{
				if (Time.unscaledTime >= _nextLive)
				{
					_nextLive = Time.unscaledTime + 5f;
					_live = Prestige.Calculate()?.Total ?? 0f;
				}
				num = _live;
			}
			return $"Prestige {num:0.0}  ·  {Prestige.TierName(num)}";
		}

		private static TextMeshProUGUI Make(TextMeshProUGUI levelText, RectTransform bar)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)levelText).gameObject, ((TMP_Text)levelText).transform.parent, false);
			((Object)val).name = "ShopPrestigeLine";
			for (int num = val.transform.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)val.transform.GetChild(num)).gameObject);
			}
			MonoBehaviour[] components = val.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val2 in components)
			{
				if (!(val2 is TextMeshProUGUI))
				{
					Object.Destroy((Object)(object)val2);
				}
			}
			val.AddComponent<LayoutElement>().ignoreLayout = true;
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).enableAutoSizing = false;
			((TMP_Text)component).fontSize = Math.Max(10f, ((TMP_Text)levelText).fontSize * 0.72f);
			((TMP_Text)component).alignment = (TextAlignmentOptions)258;
			((TMP_Text)component).enableWordWrapping = false;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private static void Place(RectTransform line, RectTransform bar)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			line.anchorMax = val;
			line.anchorMin = val;
			line.pivot = new Vector2(0.5f, 1f);
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			bar.GetWorldCorners(array);
			Vector3 val2 = (array[0] + array[3]) / 2f;
			Vector3 val3 = ((Transform)(RectTransform)((Transform)line).parent).InverseTransformPoint(val2);
			((Transform)line).localPosition = new Vector3(val3.x, val3.y - 2f, 0f);
			Rect rect = bar.rect;
			line.sizeDelta = new Vector2(((Rect)(ref rect)).width * 1.4f, ((TMP_Text)((Component)line).GetComponent<TextMeshProUGUI>()).fontSize * 1.3f);
		}
	}
	public static class Links
	{
		public const int Version = 2;

		public static float Score => Math.Max(0f, Prestige.Active);

		public static int Tier()
		{
			return Prestige.Tier(Score);
		}

		public static float TierProgress()
		{
			float[] array = Prestige.Thresholds();
			float score = Score;
			int num = Prestige.Tier(score);
			float num2 = array[num];
			float num3 = ((num < array.Length - 1) ? array[num + 1] : (array[num] * 2f));
			if (!(num3 > num2))
			{
				return 1f;
			}
			return Math.Max(0f, Math.Min(1f, (score - num2) / (num3 - num2)));
		}

		public static int SpreeSize()
		{
			return Whales.SpreeSize(Score);
		}

		public static bool IsWhale(Customer c)
		{
			return Whales.Is(c);
		}

		public static bool IsWealthy(Customer c)
		{
			return Wealthy.Is(c);
		}

		public static void TournamentFinished(int players)
		{
			Outside.TournamentFinished(players);
		}

		public static void Refresh()
		{
			Outside.RefreshSoon();
		}

		public static void Notice(string icon, string text)
		{
			Toast.Show(icon, text);
		}
	}
	internal sealed class LookCard
	{
		private const float Width = 24f;

		private const float Pad = 1f;

		private const float Gap = 0.35f;

		private const float Line = 1.25f;

		private const float Icon = 1.5f;

		private const float BodySize = 0.85f;

		private const float SmallSize = 0.75f;

		private const float TitleSize = 1.15f;

		private const float PixelsPerUnit = 17f;

		private Palette _pal = Palette.Phone;

		private IUiKit? _kit;

		private bool _phoneLookFailed;

		private bool _failed;

		private GameObject? _canvas;

		private RectTransform? _root;

		private InteractionPlayerController? _player;

		private CardShelf? _shelf;

		private float _nextRay;

		private float _nextBuild;

		private int _mask;

		private string _shown = "";

		private Color AccentLight => _pal.AccentLight;

		private Color Surface => _pal.Surface;

		private Color Teal => _pal.Teal;

		private Color Empty => _pal.Dashed;

		public void Update(bool panelOpen)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			if (_failed)
			{
				return;
			}
			try
			{
				if (!(Time.unscaledTime < _nextRay))
				{
					_nextRay = Time.unscaledTime + 0.1f;
					CardShelf val = ((!panelOpen && Plugin.LookAtCardEnabled.Value && (int)Cursor.lockState == 1) ? Aimed() : null);
					if ((Object)(object)val == (Object)null)
					{
						Hide();
					}
					else if ((Object)(object)val != (Object)(object)_shelf || Time.unscaledTime >= _nextBuild)
					{
						_shelf = val;
						_nextBuild = Time.unscaledTime + 1f;
						Show(val);
					}
				}
			}
			catch (Exception e)
			{
				Fail(e);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_canvas != (Object)null)
			{
				Object.Destroy((Object)(object)_canvas);
			}
			_canvas = null;
			_root = null;
		}

		public void ResetLook()
		{
			Destroy();
			_kit = null;
			_shelf = null;
			_shown = "";
		}

		private void Hide()
		{
			_shelf = null;
			_shown = "";
			if ((Object)(object)_canvas != (Object)null && _canvas.activeSelf)
			{
				_canvas.SetActive(false);
			}
		}

		private void Fail(Exception e)
		{
			bool flag = _kit != null && !(_kit is BuiltInUiKit);
			Plugin.Log.LogWarning((object)((flag ? "The case card failed with the Phone - Overhaul look; switching to the built-in look. " : "The case card failed and is turned off. ") + e));
			Destroy();
			_kit = null;
			if (flag)
			{
				_phoneLookFailed = true;
			}
			else
			{
				_failed = true;
			}
		}

		private CardShelf? Aimed()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_player == (Object)null)
			{
				_player = Object.FindObjectOfType<InteractionPlayerController>();
				if ((Object)(object)_player == (Object)null)
				{
					return null;
				}
			}
			Camera cam = _player.m_Cam;
			if ((Object)(object)cam == (Object)null)
			{
				return null;
			}
			if (_mask == 0)
			{
				_mask = LayerMask.GetMask(new string[4] { "ShopModel", "Physics", "ItemCompartment", "Obstacles" });
			}
			int mask = _mask;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(new Ray(((Component)cam).transform.position, ((Component)cam).transform.forward), ref val, 4f, mask))
			{
				return null;
			}
			CardShelf componentInParent = ((Component)((RaycastHit)(ref val)).transform).GetComponentInParent<CardShelf>();
			if (!((Object)(object)componentInParent != (Object)null) || !componentInParent.m_ItemNotForSale)
			{
				return null;
			}
			return componentInParent;
		}

		private IUiKit Kit()
		{
			if (_kit == null)
			{
				_pal = Looks.Palette();
				_kit = Looks.Kit(_phoneLookFailed);
			}
			return _kit;
		}

		private void EnsureCanvas()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_0134: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvas != (Object)null))
			{
				IUiKit uiKit = Kit();
				_canvas = new GameObject("ShopPrestigeCaseCard", new Type[1] { typeof(RectTransform) });
				Object.DontDestroyOnLoad((Object)(object)_canvas);
				Canvas obj = _canvas.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 400;
				CanvasScaler obj2 = _canvas.AddComponent<CanvasScaler>();
				obj2.uiScaleMode = (ScaleMode)1;
				obj2.referenceResolution = new Vector2(1920f, 1080f);
				obj2.matchWidthOrHeight = 1f;
				_root = uiKit.Node(_canvas.transform, "Root");
				RectTransform? root = _root;
				RectTransform? root2 = _root;
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(1f, 0.5f);
				root2.anchorMax = val;
				root.anchorMin = val;
				_root.pivot = new Vector2(1f, 0.5f);
				_root.anchoredPosition = new Vector2(-60f, 0f);
				_root.sizeDelta = new Vector2(24f, 40f);
				((Transform)_root).localScale = Vector3.one * 17f;
				_canvas.SetActive(false);
			}
		}

		private void Show(CardShelf shelf)
		{
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0716: Unknown result type (might be due to invalid IL or missing references)
			//IL_075e: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0818: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0662: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c5: Unknown result type (might be due to invalid IL or missing references)
			CaseReport caseReport = Themes.Find(Themes.Evaluate(), shelf);
			if (caseReport == null)
			{
				Hide();
				return;
			}
			string text = $"{caseReport.Name}|{caseReport.Cards}|{caseReport.Slots}|{caseReport.Value}|{caseReport.Multiplier}|{caseReport.Points}|" + string.Join(",", caseReport.Themes.Select((ThemeHit t) => t.Label + t.Applied)) + "|" + string.Join(",", caseReport.Quality.Select((QualityHit q) => q.Label)) + "|" + string.Join(",", caseReport.Near.Select((ThemeHit n) => n.Label + n.Have));
			if (text == _shown && (Object)(object)_canvas != (Object)null && _canvas.activeSelf)
			{
				return;
			}
			_shown = text;
			EnsureCanvas();
			IUiKit kit = Kit();
			for (int num = ((Transform)_root).childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)((Transform)_root).GetChild(num)).gameObject);
			}
			Image val = kit.Panel((Transform)(object)_root, "Card", kit.Bg, 1.4f, raycast: false);
			kit.Border(((Component)val).transform, kit.Outline, 1.4f);
			RectTransform content = ((Graphic)val).rectTransform;
			float inner = 22f;
			float y = 1f;
			string text2 = "x" + caseReport.Multiplier.ToString("0.00");
			Text(caseReport.Name, 1f, inner - 6.2f, 1.6f, 1.15f, kit.Text, (TextAlignmentOptions)4097, bold: true);
			Text(text2, 1f + inner - 6f, 6f, 2f, 1.9f, (caseReport.Multiplier > 1.001f) ? AccentLight : kit.TextMuted, (TextAlignmentOptions)4100, bold: true);
			y += 1.6f;
			Text($"{caseReport.Cards} of {caseReport.Slots} cards, worth {caseReport.Value:N0}", 1f, inner - 6.2f, 1.1f, 0.75f, kit.TextMuted, (TextAlignmentOptions)4097, bold: true);
			y += 1.8f;
			if (caseReport.Slots > 0 && caseReport.Slots <= 12)
			{
				float num2 = (inner - 0.3f * (float)(caseReport.Slots - 1)) / (float)caseReport.Slots;
				for (int num3 = 0; num3 < caseReport.Slots; num3++)
				{
					Block(1f + (float)num3 * (num2 + 0.3f), y, num2, 0.6f, (num3 < caseReport.Cards) ? Teal : Empty, 0.25f);
				}
			}
			else if (caseReport.Slots > 0)
			{
				Block(1f, y, inner, 0.6f, Empty, 0.3f);
				Block(1f, y, Math.Max(0.6f, inner * (float)caseReport.Cards / (float)caseReport.Slots), 0.6f, caseReport.Full ? Teal : kit.TextMuted, 0.3f);
			}
			y += 1.65f;
			if (!Plugin.ThemesEnabled.Value)
			{
				Text("Themes are off in the settings.", 1f, inner, 1.25f, 0.75f, kit.TextMuted, (TextAlignmentOptions)4097, bold: true);
				y += 1.25f;
			}
			else
			{
				foreach (ThemeHit theme in caseReport.Themes)
				{
					Row(theme.Icon, (theme.Applied < theme.Bonus - 0.001f) ? (theme.Label + " (extra)") : theme.Label, "+" + Percent(theme.Applied), muted: false);
				}
				foreach (QualityHit item in caseReport.Quality)
				{
					Row(item.Icon, item.Label, "+" + Percent(item.Bonus), muted: false);
				}
				foreach (ThemeHit item2 in caseReport.Near.Take(3))
				{
					Row(item2.Icon, $"{item2.Label} {item2.Have} of {item2.Need}", "", muted: true);
				}
				if (!caseReport.Full)
				{
					Text("Fill every slot to earn a bonus.", 1f, inner, 1.25f, 0.75f, kit.TextMuted, (TextAlignmentOptions)4097, bold: true);
					y += 1.25f;
				}
				else if (caseReport.Themes.Count == 0 && caseReport.Quality.Count == 0)
				{
					Text("No bonus yet.", 1f, inner, 1.25f, 0.75f, kit.TextMuted, (TextAlignmentOptions)4097, bold: true);
					y += 1.25f;
				}
			}
			y += 0.35f;
			Block(1f, y, inner, 2.6f, Surface, 0.8f);
			Text($"{caseReport.Base:0.00} from cards", 1.8f, inner / 2f, 2.6f, 0.75f, kit.TextMuted, (TextAlignmentOptions)4097, bold: true);
			Text($"{caseReport.Points:0.00} Prestige",