Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of HighBallerMod Patched Mono v2.6.0
Mods/HighBaller_Mono.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using FishNet; using HarmonyLib; using HighBaller; using HighBaller.Models; using HighBaller.Services; using MelonLoader; using MelonLoader.Preferences; using ScheduleOne; using ScheduleOne.DevUtilities; using ScheduleOne.Economy; using ScheduleOne.GameTime; using ScheduleOne.ItemFramework; using ScheduleOne.Levelling; using ScheduleOne.Messaging; using ScheduleOne.NPCs; using ScheduleOne.NPCs.Relation; using ScheduleOne.Persistence; using ScheduleOne.PlayerScripts; using ScheduleOne.Product; using ScheduleOne.Product.Packaging; using ScheduleOne.Quests; using ScheduleOne.UI; using ScheduleOne.UI.Handover; using ScheduleOne.UI.Phone; using ScheduleOne.UI.Phone.ContactsApp; using ScheduleOne.UI.Phone.Messages; using ScheduleOne.UI.Phone.ProductManagerApp; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "HighBaller", "2.6.0", "zocke1r, Patched by: SFox", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("HighBaller_Mono")] [assembly: AssemblyConfiguration("Release_Mono")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("HighBaller_Mono")] [assembly: AssemblyTitle("HighBaller_Mono")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace HighBaller { public static class BuildInfo { public const string Name = "HighBaller_IL2CPP"; public const string Author = "zocke1r"; public const string Version = "2.5.4"; } public static class Config { private static MelonPreferences_Category DealOptimizerCategory; public static MelonPreferences_Entry<float> MinSuccessProbability; public static MelonPreferences_Entry<bool> PriceOptimizationEnabled; public static MelonPreferences_Entry<bool> CounterOfferDarkModeEnabled; private static MelonPreferences_Category DealOptimizerCategory_Automation; public static MelonPreferences_Entry<bool> AutoCounterOfferEnabled; public static MelonPreferences_Entry<bool> AutoContractAcceptedEnabled; public static MelonPreferences_Entry<int> AutoContractAcceptedWindow; public static MelonPreferences_Entry<bool> IncreaseQuantityEnabled; public static MelonPreferences_Entry<bool> AutoHandoverEnabled; public static MelonPreferences_Entry<int> CounterOfferQuantityMultiplier; public static MelonPreferences_Entry<bool> AutoInstantDealEnabled; private static MelonPreferences_Category DealOptimizerCategory_Features; public static MelonPreferences_Entry<bool> DelayAutoResponseDuringSave; public static void Initialize() { DealOptimizerCategory = MelonPreferences.CreateCategory("HighBaller_IL2CPP"); MinSuccessProbability = DealOptimizerCategory.CreateEntry<float>("MinSuccessProbability", 0.98f, "Minimum Success Probability", "The minimum probability of success required for a deal (0.0 to 1.0)", false, false, (ValueValidator)null, (string)null); PriceOptimizationEnabled = DealOptimizerCategory.CreateEntry<bool>("PriceOptimizationEnabled", false, "Price Optimization Enabled", "Whether to enable price optimization", false, false, (ValueValidator)null, (string)null); CounterOfferDarkModeEnabled = DealOptimizerCategory.CreateEntry<bool>("CounterOfferDarkModeEnabled", true, "Counter Offer Dark Mode Enabled", "Whether to enable counter offer dark mode", false, false, (ValueValidator)null, (string)null); DealOptimizerCategory_Automation = MelonPreferences.CreateCategory("HighBaller_IL2CPP_Automation"); AutoCounterOfferEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoCounterOfferEnabled", false, "Enable Auto Counter Offer", "Whether to enable auto counter offer", false, false, (ValueValidator)null, (string)null); AutoContractAcceptedEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoContractAcceptedEnabled", false, "Enable Auto Deal Scheduling", "Whether to enable auto deal scheduling", false, false, (ValueValidator)null, (string)null); AutoContractAcceptedWindow = DealOptimizerCategory_Automation.CreateEntry<int>("AutoContractAcceptedWindow", 4, "Auto Deal Time Window (1 = Morning, 2 = Afternoon, 3 = Night, 4 = Late Night)", "The window to auto accept deal", false, false, (ValueValidator)null, (string)null); IncreaseQuantityEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("IncreaseQuantityEnabled", false, "Increase Quantity till max spend is reached", "If enabled, the quantity will be increased until the max spend is reached", false, false, (ValueValidator)null, (string)null); AutoHandoverEnabled = DealOptimizerCategory_Automation.CreateEntry<bool>("AutoHandoverEnabled", false, "Enable automatic handovers", "Whether to enable automatic handover", false, false, (ValueValidator)null, (string)null); DealOptimizerCategory_Features = MelonPreferences.CreateCategory("HighBaller_IL2CPP_Features"); DelayAutoResponseDuringSave = DealOptimizerCategory_Features.CreateEntry<bool>("DelayAutoResponseDuringSave", true, "Don't send auto responses during save", "Whether to delay auto response during save", false, false, (ValueValidator)null, (string)null); } } public class Core : MelonMod { public class InitialOfferData { public string ProductId { get; set; } public int Quantity { get; set; } public float Payment { get; set; } } public static class DealCalculator { public static float CalculateSuccessProbability(Customer customer, ProductDefinition product, int quantity, float price, InitialOfferData initialOfferData) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) CustomerData customerData = customer.CustomerData; float valueProposition = Customer.GetValueProposition(Registry.GetItem<ProductDefinition>(initialOfferData.ProductId), initialOfferData.Payment / (float)initialOfferData.Quantity); float productEnjoyment = customer.GetProductEnjoyment(product, StandardsMethod.GetCorrespondingQuality(customerData.Standards)); float num = Mathf.InverseLerp(-1f, 1f, productEnjoyment); float valueProposition2 = Customer.GetValueProposition(product, price / (float)quantity); float num2 = Mathf.Lerp(1f, 0f, Mathf.Abs(Mathf.Lerp(0f, 2f, Mathf.Pow((float)quantity / (float)initialOfferData.Quantity, 0.6f) * 0.5f) - 1f)); if (valueProposition2 * num2 > valueProposition) { return 1f; } if ((double)valueProposition2 < 0.11999999731779099) { return 0f; } float num3 = productEnjoyment * valueProposition; float num4 = num * num2 * valueProposition2; return (num4 > num3) ? 1f : Mathf.Clamp01((float)((0.8999999761581421 - (double)(Mathf.Lerp(0f, 1f, (num3 - num4) / 0.2f) - Mathf.Lerp(0f, 0.2f, Mathf.Max(customer.CurrentAddiction, customer.NPC.RelationData.NormalizedRelationDelta)))) / 0.8999999761581421)); } public static (float maxSpend, float dailyAverage) CalculateSpendingLimits(Customer customer) { CustomerData customerData = customer.CustomerData; float num = customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (float)customerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count; return (num * 3f, num); } public static int FindOptimalPrice(Customer customer, ProductDefinition product, int quantity, float currentPrice, float maxSpend, float minSuccessProbability = -1f, InitialOfferData initialOfferData = null, bool log = false) { if ((double)minSuccessProbability < 0.0) { minSuccessProbability = Config.MinSuccessProbability.Value; } int num = (int)currentPrice; int num2 = (int)maxSpend; int num3 = (int)currentPrice; int num4 = 20; int i = 0; if (initialOfferData == null) { initialOfferData = new InitialOfferData { ProductId = customer.OfferedContractInfo.Products.entries[0].ProductID, Quantity = customer.OfferedContractInfo.Products.entries[0].Quantity, Payment = customer.OfferedContractInfo.Payment }; } if (log) { Melon<Core>.Logger.Msg($"Initial Offer Data: ProductId: {initialOfferData.ProductId}, Quantity: {initialOfferData.Quantity}, Payment: {initialOfferData.Payment}"); Melon<Core>.Logger.Msg($"Binary Search Start - Product: {((ItemDefinition)product).ID}, Price: {currentPrice}, MaxSpend: {maxSpend}, Quantity: {quantity}, MinProbability: {minSuccessProbability}, Low: {num}, High: {num2}"); } for (; i < num4; i++) { if (num >= num2) { break; } int num5 = (num + num2) / 2; if (CalculateSuccessProbability(customer, product, quantity, num5, initialOfferData) >= minSuccessProbability) { num = num5 + 1; if (num == num2) { num3 = ((CalculateSuccessProbability(customer, product, quantity, num5 + 1, initialOfferData) > minSuccessProbability) ? (num5 + 1) : num5); break; } num3 = num5; } else { num2 = num5; } } if (log) { Melon<Core>.Logger.Msg("Binary Search Complete:"); Melon<Core>.Logger.Msg($" Final bestFailingPrice: {num3}"); Melon<Core>.Logger.Msg($" Final Probability: {CalculateSuccessProbability(customer, product, quantity, num3, initialOfferData)}"); } return num3; } public static (int optimalQuantity, int optimalPrice) FindOptimalQuantity(Customer customer, ProductDefinition product, int initialQuantity, float initialPrice, InitialOfferData initialOfferData = null) { float item = CalculateSpendingLimits(customer).maxSpend; if (!Config.IncreaseQuantityEnabled.Value) { int item2 = FindOptimalPrice(customer, product, initialQuantity, initialPrice, item, -1f, initialOfferData); return (initialQuantity, item2); } int i = 0; int num = 20; int num2 = FindOptimalPrice(customer, product, initialQuantity, initialPrice, item, -1f, initialOfferData); int item3 = initialQuantity; int num3 = num2; if ((double)num3 >= Math.Floor((double)item * 0.9900000095367432)) { return (item3, num3); } int num4 = initialQuantity; for (; i < num; i++) { num4++; int num5 = FindOptimalPrice(customer, product, num4, initialPrice, item, -1f, initialOfferData); if (num5 > num3) { item3 = num4; num3 = num5; if ((double)num3 >= Math.Floor((double)item * 0.9900000095367432)) { break; } continue; } break; } return (item3, num3); } } private static class DisplayHelper { public static void UpdateCounterOfferDisplayText(string text, string reasonText) { Instance.uiHandler.UpdateCounterOfferDisplayText(text, reasonText); } } [HarmonyPatch(typeof(CounterofferInterface), "SetProduct")] private static class CounterofferInterfaceChangeProductPatch { private static void Postfix(ProductDefinition newProduct) { MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; Melon<Core>.Logger.Msg("CounterofferInterfaceChangeProductPatch: " + ((ItemDefinition)newProduct).Name); OfferData offerData = GetOfferData(); Customer customer = offerData.Customer; int quantity = offerData.Quantity; float price = offerData.Price; (int optimalQuantity, int optimalPrice) tuple = DealCalculator.FindOptimalQuantity(customer, newProduct, quantity, price * 0.25f); int item = tuple.optimalQuantity; int item2 = tuple.optimalPrice; int num = quantity; if ((float)item2 != price) { instance.CounterofferInterface.ChangePrice((float)(item2 - (int)price)); instance.CounterofferInterface.ChangeQuantity(item - num); } } } [HarmonyPatch(typeof(CounterofferInterface), "Open")] private static class CounterofferInterfacePostOpenPatch { private static void Postfix(ProductDefinition product, int quantity, float price, MSGConversation _conversation, Action<ProductDefinition, int, float> _orderConfirmedCallback) { MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; (int optimalQuantity, int optimalPrice) tuple = DealCalculator.FindOptimalQuantity(CustomerHelper.GetCustomerFromConversation(_conversation), product, quantity, price); int item = tuple.optimalQuantity; int item2 = tuple.optimalPrice; if (!((float)item2 <= price)) { instance.CounterofferInterface.ChangePrice((float)(item2 - (int)price)); instance.CounterofferInterface.ChangeQuantity(item - quantity); } } } [HarmonyPatch(typeof(CounterofferInterface), "ChangePrice")] private static class CounterofferInterfacePostChangePricePatch { private static void Postfix(float change) { OfferPriceChangeCheckNoLog(); } } [HarmonyPatch(typeof(CounterofferInterface), "ChangeQuantity")] private static class CounterofferInterfacePostChangeQuantityPatch { private static void Postfix(int change) { MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; if (!((Object)(object)instance == (Object)null) && instance.CounterofferInterface.IsOpen) { Customer customerFromMessagesApp = CustomerHelper.GetCustomerFromMessagesApp(instance); float item = DealCalculator.CalculateSpendingLimits(customerFromMessagesApp).maxSpend; CounterofferInterface counterofferInterface = instance.CounterofferInterface; int quantity = int.Parse(counterofferInterface.ProductLabel.text.Split("x ")[0]); string text = counterofferInterface.PriceInput.text; float num = ((text == "") ? 0f : float.Parse(text)); int num2 = DealCalculator.FindOptimalPrice(customerFromMessagesApp, Registry.GetItem<ProductDefinition>(((ItemDefinition)counterofferInterface.selectedProduct).ID), quantity, num * 0.25f, item, -1f, null, log: true); if (!Mathf.Approximately((float)num2, num)) { counterofferInterface.ChangePrice((float)(num2 - (int)num)); } OfferPriceChangeCheckNoLog(); } } } private class OfferData { public Customer Customer { get; } public ProductDefinition Product { get; } public int Quantity { get; } public float Price { get; } public OfferData(Customer customer, ProductDefinition product, int quantity, float price) { Customer = customer; Product = product; Quantity = quantity; Price = price; } } [HarmonyPatch(typeof(ProductManager), "SendPrice")] private static class ProductManagerSetPricePatch { private static void Postfix(string productID, float value) { MelonLogger.Msg($"ProductManager: Set price: {value} for {productID}"); if ((Object)(object)UIHandler.SelectedProduct != (Object)null && ((ItemDefinition)UIHandler.SelectedProduct.Definition).ID == productID) { optimalPriceCache.Remove(productID); Instance.uiHandler.UpdateSalesInfoPanel(UIHandler.SelectedProduct, value); } } } [HarmonyPatch(typeof(ProductManagerApp), "SelectProduct")] private static class ProductManagerSelectProductPatch { public static void Prefix(ProductManagerApp __instance, ProductEntry entry) { productManagerApp = __instance; } private static void Postfix(ProductEntry entry) { Instance.uiHandler.UpdateSalesInfoPanel(entry); } } [HarmonyPatch(typeof(ContactsDetailPanel), "Open")] public static class ContactsDetailPanelOpenPatch { [HarmonyPostfix] public static void Postfix(NPC npc, ContactsDetailPanel __instance) { if (!((Object)(object)npc == (Object)null)) { Melon<Core>.Logger.Msg($"RelationCircle: {npc.ID}, Name: {npc.fullName}, RelationDelta: {npc.RelationData.RelationDelta}, Unlocked: {npc.RelationData.Unlocked}"); Customer customerFromNPC = CustomerHelper.GetCustomerFromNPC(npc); if ((Object)(object)customerFromNPC == (Object)null) { Melon<Core>.Logger.Msg("Not a customer"); Instance.uiHandler.UpdateContactInfoPanel(null); } else { Instance.uiHandler.UpdateContactInfoPanel(customerFromNPC); } } } } public class CustomerAppeal { public Customer Customer { get; set; } public float Appeal { get; set; } public PaymentQuantityResult PaymentQuantity { get; set; } } [HarmonyPatch(typeof(Customer), "OfferContract")] public static class OfferContractPatch { public static void Postfix(ContractInfo info, Customer __instance, MethodBase __originalMethod) { if (Config.AutoCounterOfferEnabled.Value) { Melon<Core>.Logger.Msg("Customer: " + ((Object)__instance.customerData).name + ", Contract: " + info.Products.entries[0].ProductID); Entry entry = info.Products.entries[0]; Predicate<ProductDefinition> match = (ProductDefinition product) => ((ItemDefinition)product).ID.Equals(entry.ProductID); ProductDefinition product2 = ProductManager.ListedProducts.Find(match); float item = DealCalculator.CalculateSpendingLimits(__instance).maxSpend; if ((double)info.Payment >= Math.Floor(item)) { Melon<Core>.Logger.Msg("Skipping counter offer for " + ((Object)__instance.customerData).name + " because they are over their max spend"); new DelayedCounterOffer(__instance, product2, entry.Quantity, info.Payment, skipCounterOffer: true).Start(); } else { var (quantity, num) = DealCalculator.FindOptimalQuantity(__instance, product2, entry.Quantity, info.Payment); new DelayedCounterOffer(__instance, product2, quantity, num).Start(); } } } } [HarmonyPatch(typeof(Customer), "EvaluateCounteroffer")] public static class EvaluateCounterOfferPatch { public static void Postfix(Customer __instance, bool __result) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (!Config.AutoContractAcceptedEnabled.Value) { return; } if (!__result) { Melon<Core>.Logger.Warning("Counter failed"); return; } Melon<Core>.Logger.Msg($"Customer: {((Object)__instance.customerData).name}, Contract: {__result}, Counteroffer: {__instance.OfferedContractInfo.IsCounterOffer}"); int value = Config.AutoContractAcceptedWindow.Value; Melon<Core>.Logger.Msg($"Conversation: {__instance.NPC.MSGConversation}"); EDealWindow window; string text; switch (value) { case 1: window = (EDealWindow)0; text = "Morning"; break; case 2: window = (EDealWindow)1; text = "Afternoon"; break; case 3: window = (EDealWindow)2; text = "Night"; break; case 4: window = (EDealWindow)3; text = "Late Night"; break; default: window = (EDealWindow)3; text = "Late Night"; Melon<Core>.Logger.Warning("AutoContractAcceptedWindow is not correctly set!\nDefaulting to Late Night \nCorrect Values: 1 = Morning, 2 = Afternoon, 3 = Night, 4 = Late Night"); break; } __instance.NPC.MSGConversation.SendMessage(new Message(text, (ESenderType)0, true, -1), true, true); __instance.NPC.MSGConversation.ClearResponses(true); new DelayedScheduler(__instance, window).Start(); } } [HarmonyPatch(typeof(LevelManager), "AddXP")] public static class LevelManagerLoggingPatch { public static void Postfix(int xp) { Melon<Core>.Logger.Msg($"LevelManager: AddXP: {xp}"); } } private bool listening; private UIHandler uiHandler; private static Dictionary<string, (float bestPrice, float spenderScore)> optimalPriceCache = new Dictionary<string, (float, float)>(); public static ProductManager productManager; public static ProductManagerApp productManagerApp; public static Core Instance { get; private set; } private static bool DefinitelyLessThan(float a, float b) { return (double)(b - a) > (double)((Math.Abs(a) < Math.Abs(b)) ? Math.Abs(b) : Math.Abs(a)) * 1E-15; } private static OfferData GetOfferData() { MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; Customer customerFromMessagesApp = CustomerHelper.GetCustomerFromMessagesApp(instance); ProductDefinition item = Registry.GetItem<ProductDefinition>(customerFromMessagesApp.OfferedContractInfo.Products.entries[0].ProductID); int quantity = int.Parse(instance.CounterofferInterface.ProductLabel.text.Split('x')[0]); string text = instance.CounterofferInterface.PriceInput.text; float price = ((text == "") ? 0f : float.Parse(text)); return new OfferData(customerFromMessagesApp, item, quantity, price); } public static void OfferPriceChangeCheckNoLog() { EvaluateCounterOffer(GetOfferData()); } private void OfferPriceChangeCheckWithLog() { OfferData offerData = GetOfferData(); string text = "\nCustomer Name: " + ((Object)offerData.Customer).name + "\nProduct: " + ((ItemDefinition)offerData.Product).ID + "\n" + $"Quantity: {offerData.Quantity}\n" + $"Price: {offerData.Price}\n"; EvaluateCounterOffer(text, offerData); ((MelonBase)this).LoggerInstance.Msg(text.ToString()); } private static void EvaluateCounterOffer(OfferData offerData) { float item = DealCalculator.CalculateSpendingLimits(offerData.Customer).maxSpend; decimal num = Math.Round((decimal)item, 2); if (offerData.Price >= item) { DisplayHelper.UpdateCounterOfferDisplayText("Guaranteed Failure", $"Exceeded Max Spend ({num})"); return; } ProductDefinition selectedProduct = PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.selectedProduct; InitialOfferData initialOfferData = new InitialOfferData { ProductId = offerData.Customer.OfferedContractInfo.Products.entries[0].ProductID, Quantity = offerData.Customer.OfferedContractInfo.Products.entries[0].Quantity, Payment = offerData.Customer.OfferedContractInfo.Payment }; DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {Math.Round((decimal)(DealCalculator.CalculateSuccessProbability(offerData.Customer, selectedProduct, offerData.Quantity, offerData.Price, initialOfferData) * 100f), 3)}%", $"Price per unit: {offerData.Price / (float)offerData.Quantity}\nMax Spend: {num}"); } private void EvaluateCounterOffer(string stringBuilder, OfferData offerData) { (float maxSpend, float dailyAverage) tuple = DealCalculator.CalculateSpendingLimits(offerData.Customer); float item = tuple.maxSpend; float item2 = tuple.dailyAverage; decimal num = Math.Round((decimal)item, 2); string text = "\nAdjusted Weekly Spend: " + $"{offerData.Customer.CustomerData.GetAdjustedWeeklySpend(offerData.Customer.NPC.RelationData.RelationDelta / 5f)}\n" + "Order Days: " + $"{offerData.Customer.CustomerData.GetOrderDays(offerData.Customer.CurrentAddiction, offerData.Customer.NPC.RelationData.RelationDelta / 5f).Count}\n" + "Average Daily Spend: " + $"{item2}\n" + "Daily Spend Threshold (3x Avg): " + $"{num}\n" + "Min Weekly Spend: " + $"{offerData.Customer.CustomerData.MinWeeklySpend}\n" + "Max Weekly Spend: " + $"{offerData.Customer.CustomerData.MaxWeeklySpend}\n"; bool flag = (Object)(object)offerData.Customer.AssignedDealer == (Object)null; string text2 = ""; foreach (ProductDefinition orderableProduct in offerData.Customer.GetOrderableProducts(flag ? null : offerData.Customer.AssignedDealer)) { text2 += $"[Name: {((ItemDefinition)orderableProduct).Name}, Price: {orderableProduct.Price}, Market: {orderableProduct.MarketValue}],\n"; } text = text + "Orderable Products: " + text2 + "\n"; if (offerData.Price >= item) { text += "\nGuaranteed Failure - order must be less than 3x average daily spend\n"; string reasonText = $"Exceeded Max Spend ({num})"; DisplayHelper.UpdateCounterOfferDisplayText("Guaranteed Failure", reasonText); return; } InitialOfferData initialOfferData = new InitialOfferData { ProductId = offerData.Customer.OfferedContractInfo.Products.entries[0].ProductID, Quantity = offerData.Customer.OfferedContractInfo.Products.entries[0].Quantity, Payment = offerData.Customer.OfferedContractInfo.Payment }; decimal num2 = Math.Round((decimal)(DealCalculator.CalculateSuccessProbability(offerData.Customer, offerData.Product, offerData.Quantity, offerData.Price, initialOfferData) * 100f), 3); text = text + "\nProbability of success: " + $"{num2}\n"; DisplayHelper.UpdateCounterOfferDisplayText($"Probability of success: {num2}", ""); MelonLogger.Msg(text); } public override void OnInitializeMelon() { Instance = this; uiHandler = new UIHandler(); Config.Initialize(); ((MelonBase)this).LoggerInstance.Msg("Initialized Mod"); } public override void OnGUI() { uiHandler.OnGUI(); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main") { try { productManager = Object.FindObjectsOfType<ProductManager>()[0]; Melon<Core>.Logger.Msg($"ProductManager: {productManager}"); } catch (Exception ex) { MelonLogger.Error("Error finding ProductManager: " + ex.Message); } } ((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName); } public static float EvaluatePriceAcceptance(ProductDefinition product, List<CustomerAppeal> customerAppeals, float price) { float num = 0f; foreach (CustomerAppeal customerAppeal in customerAppeals) { Customer customer = customerAppeal.Customer; if (!((double)customerAppeal.Appeal >= 0.05000000074505806)) { continue; } float item = DealCalculator.CalculateSpendingLimits(customer).maxSpend; PaymentQuantityResult paymentQuantityResult = CustomerHelper.CalculatePaymentQuantity(product, customer, price); InitialOfferData initialOfferData = new InitialOfferData { ProductId = ((ItemDefinition)product).ID, Quantity = paymentQuantityResult.Quantity, Payment = paymentQuantityResult.Payment }; var (num2, num3) = DealCalculator.FindOptimalQuantity(customer, product, paymentQuantityResult.Quantity, paymentQuantityResult.Payment, initialOfferData); if (num3 != 0 && num2 != 0) { float num4 = (float)num3 / (float)Math.Floor(item); if (num4 >= Config.MinSuccessProbability.Value) { num += num4; } } } return num; } public static (float bestPrice, float spenderScore) GetOptimalPrice(ProductDefinition product, List<CustomerAppeal> customerAppeals, float initialPrice, float minPrice, float maxPrice, Action<(float bestPrice, float spenderScore)> callback = null) { Melon<Core>.Logger.Msg($"Getting optimal price for {((ItemDefinition)product).Name} at {initialPrice}"); if (optimalPriceCache.TryGetValue(((ItemDefinition)product).ID, out (float, float) value)) { callback?.Invoke(value); return value; } new DelayedPriceCalculator(product, customerAppeals, initialPrice, minPrice, maxPrice, delegate((float, float) result) { optimalPriceCache[((ItemDefinition)product).ID] = result; callback?.Invoke(result); }).Start(); return (initialPrice, 0f); } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { if (listening) { listening = false; } } public override void OnUpdate() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) SceneManager.GetActiveScene(); Scene activeScene = SceneManager.GetActiveScene(); bool flag = ((Scene)(ref activeScene)).name == "Main"; MessagesApp instance = PlayerSingleton<MessagesApp>.Instance; if (flag && !listening && (Object)(object)instance != (Object)null) { Subscribe(); } } private void Subscribe() { UnityAction<string> val = delegate { OfferPriceChangeCheckWithLog(); }; ((UnityEvent<string>)(object)PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.PriceInput.onValueChanged).AddListener(val); ((MelonBase)this).LoggerInstance.Msg("Attached listener"); listening = true; } } public class DelayedCounterOffer { [CompilerGenerated] private sealed class <DelayedCounterOfferCoroutine>d__8 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DelayedCounterOffer <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedCounterOfferCoroutine>d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; Melon<Core>.Logger.Msg("Delayed counter offer started"); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } if (Singleton<SaveManager>.Instance.IsSaving) { Melon<Core>.Logger.Msg("Waiting for save to finish"); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 2; return true; } Melon<Core>.Logger.Msg("Delayed counter offer ended"); if (<>4__this.skipCounterOffer) { Melon<Core>.Logger.Msg("Directly accepting contract for " + ((Object)<>4__this.customer.customerData).name); <>4__this.customer.AcceptContractClicked(); if (Config.AutoContractAcceptedEnabled.Value) { Core.EvaluateCounterOfferPatch.Postfix(<>4__this.customer, __result: true); } } else { <>4__this.customer.SendCounteroffer(<>4__this.product, <>4__this.quantity, <>4__this.price); } MelonCoroutines.Stop(<>4__this.coroutineToken); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Customer customer; private ProductDefinition product; private int quantity; private float price; private object coroutineToken; private bool skipCounterOffer; public DelayedCounterOffer(Customer customer, ProductDefinition product, int quantity, float price, bool skipCounterOffer = false) { this.customer = customer; this.product = product; this.quantity = quantity; this.price = price; this.skipCounterOffer = skipCounterOffer; } public void Start() { coroutineToken = MelonCoroutines.Start(DelayedCounterOfferCoroutine()); } [IteratorStateMachine(typeof(<DelayedCounterOfferCoroutine>d__8))] private IEnumerator DelayedCounterOfferCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedCounterOfferCoroutine>d__8(0) { <>4__this = this }; } } public class DelayedPriceCalculator { [CompilerGenerated] private sealed class <CalculatePriceCoroutine>d__12 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DelayedPriceCalculator <>4__this; private int <low>5__1; private int <high>5__2; private int <bestPrice>5__3; private float <spenderScore>5__4; private int <iterations>5__5; private int <maxIterations>5__6; private int <price1>5__7; private int <price2>5__8; private float <withUpdatedAppeals1>5__9; private float <withUpdatedAppeals2>5__10; private int <price>5__11; private float <withUpdatedAppeals>5__12; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CalculatePriceCoroutine>d__12(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; Melon<Core>.Logger.Msg("Starting delayed price calculation for " + ((ItemDefinition)<>4__this.product).Name); <low>5__1 = Mathf.FloorToInt(<>4__this.minPrice); <high>5__2 = Mathf.CeilToInt(<>4__this.maxPrice); <bestPrice>5__3 = Mathf.RoundToInt(<>4__this.initialPrice); <spenderScore>5__4 = Core.EvaluatePriceAcceptance(<>4__this.product, <>4__this.customerAppeals, <bestPrice>5__3); <iterations>5__5 = 0; <maxIterations>5__6 = 20; goto IL_01fa; case 1: <>1__state = -1; goto IL_01fa; case 2: { <>1__state = -1; int num = <price>5__11 + 1; <price>5__11 = num; break; } IL_01fa: if (<iterations>5__5 < <maxIterations>5__6 && <high>5__2 - <low>5__1 > 1 && !<>4__this.isCancelled) { <price1>5__7 = <low>5__1 + (<high>5__2 - <low>5__1) / 3; <price2>5__8 = <high>5__2 - (<high>5__2 - <low>5__1) / 3; <withUpdatedAppeals1>5__9 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price1>5__7); <withUpdatedAppeals2>5__10 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price2>5__8); if ((double)<withUpdatedAppeals1>5__9 > (double)<spenderScore>5__4) { <bestPrice>5__3 = <price1>5__7; <spenderScore>5__4 = <withUpdatedAppeals1>5__9; } if ((double)<withUpdatedAppeals2>5__10 > (double)<spenderScore>5__4) { <bestPrice>5__3 = <price2>5__8; <spenderScore>5__4 = <withUpdatedAppeals2>5__10; } if ((double)<withUpdatedAppeals1>5__9 > (double)<withUpdatedAppeals2>5__10) { <high>5__2 = <price2>5__8; } else { <low>5__1 = <price1>5__7; } int num = <iterations>5__5 + 1; <iterations>5__5 = num; <>2__current = (object)new WaitForSeconds(0.01f); <>1__state = 1; return true; } <price>5__11 = <low>5__1; break; } if (<price>5__11 <= <high>5__2 && !<>4__this.isCancelled) { <withUpdatedAppeals>5__12 = <>4__this.EvaluatePriceWithUpdatedAppeals(<price>5__11); if ((double)<withUpdatedAppeals>5__12 > (double)<spenderScore>5__4) { <bestPrice>5__3 = <price>5__11; <spenderScore>5__4 = <withUpdatedAppeals>5__12; } <>2__current = (object)new WaitForSeconds(0.01f); <>1__state = 2; return true; } if (!<>4__this.isCancelled) { Melon<Core>.Logger.Msg($"Price calculation complete for {((ItemDefinition)<>4__this.product).Name}: {<bestPrice>5__3}"); <>4__this.callback((<bestPrice>5__3, <spenderScore>5__4)); } <>4__this.isCalculating = false; MelonCoroutines.Stop(<>4__this.coroutineToken); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private ProductDefinition product; private List<Core.CustomerAppeal> customerAppeals; private float initialPrice; private float minPrice; private float maxPrice; private Action<(float bestPrice, float spenderScore)> callback; private object coroutineToken; private bool isCalculating; private bool isCancelled; public DelayedPriceCalculator(ProductDefinition product, List<Core.CustomerAppeal> customerAppeals, float initialPrice, float minPrice, float maxPrice, Action<(float bestPrice, float spenderScore)> callback) { this.product = product; this.customerAppeals = customerAppeals; this.initialPrice = initialPrice; this.minPrice = minPrice; this.maxPrice = maxPrice; this.callback = callback; } public void Start() { if (!isCalculating) { isCalculating = true; isCancelled = false; coroutineToken = MelonCoroutines.Start(CalculatePriceCoroutine()); } } public void Cancel() { isCancelled = true; if (coroutineToken != null) { MelonCoroutines.Stop(coroutineToken); coroutineToken = null; } isCalculating = false; } [IteratorStateMachine(typeof(<CalculatePriceCoroutine>d__12))] private IEnumerator CalculatePriceCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CalculatePriceCoroutine>d__12(0) { <>4__this = this }; } private float EvaluatePriceWithUpdatedAppeals(float price) { return Core.EvaluatePriceAcceptance(product, customerAppeals.Select((Core.CustomerAppeal c) => new Core.CustomerAppeal { Customer = c.Customer, Appeal = CustomerHelper.GetProductAppeal(product, c.Customer, price), PaymentQuantity = CustomerHelper.CalculatePaymentQuantity(product, c.Customer, price) }).ToList(), price); } } public class DelayedScheduler { [CompilerGenerated] private sealed class <DelayedSchedulerCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DelayedScheduler <>4__this; private DealWindowInfo <windowInfo>5__1; private ContractInfo <offeredContractInfo>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedSchedulerCoroutine>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <offeredContractInfo>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; Melon<Core>.Logger.Msg("Delayed scheduling started"); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } if (Singleton<SaveManager>.Instance.IsSaving) { Melon<Core>.Logger.Msg("Waiting for save to finish"); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 2; return true; } Melon<Core>.Logger.Msg("Delayed scheduling ended"); <windowInfo>5__1 = DealWindowInfo.GetWindowInfo(<>4__this.window); <offeredContractInfo>5__2 = <>4__this.customer.OfferedContractInfo; Melon<Core>.Logger.Msg($"Payment: {<offeredContractInfo>5__2.Payment}, Quantity: {<offeredContractInfo>5__2.Products.GetTotalQuantity()}, ProductID: {<offeredContractInfo>5__2.Products.entries[0].ProductID}, Quantity: {<offeredContractInfo>5__2.Products.entries[0].Quantity}"); <>4__this.customer.OfferedContractInfo.DeliveryWindow.WindowStartTime = <windowInfo>5__1.StartTime; <>4__this.customer.OfferedContractInfo.DeliveryWindow.WindowEndTime = <windowInfo>5__1.EndTime; Melon<Core>.Logger.Msg($"Window: {<windowInfo>5__1.StartTime} - {<windowInfo>5__1.EndTime}"); <>4__this.customer.PlayContractAcceptedReaction(); Melon<Core>.Logger.Msg("Played contract accepted reaction"); <>4__this.customer.SendContractAccepted(<>4__this.window, true); Melon<Core>.Logger.Msg("Sent contract accepted"); if (!InstanceFinder.IsServer) { Melon<Core>.Logger.Msg("Clearing contract"); <>4__this.customer.OfferedContractInfo = null; } MelonCoroutines.Stop(<>4__this.coroutineToken); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Customer customer; private EDealWindow window; private object coroutineToken; public DelayedScheduler(Customer customer, EDealWindow window) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) this.customer = customer; this.window = window; } public void Start() { coroutineToken = MelonCoroutines.Start(DelayedSchedulerCoroutine()); } [IteratorStateMachine(typeof(<DelayedSchedulerCoroutine>d__5))] private IEnumerator DelayedSchedulerCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedSchedulerCoroutine>d__5(0) { <>4__this = this }; } } public class UIHandler { private class PanelState { public bool IsVisible; public bool IsDragging; public Vector2 Position; public Vector2 DragOffset; public Vector2 ScrollPosition; public string Content; public string Title; public PanelState(string title) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) IsVisible = false; IsDragging = false; Position = new Vector2(20f, 20f); DragOffset = Vector2.zero; ScrollPosition = Vector2.zero; Content = ""; Title = title; } } private GUIStyle displayTextStyle; private static string counterOfferDisplayText = ""; private static GUIStyle salesPanelStyle; private static GUIStyle salesHeaderStyle; private static GUIStyle salesTextStyle; private GUIStyle sectionHeaderStyle; private GUIStyle infoLabelStyle; private GUIStyle infoValueStyle; private PanelState salesPanel; private PanelState contactPanel; private DelayedPriceCalculator currentPriceCalculator; public static ProductEntry SelectedProduct { get; set; } = null; public static Customer SelectedCustomer { get; set; } = null; public UIHandler() { InitializeStyles(); salesPanel = new PanelState("Sales Information"); contactPanel = new PanelState("Contact Information"); } private void InitializeStyles() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Expected O, but got Unknown displayTextStyle = new GUIStyle(GUIStyle.op_Implicit("label")); displayTextStyle.fontSize = 18; displayTextStyle.normal.background = Texture2D.whiteTexture; displayTextStyle.alignment = (TextAnchor)4; salesPanelStyle = new GUIStyle(GUIStyle.op_Implicit("box")); salesPanelStyle.normal.background = Texture2D.whiteTexture; salesPanelStyle.normal.textColor = Color.white; salesPanelStyle.padding = new RectOffset(10, 10, 10, 10); salesHeaderStyle = new GUIStyle(GUIStyle.op_Implicit("label")); salesHeaderStyle.fontSize = 20; salesHeaderStyle.fontStyle = (FontStyle)1; salesHeaderStyle.normal.textColor = Color.white; salesHeaderStyle.alignment = (TextAnchor)4; salesTextStyle = new GUIStyle(GUIStyle.op_Implicit("label")); salesTextStyle.fontSize = 14; salesTextStyle.normal.textColor = Color.white; salesTextStyle.wordWrap = true; salesTextStyle.padding = new RectOffset(10, 0, 0, 0); sectionHeaderStyle = new GUIStyle(GUIStyle.op_Implicit("label")); sectionHeaderStyle.fontSize = 16; sectionHeaderStyle.fontStyle = (FontStyle)1; sectionHeaderStyle.normal.textColor = new Color(0.9f, 0.9f, 1f); sectionHeaderStyle.padding = new RectOffset(0, 0, 10, 5); infoLabelStyle = new GUIStyle(GUIStyle.op_Implicit("label")); infoLabelStyle.fontSize = 14; infoLabelStyle.fontStyle = (FontStyle)1; infoLabelStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f); infoLabelStyle.padding = new RectOffset(10, 0, 2, 2); infoValueStyle = new GUIStyle(GUIStyle.op_Implicit("label")); infoValueStyle.fontSize = 14; infoValueStyle.normal.textColor = new Color(1f, 0.95f, 0.8f); infoValueStyle.padding = new RectOffset(10, 0, 2, 8); } private string FormatCurrency(float amount) { return $"${amount:F2}"; } public void UpdateCounterOfferDisplayText(string text, string reasonText) { counterOfferDisplayText = text + "\n" + reasonText; } private string FormatSalesInfo(ProductEntry entry, float? overridePrice = null) { string text = "<section>Product Details</section>\n<label>Product:</label> <value>" + ((ItemDefinition)entry.Definition).Name + "</value>\n<label>Base Price:</label> <value>" + FormatCurrency(entry.Definition.Price) + "</value>\n<label>Market Value:</label> <value>" + FormatCurrency(entry.Definition.MarketValue) + "</value>\n"; if (overridePrice.HasValue && overridePrice.Value != entry.Definition.Price) { text = text + "<label>Current Price:</label> <value>" + FormatCurrency(overridePrice.Value) + "</value>\n"; } List<Customer> unlockedCustomers = Customer.UnlockedCustomers; List<Core.CustomerAppeal> list = new List<Core.CustomerAppeal>(); for (int i = 0; i < unlockedCustomers.Count; i++) { list.Add(new Core.CustomerAppeal { Customer = unlockedCustomers[i], Appeal = CustomerHelper.GetProductAppeal(entry.Definition, unlockedCustomers[i], overridePrice), PaymentQuantity = CustomerHelper.CalculatePaymentQuantity(entry.Definition, unlockedCustomers[i], overridePrice) }); } List<Core.CustomerAppeal> list2 = list.OrderByDescending((Core.CustomerAppeal ca) => ca.Appeal).ToList(); List<Core.CustomerAppeal> list3 = list2.FindAll((Core.CustomerAppeal ca) => (double)ca.Appeal > 0.05000000074505806); float num = Core.EvaluatePriceAcceptance(entry.Definition, list2, overridePrice ?? entry.Definition.Price); text = text + "<section>Market Analysis</section>\n<label>Potential Customers:</label> <value>" + $"{list3.Count}" + "</value>\n<label>Average Order Size:</label> <value>" + $"{((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Quantity) : 0.0):F1}" + "</value>\n<label>Average Payment:</label> <value>" + ((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment)) : FormatCurrency(0f)) + "</value>\n<label>Per-Unit Price:</label> <value>" + ((list3.Count > 0) ? FormatCurrency(list3.Average((Core.CustomerAppeal ca) => ca.PaymentQuantity.Payment / (float)ca.PaymentQuantity.Quantity)) : FormatCurrency(0f)) + "</value>\n<label>Max Spender Score:</label> <value>" + $"{num:F2}" + "</value>\n"; text = text + "<section>Appeal Statistics</section>\n<label>Customer Appeal:</label>\n" + $"<value>Average: {((list3.Count > 0) ? list3.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + $"<value>Min: {((list3.Count > 0) ? list3.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + $"<value>Max: {((list3.Count > 0) ? list3.Max((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}</value>\n" + "<label>Overall Appeal:</label>\n<value>Average: " + $"{((list2.Count > 0) ? list2.Average((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}" + "</value>\n<value>Min: " + $"{((list2.Count > 0) ? list2.Min((Core.CustomerAppeal ca) => ca.Appeal) : 0f):F2}" + "</value>\n"; if (Config.PriceOptimizationEnabled.Value) { text = text + "<section>Price Optimization</section>\n<label>Original Price:</label> <value>" + FormatCurrency(entry.Definition.Price) + "</value>\n<label>Optimal Price:</label> <value>Calculating...</value>\n<label>Price Change:</label> <value>Calculating...</value>\n"; float num2 = overridePrice ?? entry.Definition.Price; float minPrice = num2 * 0.5f; float maxPrice = num2 * 2f; currentPriceCalculator = new DelayedPriceCalculator(entry.Definition, list2, num2, minPrice, maxPrice, delegate((float bestPrice, float spenderScore) result) { float item = result.bestPrice; string[] array = salesPanel.Content.Split('\n'); for (int j = 0; j < array.Length; j++) { if (array[j].Contains("Optimal Price:")) { array[j] = "<label>Optimal Price:</label> <value>" + FormatCurrency(item) + "</value>\n"; } else if (array[j].Contains("Price Change:")) { array[j] = $"<label>Price Change:</label> <value>{(float)(((double)item - (double)entry.Definition.Price) / (double)entry.Definition.Price * 100.0):F1}%</value>\n"; } } salesPanel.Content = string.Join("\n", array); }); currentPriceCalculator.Start(); } return text; } private List<EDay> GetSortedOrderDays(List<EDay> orderDays, EDay currentDay) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) List<EDay> list = new List<EDay>(); for (int i = 0; i < orderDays.Count; i++) { list.Add(orderDays[i]); } Comparison<EDay> comparison = delegate(EDay a, EDay b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected I4, but got Unknown //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown int num = a - currentDay; int num2 = b - currentDay; if (num < 0) { num += 7; } if (num2 < 0) { num2 += 7; } return num.CompareTo(num2); }; list.Sort(comparison); return list; } private string FormatCustomerInfo(Customer customer, CustomerData customerData, NPCRelationData relationData, EDay currentDay) { //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) string text = "<section>Customer Details</section>\n<label>Name:</label> <value>" + customer.NPC.fullName + "</value>\n"; if ((Object)(object)customer.AssignedDealer != (Object)null) { text = text + "<label>Assigned Dealer:</label> <value>" + ((NPC)customer.AssignedDealer).FirstName + " " + ((NPC)customer.AssignedDealer).LastName + "</value>\n"; } List<EDay> orderDays = customerData.GetOrderDays(customer.CurrentAddiction, relationData.RelationDelta / 5f); float amount = customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) * 3f / (float)orderDays.Count; text = text + "<section>Financial Information</section>\n<label>Max Spend:</label> <value>" + FormatCurrency(customerData.MaxWeeklySpend) + "</value>\n<label>Min Spend:</label> <value>" + FormatCurrency(customerData.MinWeeklySpend) + "</value>\n<label>Max Daily Spend:</label> <value>" + FormatCurrency(amount) + " (" + $"{(double)customerData.GetAdjustedWeeklySpend(relationData.RelationDelta / 5f) / (double)customerData.GetAdjustedWeeklySpend(1f) * 100.0:F2}" + "% of Max)</value>\n"; List<EDay> sortedOrderDays = GetSortedOrderDays(orderDays, currentDay); text += "<section>Schedule Information</section>\n<label>Next Order Days:</label>\n"; for (int i = 0; i < sortedOrderDays.Count; i++) { text = text + "<value> " + $"{i + 1}. {sortedOrderDays[i]}" + "</value>\n"; } text += "<section>Product Preferences</section>\n"; var list = CustomerHelper.GetProductsFromCustomer(customer).Select((CustomerHelper.ProductOrders p, int index) => new { ProductInfo = p, Index = index }).ToList(); if (list.Count == 0) { text = ((!((Object)(object)customer.AssignedDealer == (Object)null)) ? (text + "<value>Dealer has no appealing products for sale</value>\n") : (text + "<value>Won't buy anything</value>\n")); } foreach (var item in list) { text = text + "<value>" + ((ItemDefinition)item.ProductInfo.Product).Name + " - $" + $"{item.ProductInfo.PaymentQuantity.Payment:F2}" + " × " + $"{item.ProductInfo.PaymentQuantity.Quantity}" + " (Appeal: " + $"{item.ProductInfo.PaymentQuantity.Appeal:F3}" + ")</value>\n"; } return text; } private void HandlePanelDragging(PanelState panel, Rect dragRect, Event currentEvent) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((int)currentEvent.type == 0 && ((Rect)(ref dragRect)).Contains(currentEvent.mousePosition)) { panel.IsDragging = true; panel.DragOffset = currentEvent.mousePosition - panel.Position; currentEvent.Use(); } else if ((int)currentEvent.type == 1) { panel.IsDragging = false; } if (panel.IsDragging && (int)currentEvent.type == 3) { panel.Position = currentEvent.mousePosition - panel.DragOffset; currentEvent.Use(); } } private void DrawPanel(PanelState panel, float width, float height) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) if (!panel.IsVisible) { return; } Rect dragRect = default(Rect); ((Rect)(ref dragRect))..ctor(panel.Position.x, panel.Position.y, width, 40f); HandlePanelDragging(panel, dragRect, Event.current); panel.Position.x = Mathf.Clamp(panel.Position.x, 0f, (float)Screen.width - width); panel.Position.y = Mathf.Clamp(panel.Position.y, 0f, (float)Screen.height - height); GUI.backgroundColor = Color.black; Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, new Color(0.15f, 0.15f, 0.2f, 0.95f)); val.Apply(); GUI.DrawTexture(new Rect(panel.Position.x, panel.Position.y, width, height), (Texture)(object)val); string[] array = panel.Content.Split('\n'); float num = panel.Position.y + 40f; float num2 = width - 20f; panel.ScrollPosition = GUI.BeginScrollView(new Rect(panel.Position.x, num, width, height - 40f), panel.ScrollPosition, new Rect(0f, 0f, num2, (float)(array.Length * 25))); float num3 = 0f; string[] array2 = array; foreach (string text in array2) { if (text.StartsWith("<section>")) { string text2 = text.Replace("<section>", "").Replace("</section>", ""); GUI.Label(new Rect(10f, num3, num2, 25f), text2, sectionHeaderStyle); num3 += 30f; } else if (text.Contains("<label>")) { string text3 = ""; string text4 = ""; int num4 = text.IndexOf("<label>") + 7; int num5 = text.IndexOf("</label>"); if (num4 >= 7 && num5 > num4) { text3 = text.Substring(num4, num5 - num4); } int num6 = text.IndexOf("<value>") + 7; int num7 = text.IndexOf("</value>"); if (num6 >= 7 && num7 > num6) { text4 = text.Substring(num6, num7 - num6); } if (!string.IsNullOrEmpty(text3)) { GUI.Label(new Rect(10f, num3, 140f, 20f), text3, infoLabelStyle); if (!string.IsNullOrEmpty(text4)) { GUI.Label(new Rect(160f, num3, num2 - 160f, 20f), text4, infoValueStyle); } num3 += 25f; } } else if (text.StartsWith("<value>")) { string text5 = text.Replace("<value>", "").Replace("</value>", ""); GUI.Label(new Rect(20f, num3, num2 - 20f, 20f), text5, infoValueStyle); num3 += 25f; } else if (!string.IsNullOrWhiteSpace(text)) { GUI.Label(new Rect(10f, num3, num2, 20f), text, infoValueStyle); num3 += 25f; } } GUI.EndScrollView(); GUI.Box(new Rect(panel.Position.x, panel.Position.y, width, 40f), "", salesPanelStyle); GUI.Label(new Rect(panel.Position.x, panel.Position.y, width, 40f), panel.Title + " (Drag to Move)", salesHeaderStyle); if (GUI.Button(new Rect((float)((double)panel.Position.x + (double)width - 30.0), panel.Position.y + 5f, 25f, 25f), "X")) { panel.IsVisible = false; panel.Position = new Vector2(20f, 20f); if (panel == salesPanel) { SelectedProduct = null; } else if (panel == contactPanel) { SelectedCustomer = null; } } Object.Destroy((Object)(object)val); } public void UpdateSalesInfoPanel(ProductEntry entry, float? overridePrice = null) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (currentPriceCalculator != null) { currentPriceCalculator.Cancel(); currentPriceCalculator = null; } SelectedProduct = entry; salesPanel.IsVisible = true; salesPanel.ScrollPosition = Vector2.zero; salesPanel.Content = FormatSalesInfo(entry, overridePrice); } public void UpdateContactInfoPanel(Customer customer) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)customer == (Object)null) { contactPanel.IsVisible = false; return; } EDay currentDay = NetworkSingleton<TimeManager>.Instance.CurrentDay; SelectedCustomer = customer; contactPanel.IsVisible = true; contactPanel.ScrollPosition = Vector2.zero; contactPanel.Content = FormatCustomerInfo(customer, customer.customerData, customer.NPC.RelationData, currentDay); } private void DrawSalesInfoPanel() { DrawPanel(salesPanel, 400f, 800f); } private void DrawContactInfoPanel() { DrawPanel(contactPanel, 400f, 700f); } public void OnGUI() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) SceneManager.GetActiveScene(); Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "Main") { return; } Phone instance = PlayerSingleton<Phone>.Instance; if (!((Object)(object)instance == (Object)null)) { if (!instance.IsOpen) { return; } } else if (0 == 0) { return; } if (((!PlayerSingleton<HomeScreen>.Instance.isOpen || 1 == 0) & ((Object)(object)PlayerSingleton<MessagesApp>.Instance != (Object)null)) && PlayerSingleton<MessagesApp>.Instance.CounterofferInterface.IsOpen) { if (Config.CounterOfferDarkModeEnabled.Value) { GUI.backgroundColor = new Color(0.15f, 0.15f, 0.2f, 0.95f); displayTextStyle.normal.textColor = Color.white; } else { displayTextStyle.normal.textColor = Color.black; } GUI.Label(new Rect((float)(Screen.width / 2 - 190), (float)(Screen.height / 2 - 250), 380f, 70f), counterOfferDisplayText, displayTextStyle); GUI.backgroundColor = Color.white; } if ((Object)(object)Core.productManagerApp != (Object)null && ((App<ProductManagerApp>)(object)Core.productManagerApp).isOpen && salesPanel.IsVisible) { DrawSalesInfoPanel(); } if (!((Object)(object)PlayerSingleton<ContactsApp>.Instance == (Object)null) && ((App<ContactsApp>)(object)PlayerSingleton<ContactsApp>.Instance).isOpen && contactPanel.IsVisible) { DrawContactInfoPanel(); } } } } namespace HighBaller.Services { public static class CustomerHelper { public class ProductOrders { public ProductDefinition Product { get; set; } public PaymentQuantityResult PaymentQuantity { get; set; } } public static Customer GetCustomerFromConversation(MSGConversation conversation) { string contactName = conversation.contactName; Predicate<Customer> match = (Customer customer) => customer.NPC.fullName == contactName; return Customer.UnlockedCustomers.Find(match); } public static Customer GetCustomerFromMessagesApp(MessagesApp messagesApp) { return GetCustomerFromConversation(messagesApp.currentConversation); } public static float GetProductAppeal(ProductDefinition product, Customer customer, float? overridePrice = null) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) float productEnjoyment = customer.GetProductEnjoyment(product, StandardsMethod.GetCorrespondingQuality(customer.customerData.Standards)); float num = (overridePrice ?? product.Price) / product.MarketValue; float num2 = Mathf.Lerp(1f, -1f, num / 2f); return productEnjoyment + num2; } public static PaymentQuantityResult CalculatePaymentQuantity(ProductDefinition product, Customer customer, float? overridePrice = null) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) CustomerData customerData = customer.customerData; if ((Object)(object)product == (Object)null) { return null; } EQuality correspondingQuality = StandardsMethod.GetCorrespondingQuality(customerData.Standards); float num = overridePrice ?? product.Price; float productAppeal = GetProductAppeal(product, customer, overridePrice); if ((double)productAppeal < 0.05000000074505806) { return new PaymentQuantityResult { Payment = 0f, Quantity = 0, Quality = correspondingQuality, Appeal = productAppeal }; } float productEnjoyment = customer.GetProductEnjoyment(product, correspondingQuality); int num2 = 7; if ((Object)(object)customer.AssignedDealer == (Object)null) { num2 = customerData.GetOrderDays(customer.CurrentAddiction, customer.NPC.RelationData.RelationDelta / 5f).Count; } double num3 = (double)customerData.GetAdjustedWeeklySpend(customer.NPC.RelationData.RelationDelta / 5f) / (double)num2 * (double)Mathf.Lerp(0.66f, 1.5f, productEnjoyment); float num4 = num * Mathf.Lerp(0.66f, 1.5f, productEnjoyment); double num5 = num; int num6 = Mathf.Clamp(Mathf.RoundToInt((float)(num3 / num5)), 1, 1000); if (num6 >= 14) { num6 = Mathf.RoundToInt((float)(num6 / 5)) * 5; } float payment = Mathf.RoundToInt((float)((double)num4 * (double)num6 / 5.0)) * 5; return new PaymentQuantityResult { Payment = payment, Quantity = num6, Quality = correspondingQuality, Appeal = productAppeal }; } public static Customer GetCustomerFromNPC(NPC npc) { Predicate<Customer> match = (Customer cust) => ((object)cust.NPC).Equals((object?)npc); return Customer.UnlockedCustomers.Find(match); } public static IEnumerable<ProductOrders> GetProductsFromCustomer(Customer customer) { List<ProductOrders> list = new List<ProductOrders>(); foreach (ProductDefinition orderableProduct in customer.GetOrderableProducts((Dealer)null)) { if ((double)CalculatePaymentQuantity(orderableProduct, customer).Appeal >= 0.05000000074505806) { list.Add(new ProductOrders { Product = orderableProduct, PaymentQuantity = CalculatePaymentQuantity(orderableProduct, customer) }); } } list.Sort((ProductOrders a, ProductOrders b) => b.PaymentQuantity.Appeal.CompareTo(a.PaymentQuantity.Appeal)); return list.Take(4); } } [HarmonyPatch(typeof(Customer), "HandoverChosen")] public static class HandoverService { public static bool Prefix(Customer __instance) { return doDeal(__instance); } private static bool doDeal(Customer customer) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) if (!Config.AutoHandoverEnabled.Value || customer.CurrentContract?.ProductList?.entries == null || customer.CurrentContract.ProductList.entries.Count == 0) { return true; } Melon<Core>.Logger.Msg("Customer: " + customer.NPC.fullName); Entry val = customer.CurrentContract.ProductList.entries[0]; string productID = val.ProductID; int quantity = val.Quantity; if (quantity <= 0) { return true; } EQuality minQuality = StandardsMethod.GetCorrespondingQuality(customer.CustomerData.Standards); List<ProductPackage<ItemSlot>> list = new List<ProductPackage<ItemSlot>>(); ItemSlot[] inventory = Player.Local.Inventory; foreach (ItemSlot val2 in inventory) { ItemInstance itemInstance = val2.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 val3 = (ProductItemInstance)itemInstance; if (val3 != null && (Object)(object)val3.packaging != (Object)null && ((QualityItemInstance)val3).Quality >= minQuality) { Melon<Core>.Logger.Msg($"ProductItem: {itemInstance.ID} - {itemInstance.Quantity} - {((ItemDefinition)val3.packaging).Name}"); PackagingDefinition packaging = val3.packaging; Melon<Core>.Logger.Msg($"Packaging: {packaging.Quantity} {((ItemDefinition)packaging).ID}"); list.Add(new ProductPackage<ItemSlot>(packaging.Quantity, val2, itemInstance.Quantity, ((QualityItemInstance)val3).Quality)); } } } List<ProductPackage<ItemSlot>> list2 = new List<ProductPackage<ItemSlot>>(); foreach (EQuality item in from EQuality q in Enum.GetValues(typeof(EQuality)) where q >= minQuality select q) { EQuality qualityLevel = item; Melon<Core>.Logger.Msg($"Finding optimal packages for quality: {qualityLevel}"); list2 = FindOptimalPackages(list.Where((ProductPackage<ItemSlot> p) => p.Quality == qualityLevel).ToList(), quantity); if (list2.Count > 0) { Melon<Core>.Logger.Msg($"Found optimal packages for quality: {qualityLevel}"); break; } } if (list2.Count == 0) { Melon<Core>.Logger.Warning("No suitable combination of packages found to meet target quantity"); return true; } List<ItemInstance> list3 = new List<ItemInstance>(); foreach (ProductPackage<ItemSlot> item2 in list2) { Melon<Core>.Logger.Msg($"Selected package: {item2?.PackageSize} units, {item2?.AvailableQuantity} packages"); ItemInstance copy = item2.Slot.ItemInstance.GetCopy(-1); if (item2.Slot.Quantity.Equals(item2.AvailableQuantity)) { item2.Slot.ItemInstance.RequestClearSlot(); } else { item2.Slot.ChangeQuantity(-item2.AvailableQuantity, false); } copy.Quantity = item2.AvailableQuantity; list3.Add(copy); } customer.ProcessHandover((EHandoverOutcome)1, customer.CurrentContract, list3, true, true); return false; } public static List<ProductPackage<T>> FindOptimalPackages<T>(List<ProductPackage<T>> availablePackages, int targetQuantity) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (targetQuantity <= 0) { return new List<ProductPackage<T>>(); } if (availablePackages.Sum((ProductPackage<T> p) => p.TotalUnits) < targetQuantity) { return new List<ProductPackage<T>>(); } List<ProductPackage<T>> selectedPackages = new List<ProductPackage<T>>(); int num = targetQuantity; List<ProductPackage<T>> list = availablePackages.OrderByDescending((ProductPackage<T> p) => p.PackageSize).ToList(); foreach (ProductPackage<T> item in list) { if (num > 0) { int num2 = Math.Min(item.AvailableQuantity, num / item.PackageSize); if (num2 > 0) { selectedPackages.Add(new ProductPackage<T>(item.PackageSize, item.Slot, num2, item.Quality)); num -= num2 * item.PackageSize; } continue; } break; } if (num > 0) { List<ProductPackage<T>> list2 = FindExactMatch(list.Where((ProductPackage<T> p) => !selectedPackages.Any((ProductPackage<T> sp) => sp.Slot.Equals(p.Slot))).ToList(), num); if (list2 == null) { return new List<ProductPackage<T>>(); } selectedPackages.AddRange(list2); } return selectedPackages; } private static List<ProductPackage<T>> FindExactMatch<T>(List<ProductPackage<T>> packages, int target) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (target == 0) { return new List<ProductPackage<T>>(); } if (packages.Count == 0 || target < 0) { return null; } ProductPackage<T> productPackage = packages[0]; List<ProductPackage<T>> packages2 = packages.Skip(1).ToList(); int num = Math.Min(productPackage.AvailableQuantity, target / productPackage.PackageSize); for (int i = 0; i <= num; i++) { int target2 = target - i * productPackage.PackageSize; List<ProductPackage<T>> list = FindExactMatch(packages2, target2); if (list != null) { if (i > 0) { list.Add(new ProductPackage<T>(productPackage.PackageSize, productPackage.Slot, i, productPackage.Quality)); } return list; } } return null; } } public class ProductPackage<T> { public int PackageSize { get; } public T Slot { get; } public int AvailableQuantity { get; } public EQuality Quality { get; } public int TotalUnits => PackageSize * AvailableQuantity; public ProductPackage(int packageSize, T slot, int quantity, EQuality quality) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) PackageSize = packageSize; Slot = slot; AvailableQuantity = quantity; Quality = quality; } } } namespace HighBaller.Models { public class PaymentQuantityResult { public float Payment { get; set; } public int Quantity { get; set; } public EQuality Quality { get; set; } public float Appeal { get; set; } public override string ToString() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) return $"[Payment: {Payment}, Quantity: {Quantity}, Quality: {Quality}, Appeal: {Appeal}]"; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }