Decompiled source of HighBallerMod Patched v2.6.0

Mods/HighBaller_IL2CPP.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using HighBaller;
using HighBaller.Models;
using HighBaller.Services;
using Il2CppFishNet;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Levelling;
using Il2CppScheduleOne.Messaging;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Relation;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.Product.Packaging;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Handover;
using Il2CppScheduleOne.UI.Phone;
using Il2CppScheduleOne.UI.Phone.ContactsApp;
using Il2CppScheduleOne.UI.Phone.Messages;
using Il2CppScheduleOne.UI.Phone.ProductManagerApp;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "HighBaller", "2.6.0", "zocke1r, Patched by: SFox", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("HighBaller_IL2CPP")]
[assembly: AssemblyConfiguration("Release_IL2CPP")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HighBaller_IL2CPP")]
[assembly: AssemblyTitle("HighBaller_IL2CPP")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace HighBaller
{
	public static class BuildInfo
	{
		public const string Name = "HighBaller_IL2CPP";

		public const string Author = "zocke1r";

		public const string Version = "2.5.4";
	}
	public static class Config
	{
		private static MelonPreferences_Category DealOptimizerCategory;

		public static MelonPreferences_Entry<float> MinSuccessProbability;

		public static MelonPreferences_Entry<bool> PriceOptimizationEnabled;

		public static MelonPreferences_Entry<bool> CounterOfferDarkModeEnabled;

		private static MelonPreferences_Category DealOptimizerCategory_Automation;

		public static MelonPreferences_Entry<bool> AutoCounterOfferEnabled;

		public static MelonPreferences_Entry<bool> AutoContractAcceptedEnabled;

		public static MelonPreferences_Entry<int> AutoContractAcceptedWindow;

		public static MelonPreferences_Entry<bool> IncreaseQuantityEnabled;

		public static MelonPreferences_Entry<bool> AutoHandoverEnabled;

		public static MelonPreferences_Entry<int> CounterOfferQuantityMultiplier;

		public static MelonPreferences_Entry<bool> AutoInstantDealEnabled;

		private static MelonPreferences_Category DealOptimizerCategory_Features;

		public static MelonPreferences_Entry<bool> DelayAutoResponseDuringSave;

		public static void Initialize()
		{
			DealOptimizerCategory = MelonPreferences.CreateCategory("HighBaller_IL2CPP");
			MinSuccessProbability = DealOptimizerCategory.CreateEntry<float>("MinSuccessProbability", 0.98f, "Minimum Success Probability", "The minimum probability of success required for a deal (0.0 to 1.0)", false, false, (ValueValidator)null, (string)null);
			PriceOptimizationEnabled = DealOptimizerCategory.CreateEntry<bool>("PriceOptimizationEnabled", false, "Price Optimization Enabled", "Whether to enable price optimization", false, false, (ValueValidator)null, (string)null);
			CounterOfferDarkModeEnabled = DealOptimizerCategory.CreateEntry<bool>("CounterOfferDarkModeEnabled", true, "Counter Offer Dark Mode Enabled", "Whether to enable counter offer dark mode", false, false, (ValueValidator)null, (string)null);
			DealOptimizerCategory_Automation = MelonPreferences.CreateCategory("HighBaller_IL2CPP_Automation");
			AutoCounterOfferEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoCounterOfferEnabled", false, "Enable Auto Counter Offer", "Whether to enable auto counter offer", false, false, (ValueValidator)null, (string)null);
			AutoContractAcceptedEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoContractAcceptedEnabled", false, "Enable Auto Deal Scheduling", "Whether to enable auto deal scheduling", false, false, (ValueValidator)null, (string)null);
			AutoContractAcceptedWindow = DealOptimizerCategory_Automation.CreateEntry<int>("AutoContractAcceptedWindow", 4, "Auto Deal Time Window (1 = Morning, 2 = Afternoon, 3 = Night, 4 = Late Night)", "The window to auto accept deal", false, false, (ValueValidator)null, (string)null);
			IncreaseQuantityEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("IncreaseQuantityEnabled", false, "Increase Quantity till max spend is reached", "If enabled, the quantity will be increased until the max spend is reached", false, false, (ValueValidator)null, (string)null);
			AutoHandoverEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoHandoverEnabled", false, "Enable automatic handovers", "Whether to enable automatic handover", false, false, (ValueValidator)null, (string)null);
			DealOptimizerCategory_Features = MelonPreferences.CreateCategory("HighBaller_IL2CPP_Features");
			DelayAutoResponseDuringSave = DealOptimizerCategory_Features.CreateEntry<bool>("DelayAutoResponseDuringSave", true, "Don't send auto responses during save", "Whether to delay auto response during save", false, false, (ValueValidator)null, (string)null);
		}
	}
	public class Core : MelonMod
	{
		public class InitialOfferData
		{
			public string ProductId { get; set; }

			public int Quantity { get; set; }

			public float Payment { get; set; }
		}

		public static class DealCalculator
		{
			public static float CalculateSuccessProbability(Customer customer, ProductDefinition product, int quantity, float price, InitialOfferData initialOfferData)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				CustomerData customerData = customer.CustomerData;
				float valueProposition = Customer.GetValueProposition(Registry.GetItem<ProductDefinition>(initialOfferData.ProductId), initialOfferData.Payment / (float)initialOfferData.Quantity);
				float productEnjoyment = customer.GetProductEnjoyment(product, StandardsMethod.GetCorrespondingQuality(customerData.Standards));
				float num = Mathf.InverseLerp(-1f, 1f, productEnjoyment);
				float valueProposition2 = Customer.GetValueProposition(product, price / (float)quantity);
				float num2 = Mathf.Lerp(1f, 0f, Mathf.Abs(Mathf.Lerp(0f, 2f, Mathf.Pow((float)quantity / (float)initialOfferData.Quantity, 0.6f) * 0.5f) - 1f));
				if (valueProposition2 * num2 > valueProposition)
				{
					return 1f;
				}
				if ((double)valueProposition2 < 0.11999999731779099)
				{
					return 0f;
				}
				float num3 = productEnjoyment * valueProposition;
				float num4 = num * num2 * valueProposition2;
				return (num4 > num3) ? 1f : Mathf.Clamp01((float)((0.8999999761581421 - (double)(Mathf.Lerp(0f, 1f, (num3 - num4) / 0.2f) - Mathf.Lerp(0f, 0.2f, Mathf.Max(customer.CurrentAddiction, customer.NPC.RelationData.NormalizedRelationDelta)))) / 0.8999999761581421));
			}

			public static (float maxSpend, float dailyAverage) CalculateSpendingLimits(Customer customer)
			{
				CustomerData customerData = customer.CustomerData;
				float num = customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count;
				return (num * 3f, num);
			}

			public static int FindOptimalPrice(Customer customer, ProductDefinition product, int quantity, float currentPrice, float maxSpend, float minSuccessProbability = -1f, InitialOfferData initialOfferData = null, bool log = false)
			{
				if ((double)minSuccessProbability < 0.0)
				{
					minSuccessProbability = Config.MinSuccessProbability.Value;
				}
				int num = (int)currentPrice;
				int num2 = (int)maxSpend;
				int num3 = (int)currentPrice;
				int num4 = 20;
				int i = 0;
				if (initialOfferData == null)
				{
					initialOfferData = new InitialOfferData
					{
						ProductId = customer.OfferedContractInfo.Products.entries[0].ProductID,
						Quantity = customer.OfferedContractInfo.Products.entries[0].Quantity,
						Payment = customer.OfferedContractInfo.Payment
					};
				}
				if (log)
				{
					Melon<Core>.Logger.Msg($"Initial Offer Data: ProductId: {initialOfferData.ProductId}, Quantity: {initialOfferData.Quantity}, Payment: {initialOfferData.Payment}");
					Melon<Core>.Logger.Msg($"Binary Search Start - Product: {((ItemDefinition)product).ID}, Price: {currentPrice}, MaxSpend: {maxSpend}, Quantity: {quantity}, MinProbability: {minSuccessProbability}, Low: {num}, High: {num2}");
				}
				for (; i < num4; i++)
				{
					if (num >= num2)
					{
						break;
					}
					int num5 = (num + num2) / 2;
					if (CalculateSuccessProbability(customer, product, quantity, num5, initialOfferData) >= minSuccessProbability)
					{
						num = num5 + 1;
						if (num == num2)
						{
							num3 = ((CalculateSuccessProbability(customer, product, quantity, num5 + 1, initialOfferData) > minSuccessProbability) ? (num5 + 1) : num5);
							break;
						}
						num3 = num5;
					}
					else
					{
						num2 = num5;
					}
				}
				if (log)
				{
					Melon<Core>.Logger.Msg("Binary Search Complete:");
					Melon<Core>.Logger.Msg($"  Final bestFailingPrice: {num3}");
					Melon<Core>.Logger.Msg($"  Final Probability: {CalculateSuccessProbability(customer, product, quantity, num3, initialOfferData)}");
				}
				return num3;
			}

			public static (int optimalQuantity, int optimalPrice) FindOptimalQuantity(Customer customer, ProductDefinition product, int initialQuantity, float initialPrice, InitialOfferData initialOfferData = null)
			{
				float item = CalculateSpendingLimits(customer).maxSpend;
				if (!Config.IncreaseQuantityEnabled.Value)
				{
					int item2 = FindOptimalPrice(customer, product, initialQuantity, initialPrice, item, -1f, initialOfferData);
					return (initialQuantity, item2);
				}
				int i = 0;
				int num = 20;
				int num2 = FindOptimalPrice(customer, product, initialQuantity, initialPrice, item, -1f, initialOfferData);
				int item3 = initialQuantity;
				int num3 = num2;
				if ((double)num3 >= Math.Floor((double)item * 0.9900000095367432))
				{
					return (item3, num3);
				}
				int num4 = initialQuantity;
				for (; i < num; i++)
				{
					num4++;
					int num5 = FindOptimalPrice(customer, product, num4, initialPrice, item, -1f, initialOfferData);
					if (num5 > num3)
					{
						item3 = num4;
						num3 = num5;
						if ((double)num3 >= Math.Floor((double)item * 0.9900000095367432))
						{
							break;
						}
						continue;
					}
					break;
				}
				return (item3, num3);
			}
		}

		private static class DisplayHelper
		{
			public static void UpdateCounterOfferDisplayText(string text, string reasonText)
			{
				Instance.uiHandler.UpdateCounterOfferDisplayText(text, reasonText);
			}
		}

		[HarmonyPatch(typeof(CounterofferInterface), "SetProduct")]
		private static class CounterofferInterfaceChangeProductPatch
		{
			private static void Postfix(ProductDefinition newProduct)
			{
				MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
				Melon<Core>.Logger.Msg("CounterofferInterfaceChangeProductPatch: " + ((ItemDefinition)newProduct).Name);
				OfferData offerData = GetOfferData();
				Customer customer = offerData.Customer;
				int quantity = offerData.Quantity;
				float price = offerData.Price;
				(int optimalQuantity, int optimalPrice) tuple = DealCalculator.FindOptimalQuantity(customer, newProduct, quantity, price * 0.25f);
				int item = tuple.optimalQuantity;
				int item2 = tuple.optimalPrice;
				int num = quantity;
				if ((float)item2 != price)
				{
					instance.CounterofferInterface.ChangePrice((float)(item2 - (int)price));
					instance.CounterofferInterface.ChangeQuantity(item - num);
				}
			}
		}

		[HarmonyPatch(typeof(CounterofferInterface), "Open")]
		private static class CounterofferInterfacePostOpenPatch
		{
			private static void Postfix(ProductDefinition product, int quantity, float price, MSGConversation _conversation, Action<ProductDefinition, int, float> _orderConfirmedCallback)
			{
				MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
				(int optimalQuantity, int optimalPrice) tuple = DealCalculator.FindOptimalQuantity(CustomerHelper.GetCustomerFromConversation(_conversation), product, quantity, price);
				int item = tuple.optimalQuantity;
				int item2 = tuple.optimalPrice;
				if (!((float)item2 <= price))
				{
					instance.CounterofferInterface.ChangePrice((float)(item2 - (int)price));
					instance.CounterofferInterface.ChangeQuantity(item - quantity);
				}
			}
		}

		[HarmonyPatch(typeof(CounterofferInterface), "ChangePrice")]
		private static class CounterofferInterfacePostChangePricePatch
		{
			private static void Postfix(float change)
			{
				OfferPriceChangeCheckNoLog();
			}
		}

		[HarmonyPatch(typeof(CounterofferInterface), "ChangeQuantity")]
		private static class CounterofferInterfacePostChangeQuantityPatch
		{
			private static void Postfix(int change)
			{
				MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
				if (!((Object)(object)instance == (Object)null) && instance.CounterofferInterface.IsOpen)
				{
					Customer customerFromMessagesApp = CustomerHelper.GetCustomerFromMessagesApp(instance);
					float item = DealCalculator.CalculateSpendingLimits(customerFromMessagesApp).maxSpend;
					CounterofferInterface counterofferInterface = instance.CounterofferInterface;
					int quantity = int.Parse(counterofferInterface.ProductLabel.text.Split("x ")[0]);
					string text = counterofferInterface.PriceInput.text;
					float num = ((text == "") ? 0f : float.Parse(text));
					int num2 = DealCalculator.FindOptimalPrice(customerFromMessagesApp, Registry.GetItem<ProductDefinition>(((ItemDefinition)counterofferInterface.selectedProduct).ID), quantity, num * 0.25f, item, -1f, null, log: true);
					if (!Mathf.Approximately((float)num2, num))
					{
						counterofferInterface.ChangePrice((float)(num2 - (int)num));
					}
					OfferPriceChangeCheckNoLog();
				}
			}
		}

		private class OfferData
		{
			public Customer Customer { get; }

			public ProductDefinition Product { get; }

			public int Quantity { get; }

			public float Price { get; }

			public OfferData(Customer customer, ProductDefinition product, int quantity, float price)
			{
				Customer = customer;
				Product = product;
				Quantity = quantity;
				Price = price;
			}
		}

		[HarmonyPatch(typeof(ProductManager), "SendPrice")]
		private static class ProductManagerSetPricePatch
		{
			private static void Postfix(string productID, float value)
			{
				MelonLogger.Msg($"ProductManager: Set price: {value} for {productID}");
				if ((Object)(object)UIHandler.SelectedProduct != (Object)null && ((ItemDefinition)UIHandler.SelectedProduct.Definition).ID == productID)
				{
					optimalPriceCache.Remove(productID);
					Instance.uiHandler.UpdateSalesInfoPanel(UIHandler.SelectedProduct, value);
				}
			}
		}

		[HarmonyPatch(typeof(ProductManagerApp), "SelectProduct")]
		private static class ProductManagerSelectProductPatch
		{
			public static void Prefix(ProductManagerApp __instance, ProductEntry entry)
			{
				productManagerApp = __instance;
			}

			private static void Postfix(ProductEntry entry)
			{
				Instance.uiHandler.UpdateSalesInfoPanel(entry);
			}
		}

		[HarmonyPatch(typeof(ContactsDetailPanel), "Open")]
		public static class ContactsDetailPanelOpenPatch
		{
			[HarmonyPostfix]
			public static void Postfix(NPC npc, ContactsDetailPanel __instance)
			{
				if (!((Object)(object)npc == (Object)null))
				{
					Melon<Core>.Logger.Msg($"RelationCircle: {npc.ID}, Name: {npc.fullName}, RelationDelta: {npc.RelationData.RelationDelta}, Unlocked: {npc.RelationData.Unlocked}");
					Customer customerFromNPC = CustomerHelper.GetCustomerFromNPC(npc);
					if ((Object)(object)customerFromNPC == (Object)null)
					{
						Melon<Core>.Logger.Msg("Not a customer");
						Instance.uiHandler.UpdateContactInfoPanel(null);
					}
					else
					{
						Instance.uiHandler.UpdateContactInfoPanel(customerFromNPC);
					}
				}
			}
		}

		public class CustomerAppeal
		{
			public Customer Customer { get; set; }

			public float Appeal { get; set; }

			public PaymentQuantityResult PaymentQuantity { get; set; }
		}

		[HarmonyPatch(typeof(Customer), "OfferContract")]
		public static class OfferContractPatch
		{
			public static void Postfix(ContractInfo info, Customer __instance, MethodBase __originalMethod)
			{
				if (Config.AutoCounterOfferEnabled.Value)
				{
					Melon<Core>.Logger.Msg("Customer: " + ((Object)__instance.customerData).name + ", Contract: " + info.Products.entries[0].ProductID);
					Entry entry = info.Products.entries[0];
					Func<ProductDefinition, bool> func = (ProductDefinition product) => ((ItemDefinition)product).ID.Equals(entry.ProductID);
					ProductDefinition product2 = ProductManager.ListedProducts.Find(Predicate<ProductDefinition>.op_Implicit(func));
					float item = DealCalculator.CalculateSpendingLimits(__instance).maxSpend;
					if ((double)info.Payment >= Math.Floor(item))
					{
						Melon<Core>.Logger.Msg("Skipping counter offer for " + ((Object)__instance.customerData).name + " because they are over their max spend");
						new DelayedCounterOffer(__instance, product2, entry.Quantity, info.Payment, skipCounterOffer: true).Start();
					}
					else
					{
						var (quantity, num) = DealCalculator.FindOptimalQuantity(__instance, product2, entry.Quantity, info.Payment);
						new DelayedCounterOffer(__instance, product2, quantity, num).Start();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Customer), "EvaluateCounteroffer")]
		public static class EvaluateCounterOfferPatch
		{
			public static void Postfix(Customer __instance, bool __result)
			{
				//IL_0115: 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_012d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_0170: Unknown result type (might be due to invalid IL or missing references)
				//IL_017c: Expected O, but got Unknown
				//IL_0190: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				if (!Config.AutoContractAcceptedEnabled.Value)
				{
					return;
				}
				if (!__result)
				{
					Melon<Core>.Logger.Warning("Counter failed");
					return;
				}
				Melon<Core>.Logger.Msg($"Customer: {((Object)__instance.customerData).name}, Contract: {__result}, Counteroffer: {__instance.OfferedContractInfo.IsCounterOffer}");
				int value = Config.AutoContractAcceptedWindow.Value;
				Melon<Core>.Logger.Msg($"Conversation: {__instance.NPC.MSGConversation}");
				EDealWindow window;
				string text;
				switch (value)
				{
				case 1:
					window = (EDealWindow)0;
					text = "Morning";
					break;
				case 2:
					window = (EDealWindow)1;
					text = "Afternoon";
					break;
				case 3:
					window = (EDealWindow)2;
					text = "Night";
					break;
				case 4:
					window = (EDealWindow)3;
					text = "Late Night";
					break;
				default:
					window = (EDealWindow)3;
					text = "Late Night";
					Melon<Core>.Logger.Warning("AutoContractAcceptedWindow is not correctly set!\nDefaulting to Late Night \nCorrect Values: 1 = Morning, 2 = Afternoon, 3 = Night, 4 = Late Night");
					break;
				}
				__instance.NPC.MSGConversation.SendMessage(new Message(text, (ESenderType)0, true, -1), true, true);
				__instance.NPC.MSGConversation.ClearResponses(true);
				new DelayedScheduler(__instance, window).Start();
			}
		}

		[HarmonyPatch(typeof(LevelManager), "AddXP")]
		public static class LevelManagerLoggingPatch
		{
			public static void Postfix(int xp)
			{
				Melon<Core>.Logger.Msg($"LevelManager: AddXP: {xp}");
			}
		}

		private bool listening;

		private UIHandler uiHandler;

		private static Dictionary<string, (float bestPrice, float spenderScore)> optimalPriceCache = new Dictionary<string, (float, float)>();

		public static ProductManager productManager;

		public static ProductManagerApp productManagerApp;

		public static Core Instance { get; private set; }

		private static bool DefinitelyLessThan(float a, float b)
		{
			return (double)(b - a) > (double)((Math.Abs(a) < Math.Abs(b)) ? Math.Abs(b) : Math.Abs(a)) * 1E-15;
		}

		private static OfferData GetOfferData()
		{
			MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
			Customer customerFromMessagesApp = CustomerHelper.GetCustomerFromMessagesApp(instance);
			ProductDefinition item = Registry.GetItem<ProductDefinition>(customerFromMessagesApp.OfferedContractInfo.Products.entries[0].ProductID);
			int quantity = int.Parse(instance.CounterofferInterface.ProductLabel.text.Split('x')[0]);
			string text = instance.CounterofferInterface.PriceInput.text;
			float price = ((text == "") ? 0f : float.Parse(text));
			return new OfferData(customerFromMessagesApp, item, quantity, price);
		}

		public static void OfferPriceChangeCheckNoLog()
		{
			EvaluateCounterOffer(GetOfferData());
		}

		private void OfferPriceChangeCheckWithLog()
		{
			OfferData offerData = GetOfferData();
			string text = $"\nCustomer Name: {((Object)offerData.Customer).name}\nProduct: {((ItemDefinition)offerData.Product).ID}\nQuantity: {offerData.Quantity}\nPrice: {offerData.Price}\n";
			EvaluateCounterOffer(text, offerData);
			((MelonBase)this).LoggerInstance.Msg(text.ToString());
		}

		private static void EvaluateCounterOffer(OfferData offerData)
		{
			float item = DealCalculator.CalculateSpendingLimits(offerData.Customer).maxSpend;
			decimal value = Math.Round((decimal)item, 2);
			if (offerData.Price >= item)
			{
				DisplayHelper.UpdateCounterOfferDisplayText("Guaranteed Failure", $"Exceeded Max Spend ({value})");
				return;
			}
			ProductDefinition selectedProduct = PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.selectedProduct;
			InitialOfferData initialOfferData = new InitialOfferData
			{
				ProductId = offerData.Customer.OfferedContractInfo.Products.entries[0].ProductID,
				Quantity = offerData.Customer.OfferedContractInfo.Products.entries[0].Quantity,
				Payment = offerData.Customer.OfferedContractInfo.Payment
			};
			DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {Math.Round((decimal)(DealCalculator.CalculateSuccessProbability(offerData.Customer, selectedProduct, offerData.Quantity, offerData.Price, initialOfferData) * 100f), 3)}%", $"Price per unit: {offerData.Price / (float)offerData.Quantity}\nMax Spend: {value}");
		}

		private void EvaluateCounterOffer(string stringBuilder, OfferData offerData)
		{
			(float maxSpend, float dailyAverage) tuple = DealCalculator.CalculateSpendingLimits(offerData.Customer);
			float item = tuple.maxSpend;
			float item2 = tuple.dailyAverage;
			decimal value = Math.Round((decimal)item, 2);
			string text = "\nAdjusted Weekly Spend: " + $"{offerData.Customer.CustomerData.GetAdjustedWeeklySpend(offerData.Customer.NPC.RelationData.RelationDelta / 5f)}\n" + "Order Days: " + $"{offerData.Customer.CustomerData.GetOrderDays(offerData.Customer.CurrentAddiction, offerData.Customer.NPC.RelationData.RelationDelta / 5f).Count}\n" + "Average Daily Spend: " + $"{item2}\n" + "Daily Spend Threshold (3x Avg): " + $"{value}\n" + "Min Weekly Spend: " + $"{offerData.Customer.CustomerData.MinWeeklySpend}\n" + "Max Weekly Spend: " + $"{offerData.Customer.CustomerData.MaxWeeklySpend}\n";
			bool flag = (Object)(object)offerData.Customer.AssignedDealer == (Object)null;
			string text2 = "";
			Enumerator<ProductDefinition> enumerator = offerData.Customer.GetOrderableProducts(flag ? null : offerData.Customer.AssignedDealer).GetEnumerator();
			while (enumerator.MoveNext())
			{
				ProductDefinition current = enumerator.Current;
				text2 += $"[Name: {((ItemDefinition)current).Name}, Price: {current.Price}, Market: {current.MarketValue}],\n";
			}
			text = text + "Orderable Products: " + text2 + "\n";
			if (offerData.Price >= item)
			{
				text += "\nGuaranteed Failure - order must be less than 3x average daily spend\n";
				string reasonText = $"Exceeded Max Spend ({value})";
				DisplayHelper.UpdateCounterOfferDisplayText("Guaranteed Failure", reasonText);
				return;
			}
			InitialOfferData initialOfferData = new InitialOfferData
			{
				ProductId = offerData.Customer.OfferedContractInfo.Products.entries[0].ProductID,
				Quantity = offerData.Customer.OfferedContractInfo.Products.entries[0].Quantity,
				Payment = offerData.Customer.OfferedContractInfo.Payment
			};
			decimal value2 = Math.Round((decimal)(DealCalculator.CalculateSuccessProbability(offerData.Customer, offerData.Product, offerData.Quantity, offerData.Price, initialOfferData) * 100f), 3);
			text = text + "\nProbability of success: " + $"{value2}\n";
			DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {value2}", "");
			MelonLogger.Msg(text);
		}

		public override void OnInitializeMelon()
		{
			Instance = this;
			uiHandler = new UIHandler();
			Config.Initialize();
			((MelonBase)this).LoggerInstance.Msg("Initialized Mod");
		}

		public override void OnGUI()
		{
			uiHandler.OnGUI();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (sceneName == "Main")
			{
				try
				{
					productManager = Object.FindObjectsOfType<ProductManager>()[0];
					Melon<Core>.Logger.Msg($"ProductManager: {productManager}");
				}
				catch (Exception ex)
				{
					MelonLogger.Error("Error finding ProductManager: " + ex.Message);
				}
			}
			((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
		}

		public static float EvaluatePriceAcceptance(ProductDefinition product, List<CustomerAppeal> customerAppeals, float price)
		{
			float num = 0f;
			foreach (CustomerAppeal customerAppeal in customerAppeals)
			{
				Customer customer = customerAppeal.Customer;
				if (!((double)customerAppeal.Appeal >= 0.05000000074505806))
				{
					continue;
				}
				float item = DealCalculator.CalculateSpendingLimits(customer).maxSpend;
				PaymentQuantityResult paymentQuantityResult = CustomerHelper.CalculatePaymentQuantity(product, customer, price);
				InitialOfferData initialOfferData = new InitialOfferData
				{
					ProductId = ((ItemDefinition)product).ID,
					Quantity = paymentQuantityResult.Quantity,
					Payment = paymentQuantityResult.Payment
				};
				var (num2, num3) = DealCalculator.FindOptimalQuantity(customer, product, paymentQuantityResult.Quantity, paymentQuantityResult.Payment, initialOfferData);
				if (num3 != 0 && num2 != 0)
				{
					float num4 = (float)num3 / (float)Math.Floor(item);
					if (num4 >= Config.MinSuccessProbability.Value)
					{
						num += num4;
					}
				}
			}
			return num;
		}

		public static (float bestPrice, float spenderScore) GetOptimalPrice(ProductDefinition product, List<CustomerAppeal> customerAppeals, float initialPrice, float minPrice, float maxPrice, Action<(float bestPrice, float spenderScore)> callback = null)
		{
			Melon<Core>.Logger.Msg($"Getting optimal price for {((ItemDefinition)product).Name} at {initialPrice}");
			if (optimalPriceCache.TryGetValue(((ItemDefinition)product).ID, out (float, float) value))
			{
				callback?.Invoke(value);
				return value;
			}
			new DelayedPriceCalculator(product, customerAppeals, initialPrice, minPrice, maxPrice, delegate((float, float) result)
			{
				optimalPriceCache[((ItemDefinition)product).ID] = result;
				callback?.Invoke(result);
			}).Start();
			return (initialPrice, 0f);
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			if (listening)
			{
				listening = false;
			}
		}

		public override void OnUpdate()
		{
			//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)
			SceneManager.GetActiveScene();
			Scene activeScene = SceneManager.GetActiveScene();
			bool flag = ((Scene)(ref activeScene)).name == "Main";
			MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
			if (flag && !listening && (Object)(object)instance != (Object)null)
			{
				Subscribe();
			}
		}

		private void Subscribe()
		{
			UnityAction<string> val = UnityAction<string>.op_Implicit((Action<string>)delegate
			{
				OfferPriceChangeCheckWithLog();
			});
			((UnityEvent<string>)(object)PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.PriceInput.onValueChanged).AddListener(val);
			((MelonBase)this).LoggerInstance.Msg("Attached listener");
			listening = true;
		}
	}
	public class DelayedCounterOffer
	{
		[CompilerGenerated]
		private sealed class <DelayedCounterOfferCoroutine>d__8 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public DelayedCounterOffer <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedCounterOfferCoroutine>d__8(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Expected O, but got Unknown
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Melon<Core>.Logger.Msg("Delayed counter offer started");
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (Singleton<SaveManager>.Instance.IsSaving)
				{
					Melon<Core>.Logger.Msg("Waiting for save to finish");
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 2;
					return true;
				}
				Melon<Core>.Logger.Msg("Delayed counter offer ended");
				if (<>4__this.skipCounterOffer)
				{
					Melon<Core>.Logger.Msg("Directly accepting contract for " + ((Object)<>4__this.customer.customerData).name);
					<>4__this.customer.AcceptContractClicked();
					if (Config.AutoContractAcceptedEnabled.Value)
					{
						Core.EvaluateCounterOfferPatch.Postfix(<>4__this.customer, __result: true);
					}
				}
				else
				{
					<>4__this.customer.SendCounteroffer(<>4__this.product, <>4__this.quantity, <>4__this.price);
				}
				MelonCoroutines.Stop(<>4__this.coroutineToken);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Customer customer;

		private ProductDefinition product;

		private int quantity;

		private float price;

		private object coroutineToken;

		private bool skipCounterOffer;

		public DelayedCounterOffer(Customer customer, ProductDefinition product, int quantity, float price, bool skipCounterOffer = false)
		{
			this.customer = customer;
			this.product = product;
			this.quantity = quantity;
			this.price = price;
			this.skipCounterOffer = skipCounterOffer;
		}

		public void Start()
		{
			coroutineToken = MelonCoroutines.Start(DelayedCounterOfferCoroutine());
		}

		[IteratorStateMachine(typeof(<DelayedCounterOfferCoroutine>d__8))]
		private IEnumerator DelayedCounterOfferCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedCounterOfferCoroutine>d__8(0)
			{
				<>4__this = this
			};
		}
	}
	public class DelayedPriceCalculator
	{
		[CompilerGenerated]
		private sealed class <CalculatePriceCoroutine>d__12 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public DelayedPriceCalculator <>4__this;

			private int <low>5__1;

			private int <high>5__2;

			private int <bestPrice>5__3;

			private float <spenderScore>5__4;

			private int <iterations>5__5;

			private int <maxIterations>5__6;

			private int <price1>5__7;

			private int <price2>5__8;

			private float <withUpdatedAppeals1>5__9;

			private float <withUpdatedAppeals2>5__10;

			private int <price>5__11;

			private float <withUpdatedAppeals>5__12;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CalculatePriceCoroutine>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_028f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0299: Expected O, but got Unknown
				//IL_01df: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e9: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Melon<Core>.Logger.Msg("Starting delayed price calculation for " + ((ItemDefinition)<>4__this.product).Name);
					<low>5__1 = Mathf.FloorToInt(<>4__this.minPrice);
					<high>5__2 = Mathf.CeilToInt(<>4__this.maxPrice);
					<bestPrice>5__3 = Mathf.RoundToInt(<>4__this.initialPrice);
					<spenderScore>5__4 = Core.EvaluatePriceAcceptance(<>4__this.product, <>4__this.customerAppeals, <bestPrice>5__3);
					<iterations>5__5 = 0;
					<maxIterations>5__6 = 20;
					goto IL_01fa;
				case 1:
					<>1__state = -1;
					goto IL_01fa;
				case 2:
					{
						<>1__state = -1;
						int num = <price>5__11 + 1;
						<price>5__11 = num;
						break;
					}
					IL_01fa:
					if (<iterations>5__5 < <maxIterations>5__6 && <high>5__2 - <low>5__1 > 1 && !<>4__this.isCancelled)
					{
						<price1>5__7 = <low>5__1 + (<high>5__2 - <low>5__1) / 3;
						<price2>5__8 = <high>5__2 - (<high>5__2 - <low>5__1) / 3;
						<withUpdatedAppeals1>5__9 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price1>5__7);
						<withUpdatedAppeals2>5__10 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price2>5__8);
						if ((double)<withUpdatedAppeals1>5__9 > (double)<spenderScore>5__4)
						{
							<bestPrice>5__3 = <price1>5__7;
							<spenderScore>5__4 = <withUpdatedAppeals1>5__9;
						}
						if ((double)<withUpdatedAppeals2>5__10 > (double)<spenderScore>5__4)
						{
							<bestPrice>5__3 = <price2>5__8;
							<spenderScore>5__4 = <withUpdatedAppeals2>5__10;
						}
						if ((double)<withUpdatedAppeals1>5__9 > (double)<withUpdatedAppeals2>5__10)
						{
							<high>5__2 = <price2>5__8;
						}
						else
						{
							<low>5__1 = <price1>5__7;
						}
						int num = <iterations>5__5 + 1;
						<iterations>5__5 = num;
						<>2__current = (object)new WaitForSeconds(0.01f);
						<>1__state = 1;
						return true;
					}
					<price>5__11 = <low>5__1;
					break;
				}
				if (<price>5__11 <= <high>5__2 && !<>4__this.isCancelled)
				{
					<withUpdatedAppeals>5__12 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price>5__11);
					if ((double)<withUpdatedAppeals>5__12 > (double)<spenderScore>5__4)
					{
						<bestPrice>5__3 = <price>5__11;
						<spenderScore>5__4 = <withUpdatedAppeals>5__12;
					}
					<>2__current = (object)new WaitForSeconds(0.01f);
					<>1__state = 2;
					return true;
				}
				if (!<>4__this.isCancelled)
				{
					Melon<Core>.Logger.Msg($"Price calculation complete for {((ItemDefinition)<>4__this.product).Name}: {<bestPrice>5__3}");
					<>4__this.callback((<bestPrice>5__3, <spenderScore>5__4));
				}
				<>4__this.isCalculating = false;
				MelonCoroutines.Stop(<>4__this.coroutineToken);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private ProductDefinition product;

		private List<Core.CustomerAppeal> customerAppeals;

		private float initialPrice;

		private float minPrice;

		private float maxPrice;

		private Action<(float bestPrice, float spenderScore)> callback;

		private object coroutineToken;

		private bool isCalculating;

		private bool isCancelled;

		public DelayedPriceCalculator(ProductDefinition product, List<Core.CustomerAppeal> customerAppeals, float initialPrice, float minPrice, float maxPrice, Action<(float bestPrice, float spenderScore)> callback)
		{
			this.product = product;
			this.customerAppeals = customerAppeals;
			this.initialPrice = initialPrice;
			this.minPrice = minPrice;
			this.maxPrice = maxPrice;
			this.callback = callback;
		}

		public void Start()
		{
			if (!isCalculating)
			{
				isCalculating = true;
				isCancelled = false;
				coroutineToken = MelonCoroutines.Start(CalculatePriceCoroutine());
			}
		}

		public void Cancel()
		{
			isCancelled = true;
			if (coroutineToken != null)
			{
				MelonCoroutines.Stop(coroutineToken);
				coroutineToken = null;
			}
			isCalculating = false;
		}

		[IteratorStateMachine(typeof(<CalculatePriceCoroutine>d__12))]
		private IEnumerator CalculatePriceCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CalculatePriceCoroutine>d__12(0)
			{
				<>4__this = this
			};
		}

		private float EvaluatePriceWithUpdatedAppeals(float price)
		{
			return Core.EvaluatePriceAcceptance(product, customerAppeals.Select((Core.CustomerAppeal c) => new Core.CustomerAppeal
			{
				Customer = c.Customer,
				Appeal = CustomerHelper.GetProductAppeal(product, c.Customer, price),
				PaymentQuantity = CustomerHelper.CalculatePaymentQuantity(product, c.Customer, price)
			}).ToList(), price);
		}
	}
	public class DelayedScheduler
	{
		[CompilerGenerated]
		private sealed class <DelayedSchedulerCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public DelayedScheduler <>4__this;

			private DealWindowInfo <windowInfo>5__1;

			private ContractInfo <offeredContractInfo>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedSchedulerCoroutine>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<offeredContractInfo>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Expected O, but got Unknown
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Expected O, but got Unknown
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_0274: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Melon<Core>.Logger.Msg("Delayed scheduling started");
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (Singleton<SaveManager>.Instance.IsSaving)
				{
					Melon<Core>.Logger.Msg("Waiting for save to finish");
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 2;
					return true;
				}
				Melon<Core>.Logger.Msg("Delayed scheduling ended");
				<windowInfo>5__1 = DealWindowInfo.GetWindowInfo(<>4__this.window);
				<offeredContractInfo>5__2 = <>4__this.customer.OfferedContractInfo;
				Melon<Core>.Logger.Msg($"Payment: {<offeredContractInfo>5__2.Payment}, Quantity: {<offeredContractInfo>5__2.Products.GetTotalQuantity()}, ProductID: {<offeredContractInfo>5__2.Products.entries[0].ProductID}, Quantity: {<offeredContractInfo>5__2.Products.entries[0].Quantity}");
				<>4__this.customer.OfferedContractInfo.DeliveryWindow.WindowStartTime = <windowInfo>5__1.StartTime;
				<>4__this.customer.OfferedContractInfo.DeliveryWindow.WindowEndTime = <windowInfo>5__1.EndTime;
				Melon<Core>.Logger.Msg($"Window: {<windowInfo>5__1.StartTime} - {<windowInfo>5__1.EndTime}");
				<>4__this.customer.PlayContractAcceptedReaction();
				Melon<Core>.Logger.Msg("Played contract accepted reaction");
				<>4__this.customer.SendContractAccepted(<>4__this.window, true);
				Melon<Core>.Logger.Msg("Sent contract accepted");
				if (!InstanceFinder.IsServer)
				{
					Melon<Core>.Logger.Msg("Clearing contract");
					<>4__this.customer.OfferedContractInfo = null;
				}
				MelonCoroutines.Stop(<>4__this.coroutineToken);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Customer customer;

		private EDealWindow window;

		private object coroutineToken;

		public DelayedScheduler(Customer customer, EDealWindow window)
		{
			//IL_0010: 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)
			this.customer = customer;
			this.window = window;
		}

		public void Start()
		{
			coroutineToken = MelonCoroutines.Start(DelayedSchedulerCoroutine());
		}

		[IteratorStateMachine(typeof(<DelayedSchedulerCoroutine>d__5))]
		private IEnumerator DelayedSchedulerCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedSchedulerCoroutine>d__5(0)
			{
				<>4__this = this
			};
		}
	}
	public class UIHandler
	{
		private class PanelState
		{
			public bool IsVisible;

			public bool IsDragging;

			public Vector2 Position;

			public Vector2 DragOffset;

			public Vector2 ScrollPosition;

			public string Content;

			public string Title;

			public PanelState(string title)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				IsVisible = false;
				IsDragging = false;
				Position = new Vector2(20f, 20f);
				DragOffset = Vector2.zero;
				ScrollPosition = Vector2.zero;
				Content = "";
				Title = title;
			}
		}

		private GUIStyle displayTextStyle;

		private static string counterOfferDisplayText = "";

		private static GUIStyle salesPanelStyle;

		private static GUIStyle salesHeaderStyle;

		private static GUIStyle salesTextStyle;

		private GUIStyle sectionHeaderStyle;

		private GUIStyle infoLabelStyle;

		private GUIStyle infoValueStyle;

		private PanelState salesPanel;

		private PanelState contactPanel;

		private DelayedPriceCalculator currentPriceCalculator;

		public static ProductEntry SelectedProduct { get; set; } = null;


		public static Customer SelectedCustomer { get; set; } = null;


		public UIHandler()
		{
			InitializeStyles();
			salesPanel = new PanelState("Sales Information");
			contactPanel = new PanelState("Contact Information");
		}

		private void InitializeStyles()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0116: 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_0141: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Expected O, but got Unknown
			displayTextStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			displayTextStyle.fontSize = 18;
			displayTextStyle.normal.background = Texture2D.whiteTexture;
			displayTextStyle.alignment = (TextAnchor)4;
			salesPanelStyle = new GUIStyle(GUIStyle.op_Implicit("box"));
			salesPanelStyle.normal.background = Texture2D.whiteTexture;
			salesPanelStyle.normal.textColor = Color.white;
			salesPanelStyle.padding = new RectOffset(10, 10, 10, 10);
			salesHeaderStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			salesHeaderStyle.fontSize = 20;
			salesHeaderStyle.fontStyle = (FontStyle)1;
			salesHeaderStyle.normal.textColor = Color.white;
			salesHeaderStyle.alignment = (TextAnchor)4;
			salesTextStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			salesTextStyle.fontSize = 14;
			salesTextStyle.normal.textColor = Color.white;
			salesTextStyle.wordWrap = true;
			salesTextStyle.padding = new RectOffset(10, 0, 0, 0);
			sectionHeaderStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			sectionHeaderStyle.fontSize = 16;
			sectionHeaderStyle.fontStyle = (FontStyle)1;
			sectionHeaderStyle.normal.textColor = new Color(0.9f, 0.9f, 1f);
			sectionHeaderStyle.padding = new RectOffset(0, 0, 10, 5);
			infoLabelStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			infoLabelStyle.fontSize = 14;
			infoLabelStyle.fontStyle = (FontStyle)1;
			infoLabelStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
			infoLabelStyle.padding = new RectOffset(10, 0, 2, 2);
			infoValueStyle = new GUIStyle(GUIStyle.op_Implicit("label"));
			infoValueStyle.fontSize = 14;
			infoValueStyle.normal.textColor = new Color(1f, 0.95f, 0.8f);
			infoValueStyle.padding = new RectOffset(10, 0, 2, 8);
		}

		private string FormatCurrency(float amount)
		{
			return $"${amount:F2}";
		}

		public void UpdateCounterOfferDisplayText(string text, string reasonText)
		{
			counterOfferDisplayText = text + "\n" + reasonText;
		}

		private string FormatSalesInfo(ProductEntry entry, float? overridePrice = null)
		{
			string text = "<section>Product Details</section>\n<label>Product:</label> <value>" + ((ItemDefinition)entry.Definition).Name + "</value>\n<label>Base Price:</label> <value>" + FormatCurrency(entry.Definition.Price) + "</value>\n<label>Market Value:</label> <value>" + FormatCurrency(entry.Definition.MarketValue) + "</value>\n";
			if (overridePrice.HasValue && overridePrice.Value != entry.Definition.Price)
			{
				text = text + "<label>Current Price:</label> <value>" + FormatCurrency(overridePrice.Value) + "</value>\n";
			}
			List<Customer> unlockedCustomers = Customer.UnlockedCustomers;
			List<Core.CustomerAppeal> list = new List<Core.CustomerAppeal>();
			for (int i = 0; i < unlockedCustomers.Count; i++)
			{
				list.Add(new Core.CustomerAppeal
				{
					Customer = unlockedCustomers[i],
					Appeal = CustomerHelper.GetProductAppeal(entry.Definition, unlockedCustomers[i], overridePrice),
					PaymentQuantity = CustomerHelper.CalculatePaymentQuantity(entry.Definition, unlockedCustomers[i], overridePrice)
				});
			}
			List<Core.CustomerAppeal> list2 = list.OrderByDescending((Core.CustomerAppeal ca) => ca.Appeal).ToList();
			List<Core.CustomerAppeal> list3 = list2.FindAll((Core.CustomerAppeal ca) => (double)ca.Appeal > 0.05000000074505806);
			float value = Core.EvaluatePriceAcceptance(entry.Definition, list2, overridePrice ?? entry.Definition.Price);
			text = text + "<section>Market Analysis</section>\n<label>Potential Customers:</label> <value>" + $"{list3.Count}" + "</value>\n<label>Average Order Size:</label> <value>" + $"{((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Quantity) : 0.0):F1}" + "</value>\n<label>Average Payment:</label> <value>" + ((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment)) : FormatCurrency(0f)) + "</value>\n<label>Per-Unit Price:</label> <value>" + ((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment / (float)ca.PaymentQuantity.Quantity)) : FormatCurrency(0f)) + "</value>\n<label>Max Spender Score:</label> <value>" + $"{value:F2}" + "</value>\n";
			text = text + "<section>Appeal Statistics</section>\n<label>Customer Appeal:</label>\n" + $"<value>Average: {((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + $"<value>Min: {((list3.Count > 0) ? list3.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + $"<value>Max: {((list3.Count > 0) ? list3.Max((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + "<label>Overall Appeal:</label>\n<value>Average: " + $"{((list2.Count > 0) ? list2.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}" + "</value>\n<value>Min: " + $"{((list2.Count > 0) ? list2.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}" + "</value>\n";
			if (Config.PriceOptimizationEnabled.Value)
			{
				text = text + "<section>Price Optimization</section>\n<label>Original Price:</label> <value>" + FormatCurrency(entry.Definition.Price) + "</value>\n<label>Optimal Price:</label> <value>Calculating...</value>\n<label>Price Change:</label> <value>Calculating...</value>\n";
				float num = overridePrice ?? entry.Definition.Price;
				float minPrice = num * 0.5f;
				float maxPrice = num * 2f;
				currentPriceCalculator = new DelayedPriceCalculator(entry.Definition, list2, num, minPrice, maxPrice, delegate((float bestPrice, float spenderScore) result)
				{
					float item = result.bestPrice;
					string[] array = salesPanel.Content.Split('\n');
					for (int j = 0; j < array.Length; j++)
					{
						if (array[j].Contains("Optimal Price:"))
						{
							array[j] = "<label>Optimal Price:</label> <value>" + FormatCurrency(item) + "</value>\n";
						}
						else if (array[j].Contains("Price Change:"))
						{
							array[j] = $"<label>Price Change:</label> <value>{(float)(((double)item - (double)entry.Definition.Price) / (double)entry.Definition.Price * 100.0):F1}%</value>\n";
						}
					}
					salesPanel.Content = string.Join("\n", array);
				});
				currentPriceCalculator.Start();
			}
			return text;
		}

		private List<EDay> GetSortedOrderDays(List<EDay> orderDays, EDay currentDay)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			List<EDay> val = new List<EDay>();
			for (int i = 0; i < orderDays.Count; i++)
			{
				val.Add(orderDays[i]);
			}
			Func<EDay, EDay, int> func = delegate(EDay a, EDay b)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: 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_000a: Expected I4, but got Unknown
				//IL_000a: 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_0013: Expected I4, but got Unknown
				int num = a - currentDay;
				int num2 = b - currentDay;
				if (num < 0)
				{
					num += 7;
				}
				if (num2 < 0)
				{
					num2 += 7;
				}
				return num.CompareTo(num2);
			};
			val.Sort(Comparison<EDay>.op_Implicit(func));
			return val;
		}

		private string FormatCustomerInfo(Customer customer, CustomerData customerData, NPCRelationData relationData, EDay currentDay)
		{
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			string text = "<section>Customer Details</section>\n<label>Name:</label> <value>" + customer.NPC.fullName + "</value>\n";
			if ((Object)(object)customer.AssignedDealer != (Object)null)
			{
				text = text + "<label>Assigned Dealer:</label> <value>" + ((NPC)customer.AssignedDealer).FirstName + " " + ((NPC)customer.AssignedDealer).LastName + "</value>\n";
			}
			List<EDay> orderDays = customerData.GetOrderDays(customer.CurrentAddiction, relationData.RelationDelta / 5f);
			float amount = customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) * 3f / (float)orderDays.Count;
			text = text + "<section>Financial Information</section>\n<label>Max Spend:</label> <value>" + FormatCurrency(customerData.MaxWeeklySpend) + "</value>\n<label>Min Spend:</label> <value>" + FormatCurrency(customerData.MinWeeklySpend) + "</value>\n<label>Max Daily Spend:</label> <value>" + FormatCurrency(amount) + " (" + $"{(double)customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) / (double)customerData.GetAdjustedWeeklySpend(1f) * 100.0:F2}" + "% of Max)</value>\n";
			List<EDay> sortedOrderDays = GetSortedOrderDays(orderDays, currentDay);
			text += "<section>Schedule Information</section>\n<label>Next Order Days:</label>\n";
			for (int i = 0; i < sortedOrderDays.Count; i++)
			{
				text = text + "<value>  " + $"{i + 1}. {sortedOrderDays[i]}" + "</value>\n";
			}
			text += "<section>Product Preferences</section>\n";
			var list = CustomerHelper.GetProductsFromCustomer(customer).Select((CustomerHelper.ProductOrders p, int index) => new
			{
				ProductInfo = p,
				Index = index
			}).ToList();
			if (list.Count == 0)
			{
				text = ((!((Object)(object)customer.AssignedDealer == (Object)null)) ? (text + "<value>Dealer has no appealing products for sale</value>\n") : (text + "<value>Won't buy anything</value>\n"));
			}
			foreach (var item in list)
			{
				text = text + "<value>" + ((ItemDefinition)item.ProductInfo.Product).Name + " - $" + $"{item.ProductInfo.PaymentQuantity.Payment:F2}" + " × " + $"{item.ProductInfo.PaymentQuantity.Quantity}" + " (Appeal: " + $"{item.ProductInfo.PaymentQuantity.Appeal:F3}" + ")</value>\n";
			}
			return text;
		}

		private void HandlePanelDragging(PanelState panel, Rect dragRect, Event currentEvent)
		{
			//IL_0002: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((int)currentEvent.type == 0 && ((Rect)(ref dragRect)).Contains(currentEvent.mousePosition))
			{
				panel.IsDragging = true;
				panel.DragOffset = currentEvent.mousePosition - panel.Position;
				currentEvent.Use();
			}
			else if ((int)currentEvent.type == 1)
			{
				panel.IsDragging = false;
			}
			if (panel.IsDragging && (int)currentEvent.type == 3)
			{
				panel.Position = currentEvent.mousePosition - panel.DragOffset;
				currentEvent.Use();
			}
		}

		private void DrawPanel(PanelState panel, float width, float height)
		{
			//IL_003a: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: 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_0390: 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)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			if (!panel.IsVisible)
			{
				return;
			}
			Rect dragRect = default(Rect);
			((Rect)(ref dragRect))..ctor(panel.Position.x, panel.Position.y, width, 40f);
			HandlePanelDragging(panel, dragRect, Event.current);
			panel.Position.x = Mathf.Clamp(panel.Position.x, 0f, (float)Screen.width - width);
			panel.Position.y = Mathf.Clamp(panel.Position.y, 0f, (float)Screen.height - height);
			GUI.backgroundColor = Color.black;
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, new Color(0.15f, 0.15f, 0.2f, 0.95f));
			val.Apply();
			GUI.DrawTexture(new Rect(panel.Position.x, panel.Position.y, width, height), (Texture)(object)val);
			string[] array = panel.Content.Split('\n');
			float num = panel.Position.y + 40f;
			float num2 = width - 20f;
			panel.ScrollPosition = GUI.BeginScrollView(new Rect(panel.Position.x, num, width, height - 40f), panel.ScrollPosition, new Rect(0f, 0f, num2, (float)(array.Length * 25)));
			float num3 = 0f;
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (text.StartsWith("<section>"))
				{
					string text2 = text.Replace("<section>", "").Replace("</section>", "");
					GUI.Label(new Rect(10f, num3, num2, 25f), text2, sectionHeaderStyle);
					num3 += 30f;
				}
				else if (text.Contains("<label>"))
				{
					string text3 = "";
					string text4 = "";
					int num4 = text.IndexOf("<label>") + 7;
					int num5 = text.IndexOf("</label>");
					if (num4 >= 7 && num5 > num4)
					{
						text3 = text.Substring(num4, num5 - num4);
					}
					int num6 = text.IndexOf("<value>") + 7;
					int num7 = text.IndexOf("</value>");
					if (num6 >= 7 && num7 > num6)
					{
						text4 = text.Substring(num6, num7 - num6);
					}
					if (!string.IsNullOrEmpty(text3))
					{
						GUI.Label(new Rect(10f, num3, 140f, 20f), text3, infoLabelStyle);
						if (!string.IsNullOrEmpty(text4))
						{
							GUI.Label(new Rect(160f, num3, num2 - 160f, 20f), text4, infoValueStyle);
						}
						num3 += 25f;
					}
				}
				else if (text.StartsWith("<value>"))
				{
					string text5 = text.Replace("<value>", "").Replace("</value>", "");
					GUI.Label(new Rect(20f, num3, num2 - 20f, 20f), text5, infoValueStyle);
					num3 += 25f;
				}
				else if (!string.IsNullOrWhiteSpace(text))
				{
					GUI.Label(new Rect(10f, num3, num2, 20f), text, infoValueStyle);
					num3 += 25f;
				}
			}
			GUI.EndScrollView();
			GUI.Box(new Rect(panel.Position.x, panel.Position.y, width, 40f), "", salesPanelStyle);
			GUI.Label(new Rect(panel.Position.x, panel.Position.y, width, 40f), panel.Title + " (Drag to Move)", salesHeaderStyle);
			if (GUI.Button(new Rect((float)((double)panel.Position.x + (double)width - 30.0), panel.Position.y + 5f, 25f, 25f), "X"))
			{
				panel.IsVisible = false;
				panel.Position = new Vector2(20f, 20f);
				if (panel == salesPanel)
				{
					SelectedProduct = null;
				}
				else if (panel == contactPanel)
				{
					SelectedCustomer = null;
				}
			}
			Object.Destroy((Object)(object)val);
		}

		public void UpdateSalesInfoPanel(ProductEntry entry, float? overridePrice = null)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (currentPriceCalculator != null)
			{
				currentPriceCalculator.Cancel();
				currentPriceCalculator = null;
			}
			SelectedProduct = entry;
			salesPanel.IsVisible = true;
			salesPanel.ScrollPosition = Vector2.zero;
			salesPanel.Content = FormatSalesInfo(entry, overridePrice);
		}

		public void UpdateContactInfoPanel(Customer customer)
		{
			//IL_0020: 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_003f: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)customer == (Object)null)
			{
				contactPanel.IsVisible = false;
				return;
			}
			EDay currentDay = NetworkSingleton<TimeManager>.Instance.CurrentDay;
			SelectedCustomer = customer;
			contactPanel.IsVisible = true;
			contactPanel.ScrollPosition = Vector2.zero;
			contactPanel.Content = FormatCustomerInfo(customer, customer.customerData, customer.NPC.RelationData, currentDay);
		}

		private void DrawSalesInfoPanel()
		{
			DrawPanel(salesPanel, 400f, 800f);
		}

		private void DrawContactInfoPanel()
		{
			DrawPanel(contactPanel, 400f, 700f);
		}

		public void OnGUI()
		{
			//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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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)
			SceneManager.GetActiveScene();
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name != "Main")
			{
				return;
			}
			Phone instance = PlayerSingleton<Phone>.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if (!instance.IsOpen)
				{
					return;
				}
			}
			else if (0 == 0)
			{
				return;
			}
			if (((!PlayerSingleton<HomeScreen>.Instance.isOpen || 1 == 0) & ((Object)(object)PlayerSingleton<MessagesApp>.Instance != (Object)null)) && PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.IsOpen)
			{
				if (Config.CounterOfferDarkModeEnabled.Value)
				{
					GUI.backgroundColor = new Color(0.15f, 0.15f, 0.2f, 0.95f);
					displayTextStyle.normal.textColor = Color.white;
				}
				else
				{
					displayTextStyle.normal.textColor = Color.black;
				}
				GUI.Label(new Rect((float)(Screen.width / 2 - 190), (float)(Screen.height / 2 - 250), 380f, 70f), counterOfferDisplayText, displayTextStyle);
				GUI.backgroundColor = Color.white;
			}
			if ((Object)(object)Core.productManagerApp != (Object)null && ((App<ProductManagerApp>)(object)Core.productManagerApp).isOpen && salesPanel.IsVisible)
			{
				DrawSalesInfoPanel();
			}
			if (!((Object)(object)PlayerSingleton<ContactsApp>.Instance == (Object)null) && ((App<ContactsApp>)(object)PlayerSingleton<ContactsApp>.Instance).isOpen && contactPanel.IsVisible)
			{
				DrawContactInfoPanel();
			}
		}
	}
}
namespace HighBaller.Services
{
	public static class CustomerHelper
	{
		public class ProductOrders
		{
			public ProductDefinition Product { get; set; }

