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 4 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."); } }