Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Epicurean v1.3.0
Epicurean.dll
Decompiled 10 months agousing System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppFishNet.Object; using Il2CppInterop.Runtime.InteropTypes; using Il2CppScheduleOne; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Law; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Quests; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Handover; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Utils; using QualityMod; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(global::QualityMod.QualityMod), "Epicurean", "1.3.0", "Ryocery", null)] [assembly: MelonColor(255, 255, 60, 255)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("QualityMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("QualityMod")] [assembly: AssemblyTitle("QualityMod")] [assembly: AssemblyVersion("1.0.0.0")] namespace QualityMod; public static class BuildInfo { public const string Name = "Epicurean"; public const string Description = "Adds percentage bonuses per quality tier above customer standards for payment, addiction, and affinity"; public const string Author = "Ryocery"; public const string Company = null; public const string Version = "1.3.0"; public const string DownloadLink = null; } public class QualityMod : MelonMod { [HarmonyPatch(typeof(Customer), "ProcessHandover")] public static class Customer_ProcessHandover_Patch { public static bool Prefix(Customer __instance, EHandoverOutcome outcome, Contract contract, List<ItemInstance> items, bool handoverByPlayer, bool giveBonuses) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Expected O, but got Unknown //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Invalid comparison between Unknown and I4 //IL_0559: Unknown result type (might be due to invalid IL or missing references) if (!handoverByPlayer && !affectsDealers) { return true; } float num = default(float); EDrugType val = default(EDrugType); int num2 = default(int); float num3 = Mathf.Clamp01(__instance.EvaluateDelivery(contract, items, ref num, ref val, ref num2)); float num4 = 1f; float qualityScalar = CustomerData.GetQualityScalar(StandardsMethod.GetCorrespondingQuality(__instance.customerData.Standards)); Enumerator<ItemInstance> enumerator = items.GetEnumerator(); while (enumerator.MoveNext()) { ItemInstance current = enumerator.Current; ProductItemInstance val2 = ((Il2CppObjectBase)current).TryCast<ProductItemInstance>(); if (val2 != null) { float qualityScalar2 = CustomerData.GetQualityScalar(((QualityItemInstance)val2).Quality); if (qualityScalar2 < num4) { num4 = qualityScalar2; } } else { MelonLogger.Msg("Found null product item! Please report this bug."); } } float num5 = num4 - qualityScalar; int num6 = 0; if (num5 > 0f) { num6 = Mathf.RoundToInt(num5 / 0.25f); } float num7 = 1f; if (num6 > 0) { num7 = 1f + (float)num6 * addictionBonusPercent / 100f; } __instance.ChangeAddiction(num / 5f * num7); float relationDelta = __instance.NPC.RelationData.RelationDelta; float relationshipChange = CustomerSatisfaction.GetRelationshipChange(num3); float num8 = relationshipChange * 0.2f * Mathf.Lerp(0.75f, 1.5f, num); float num9 = 1f; if (num6 > 0) { num9 = 1f + (float)num6 * affinityBonusPercent / 100f; } float num10 = num8 * num9; __instance.AdjustAffinity(val, num10); float num11 = relationshipChange; if (num6 > 0 && affinityBonusPercent > 0f) { num11 = relationshipChange * num9; } __instance.NPC.RelationData.ChangeRelationship(num11, true); List<BonusPayment> val3 = new List<BonusPayment>(); if (NetworkSingleton<CurfewManager>.Instance.IsCurrentlyActive && giveBonuses) { val3.Add(new BonusPayment("Curfew Bonus", contract.Payment * 0.2f)); } if (num2 > contract.ProductList.GetTotalQuantity() && giveBonuses) { val3.Add(new BonusPayment("Generosity Bonus", 10f * (float)(num2 - contract.ProductList.GetTotalQuantity()))); } GameDateTime acceptTime = contract.AcceptTime; GameDateTime val4 = default(GameDateTime); ((GameDateTime)(ref val4))..ctor(acceptTime.elapsedDays, TimeManager.AddMinutesTo24HourTime(contract.DeliveryWindow.WindowStartTime, 60)); if (NetworkSingleton<TimeManager>.Instance.IsCurrentDateWithinRange(acceptTime, val4) && giveBonuses) { val3.Add(new BonusPayment("Quick Delivery Bonus", contract.Payment * 0.1f)); } MelonLogger.Msg($"Contract payment: ${contract.Payment:F2}, Items quantity: {contract.ProductList.GetTotalQuantity()}"); if (num5 > 0f) { float num12 = (float)num6 * qualityBonusPercent / 100f; float num13 = contract.Payment * num12; val3.Add(new BonusPayment("Quality Bonus", num13)); MelonLogger.Msg($"Tiers above standard: {num6} ({(float)num6 * qualityBonusPercent}% bonus), Bonus: ${num13:F2}"); } float num14 = 0f; Enumerator<BonusPayment> enumerator2 = val3.GetEnumerator(); while (enumerator2.MoveNext()) { BonusPayment current2 = enumerator2.Current; Console.Log(Object.op_Implicit($"Bonus: {current2.Title} Amount: {current2.Amount}"), (Object)null); num14 += current2.Amount; } if (handoverByPlayer) { Singleton<HandoverScreen>.Instance.ClearCustomerSlots(false); } if (handoverByPlayer) { contract.SubmitPayment(num14); } if ((int)outcome == 1 && handoverByPlayer) { Singleton<DealCompletionPopup>.Instance.PlayPopup(__instance, num3, relationDelta, contract.Payment, val3); } __instance.TimeSinceLastDealCompleted = 0; __instance.NPC.SendAnimationTrigger("GrabItem"); NetworkObject val5 = null; if ((Object)(object)contract.Dealer != (Object)null) { val5 = ((NetworkBehaviour)contract.Dealer).NetworkObject; } Console.Log(Object.op_Implicit($"Base payment: {contract.Payment} Total Bonus: {num14} Satisfaction: {num3} Dealer: {((val5 != null) ? ((Object)val5).name : null)}"), (Object)null); float num15 = Mathf.Clamp(contract.Payment + num14, 0f, float.MaxValue); __instance.ProcessHandoverServerSide(outcome, items, handoverByPlayer, num15, contract.ProductList, num3, val5); return false; } } private static string configPath = Path.Combine(MelonEnvironment.UserDataDirectory, "Epicurean.cfg"); private static float qualityBonusPercent = 10f; private static float addictionBonusPercent = 20f; private static float affinityBonusPercent = 15f; private static bool affectsDealers = true; public override void OnInitializeMelon() { MelonLogger.Msg("Epicurean v1.3.0 loaded! :3"); LoadConfig(); } private void LoadConfig() { if (File.Exists(configPath)) { string[] array = File.ReadAllLines(configPath); foreach (string text in array) { bool result4; if (text.StartsWith("BonusPercentage=")) { if (float.TryParse(text.Split('=')[1].Trim(), out var result)) { qualityBonusPercent = result; } } else if (text.StartsWith("AddictionBonusPercentage=")) { if (float.TryParse(text.Split('=')[1].Trim(), out var result2)) { addictionBonusPercent = result2; } } else if (text.StartsWith("AffinityBonusPercentage=")) { if (float.TryParse(text.Split('=')[1].Trim(), out var result3)) { affinityBonusPercent = result3; } } else if (text.StartsWith("AffectsDealers=") && bool.TryParse(text.Split('=')[1].Trim(), out result4)) { affectsDealers = result4; } } } else { SaveConfig(); } MelonLogger.Msg("Config loaded."); } private static void SaveConfig() { File.WriteAllText(configPath, $"BonusPercentage={qualityBonusPercent}\nAddictionBonusPercentage={addictionBonusPercent}\nAffinityBonusPercentage={affinityBonusPercent}\nAffectsDealers={affectsDealers}"); MelonLogger.Msg("Config file created."); } }