			public PaymentQuantityResult PaymentQuantity { get; set; }
		}

		public static Customer GetCustomerFromConversation(MSGConversation conversation)
		{
			string contactName = conversation.contactName;
			Func<Customer, bool> func = (Customer customer) => customer.NPC.fullName == contactName;
			return Customer.UnlockedCustomers.Find(Predicate<Customer>.op_Implicit(func));
		}

		public static Customer GetCustomerFromMessagesApp(MessagesApp messagesApp)
		{
			return GetCustomerFromConversation(messagesApp.currentConversation);
		}

		public static float GetProductAppeal(ProductDefinition product, Customer customer, float? overridePrice = null)
		{
			//IL_0009: 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)
			float productEnjoyment = customer.GetProductEnjoyment(product, StandardsMethod.GetCorrespondingQuality(customer.customerData.Standards));
			float num = (overridePrice ?? product.Price) / product.MarketValue;
			float num2 = Mathf.Lerp(1f, -1f, num / 2f);
			return productEnjoyment + num2;
		}

		public static PaymentQuantityResult CalculatePaymentQuantity(ProductDefinition product, Customer customer, float? overridePrice = null)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			CustomerData customerData = customer.customerData;
			if ((Object)(object)product == (Object)null)
			{
				return null;
			}
			EQuality correspondingQuality = StandardsMethod.GetCorrespondingQuality(customerData.Standards);
			float num = overridePrice ?? product.Price;
			float productAppeal = GetProductAppeal(product, customer, overridePrice);
			if ((double)productAppeal < 0.05000000074505806)
			{
				return new PaymentQuantityResult
				{
					Payment = 0f,
					Quantity = 0,
					Quality = correspondingQuality,
					Appeal = productAppeal
				};
			}
			float productEnjoyment = customer.GetProductEnjoyment(product, correspondingQuality);
			int num2 = 7;
			if ((Object)(object)customer.AssignedDealer == (Object)null)
			{
				num2 = customerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count;
			}
			double num3 = (double)customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (double)num2 * (double)Mathf.Lerp(0.66f, 1.5f, productEnjoyment);
			float num4 = num * Mathf.Lerp(0.66f, 1.5f, productEnjoyment);
			double num5 = num;
			int num6 = Mathf.Clamp(Mathf.RoundToInt((float)(num3 / num5)), 1, 1000);
			if (num6 >= 14)
			{
				num6 = Mathf.RoundToInt((float)(num6 / 5)) * 5;
			}
			float payment = Mathf.RoundToInt((float)((double)num4 * (double)num6 / 5.0)) * 5;
			return new PaymentQuantityResult
			{
				Payment = payment,
				Quantity = num6,
				Quality = correspondingQuality,
				Appeal = productAppeal
			};
		}

