Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of high baller v2.5.1
HighBaller_IL2CPP.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 System.Text; using DealOptimizer_IL2CPP; using DealOptimizer_IL2CPP.Models; using DealOptimizer_IL2CPP.Services; using HarmonyLib; 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 Il2CppSystem.Reflection; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "HighBaller_IL2CPP", "2.5.3", "zocke1r", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("HighBaller_IL2CPP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5b175bb85251367c65555e925ae2112563bf5625")] [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] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DealOptimizer_IL2CPP { public static class BuildInfo { public const string Name = "HighBaller_IL2CPP"; public const string Author = "zocke1r"; public const string Version = "2.5.3"; } 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_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) 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.Pow((float)quantity / (float)initialOfferData.Quantity, 0.6f); float num3 = Mathf.Lerp(0f, 2f, num2 * 0.5f); float num4 = Mathf.Lerp(1f, 0f, Mathf.Abs(num3 - 1f)); if (valueProposition2 * num4 > valueProposition) { return 1f; } if (valueProposition2 < 0.12f) { return 0f; } float num5 = productEnjoyment * valueProposition; float num6 = num * num4 * valueProposition2; if (num6 > num5) { return 1f; } float num7 = num5 - num6; float num8 = Mathf.Lerp(0f, 1f, num7 / 0.2f); float num9 = Mathf.Lerp(0f, 0.2f, Mathf.Max(customer.CurrentAddiction, customer.NPC.RelationData.NormalizedRelationDelta)); float num10 = num8 - num9; return Mathf.Clamp01((0.9f - num10) / 0.9f); } public static (float maxSpend, float dailyAverage) CalculateSpendingLimits(Customer customer) { CustomerData customerData = customer.CustomerData; float adjustedWeeklySpend = customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f); List<EDay> orderDays = customerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f); float num = adjustedWeeklySpend / (float)orderDays.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 (minSuccessProbability < 0f) { 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 num = initialQuantity; int num2 = (int)initialPrice; int i = 0; int num3 = 20; int num4 = FindOptimalPrice(customer, product, initialQuantity, initialPrice, item, -1f, initialOfferData); num = initialQuantity; num2 = num4; if ((double)num2 >= Math.Floor(item * 0.99f)) { return (num, num2); } int num5 = initialQuantity; for (; i < num3; i++) { num5++; int num6 = FindOptimalPrice(customer, product, num5, initialPrice, item, -1f, initialOfferData); if (num6 <= num2) { break; } num = num5; num2 = num6; if ((double)num2 >= Math.Floor(item * 0.99f)) { break; } } return (num, num2); } } 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)); ProductDefinition item2 = Registry.GetItem<ProductDefinition>(((ItemDefinition)counterofferInterface.selectedProduct).ID); int num2 = DealCalculator.FindOptimalPrice(customerFromMessagesApp, item2, 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) { Melon<Core>.Logger.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) { 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(Customer __instance, ContractInfo info, 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]; ProductDefinition product = __instance.OrderableProducts.Find(Predicate<ProductDefinition>.op_Implicit((Func<ProductDefinition, bool>)((ProductDefinition p) => ((ItemDefinition)p).ID == entry.ProductID))); var (quantity, num) = DealCalculator.FindOptimalQuantity(__instance, product, entry.Quantity, info.Payment); new DelayedCounterOffer(__instance, product, quantity, num).Start(); } } } [HarmonyPatch(typeof(Customer), "EvaluateCounteroffer")] public static class EvaluateCounterOfferPatch { public static void Postfix(Customer __instance, bool __result) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_015d: 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) 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}"); string text = ""; EDealWindow window; 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(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('\n'); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2); handler.AppendLiteral("Customer Name: "); handler.AppendFormatted(((Object)offerData.Customer).name); handler.AppendLiteral("\n"); stringBuilder3.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2); handler.AppendLiteral("Product: "); handler.AppendFormatted(((ItemDefinition)offerData.Product).ID); handler.AppendLiteral("\n"); stringBuilder4.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2); handler.AppendLiteral("Quantity: "); handler.AppendFormatted(offerData.Quantity); handler.AppendLiteral("\n"); stringBuilder5.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2); handler.AppendLiteral("Price: "); handler.AppendFormatted(offerData.Price); handler.AppendLiteral("\n"); stringBuilder6.Append(ref handler); EvaluateCounterOffer(stringBuilder, offerData); ((MelonBase)this).LoggerInstance.Msg(stringBuilder.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 }; decimal value2 = Math.Round((decimal)(DealCalculator.CalculateSuccessProbability(offerData.Customer, selectedProduct, offerData.Quantity, offerData.Price, initialOfferData) * 100f), 3); DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {value2}%", $"Price per unit: {offerData.Price / (float)offerData.Quantity}\nMax Spend: {value}"); } private void EvaluateCounterOffer(StringBuilder 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); stringBuilder.Append('\n'); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder2); handler.AppendLiteral("Adjusted Weekly Spend: "); handler.AppendFormatted(offerData.Customer.CustomerData.GetAdjustedWeeklySpend(offerData.Customer.NPC.RelationData.RelationDelta / 5f)); handler.AppendLiteral("\n"); stringBuilder3.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2); handler.AppendLiteral("Order Days: "); handler.AppendFormatted(offerData.Customer.CustomerData.GetOrderDays(offerData.Customer.CurrentAddiction, offerData.Customer.NPC.RelationData.RelationDelta / 5f).Count); handler.AppendLiteral("\n"); stringBuilder4.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2); handler.AppendLiteral("Average Daily Spend: "); handler.AppendFormatted(item2); handler.AppendLiteral("\n"); stringBuilder5.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(33, 1, stringBuilder2); handler.AppendLiteral("Daily Spend Threshold (3x Avg): "); handler.AppendFormatted(value); handler.AppendLiteral("\n"); stringBuilder6.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder7 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2); handler.AppendLiteral("Min Weekly Spend: "); handler.AppendFormatted(offerData.Customer.customerData.MinWeeklySpend); handler.AppendLiteral("\n"); stringBuilder7.Append(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder8 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2); handler.AppendLiteral("Max Weekly Spend: "); handler.AppendFormatted(offerData.Customer.customerData.MaxWeeklySpend); handler.AppendLiteral("\n"); stringBuilder8.Append(ref handler); string text = ""; Enumerator<ProductDefinition> enumerator = offerData.Customer.OrderableProducts.GetEnumerator(); while (enumerator.MoveNext()) { ProductDefinition current = enumerator.Current; text += $"[Name: {((ItemDefinition)current).Name}, Price: {current.Price}, Market: {current.MarketValue}],\n"; } stringBuilder2 = stringBuilder; StringBuilder stringBuilder9 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(21, 1, stringBuilder2); handler.AppendLiteral("Orderable Products: "); handler.AppendFormatted(text); handler.AppendLiteral("\n"); stringBuilder9.Append(ref handler); if (offerData.Price >= item) { stringBuilder.Append("\nGuaranteed Failure - order must be less than 3x average daily spend\n"); DisplayHelper.UpdateCounterOfferDisplayText("Guaranteed Failure", $"Exceeded Max Spend ({value})"); 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); stringBuilder2 = stringBuilder; StringBuilder stringBuilder10 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(27, 1, stringBuilder2); handler.AppendLiteral("\nProbability of success: "); handler.AppendFormatted(value2); handler.AppendLiteral("%\n"); stringBuilder10.Append(ref handler); DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {value2}%", ""); } 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) { Melon<Core>.Logger.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 (customerAppeal.Appeal < 0.05f) { 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); _ = 1f; 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) { if (optimalPriceCache.TryGetValue(((ItemDefinition)product).ID, out (float, float) value)) { callback?.Invoke(value); return value; } new DelayedPriceCalculator(product, customerAppeals, initialPrice, minPrice, maxPrice, delegate((float bestPrice, float spenderScore) 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_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) SceneManager.GetActiveScene(); Scene activeScene = SceneManager.GetActiveScene(); bool num = ((Scene)(ref activeScene)).name == "Main"; MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; if (num && !listening && (Object)(object)instance != (Object)null) { Subscribe(); } } private UnityAction Subscribe() { UnityAction<string> changeListener = UnityAction<string>.op_Implicit((Action<string>)delegate { OfferPriceChangeCheckWithLog(); }); ((UnityEvent<string>)(object)PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.PriceInput.onValueChanged).AddListener(changeListener); ((MelonBase)this).LoggerInstance.Msg("Attached listener"); listening = true; return UnityAction.op_Implicit((Action)delegate { ((UnityEvent<string>)(object)PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.PriceInput.onValueChanged).RemoveListener(changeListener); }); } } 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<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); ((MelonEventBase<LemonAction<float, float>>)(object)MinSuccessProbability.OnEntryValueChanged).Subscribe((LemonAction<float, float>)delegate { Melon<Core>.Logger.Msg($"Minimum success probability changed to: {MinSuccessProbability.Value}"); }, 0, false); 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 DelayedCounterOffer { [CompilerGenerated] private sealed class <DelayedCounterOfferCoroutine>d__7 : 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__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown int num = <>1__state; DelayedCounterOffer delayedCounterOffer = <>4__this; switch (num) { 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"); delayedCounterOffer.customer.SendCounteroffer(delayedCounterOffer.product, delayedCounterOffer.quantity, delayedCounterOffer.price); MelonCoroutines.Stop(delayedCounterOffer.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; public DelayedCounterOffer(Customer customer, ProductDefinition product, int quantity, float price) { this.customer = customer; this.product = product; this.quantity = quantity; this.price = price; } public void Start() { coroutineToken = MelonCoroutines.Start(DelayedCounterOfferCoroutine()); } [IteratorStateMachine(typeof(<DelayedCounterOfferCoroutine>d__7))] private IEnumerator DelayedCounterOfferCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedCounterOfferCoroutine>d__7(0) { <>4__this = this }; } } 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; 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() { <>1__state = -2; } private bool MoveNext() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; DelayedScheduler delayedScheduler = <>4__this; switch (num) { 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"); DealWindowInfo windowInfo = DealWindowInfo.GetWindowInfo(delayedScheduler.window); ContractInfo offeredContractInfo = delayedScheduler.customer.OfferedContractInfo; Melon<Core>.Logger.Msg($"Payment: {offeredContractInfo.Payment}, Quantity: {offeredContractInfo.Products.GetTotalQuantity()}, ProductID: {offeredContractInfo.Products.entries[0].ProductID}, Quantity: {offeredContractInfo.Products.entries[0].Quantity}"); delayedScheduler.customer.OfferedContractInfo.DeliveryWindow.WindowStartTime = windowInfo.StartTime; delayedScheduler.customer.OfferedContractInfo.DeliveryWindow.WindowEndTime = windowInfo.EndTime; Melon<Core>.Logger.Msg($"Window: {windowInfo.StartTime} - {windowInfo.EndTime}"); delayedScheduler.customer.PlayContractAcceptedReaction(); Melon<Core>.Logger.Msg("Played contract accepted reaction"); delayedScheduler.customer.SendContractAccepted(delayedScheduler.window, true); Melon<Core>.Logger.Msg("Sent contract accepted"); if (!InstanceFinder.IsServer) { Melon<Core>.Logger.Msg("Clearing contract"); delayedScheduler.customer.OfferedContractInfo = null; } MelonCoroutines.Stop(delayedScheduler.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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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 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__2; private int <high>5__3; private int <bestPrice>5__4; private float <spenderScore>5__5; private int <iterations>5__6; private int <maxIterations>5__7; private int <price>5__8; 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_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown int num = <>1__state; DelayedPriceCalculator delayedPriceCalculator = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; Melon<Core>.Logger.Msg("Starting delayed price calculation for " + ((ItemDefinition)delayedPriceCalculator.product).Name); <low>5__2 = Mathf.FloorToInt(delayedPriceCalculator.minPrice); <high>5__3 = Mathf.CeilToInt(delayedPriceCalculator.maxPrice); <bestPrice>5__4 = Mathf.RoundToInt(delayedPriceCalculator.initialPrice); <spenderScore>5__5 = Core.EvaluatePriceAcceptance(delayedPriceCalculator.product, delayedPriceCalculator.customerAppeals, <bestPrice>5__4); <iterations>5__6 = 0; <maxIterations>5__7 = 20; goto IL_017f; case 1: <>1__state = -1; goto IL_017f; case 2: { <>1__state = -1; <price>5__8++; break; } IL_017f: if (<iterations>5__6 < <maxIterations>5__7 && <high>5__3 - <low>5__2 > 1 && !delayedPriceCalculator.isCancelled) { int num2 = <low>5__2 + (<high>5__3 - <low>5__2) / 3; int num3 = <high>5__3 - (<high>5__3 - <low>5__2) / 3; float num4 = Core.EvaluatePriceAcceptance(delayedPriceCalculator.product, delayedPriceCalculator.customerAppeals, num2); float num5 = Core.EvaluatePriceAcceptance(delayedPriceCalculator.product, delayedPriceCalculator.customerAppeals, num3); if (num4 > <spenderScore>5__5) { <bestPrice>5__4 = num2; <spenderScore>5__5 = num4; } if (num5 > <spenderScore>5__5) { <bestPrice>5__4 = num3; <spenderScore>5__5 = num5; } if (num4 > num5) { <high>5__3 = num3; } else { <low>5__2 = num2; } <iterations>5__6++; <>2__current = (object)new WaitForSeconds(0.01f); <>1__state = 1; return true; } <price>5__8 = <low>5__2; break; } if (<price>5__8 <= <high>5__3 && !delayedPriceCalculator.isCancelled) { float num6 = Core.EvaluatePriceAcceptance(delayedPriceCalculator.product, delayedPriceCalculator.customerAppeals, <price>5__8); if (num6 > <spenderScore>5__5) { <bestPrice>5__4 = <price>5__8; <spenderScore>5__5 = num6; } <>2__current = (object)new WaitForSeconds(0.01f); <>1__state = 2; return true; } if (!delayedPriceCalculator.isCancelled) { Melon<Core>.Logger.Msg($"Price calculation complete for {((ItemDefinition)delayedPriceCalculator.product).Name}: {<bestPrice>5__4}"); delayedPriceCalculator.callback((<bestPrice>5__4, <spenderScore>5__5)); } delayedPriceCalculator.isCalculating = false; MelonCoroutines.Stop(delayedPriceCalculator.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 }; } } public class InventoryOfferService { private static float GetOfferSuccessChance(Customer customer, List<ItemInstance> items, float askingPrice) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) float num = customer.CustomerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customer.CustomerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count; float num2 = 0f; int num3 = 0; for (int i = 0; i < items.Count; i++) { if (items[i] is ProductItemInstance) { ItemInstance obj = items[i]; ProductItemInstance val = (ProductItemInstance)(object)((obj is ProductItemInstance) ? obj : null); if (!((Object)(object)val.AppliedPackaging == (Object)null)) { ? val2 = customer; ItemDefinition definition = items[i].Definition; float num4 = Mathf.InverseLerp(-1f, 1f, ((Customer)val2).GetProductEnjoyment((ProductDefinition)(object)((definition is ProductDefinition) ? definition : null), ((QualityItemInstance)val).Quality)); num2 += num4 * (float)((ItemInstance)val).Quantity * (float)val.Amount; num3 += ((ItemInstance)val).Quantity * val.Amount; } } } if (num3 == 0) { return 0f; } float num5 = num2 / (float)num3; float num6 = askingPrice / (float)num3; float num7 = 0f; for (int j = 0; j < items.Count; j++) { if (items[j] is ProductItemInstance) { ItemInstance obj2 = items[j]; ProductItemInstance val3 = (ProductItemInstance)(object)((obj2 is ProductItemInstance) ? obj2 : null); if (!((Object)(object)val3.AppliedPackaging == (Object)null)) { ItemDefinition definition2 = ((ItemInstance)val3).Definition; float valueProposition = Customer.GetValueProposition((ProductDefinition)(object)((definition2 is ProductDefinition) ? definition2 : null), num6); num7 += valueProposition * (float)val3.Amount * (float)((ItemInstance)val3).Quantity; } } } double num8 = (double)num7 / (double)num3; float num9 = askingPrice / num; float item = 1f; if ((double)num9 > 1.0) { item = Mathf.Clamp((float)(1.0 - (double)Mathf.Sqrt(num9) / 4.0), 0.01f, 1f); } List<float> list = new List<float> { num5 + customer.CurrentAddiction * 0.25f, Mathf.Pow((float)num8, 1.5f), item }; list.Sort(); if (!((double)list[0] < 0.009999999776482582) && !((double)num9 > 3.0)) { return (float)((double)list[0] * 0.699999988079071 + (double)list[1] * 0.20000000298023224 + (double)list[2] * 0.10000000149011612); } return 0f; } public static float GetOptimalPrice(Customer customer, List<ItemInstance> items, float targetSuccessChance = 0.9f) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) float num = customer.CustomerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customer.CustomerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count; float num2 = 0f; int num3 = 0; for (int i = 0; i < items.Count; i++) { ItemInstance obj = items[i]; ProductItemInstance val = (ProductItemInstance)(object)((obj is ProductItemInstance) ? obj : null); if (val != null) { Melon<Core>.Logger.Msg($"ProductItem: {((ItemInstance)val).ID} - {((ItemInstance)val).Quantity} - {((ItemInstance)val).Definition.Name}"); if (!((Object)(object)val.AppliedPackaging == (Object)null)) { ? val2 = customer; ItemDefinition definition = items[i].Definition; float num4 = Mathf.InverseLerp(-1f, 1f, ((Customer)val2).GetProductEnjoyment((ProductDefinition)(object)((definition is ProductDefinition) ? definition : null), ((QualityItemInstance)val).Quality)); Melon<Core>.Logger.Msg($"Enjoyment: {num4}"); num2 += num4 * (float)((ItemInstance)val).Quantity * (float)val.Amount; num3 += ((ItemInstance)val).Quantity * val.Amount; } } } if (num3 == 0) { return 0f; } float avgEnjoyment = num2 / (float)num3; float addictionBoost = customer.CurrentAddiction * 0.25f; float num5 = 1f; float num6 = num * 2f; float num7 = (num5 + num6) / 2f; float num8 = 0f; for (int j = 0; j < 20; j++) { num8 = CalculateSuccessChance(customer, items, num7, num, avgEnjoyment, addictionBoost, num3); if (Math.Abs(num8 - targetSuccessChance) < 0.01f) { break; } if (num8 < targetSuccessChance) { num6 = num7; } else { num5 = num7; } num7 = (num5 + num6) / 2f; } return num7; } private static float CalculateSuccessChance(Customer customer, List<ItemInstance> items, float askingPrice, float weeklySpendPerDay, float avgEnjoyment, float addictionBoost, int totalUnits) { float num = askingPrice / (float)totalUnits; float num2 = 0f; foreach (ItemInstance item2 in items) { ProductItemInstance val = (ProductItemInstance)(object)((item2 is ProductItemInstance) ? item2 : null); if (val != null) { float num3 = num2; ItemDefinition definition = ((ItemInstance)val).Definition; num2 = num3 + Customer.GetValueProposition((ProductDefinition)(object)((definition is ProductDefinition) ? definition : null), num) * (float)val.Amount * (float)((ItemInstance)val).Quantity; } } float num4 = num2 / (float)totalUnits; float num5 = askingPrice / weeklySpendPerDay; float item = 1f; if ((double)num5 > 1.0) { item = Mathf.Clamp(1f - Mathf.Sqrt(num5) / 4f, 0.01f, 1f); } List<float> list = new List<float> { avgEnjoyment + addictionBoost, Mathf.Pow(num4, 1.5f), item }; list.Sort(); if (list[0] < 0.01f || (double)num5 > 3.0) { return 0f; } return list[0] * 0.7f + list[1] * 0.2f + list[2] * 0.1f; } public static List<OfferProduct> FindOptimalInventoryOffer(Customer customer, float targetSuccessChance = 0.9f) { //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) float num = customer.CustomerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customer.CustomerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count * 3f; Melon<Core>.Logger.Msg($"Customer max spend: {num:F2}"); List<OfferProduct> list = new List<OfferProduct>(); foreach (ItemSlot item in (Il2CppArrayBase<ItemSlot>)(object)Player.Local.Inventory) { ItemInstance itemInstance = item.ItemInstance; if (itemInstance == null) { continue; } ProductItemInstance val = ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>(); if (val != null && (Object)(object)val.AppliedPackaging != (Object)null && ((ItemInstance)val).Quantity > 0) { Instance logger = Melon<Core>.Logger; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(49, 3); defaultInterpolatedStringHandler.AppendLiteral("Processing inventory item: "); defaultInterpolatedStringHandler.AppendFormatted(itemInstance.ID); defaultInterpolatedStringHandler.AppendLiteral(", Type: "); defaultInterpolatedStringHandler.AppendFormatted(((MemberInfo)((Object)itemInstance).GetIl2CppType()).Name); defaultInterpolatedStringHandler.AppendLiteral(", Definition: "); ItemDefinition definition = itemInstance.Definition; object value; if (definition == null) { value = null; } else { Type il2CppType = ((Object)definition).GetIl2CppType(); value = ((il2CppType != null) ? ((MemberInfo)il2CppType).Name : null); } defaultInterpolatedStringHandler.AppendFormatted((string?)value); logger.Msg(defaultInterpolatedStringHandler.ToStringAndClear()); OfferProduct offerProduct = new OfferProduct(val, customer); if (offerProduct.CustomerEnjoyment >= 0f) { list.Add(offerProduct); Melon<Core>.Logger.Msg($"Added available product: {offerProduct.Name}, Enjoyment: {offerProduct.CustomerEnjoyment:F2}, Quality: {offerProduct.Quality}, Quantity: {offerProduct.Quantity}"); } else { Melon<Core>.Logger.Msg($"Skipping product: {offerProduct.Name} - {offerProduct.CustomerEnjoyment:F2}, Quality: {offerProduct.Quality}, Quantity: {offerProduct.Quantity}"); } } } if (list.Count == 0) { Melon<Core>.Logger.Warning("No suitable products found in inventory for this customer"); return new List<OfferProduct>(); } list.Sort(delegate(OfferProduct a, OfferProduct b) { int num8 = b.CustomerEnjoyment.CompareTo(a.CustomerEnjoyment); return (num8 != 0) ? num8 : b.Price.CompareTo(a.Price); }); float num2 = 0f; List<OfferProduct> list2 = new List<OfferProduct>(); List<OfferProduct> list3 = new List<OfferProduct>(); list3.Add(list[0]); float num3 = CalculateOptimalPrice(customer, list3, targetSuccessChance); float num4 = num3 / num; Melon<Core>.Logger.Msg($"Initial product optimal price: {num3:F2}, Ratio to max spend: {num4:F2}"); if (num4 > 1f && list[0].Quantity > 1) { int quantity = list[0].Quantity; int num5 = 1; int num6 = quantity; int num7 = num6 / 2; while (num5 <= num6) { list[0].Quantity = num7; num3 = CalculateOptimalPrice(customer, list3, targetSuccessChance); num4 = num3 / num; if (Math.Abs(num4 - 1f) < 0.05f) { break; } if (num4 > 1f) { num6 = num7 - 1; } else { num5 = num7 + 1; } num7 = (num5 + num6) / 2; } list[0].Quantity = quantity; OfferProduct offerProduct2 = new OfferProduct(list[0]); offerProduct2.Quantity = num7; list2.Clear(); list2.Add(offerProduct2); num2 = num4; } else if (num4 <= 1f) { list2 = new List<OfferProduct>(list3); num2 = num4; for (int i = 1; i < list.Count; i++) { list3.Add(list[i]); num3 = CalculateOptimalPrice(customer, list3, targetSuccessChance); num4 = num3 / num; Melon<Core>.Logger.Msg($"Adding product {i}, new price: {num3:F2}, Ratio: {num4:F2}"); if (num4 <= 1f && num4 > num2) { list2 = new List<OfferProduct>(list3); num2 = num4; Melon<Core>.Logger.Msg("Found better combination"); } if (num4 > 1f) { list3.RemoveAt(list3.Count - 1); } } } num3 = CalculateOptimalPrice(customer, list2, targetSuccessChance); Melon<Core>.Logger.Msg($"Final optimal combination has {list2.Count} products with price {num3:F2} ({num2 * 100f:F0}% of customer's max spend)"); return list2; } public static float CalculateOptimalPrice(Customer customer, List<OfferProduct> items, float targetSuccessChance) { float num = customer.CustomerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customer.CustomerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count; float num2 = 0f; int num3 = 0; foreach (OfferProduct item in items) { num2 += item.CustomerEnjoyment * (float)item.Quantity * (float)item.Amount; num3 += item.Quantity * item.Amount; } if (num3 == 0) { return 0f; } float avgEnjoyment = num2 / (float)num3; float addictionBoost = customer.CurrentAddiction * 0.25f; float num4 = 1f; float num5 = num * 2f; float num6 = (num4 + num5) / 2f; float num7 = 0f; for (int i = 0; i < 20; i++) { num7 = CalculateSuccessChance(customer, items, num6, num, avgEnjoyment, addictionBoost, num3); if (Math.Abs(num7 - targetSuccessChance) < 0.01f) { break; } if (num7 < targetSuccessChance) { num5 = num6; } else { num4 = num6; } num6 = (num4 + num5) / 2f; } return num6; } private static float CalculateSuccessChance(Customer customer, List<OfferProduct> items, float askingPrice, float weeklySpendPerDay, float avgEnjoyment, float addictionBoost, int totalUnits) { float num = askingPrice / (float)totalUnits; float num2 = 0f; foreach (OfferProduct item2 in items) { if ((Object)(object)item2.ProductDefinition != (Object)null) { num2 += Customer.GetValueProposition(item2.ProductDefinition, num) * (float)item2.Amount * (float)item2.Quantity; } else { Melon<Core>.Logger.Warning("ProductDefinition is null for item: " + item2.Name); } } float num3 = num2 / (float)totalUnits; float num4 = askingPrice / weeklySpendPerDay; float item = 1f; if ((double)num4 > 1.0) { item = Mathf.Clamp(1f - Mathf.Sqrt(num4) / 4f, 0.01f, 1f); } List<float> list = new List<float> { avgEnjoyment + addictionBoost, Mathf.Pow(num3, 1.5f), item }; list.Sort(); if (list[0] < 0.01f || (double)num4 > 3.0) { return 0f; } return list[0] * 0.7f + list[1] * 0.2f + list[2] * 0.1f; } } public static class HandoverScreenOpenPatch { public static void Postfix(HandoverScreen __instance, Contract contract, Customer customer, EMode mode, Action<EHandoverOutcome, List<ItemInstance>, float> callback, Func<List<ItemInstance>, float, float> successChanceMethod) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)mode != 2 || !Config.AutoHandoverEnabled.Value) { return; } Instance logger = Melon<Core>.Logger; object obj; if (customer == null) { obj = null; } else { NPC nPC = customer.NPC; obj = ((nPC != null) ? nPC.fullName : null); } logger.Msg("HandoverScreen opened in Offer mode for customer: " + (string?)obj); List<OfferProduct> list = InventoryOfferService.FindOptimalInventoryOffer(customer); if (list.Count == 0) { Melon<Core>.Logger.Warning("No optimal items found for offer"); return; } float num = InventoryOfferService.CalculateOptimalPrice(customer, list, 0.9f); if (num <= 0f) { Melon<Core>.Logger.Warning("Could not calculate a valid price"); return; } Melon<Core>.Logger.Msg($"Found optimal items: {list.Count} items for {num:F2}"); foreach (OfferProduct item in list) { Melon<Core>.Logger.Msg("Processing offer product: " + (item?.Name ?? "null") + ", ID: " + (item?.ID ?? "null")); foreach (ItemSlot item2 in (Il2CppArrayBase<ItemSlot>)(object)Player.Local.Inventory) { ItemInstance val = ((item2 != null) ? item2.ItemInstance : null); if (val == null) { Melon<Core>.Logger.Warning("Found null item in inventory slot"); } else { if (!(val.ID == item.ID)) { continue; } ProductItemInstance val2 = ((Il2CppObjectBase)val).TryCast<ProductItemInstance>(); if (val2 == null) { Melon<Core>.Logger.Warning("Failed to cast item " + val.ID + " to ProductItemInstance"); continue; } if (!((Object)(object)val2.AppliedPackaging == (Object)null)) { ((Il2CppArrayBase<ItemSlotUI>)(object)__instance.CustomerSlotUIs)[0].assignedSlot.AddItem(val, false); Melon<Core>.Logger.Msg($"Added item to handover selection: {val.ID}, Quantity: {val.Quantity}"); break; } Melon<Core>.Logger.Warning("Item " + val.ID + " has null AppliedPackaging"); } } } __instance.PriceSelector.SetPrice((float)(int)num); Melon<Core>.Logger.Msg($"Set handover price to: {num:F2}"); } } 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_001f: 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) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00cb: 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_00f4: Expected O, but got Unknown //IL_010a: 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_0133: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_017b: 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_019a: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025c: 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.ToString("C2", CultureInfo.GetCultureInfo("en-US")); } public void UpdateCounterOfferDisplayText(string text, string reasonText) { counterOfferDisplayText = text + "\n" + reasonText; } private string FormatSalesInfo(ProductEntry entry, float? overridePrice = null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<section>Product Details</section>"); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(39, 1, stringBuilder2); handler.AppendLiteral("<label>Product:</label> <value>"); handler.AppendFormatted(((ItemDefinition)entry.Definition).Name); handler.AppendLiteral("</value>"); stringBuilder3.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(42, 1, stringBuilder2); handler.AppendLiteral("<label>Base Price:</label> <value>"); handler.AppendFormatted(FormatCurrency(entry.Definition.Price)); handler.AppendLiteral("</value>"); stringBuilder4.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(44, 1, stringBuilder2); handler.AppendLiteral("<label>Market Value:</label> <value>"); handler.AppendFormatted(FormatCurrency(entry.Definition.MarketValue)); handler.AppendLiteral("</value>"); stringBuilder5.AppendLine(ref handler); if (overridePrice.HasValue && overridePrice.Value != entry.Definition.Price) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(45, 1, stringBuilder2); handler.AppendLiteral("<label>Current Price:</label> <value>"); handler.AppendFormatted(FormatCurrency(overridePrice.Value)); handler.AppendLiteral("</value>"); stringBuilder6.AppendLine(ref handler); } stringBuilder.AppendLine(); 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) => ca.Appeal > 0.05f); float value = Core.EvaluatePriceAcceptance(entry.Definition, list2, overridePrice ?? entry.Definition.Price); stringBuilder.AppendLine("<section>Market Analysis</section>"); stringBuilder2 = stringBuilder; StringBuilder stringBuilder7 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(51, 1, stringBuilder2); handler.AppendLiteral("<label>Potential Customers:</label> <value>"); handler.AppendFormatted(list3.Count); handler.AppendLiteral("</value>"); stringBuilder7.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder8 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(50, 1, stringBuilder2); handler.AppendLiteral("<label>Average Order Size:</label> <value>"); handler.AppendFormatted((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Quantity) : 0.0, "F1"); handler.AppendLiteral("</value>"); stringBuilder8.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder9 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(47, 1, stringBuilder2); handler.AppendLiteral("<label>Average Payment:</label> <value>"); handler.AppendFormatted((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment)) : FormatCurrency(0f)); handler.AppendLiteral("</value>"); stringBuilder9.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder10 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(46, 1, stringBuilder2); handler.AppendLiteral("<label>Per-Unit Price:</label> <value>"); handler.AppendFormatted((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment / (float)ca.PaymentQuantity.Quantity)) : FormatCurrency(0f)); handler.AppendLiteral("</value>"); stringBuilder10.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder11 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(49, 1, stringBuilder2); handler.AppendLiteral("<label>Max Spender Score:</label> <value>"); handler.AppendFormatted(value, "F2"); handler.AppendLiteral("</value>"); stringBuilder11.AppendLine(ref handler); stringBuilder.AppendLine(); stringBuilder.AppendLine("<section>Appeal Statistics</section>"); stringBuilder.AppendLine("<label>Customer Appeal:</label>"); stringBuilder2 = stringBuilder; StringBuilder stringBuilder12 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder2); handler.AppendLiteral("<value>Average: "); handler.AppendFormatted((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f, "F2"); handler.AppendLiteral("</value>"); stringBuilder12.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder13 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2); handler.AppendLiteral("<value>Min: "); handler.AppendFormatted((list3.Count > 0) ? list3.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f, "F2"); handler.AppendLiteral("</value>"); stringBuilder13.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder14 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2); handler.AppendLiteral("<value>Max: "); handler.AppendFormatted((list3.Count > 0) ? list3.Max((Core.CustomerAppeal ca) => ca.Appeal) : 0f, "F2"); handler.AppendLiteral("</value>"); stringBuilder14.AppendLine(ref handler); stringBuilder.AppendLine(); stringBuilder.AppendLine("<label>Overall Appeal:</label>"); stringBuilder2 = stringBuilder; StringBuilder stringBuilder15 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder2); handler.AppendLiteral("<value>Average: "); handler.AppendFormatted((list2.Count > 0) ? list2.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f, "F2"); handler.AppendLiteral("</value>"); stringBuilder15.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder16 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(20, 1, stringBuilder2); handler.AppendLiteral("<value>Min: "); handler.AppendFormatted((list2.Count > 0) ? list2.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f, "F2"); handler.AppendLiteral("</value>"); stringBuilder16.AppendLine(ref handler); stringBuilder.AppendLine(); if (Config.PriceOptimizationEnabled.Value) { float num = overridePrice ?? entry.Definition.Price; float minPrice = num * 0.5f; float maxPrice = num * 2f; stringBuilder.AppendLine("<section>Price Optimization</section>"); stringBuilder2 = stringBuilder; StringBuilder stringBuilder17 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(46, 1, stringBuilder2); handler.AppendLiteral("<label>Original Price:</label> <value>"); handler.AppendFormatted(FormatCurrency(entry.Definition.Price)); handler.AppendLiteral("</value>"); stringBuilder17.AppendLine(ref handler); stringBuilder.AppendLine("<label>Optimal Price:</label> <value>Calculating...</value>"); stringBuilder.AppendLine("<label>Price Change:</label> <value>Calculating...</value>"); 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>"; } else if (array[j].Contains("Price Change:")) { array[j] = $"<label>Price Change:</label> <value>{(item - entry.Definition.Price) / entry.Definition.Price * 100f:F1}%</value>"; } } salesPanel.Content = string.Join("\n", array); }); currentPriceCalculator.Start(); } return stringBuilder.ToString(); } 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_001a: Unknown result type (might be due to invalid IL or missing references) List<EDay> list = new List<EDay>(); for (int i = 0; i < orderDays.Count; i++) { list.Add(orderDays[i]); } list.Sort(delegate(EDay a, EDay b) { //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_0009: Expected I4, but got Unknown //IL_0009: 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) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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); }); return list; } private string FormatCustomerInfo(Customer customer, CustomerData customerData, NPCRelationData relationData, EDay currentDay) { //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<section>Customer Details</section>"); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(36, 1, stringBuilder2); handler.AppendLiteral("<label>Name:</label> <value>"); handler.AppendFormatted(customer.NPC.fullName); handler.AppendLiteral("</value>"); stringBuilder3.AppendLine(ref handler); if ((Object)(object)customer.AssignedDealer != (Object)null) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(48, 2, stringBuilder2); handler.AppendLiteral("<label>Assigned Dealer:</label> <value>"); handler.AppendFormatted(((NPC)customer.AssignedDealer).FirstName); handler.AppendLiteral(" "); handler.AppendFormatted(((NPC)customer.AssignedDealer).LastName); handler.AppendLiteral("</value>"); stringBuilder4.AppendLine(ref handler); } stringBuilder.AppendLine(); List<EDay> orderDays = customerData.GetOrderDays(customer.CurrentAddiction, relationData.RelationDelta / 5f); stringBuilder.AppendLine("<section>Financial Information</section>"); stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(41, 1, stringBuilder2); handler.AppendLiteral("<label>Max Spend:</label> <value>"); handler.AppendFormatted(FormatCurrency(customerData.MaxWeeklySpend)); handler.AppendLiteral("</value>"); stringBuilder5.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(41, 1, stringBuilder2); handler.AppendLiteral("<label>Min Spend:</label> <value>"); handler.AppendFormatted(FormatCurrency(customerData.MinWeeklySpend)); handler.AppendLiteral("</value>"); stringBuilder6.AppendLine(ref handler); float amount = customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) * 3f / (float)orderDays.Count; stringBuilder2 = stringBuilder; StringBuilder stringBuilder7 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(58, 2, stringBuilder2); handler.AppendLiteral("<label>Max Daily Spend:</label> <value>"); handler.AppendFormatted(FormatCurrency(amount)); handler.AppendLiteral(" ("); handler.AppendFormatted(customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) / customerData.GetAdjustedWeeklySpend(1f) * 100f, "F2"); handler.AppendLiteral("% of Max)</value>"); stringBuilder7.AppendLine(ref handler); stringBuilder.AppendLine(); stringBuilder.AppendLine("<section>Schedule Information</section>"); List<EDay> sortedOrderDays = GetSortedOrderDays(orderDays, currentDay); stringBuilder.AppendLine("<label>Next Order Days:</label>"); for (int i = 0; i < sortedOrderDays.Count; i++) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder8 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(19, 2, stringBuilder2); handler.AppendLiteral("<value> "); handler.AppendFormatted(i + 1); handler.AppendLiteral(". "); handler.AppendFormatted<EDay>(sortedOrderDays[i]); handler.AppendLiteral("</value>"); stringBuilder8.AppendLine(ref handler); } stringBuilder.AppendLine(); stringBuilder.AppendLine("<section>Product Preferences</section>"); var list = CustomerHelper.GetProductsFromCustomer(customer).Select((CustomerHelper.ProductOrders p, int index) => new { ProductInfo = p, Index = index }).ToList(); if (list.Count == 0) { if ((Object)(object)customer.AssignedDealer == (Object)null) { stringBuilder.AppendLine("<value>Won't buy anything</value>"); } else { stringBuilder.AppendLine("<value>Dealer has no appealing products for sale</value>"); } } foreach (var item in list) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder9 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(32, 4, stringBuilder2); handler.AppendLiteral("<value>"); handler.AppendFormatted(((ItemDefinition)item.ProductInfo.Product).Name); handler.AppendLiteral(" - "); handler.AppendFormatted(item.ProductInfo.PaymentQuantity.Payment, "C"); handler.AppendLiteral(" × "); handler.AppendFormatted(item.ProductInfo.PaymentQuantity.Quantity); handler.AppendLiteral(" (Appeal: "); handler.AppendFormatted(item.ProductInfo.PaymentQuantity.Appeal, "F3"); handler.AppendLiteral(")</value>"); stringBuilder9.AppendLine(ref handler); } stringBuilder.AppendLine(); return stringBuilder.ToString(); } private void HandlePanelDragging(PanelState panel, Rect dragRect, Event currentEvent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_000b: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 //IL_0060: 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_0070: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_012a: 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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: 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_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: 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))); num = 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, num, num2, 25f), text2, sectionHeaderStyle); num += 30f; } else if (text.Contains("<label>")) { string text3 = ""; string text4 = ""; int num3 = text.IndexOf("<label>") + 7; int num4 = text.IndexOf("</label>"); if (num3 >= 7 && num4 > num3) { text3 = text.Substring(num3, num4 - num3); } int num5 = text.IndexOf("<value>") + 7; int num6 = text.IndexOf("</value>"); if (num5 >= 7 && num6 > num5) { text4 = text.Substring(num5, num6 - num5); } if (!string.IsNullOrEmpty(text3)) { GUI.Label(new Rect(10f, num, 140f, 20f), text3, infoLabelStyle); if (!string.IsNullOrEmpty(text4)) { GUI.Label(new Rect(160f, num, num2 - 160f, 20f), text4, infoValueStyle); } num += 25f; } } else if (text.StartsWith("<value>")) { string text5 = text.Replace("<value>", "").Replace("</value>", ""); GUI.Label(new Rect(20f, num, num2 - 20f, 20f), text5, infoValueStyle); num += 25f; } else if (!string.IsNullOrWhiteSpace(text)) { GUI.Label(new Rect(10f, num, num2, 20f), text, infoValueStyle); num += 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(panel.Position.x + width - 30f, 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_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) 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_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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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) SceneManager.GetActiveScene(); Scene activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name == "Main")) { return; } Phone instance = PlayerSingleton<Phone>.Instance; if (!((Object)(object)instance != (Object)null) || !instance.IsOpen) { return; } bool isOpen = PlayerSingleton<HomeScreen>.Instance.isOpen; bool flag = (Object)(object)PlayerSingleton<MessagesApp>.Instance != (Object)null && PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.IsOpen; if (!isOpen && flag) { 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 DealOptimizer_IL2CPP.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; return Customer.UnlockedCustomers.Find(Predicate<Customer>.op_Implicit((Func<Customer, bool>)((Customer cust) => cust.NPC.fullName == contactName))); } public static Customer GetCustomerFromMessagesApp(MessagesApp messagesApp) { return GetCustomerFromConversation(messagesApp.currentConversation); } public static float GetProductAppeal(ProductDefinition product, Customer customer, float? overridePrice = null) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0154: 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 (productAppeal < 0.05f) { 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; } float num3 = customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)num2 * Mathf.Lerp(0.66f, 1.5f, productEnjoyment); float num4 = num * Mathf.Lerp(0.66f, 1.5f, productEnjoyment); int num5 = Mathf.RoundToInt(num3 / num); num5 = Mathf.Clamp(num5, 1, 1000); if (num5 >= 14) { num5 = Mathf.RoundToInt((float)(num5 / 5)) * 5; } float payment = Mathf.RoundToInt(num4 * (float)num5 / 5f) * 5; return new PaymentQuantityResult { Payment = payment, Quantity = num5, Quality = correspondingQuality, Appeal = productAppeal }; } public static Customer GetCustomerFromNPC(NPC npc) { return Customer.UnlockedCustomers.Find(Predicate<Customer>.op_Implicit((Func<Customer, bool>)((Customer cust) => (Object)(object)cust.NPC == (Object)(object)npc))); } public static IEnumerable<ProductOrders> GetProductsFromCustomer(Customer customer) { List<ProductOrders> list = new List<ProductOrders>(); Enumerator<ProductDefinition> enumerator = customer.OrderableProducts.GetEnumerator(); while (enumerator.MoveNext()) { ProductDefinition current = enumerator.Current; if (!(CalculatePaymentQuantity(current, customer).Appeal < 0.05f)) { 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); } } 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_001c: 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) PackageSize = packageSize; Slot = slot; AvailableQuantity = quantity; Quality = quality; } } [HarmonyPatch(typeof(Customer), "HandoverChosen")] public static class HandoverService { public static bool Prefix(Customer __instance) { return doDeal(__instance); } private static bool doDeal(Customer customer) { //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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_0307: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) if (!Config.AutoHandoverEnabled.Value) { return true; } 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) { return true; } Melon<Core>.Logger.Msg("Customer: " + customer.NPC.fullName); Entry obj2 = customer.CurrentContract.ProductList.entries[0]; string productID = obj2.ProductID; int quantity = obj2.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 val = ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>(); if (val != null && (Object)(object)val.packaging != (Object)null && ((QualityItemInstance)val).Quality >= minQuality) { Melon<Core>.Logger.Msg($"ProductItem: {itemInstance.ID} - {itemInstance.Quantity} - {((ItemDefinition)val.