		public static Customer GetCustomerFromNPC(NPC npc)
		{
			Func<Customer, bool> func = (Customer cust) => ((Object)cust.NPC).Equals((Object)(object)npc);
			return Customer.UnlockedCustomers.Find(Predicate<Customer>.op_Implicit(func));
		}

		public static IEnumerable<ProductOrders> GetProductsFromCustomer(Customer customer)
		{
			List<ProductOrders> list = new List<ProductOrders>();
			Enumerator<ProductDefinition> enumerator = customer.GetOrderableProducts((Dealer)null).GetEnumerator();
			while (enumerator.MoveNext())
			{
				ProductDefinition current = enumerator.Current;
				if ((double)CalculatePaymentQuantity(current, customer).Appeal >= 0.05000000074505806)
				{
					list.Add(new ProductOrders
					{
						Product = current,
						PaymentQuantity = CalculatePaymentQuantity(current, customer)
					});
				}
			}
			list.Sort((ProductOrders a, ProductOrders b) => b.PaymentQuantity.Appeal.CompareTo(a.PaymentQuantity.Appeal));
			return list.Take(4);
		}
	}
	[HarmonyPatch(typeof(Customer), "HandoverChosen")]
	public static class HandoverService
	{
		public static bool Prefix(Customer __instance)
		{
			return doDeal(__instance);
		}

		private static bool doDeal(Customer customer)
		{
			//IL_00bd: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: 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_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			if (Config.AutoHandoverEnabled.Value)
			{
				Contract currentContract = customer.CurrentContract;
				object obj;
				if (currentContract == null)
				{
					obj = null;
				}
				else
				{
					ProductList productList = currentContract.ProductList;
					obj = ((productList != null) ? productList.entries : null);
				}
				if (obj != null && customer.CurrentContract.ProductList.entries.Count != 0)
				{
					Melon<Core>.Logger.Msg("Customer: " + customer.NPC.fullName);
					Entry val = customer.CurrentContract.ProductList.entries[0];
					string productID = val.ProductID;
					int quantity = val.Quantity;
					if (quantity <= 0)
					{
						return true;
					}
					EQuality minQuality = StandardsMethod.GetCorrespondingQuality(customer.CustomerData.Standards);
					List<ProductPackage<ItemSlot>> list = new List<ProductPackage<ItemSlot>>();
					foreach (ItemSlot item in (Il2CppArrayBase<ItemSlot>)(object)Player.Local.Inventory)
					{
						ItemInstance itemInstance = item.ItemInstance;
						if (itemInstance == null)
						{
							continue;
						}
						Melon<Core>.Logger.Msg($"Item: {itemInstance.ID} - {itemInstance.Quantity} - {itemInstance.Definition.Category}");
						if (itemInstance != null && itemInstance.ID == productID && itemInstance.Quantity > 0)
						{
							ProductItemInstance val2 = ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>();
							if (val2 != null && (Object)(object)val2.packaging != (Object)null && ((QualityItemInstance)val2).Quality >= minQuality)
							{
								Melon<Core>.Logger.Msg($"ProductItem: {itemInstance.ID} - {itemInstance.Quantity} - {((ItemDefinition)val2.packaging).Name}");
								PackagingDefinition packaging = val2.packaging;
								Melon<Core>.Logger.Msg($"Packaging: {packaging.Quantity} {((ItemDefinition)packaging).ID}");
								list.Add(new ProductPackage<ItemSlot>(packaging.Quantity, item, itemInstance.Quantity, ((QualityItemInstance)val2).Quality));
							}
						}
					}
					List<ProductPackage<ItemSlot>> list2 = new List<ProductPackage<ItemSlot>>();
					foreach (EQuality item2 in from EQuality q in Enum.GetValues(typeof(EQuality))
						where q >= minQuality
						select q)
					{
						EQuality qualityLevel = item2;
						Melon<Core>.Logger.Msg($"Finding optimal packages for quality: {qualityLevel}");
						list2 = FindOptimalPackages(list.Where((ProductPackage<ItemSlot> p) => p.Quality == qualityLevel).ToList(), quantity);
						if (list2.Count > 0)
						{
							Melon<Core>.Logger.Msg($"Found optimal packages for quality: {qualityLevel}");
							break;
						}
					}
					if (list2.Count == 0)
					{
						Melon<Core>.Logger.Warning("No suitable combination of packages found to meet target quantity");
						return true;
					}
					List<ItemInstance> val3 = new List<ItemInstance>();
					foreach (ProductPackage<ItemSlot> item3 in list2)
					{
						Melon<Core>.Logger.Msg($"Selected package: {item3?.PackageSize} units, {item3?.AvailableQuantity} packages");
						ItemInstance copy = item3.Slot.ItemInstance.GetCopy(-1);
						if (item3.Slot.Quantity.Equals(item3.AvailableQuantity))
						{
							item3.Slot.ItemInstance.RequestClearSlot();
						}
						else
						{
							item3.Slot.ChangeQuantity(-item3.AvailableQuantity, false);
						}
						copy.Quantity = item3.AvailableQuantity;
						val3.Add(copy);
					}
					customer.ProcessHandover((EHandoverOutcome)1, customer.CurrentContract, val3, true, true);
					return false;
				}
			}
			return true;
		}

		public static List<ProductPackage<T>> FindOptimalPackages<T>(List<ProductPackage<T>> availablePackages, int targetQuantity)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			if (targetQuantity <= 0)
			{
				return new List<ProductPackage<T>>();
			}
			if (availablePackages.Sum((ProductPackage<T> p) => p.TotalUnits) < targetQuantity)
			{
				return new List<ProductPackage<T>>();
			}
			List<ProductPackage<T>> selectedPackages = new List<ProductPackage<T>>();
			int num = targetQuantity;
			List<ProductPackage<T>> list = availablePackages.OrderByDescending((ProductPackage<T> p) => p.PackageSize).ToList();
			foreach (ProductPackage<T> item in list)
			{
				if (num > 0)
				{
					int num2 = Math.Min(item.AvailableQuantity, num / item.PackageSize);
					if (num2 > 0)
					{
						selectedPackages.Add(new ProductPackage<T>(item.PackageSize, item.Slot, num2, item.Quality));
						num -= num2 * item.PackageSize;
					}
					continue;
				}
				break;
			}
			if (num > 0)
			{
				List<ProductPackage<T>> list2 = FindExactMatch(list.Where((ProductPackage<T> p) => !selectedPackages.Any((ProductPackage<T> sp) => sp.Slot.Equals(p.Slot))).ToList(), num);
				if (list2 == null)
				{
					return new List<ProductPackage<T>>();
				}
				selectedPackages.AddRange(list2);
			}
			return selectedPackages;
		}

		private static List<ProductPackage<T>> FindExactMatch<T>(List<ProductPackage<T>> packages, int target)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (target == 0)
			{
				return new List<ProductPackage<T>>();
			}
			if (packages.Count == 0 || target < 0)
			{
				return null;
			}
			ProductPackage<T> productPackage = packages[0];
			List<ProductPackage<T>> packages2 = packages.Skip(1).ToList();
			int num = Math.Min(productPackage.AvailableQuantity, target / productPackage.PackageSize);
			for (int i = 0; i <= num; i++)
			{
				int target2 = target - i * productPackage.PackageSize;
				List<ProductPackage<T>> list = FindExactMatch(packages2, target2);
				if (list != null)
				{
					if (i > 0)
					{
						list.Add(new ProductPackage<T>(productPackage.PackageSize, productPackage.Slot, i, productPackage.Quality));
					}
					return list;
				}
			}
			return null;
		}
	}
	public class ProductPackage<T>
	{
		public int PackageSize { get; }

		public T Slot { get; }

		public int AvailableQuantity { get; }

		public EQuality Quality { get; }

		public int TotalUnits => PackageSize * AvailableQuantity;

		public ProductPackage(int packageSize, T slot, int quantity, EQuality quality)
		{
			//IL_001e: 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)
			PackageSize = packageSize;
			Slot = slot;
			AvailableQuantity = quantity;
			Quality = quality;
		}
	}
}
namespace HighBaller.Models
{
	public class PaymentQuantityResult
	{
		public float Payment { get; set; }

		public int Quantity { get; set; }

		public EQuality Quality { get; set; }

		public float Appeal { get; set; }

		public override string ToString()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			return $"[Payment: {Payment}, Quantity: {Quantity}, Quality: {Quality}, Appeal: {Appeal}]";
		}
	}
}