Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of SkillTree ILC2cpp v1.0.6
SkillTree_IL2cpp.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using Il2CppFishNet; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.Delivery; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.Effects; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.Growing; using Il2CppScheduleOne.Interaction; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Levelling; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.PlayerScripts.Health; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.Quests; using Il2CppScheduleOne.Tools; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.ATM; using Il2CppScheduleOne.UI.Phone; using Il2CppScheduleOne.UI.Phone.Messages; using Il2CppScheduleOne.UI.Shop; using Il2CppScheduleOne.Variables; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using SkillTree; using SkillTree.Json; using SkillTree.SkillEffect; using SkillTree.SkillPatchOperations; using SkillTree.SkillPatchSocial; using SkillTree.SkillPatchStats; using SkillTree.UI; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [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), "SkillTree", "1.0.0", "CrazyReizor", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("SkillTree_IL2cpp")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SkillTree_IL2cpp")] [assembly: AssemblyTitle("SkillTree_IL2cpp")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkillTree { public class Core : MelonMod { public static Core Instance; private TimeManager timeManager; private LevelManager levelManager; private PlayerMovement playerMovement; private Player localPlayer; private PlayerCamera playerCamera; private PlayerInventory playerInventory; private Customer[] customerList; private float timer = 2f; private SkillTreeData skillData; private SkillTreeUI skillTreeUI; private int skillPointValid = 0; private bool waiting = false; private bool firstTime = false; private int lastProcessedTier = -1; private ERank lastProcessedRank = (ERank)(-1); public override void OnInitializeMelon() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ((MelonBase)this).LoggerInstance.Msg("SkillTree Initialized."); Instance = this; Harmony val = new Harmony("com.reizor.skilltree"); val.PatchAll(); ((MelonBase)this).LoggerInstance.Msg("Harmony patches applied."); } public void Init() { ((MelonBase)this).LoggerInstance.Msg("Init()"); if ((Object)(object)timeManager == (Object)null) { timeManager = NetworkSingleton<TimeManager>.Instance; } if ((Object)(object)levelManager == (Object)null) { levelManager = NetworkSingleton<LevelManager>.Instance; } if ((Object)(object)playerMovement == (Object)null) { playerMovement = PlayerSingleton<PlayerMovement>.Instance; } if ((Object)(object)playerCamera == (Object)null) { playerCamera = PlayerSingleton<PlayerCamera>.Instance; } if ((Object)(object)playerInventory == (Object)null) { playerInventory = PlayerSingleton<PlayerInventory>.Instance; } if ((Object)(object)localPlayer == (Object)null) { localPlayer = Player.Local; } if (customerList == null) { customerList = Il2CppArrayBase<Customer>.op_Implicit(Object.FindObjectsOfType<Customer>()); } } public override void OnUpdate() { if (!((Object)(object)NetworkSingleton<TimeManager>.Instance == (Object)null) && !((Object)(object)PlayerSingleton<PlayerMovement>.Instance == (Object)null) && !((Object)(object)PlayerSingleton<PlayerCamera>.Instance == (Object)null) && (waiting || WaitTime())) { bool flag = false; if (Input.GetKeyDown((KeyCode)99) && waiting) { skillTreeUI.Visible = !skillTreeUI.Visible; flag = true; } if (skillTreeUI.Visible) { playerCamera.SetDoFActive(true, 0.06f); } if (!skillTreeUI.Visible) { playerCamera.SetDoFActive(false, 0f); } if (skillTreeUI.Visible && (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)9) || Input.GetMouseButtonDown(1))) { skillTreeUI.Visible = !skillTreeUI.Visible; flag = true; } if (flag) { flag = false; Cursor.lockState = (CursorLockMode)((!skillTreeUI.Visible) ? 1 : 0); Cursor.visible = (skillTreeUI.Visible ? true : false); PlayerSingleton<PlayerMovement>.Instance.CanMove = !skillTreeUI.Visible; ((Behaviour)PlayerSingleton<PlayerCamera>.Instance).enabled = !skillTreeUI.Visible; ((Behaviour)Singleton<PlayerManager>.Instance).enabled = !skillTreeUI.Visible; playerInventory.SetInventoryEnabled(!skillTreeUI.Visible); } } } private bool WaitTime() { if (!firstTime) { if ((Object)(object)timeManager == (Object)null || (Object)(object)levelManager == (Object)null || (Object)(object)playerMovement == (Object)null) { Init(); } skillData = SkillTreeSaveManager.LoadOrCreate(); skillTreeUI = new SkillTreeUI(skillData); SkillSystem.ApplyAll(skillData); } firstTime = true; timer -= Time.deltaTime; if (timer <= 0f) { ItemUnlocker.UnlockSpecificItems(); AttPoints(); waiting = true; return true; } return false; } public void AttPoints(bool levelUp = false) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected I4, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)timeManager == (Object)null || (Object)(object)levelManager == (Object)null || (Object)(object)playerMovement == (Object)null) { Init(); } int num = (int)levelManager.Rank; int num2 = levelManager.Tier - 1; int num3 = num * 6 + num2; int num4 = skillData.StatsPoints + skillData.OperationsPoints + skillData.SocialPoints + skillData.UsedSkillPoints; if (num3 != num4 && !levelUp) { MelonLogger.Msg("Desync detected! Synchronizing points with saved XP in the game..."); string dynamicPath = SkillTreeSaveManager.GetDynamicPath(); if (File.Exists(dynamicPath)) { File.Delete(dynamicPath); } skillData = SkillTreeSaveManager.LoadOrCreate(); skillTreeUI = new SkillTreeUI(skillData); SkillSystem.ApplyAll(skillData); skillPointValid = num3; } if ((num == 0 && num2 == 0) || (levelUp && num2 == lastProcessedTier - 1 && levelManager.Rank == lastProcessedRank)) { return; } if (levelUp) { MelonLogger.Msg("Level Up Detected! Skill points updated."); } if (levelUp) { skillPointValid = 1; if (lastProcessedTier == 5) { skillPointValid = 2; } } lastProcessedTier = levelManager.Tier; lastProcessedRank = levelManager.Rank; int num5 = skillData.StatsPoints + skillData.OperationsPoints + skillData.SocialPoints + skillData.UsedSkillPoints; if (skillPointValid <= 0) { return; } int num6 = 0; int num7 = 0; int num8 = 0; for (int i = 0; i < skillPointValid; i++) { switch ((num5 + i) % 3) { case 0: num6++; break; case 1: num7++; break; case 2: num8++; break; } } if (skillTreeUI == null) { skillTreeUI = new SkillTreeUI(skillData); } if (skillTreeUI != null) { skillTreeUI.AddPoints(num6, num7, num8); } MelonLogger.Msg($"[SkillTree] Processed: Rank {levelManager.Rank} Tier {levelManager.Tier}. Gains: Stats+{num6} Operations+{num7} Social+{num8}"); } public override void OnGUI() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 if (skillTreeUI != null && skillTreeUI.Visible) { skillTreeUI.EnsureSkin(); GUI.skin = skillTreeUI.Skin; if ((int)Event.current.type == 0) { GUI.FocusControl((string)null); } skillTreeUI.Draw(); } } } [HarmonyPatch(typeof(LevelManager), "IncreaseTier")] public static class LevelUp_Patch { [HarmonyPostfix] public static void Postfix() { if (Core.Instance != null) { Core.Instance.AttPoints(levelUp: true); } } } public static class ItemUnlocker { private static readonly Dictionary<string, FullRank> TargetRanks = new Dictionary<string, FullRank> { { "moisturepreservingpot", new FullRank((ERank)1, 5) }, { "ledgrowlight", new FullRank((ERank)1, 3) }, { "plasticpot", new FullRank((ERank)0, 5) }, { "halogengrowlight", new FullRank((ERank)0, 5) }, { "suspensionrack", new FullRank((ERank)0, 5) }, { "airpot", new FullRank((ERank)2, 2) }, { "cauldron", new FullRank((ERank)4, 3) }, { "brickpress", new FullRank((ERank)4, 5) }, { "dryingrack", new FullRank((ERank)0, 5) } }; public static void UnlockSpecificItems() { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) Registry instance = Singleton<Registry>.Instance; if ((Object)(object)instance == (Object)null) { return; } List<ItemDefinition> allItems = instance.GetAllItems(); if (allItems == null) { return; } int num = 0; Enumerator<ItemDefinition> enumerator = allItems.GetEnumerator(); while (enumerator.MoveNext()) { ItemDefinition current = enumerator.Current; if ((Object)(object)current == (Object)null || string.IsNullOrEmpty(current.ID)) { continue; } string text = current.ID.ToLowerInvariant(); if (TargetRanks.TryGetValue(text, out var value)) { StorableItemDefinition val = (StorableItemDefinition)(object)((current is StorableItemDefinition) ? current : null); if ((Object)(object)val != (Object)null) { val.RequiredRank = value; val.RequiresLevelToPurchase = true; num++; MelonLogger.Msg($"[SkillTree Unlocker] Item {text} updated to Rank: {value.Rank}, Tier: {value.Tier}"); } } } MelonLogger.Msg($"[SkillTree Unlocker] Total of {num} items successfully remapped."); } } [HarmonyPatch(typeof(ShopInterface), "Awake")] public static class ShopInjectionPatch { [HarmonyPatch] public static class SpeedEffect_SkillHarmony_Patch { [HarmonyPatch(typeof(Athletic), "ApplyToPlayer")] [HarmonyPostfix] public static void Athletic_Apply_Postfix() { float movespeedBase = PlayerMovespeed.MovespeedBase; PlayerSingleton<PlayerMovement>.Instance.MoveSpeedMultiplier = movespeedBase + 0.3f; } [HarmonyPatch(typeof(Energizing), "ApplyToPlayer")] [HarmonyPostfix] public static void Energizing_Apply_Postfix() { float movespeedBase = PlayerMovespeed.MovespeedBase; PlayerSingleton<PlayerMovement>.Instance.MoveSpeedMultiplier = movespeedBase + 0.15f; } [HarmonyPatch(typeof(Athletic), "ClearFromPlayer")] [HarmonyPostfix] public static void Athletic_Clear_Postfix() { PlayerSingleton<PlayerMovement>.Instance.MoveSpeedMultiplier = PlayerMovespeed.MovespeedBase; } [HarmonyPatch(typeof(Energizing), "ClearFromPlayer")] [HarmonyPostfix] public static void Energizing_Clear_Postfix() { PlayerSingleton<PlayerMovement>.Instance.MoveSpeedMultiplier = PlayerMovespeed.MovespeedBase; } } private static List<string> itemIdsToInject = new List<string> { "moisturepreservingpot", "ledgrowlight", "plasticpot", "halogengrowlight", "suspensionrack", "airpot", "dryingrack" }; [HarmonyPostfix] public static void Postfix(ShopInterface __instance) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown if (!__instance.ShopCode.ToLower().Contains("hardware") && !__instance.ShopCode.ToLower().Contains("handy_hanks")) { return; } StorableItemDefinition[] array = Il2CppArrayBase<StorableItemDefinition>.op_Implicit(Resources.FindObjectsOfTypeAll<StorableItemDefinition>()); foreach (string id in itemIdsToInject) { bool flag = false; Enumerator<ShopListing> enumerator2 = __instance.Listings.GetEnumerator(); while (enumerator2.MoveNext()) { ShopListing current = enumerator2.Current; if ((Object)(object)current.Item != (Object)null && ((ItemDefinition)current.Item).ID.ToLower() == id.ToLower()) { flag = true; break; } } if (flag) { continue; } StorableItemDefinition val = Array.Find(array, (StorableItemDefinition x) => ((ItemDefinition)x).ID.ToLower() == id); if ((Object)(object)val != (Object)null) { ShopListing val2 = new ShopListing(); val2.Item = val; if (id == "moisturepreservingpot") { val2.OverridePrice = true; val2.OverriddenPrice = 125f; } if (id == "ledgrowlight") { val2.OverridePrice = true; val2.OverriddenPrice = 200f; } if (id == "plasticpot") { val2.OverridePrice = true; val2.OverriddenPrice = 50f; } if (id == "halogengrowlight") { val2.OverridePrice = true; val2.OverriddenPrice = 100f; } if (id == "suspensionrack") { val2.OverridePrice = true; val2.OverriddenPrice = 100f; } if (id == "airpot") { val2.OverridePrice = true; val2.OverriddenPrice = 300f; } if (id == "dryingrack") { val2.OverridePrice = true; val2.OverriddenPrice = 400f; } Traverse val3 = Traverse.Create((object)val2); if (val2.IsUnlimitedStock) { val3.Field("isUnlimitedStock").SetValue((object)true); } else if (val3.Field("_isUnlimitedStock").FieldExists()) { val3.Field("_isUnlimitedStock").SetValue((object)true); } __instance.Listings.Add(val2); val2.Initialize(__instance); __instance.CreateListingUI(val2); MelonLogger.Msg("[SkillTree Shop] Item successfully injected: " + ((ItemDefinition)val).Name); } } } } public static class QuickPackagers { public static bool Add; } [HarmonyPatch] public static class RouteExpanderPatch { [HarmonyPatch(typeof(PackagingStation), "Awake")] [HarmonyPostfix] public static void Postfix_Speed(PackagingStation __instance) { if (QuickPackagers.Add) { __instance.PackagerEmployeeSpeedMultiplier = 2f; } } } public static class StackCache { public static Dictionary<string, int> ItemStack = new Dictionary<string, int>(); public static bool IsLoaded = false; public static void FillCache(List<ItemDefinition> business) { if (IsLoaded) { return; } Enumerator<ItemDefinition> enumerator = business.GetEnumerator(); while (enumerator.MoveNext()) { ItemDefinition current = enumerator.Current; string name = ((Object)current).name; if (!ItemStack.ContainsKey(name)) { ItemStack.Add(name, current.StackLimit); } } IsLoaded = true; MelonLogger.Msg("ItemStack Memory successfully stored!"); } } } namespace SkillTree.UI { public class SkillTreeUI { private class SkillField { public string Id; public string Name; public string Description; public string Parent; public SkillCategory Category; public FieldInfo Field; public int MaxLevel; } private Rect windowRect = new Rect(300f, 150f, 600f, 450f); private SkillTreeData originalData; private SkillTreeData editData; private SkillCategory? selectedCategory = null; private List<SkillField> skillFields = new List<SkillField>(); private bool skinReady; private bool guiInitialized = false; private float currentY; public bool Visible { get; set; } public GUISkin Skin { get; private set; } public SkillTreeUI(SkillTreeData data) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) originalData = data; editData = Clone(data); BuildSkillMap(); } public void Draw() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (Visible) { if (!guiInitialized) { CenterWindow(); guiInitialized = true; } windowRect = GUI.Window(9001, windowRect, WindowFunction.op_Implicit((Action<int>)DrawWindow), "Skill Tree"); } } private void DrawWindow(int id) { try { currentY = 80f; GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Label("Skill Tree", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.FlexibleSpace(); GUILayout.Label($"Stats: {editData.StatsPoints}", (Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Space(10f); GUILayout.Label($"Operations: {editData.OperationsPoints}", (Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Space(10f); GUILayout.Label($"Social: {editData.SocialPoints}", (Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.EndHorizontal(); GUILayout.Space(10f); if (!selectedCategory.HasValue) { DrawCategoryButtons(); } else { DrawCategoryHeader(); DrawTreeByCategory(selectedCategory.Value); } GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.EndHorizontal(); GUI.DragWindow(); } catch (Exception ex) { MelonLogger.Msg("SytemNullable shutup " + ex.Message); } } private void DrawCategoryButtons() { GUILayout.Label("Escolha uma categoria", (Il2CppReferenceArray<GUILayoutOption>)null); GUILayout.Space(10f); if (GUILayout.Button("Stats", (Il2CppReferenceArray<GUILayoutOption>)null)) { selectedCategory = SkillCategory.Stats; } if (GUILayout.Button("Operations", (Il2CppReferenceArray<GUILayoutOption>)null)) { selectedCategory = SkillCategory.Operations; } if (GUILayout.Button("Social", (Il2CppReferenceArray<GUILayoutOption>)null)) { selectedCategory = SkillCategory.Social; } } private void DrawCategoryHeader() { GUILayout.BeginHorizontal((Il2CppReferenceArray<GUILayoutOption>)null); if (GUILayout.Button("< Voltar", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) })) { selectedCategory = null; GUILayout.EndHorizontal(); GUILayout.Space(10f); return; } if (selectedCategory.HasValue) { GUILayout.Label(selectedCategory.Value.ToString(), (Il2CppReferenceArray<GUILayoutOption>)null); } GUILayout.EndHorizontal(); GUILayout.Space(10f); } private void DrawTreeByCategory(SkillCategory category) { foreach (SkillField skillField in skillFields) { if (skillField.Parent == null && skillField.Category == category) { DrawSkillNode(skillField, 0); } } } private int GetMaxLevelOfSkill(string skillId) { return skillFields.Find((SkillField s) => s.Id == skillId)?.MaxLevel ?? 1; } private void DrawSkillNode(SkillField skill, int depth) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) float num = 20f + (float)depth * 20f; float num2 = 25f; int num3 = (int)skill.Field.GetValue(editData); int maxLevel = skill.MaxLevel; bool flag = true; if (skill.Parent != null) { int skillValue = GetSkillValue(skill.Parent); int maxLevelOfSkill = GetMaxLevelOfSkill(skill.Parent); flag = skillValue >= maxLevelOfSkill; } bool enabled = flag && num3 < maxLevel && GetPoints(skill.Category) > 0; Rect val = default(Rect); ((Rect)(ref val))..ctor(num, currentY, 250f, 20f); GUI.Label(val, $"{skill.Name} ({num3}/{maxLevel})"); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(num + 270f, currentY, 24f, 20f); if (num3 < maxLevel) { GUI.enabled = enabled; if (GUI.Button(val2, "+")) { int num4 = num3 + 1; skill.Field.SetValue(editData, num4); ConsumePoint(skill.Category); SkillSystem.ApplySkill(skill.Id, editData); SkillTreeSaveManager.Save(editData); } GUI.enabled = true; } else { GUI.Label(val2, "✔"); } if (((Rect)(ref val)).Contains(Event.current.mousePosition)) { DrawTooltip(skill.Description, val); } currentY += num2; if (num3 <= 0) { return; } foreach (SkillField skillField in skillFields) { if (skillField.Parent == skill.Id) { DrawSkillNode(skillField, depth + 1); } } } private void CenterWindow() { ((Rect)(ref windowRect)).x = ((float)Screen.width - ((Rect)(ref windowRect)).width) / 2f; ((Rect)(ref windowRect)).y = ((float)Screen.height - ((Rect)(ref windowRect)).height) / 2f; } private int GetPoints(SkillCategory category) { return category switch { SkillCategory.Stats => editData.StatsPoints, SkillCategory.Operations => editData.OperationsPoints, SkillCategory.Social => editData.SocialPoints, _ => 0, }; } private void ConsumePoint(SkillCategory category) { switch (category) { case SkillCategory.Stats: editData.StatsPoints--; break; case SkillCategory.Operations: editData.OperationsPoints--; break; case SkillCategory.Social: editData.SocialPoints--; break; } editData.UsedSkillPoints++; } private void DrawTree(string parent, int depth) { foreach (SkillField skillField in skillFields) { if (skillField.Parent == parent) { DrawSkill(skillField, depth); } } } private void DrawSkill(SkillField skill, int depth) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) if (skill.Parent == null || GetSkillValue(skill.Parent) != 0) { int num = (int)skill.Field.GetValue(editData); float num2 = 20 + depth * 30; float num3 = 22f; Rect val = default(Rect); ((Rect)(ref val))..ctor(num2, currentY, 250f, 20f); GUI.Label(val, $"{skill.Name}: {num}/1"); bool flag = skill.Parent == null || GetSkillValue(skill.Parent) == 1; bool enabled = num == 0 && GetPoints(skill.Category) > 0 && flag; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(num2 + 260f, currentY, 30f, 20f); GUI.enabled = enabled; if (GUI.Button(val2, "+")) { skill.Field.SetValue(editData, 1); ConsumePoint(skill.Category); SkillTreeSaveManager.Save(editData); } GUI.enabled = true; DrawTooltip(skill.Description, val); currentY += num3; DrawTree(skill.Id, depth); } } private void DrawTooltip(string text, Rect anchorRect) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(text)) { GUIContent val = new GUIContent(text); Vector2 val2 = GUI.skin.box.CalcSize(val); float num = 10f; Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(30f, ((Rect)(ref anchorRect)).y - 20f, val2.x + num, val2.y + num); GUI.Box(val3, text); } } private void BuildSkillMap() { skillFields.Clear(); FieldInfo[] fields = typeof(SkillTreeData).GetFields(BindingFlags.Instance | BindingFlags.Public); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { SkillAttribute customAttribute = fieldInfo.GetCustomAttribute<SkillAttribute>(); if (customAttribute != null) { skillFields.Add(new SkillField { Id = fieldInfo.Name, Name = customAttribute.Name, Description = customAttribute.Description, Parent = customAttribute.Parent, Category = customAttribute.Category, Field = fieldInfo, MaxLevel = customAttribute.MaxLevel }); } } } private int GetSkillValue(string fieldName) { FieldInfo field = typeof(SkillTreeData).GetField(fieldName); return (int)field.GetValue(editData); } private SkillTreeData Clone(SkillTreeData source) { if (source == null) { return null; } string text = JsonConvert.SerializeObject((object)source); return JsonConvert.DeserializeObject<SkillTreeData>(text); } private void Copy(SkillTreeData from, SkillTreeData to) { FieldInfo[] fields = typeof(SkillTreeData).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(to, fieldInfo.GetValue(from)); } } public void EnsureSkin() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_0349: 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_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) if (!skinReady) { Skin = Object.Instantiate<GUISkin>(GUI.skin); Texture2D background = MakeTex(2, 2, new Color(0.15f, 0.15f, 0.15f, 1f)); Texture2D background2 = MakeTex(2, 2, new Color(0.25f, 0.25f, 0.25f, 1f)); Texture2D background3 = MakeTex(2, 2, new Color(0.35f, 0.35f, 0.35f, 1f)); Texture2D background4 = MakeTex(2, 2, new Color(0.2f, 0.2f, 0.2f, 1f)); Texture2D background5 = MakeTex(2, 2, new Color(0.1f, 0.1f, 0.1f, 1f)); GUIStyle val = new GUIStyle(Skin.window); Skin.window.normal.background = background; Skin.window.focused.background = background; val.normal.background = background; val.focused.background = background; val.active.background = background; val.hover.background = background; val.onNormal.background = background; val.onFocused.background = background; val.onActive.background = background; val.onHover.background = background; GUIStyleState normal = val.normal; GUIStyleState focused = val.focused; GUIStyleState active = val.active; GUIStyleState hover = val.hover; GUIStyleState onNormal = val.onNormal; GUIStyleState onFocused = val.onFocused; GUIStyleState onActive = val.onActive; Color val2 = (val.onHover.textColor = Color.white); Color val4 = (onActive.textColor = val2); Color val6 = (onFocused.textColor = val4); Color val8 = (onNormal.textColor = val6); Color val10 = (hover.textColor = val8); Color val12 = (active.textColor = val10); Color textColor = (focused.textColor = val12); normal.textColor = textColor; Skin.window = val; Skin.label.normal.textColor = Color.white; Skin.label.focused.textColor = Color.white; GUIStyle val14 = new GUIStyle(Skin.button); val14.normal.background = background2; val14.hover.background = background3; val14.active.background = background4; val14.focused.background = background2; val14.onNormal.background = background2; val14.onHover.background = background3; val14.onActive.background = background4; val14.onFocused.background = background2; GUIStyleState normal2 = val14.normal; GUIStyleState hover2 = val14.hover; GUIStyleState active2 = val14.active; GUIStyleState focused2 = val14.focused; GUIStyleState onNormal2 = val14.onNormal; GUIStyleState onHover = val14.onHover; GUIStyleState onActive2 = val14.onActive; val2 = (val14.onFocused.textColor = Color.white); val4 = (onActive2.textColor = val2); val6 = (onHover.textColor = val4); val8 = (onNormal2.textColor = val6); val10 = (focused2.textColor = val8); val12 = (active2.textColor = val10); textColor = (hover2.textColor = val12); normal2.textColor = textColor; Skin.button = val14; Skin.box.normal.background = background5; Skin.box.focused.background = background5; Skin.box.normal.textColor = Color.white; Skin.box.focused.textColor = Color.white; Skin.box.wordWrap = true; skinReady = true; } } private Texture2D MakeTex(int w, int h, Color col) { //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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Color[] array = (Color[])(object)new Color[w * h]; for (int i = 0; i < array.Length; i++) { array[i] = col; } Texture2D val = new Texture2D(w, h); val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array)); val.Apply(); return val; } public void AddPoints(int stats, int ops, int social) { editData.StatsPoints += stats; editData.OperationsPoints += ops; editData.SocialPoints += social; originalData.StatsPoints += stats; originalData.OperationsPoints += ops; originalData.SocialPoints += social; SkillTreeSaveManager.Save(editData); } } } namespace SkillTree.Json { public enum SkillCategory { Stats, Operations, Social } [AttributeUsage(AttributeTargets.Field)] public class SkillAttribute : Attribute { public string Name; public string Description; public string Parent; public SkillCategory Category; public int MaxLevel; public SkillAttribute(string name, string description, SkillCategory category, string parent = null, int maxLevel = 2) { Name = name; Description = description; Category = category; Parent = parent; MaxLevel = maxLevel; } } [Serializable] public class SkillTreeData { public int StatsPoints = 0; public int OperationsPoints = 0; public int SocialPoints = 0; public int UsedSkillPoints = 0; [Skill("More Health", "Increase Max Health by +20", SkillCategory.Stats, null, 1)] public int Stats = 0; [Skill("More Movespeed", "Increase 10% by Movespeed", SkillCategory.Stats, "Stats", 3)] public int MoreMovespeed = 0; [Skill("More XP", "Increase XP Gain by 5%", SkillCategory.Stats, "Stats", 2)] public int MoreXP = 0; [Skill("More Item Stack (x2)", "Increase Item Stack (x2)", SkillCategory.Stats, "MoreXP", 1)] public int MoreStackItem = 0; [Skill("More XP Per Sell When Earn Money", "Earn 5% bonus XP based on item value when selling drugs", SkillCategory.Stats, "MoreXP", 1)] public int MoreXPWhenEarnMoney = 0; [Skill("Better Delivery", "Make Deliveries More Fast (6H -> 2H)", SkillCategory.Stats, "Stats", 1)] public int BetterDelivery = 0; [Skill("Allow Sleep with Athletic or Energizing", "Allow sleeping while Athletic or Energizing effects are active", SkillCategory.Stats, "Stats", 1)] public int AllowSleepAthEne = 0; [Skill("Counteroffer Perception", "Allows you to see the chance of a customer making a counteroffer", SkillCategory.Stats, "Stats", 1)] public int AllowSeeCounteroffChance = 0; [Skill("Allow Use Bed to Skip the Current Schedule", "Skip Schedule Only Affect Plants (Plants Grow 33% of the time)", SkillCategory.Stats, "AllowSleepAthEne", 1)] public int SkipSchedule = 0; [Skill("More XP 2", "Increase XP Gain by an additional 5%", SkillCategory.Stats, "MoreXP", 4)] public int MoreXP2 = 0; [Skill("Better Grow Tent Quality", "Improve Grow Tent Quality (Trash -> Low)", SkillCategory.Operations, null, 1)] public int Operations = 0; [Skill("Increase Growth Speed", "Increase Growth Speed by 2.5%", SkillCategory.Operations, "Operations", 2)] public int GrowthSpeed = 0; [Skill("More Yield", "Increase Yield by 1 (Excludes Mushrooms/Grow Tents)", SkillCategory.Operations, "GrowthSpeed", 1)] public int MoreYield = 0; [Skill("Advanced Pot Techniques", "+15% Quality. [Lvl 1] Moisture Pots gain +1 Tier. [Max Lvl] All Pots gain +1 Tier.", SkillCategory.Operations, "MoreYield", 2)] public int MoreQuality = 0; [Skill("More Quality Mushroom", "Upgrade Mushroom Quality Tier", SkillCategory.Operations, "MoreQuality", 1)] public int MoreQualityMushroom = 0; [Skill("More Quality Meth", "Upgrade Meth Quality Tier", SkillCategory.Operations, "MoreYield", 1)] public int MoreQualityMeth = 0; [Skill("Increase Growth Speed 2°", "Increase Growth Speed by 2.5%", SkillCategory.Operations, "MoreQuality", 2)] public int GrowthSpeed2 = 0; [Skill("Chemist Station Quick", "Increase the speed of ALL Chemistry Station (x2 or a little more)", SkillCategory.Operations, "MoreYield", 1)] public int ChemistStationQuick = 0; [Skill("More Mix and Drying Rack Output", "Double Mix and Drying Rack Output", SkillCategory.Operations, "ChemistStationQuick", 1)] public int MoreMixAndDryingRackOutput = 0; [Skill("AbsorbentSoil", "Preserve soil additives", SkillCategory.Operations, "ChemistStationQuick", 1)] public int AbsorbentSoil = 0; [Skill("More Cauldron Output", "Double Cauldron Output", SkillCategory.Operations, "MoreMixAndDryingRackOutput", 1)] public int MoreCauldronOutput = 0; [Skill("More sample chance", "Increase Sample Chance by 5%", SkillCategory.Social, null, 2)] public int Social = 0; [Skill("Civil More Money per week", "Increase Citizens' weekly money by 10%", SkillCategory.Social, "Social", 2)] public int CityEvolving = 0; [Skill("More ATM Limit", "Increase ATM Deposit Limit by +1500", SkillCategory.Social, "Social", 4)] public int MoreATMLimit = 0; [Skill("Better Business", "Increase Max Money Laundering Capacity by 20%", SkillCategory.Social, "Social", 3)] public int BusinessEvolving = 0; [Skill("Dealer More Customer", "Increase Dealer Customers (+2)", SkillCategory.Social, "Social", 1)] public int DealerMoreCustomer = 0; [Skill("Less Dealer Cut", "Decrease Dealer's Cut by 5%", SkillCategory.Social, "DealerMoreCustomer", 2)] public int DealerCutLess = 0; [Skill("Better Supplier", "Increase Debt and Item Limits by 50%", SkillCategory.Social, "Social", 2)] public int BetterSupplier = 0; [Skill("Dealer Speed Up", "Increase Movespeed Speed of Dealers (2x)", SkillCategory.Social, "DealerMoreCustomer", 1)] public int DealerSpeedUp = 0; } public static class SkillTreeSaveManager { public static string GetDynamicPath() { string currentSaveID = GetCurrentSaveID(); return Path.Combine(MelonEnvironment.UserDataDirectory, "SkillTree_" + currentSaveID + ".json"); } public static SkillTreeData LoadOrCreate() { string dynamicPath = GetDynamicPath(); if (!File.Exists(dynamicPath)) { MelonLogger.Msg("[SkillTree] Novo save detectado ou arquivo ausente: " + dynamicPath); CustomerCache.IsLoaded = false; CustomerCache.OriginalMinSpend.Clear(); CustomerCache.OriginalMaxSpend.Clear(); SkillTreeData skillTreeData = CreateDefault(); Save(skillTreeData); return skillTreeData; } try { string text = File.ReadAllText(dynamicPath); return JsonConvert.DeserializeObject<SkillTreeData>(text); } catch (Exception value) { MelonLogger.Error($"[SkillTree] Save corrupted, recreating.\n{value}"); SkillTreeData skillTreeData2 = CreateDefault(); Save(skillTreeData2); return skillTreeData2; } } public static void Save(SkillTreeData data) { string dynamicPath = GetDynamicPath(); string contents = JsonConvert.SerializeObject((object)data, (Formatting)1); File.WriteAllText(dynamicPath, contents); } private static SkillTreeData CreateDefault() { return new SkillTreeData(); } public static string GetCurrentSaveID() { string loadedGameFolderPath = Singleton<LoadManager>.Instance.LoadedGameFolderPath; if (string.IsNullOrEmpty(loadedGameFolderPath)) { return "DefaultPlayer"; } return Path.GetFileName(loadedGameFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); } } } namespace SkillTree.SkillPatchStats { public static class PlayerMovespeed { public static float MovespeedBase = 1f; } public static class PlayerXpMoney { public static bool XpMoney; } public static class PlayerHealthConfig { public static float MaxHealth = 100f; } [HarmonyPatch(typeof(PlayerHealth))] public class PatchPlayerHealth { [HarmonyPatch("SetHealth")] [HarmonyPrefix] public static bool Prefix_SetHealth(PlayerHealth __instance, float health) { float value = Mathf.Clamp(health, 0f, PlayerHealthConfig.MaxHealth); SetInternalHealth(__instance, value); return false; } [HarmonyPatch("RecoverHealth")] [HarmonyPrefix] public static bool Prefix_RecoverHealth(PlayerHealth __instance, float recovery) { if (__instance.CurrentHealth <= 0f) { return false; } float value = Mathf.Clamp(__instance.CurrentHealth + recovery, 0f, PlayerHealthConfig.MaxHealth); SetInternalHealth(__instance, value); return false; } [HarmonyPatch("TakeDamage")] [HarmonyPrefix] public static bool Prefix_TakeDamage(PlayerHealth __instance, float damage) { if (!__instance.IsAlive || !__instance.CanTakeDamage) { return false; } float num = Mathf.Clamp(__instance.CurrentHealth - damage, 0f, PlayerHealthConfig.MaxHealth); SetInternalHealth(__instance, num); __instance.TimeSinceLastDamage = 0f; if (num <= 0f) { __instance.SendDie(); } return false; } private static void SetInternalHealth(PlayerHealth instance, float value) { float currentHealth_k__BackingField = instance._CurrentHealth_k__BackingField; instance._CurrentHealth_k__BackingField = value; instance.onHealthChanged?.Invoke(value); } } public static class PlayerXPConfig { public static float XpBase = 100f; public static float XpBase2 = 100f; } [HarmonyPatch(typeof(LevelManager), "AddXP")] public class PatchLevelManager { private static bool _jaProcessado; [HarmonyPrefix] public static void Prefix(LevelManager __instance, ref int xp) { if (!_jaProcessado) { float num = PlayerXPConfig.XpBase / 100f; if (num != 1f) { _jaProcessado = true; int value = xp; xp = Mathf.CeilToInt((float)xp * num); MelonLogger.Msg($"[XP] Apply: {value} -> {xp} (Base: {PlayerXPConfig.XpBase}%)"); MelonLogger.Msg("Total XP Now: " + (__instance.TotalXP + xp)); } } } [HarmonyPostfix] public static void Postfix() { _jaProcessado = false; } } [HarmonyPatch(typeof(Contract), "SubmitPayment")] public class PatchContractPayment { private static bool _jaProcessado; [HarmonyPrefix] public static void Prefix(Contract __instance, float bonusTotal) { if (_jaProcessado || !PlayerXpMoney.XpMoney) { return; } float payment = __instance.Payment; if (!(payment > 0f)) { return; } int num = Mathf.RoundToInt(payment * 0.05f); if (num > 0) { LevelManager instance = NetworkSingleton<LevelManager>.Instance; if ((Object)(object)instance != (Object)null) { MelonLogger.Msg($"[Contract] Payment of ${payment} converted into {num} base XP."); instance.AddXP(num); _jaProcessado = true; } } } [HarmonyPostfix] public static void Postfix() { _jaProcessado = false; } } public static class SkipSchedule { public static bool Add; } public static class AllowSleepAthEne { public static bool Add; } public static class ScheduleLogic { [HarmonyPatch(typeof(Bed), "CanSleep")] public static class Bed_AlwaysAllow { [HarmonyPrefix] public static bool Prefix(ref bool __result) { float num = NetworkSingleton<TimeManager>.Instance.CurrentTime; if (!AllowSleepAthEne.Add) { return true; } if (num > 700f && num < 1800f && !SkipSchedule.Add) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Bed), "Hovered")] public static class Bed_Hovered_Patch { [HarmonyPrefix] public static bool Prefix(Bed __instance) { if (!SkipSchedule.Add) { return true; } InteractableObject intObj = __instance.intObj; if (Singleton<ManagementClipboard>.Instance.IsEquipped || (Object)(object)__instance.AssignedEmployee != (Object)null) { return true; } float num = NetworkSingleton<TimeManager>.Instance.CurrentTime; if (num >= 0f && num < 700f) { return true; } if (!CanUseBedSkill() && num <= 1800f) { intObj.SetMessage("You've already rested today! Use it only tomorrow."); } else { if (!CanUseBedSkill() || !(num < 2357f)) { return true; } string timeRemaining = GetTimeRemaining(num); intObj.SetMessage("Next Shift in: " + timeRemaining); } return false; } } [HarmonyPatch(typeof(Bed), "Interacted")] public static class Bed_Interacted_Patch { [HarmonyPrefix] public static bool Prefix() { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected I4, but got Unknown if (!SkipSchedule.Add) { return true; } if (!CanUseBedSkill()) { MelonLogger.Msg("[BedSkill] You've already rested today! Use it only tomorrow."); return true; } float num = NetworkSingleton<TimeManager>.Instance.CurrentTime; if (num >= 700f) { int nextSchedule = GetNextSchedule(); int num2 = CalculateMinutesBetween(num, nextSchedule) / 3; if (num2 > 0) { foreach (GrowContainer item in Object.FindObjectsOfType<GrowContainer>()) { AccessTools.Method(typeof(GrowContainer), "DrainMoisture", (Type[])null, (Type[])null)?.Invoke(item, new object[1] { num2 * 3 }); } foreach (Plant item2 in Object.FindObjectsOfType<Plant>()) { item2.MinPass(num2); } } lastDayUsed = (int)NetworkSingleton<TimeManager>.Instance.CurrentDay; NetworkSingleton<TimeManager>.Instance.SetTime(nextSchedule, false); MelonLogger.Msg($"[BedSkill] Interação detectada. Próximo schedule definido para: {nextSchedule}"); return false; } return true; } } private static int lastDayUsed = -1; public static bool CanUseBedSkill() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected I4, but got Unknown int num = (int)NetworkSingleton<TimeManager>.Instance.CurrentDay; return num != lastDayUsed; } public static string GetTimeRemaining(float currentTime) { int num = GetNextSchedule(); if (num == 0) { num = 2400; } int num2 = (int)currentTime / 100 * 60 + (int)currentTime % 100; int num3 = num / 100 * 60 + num % 100; int num4 = num3 - num2; int value = num4 / 60; int value2 = num4 % 60; return $"{value:00}h {value2:00}m"; } public static int GetNextSchedule() { float num = NetworkSingleton<TimeManager>.Instance.CurrentTime; if (num >= 700f && num < 1200f) { return 1200; } if (num >= 1203f && num < 1800f) { return 1800; } if (num >= 1803f && num < 2357f) { return 2357; } return (int)num; } private static int CalculateMinutesBetween(float start, float end) { if (end == 0f) { end = 2400f; } int num = (int)start / 100; int num2 = (int)start % 100; int num3 = (int)end / 100; int num4 = (int)end % 100; int num5 = num * 60 + num2; int num6 = num3 * 60 + num4; return num6 - num5; } } public static class CounterofferHelper { [HarmonyPatch(typeof(CounterofferInterface), "Open")] public static class Counteroffer_Open_Patch { [HarmonyPostfix] public static void Postfix(CounterofferInterface __instance) { if (Counteroffer) { CreateSuccessLabel(__instance); UpdateSuccessLabel(__instance); } } } [HarmonyPatch(typeof(CounterofferInterface), "ChangeQuantity")] public static class Counteroffer_ChangeQuantity_Patch { [HarmonyPostfix] public static void Postfix(CounterofferInterface __instance) { if (Counteroffer) { UpdateSuccessLabel(__instance); } } } [HarmonyPatch(typeof(CounterofferInterface), "ChangePrice")] public static class Counteroffer_ChangePrice_Patch { [HarmonyPostfix] public static void Postfix(CounterofferInterface __instance) { if (Counteroffer) { UpdateSuccessLabel(__instance); } } } public static bool Counteroffer; public static Text SuccessLabel; public static float CalculateSuccessChance(CounterofferInterface instance) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) MSGConversation conversation = instance.conversation; float price = instance.price; ProductDefinition selectedProduct = instance.selectedProduct; int quantity = instance.quantity; Customer component = ((Component)conversation.sender).GetComponent<Customer>(); CustomerData customerData = component.CustomerData; NPC nPC = component.NPC; float adjustedWeeklySpend = customerData.GetAdjustedWeeklySpend(nPC.RelationData.RelationDelta / 5f); List<EDay> orderDays = customerData.GetOrderDays(component.CurrentAddiction, nPC.RelationData.RelationDelta / 5f); float num = adjustedWeeklySpend / (float)orderDays.Count; if (price >= num * 3f) { return 0f; } float valueProposition = Customer.GetValueProposition(Registry.GetItem<ProductDefinition>(component.OfferedContractInfo.Products.entries[0].ProductID), component.OfferedContractInfo.Payment / (float)component.OfferedContractInfo.Products.entries[0].Quantity); float productEnjoyment = component.GetProductEnjoyment(selectedProduct, StandardsMethod.GetCorrespondingQuality(customerData.Standards)); float num2 = Mathf.InverseLerp(-1f, 1f, productEnjoyment); float valueProposition2 = Customer.GetValueProposition(selectedProduct, price / (float)quantity); float num3 = Mathf.Pow((float)quantity / (float)component.OfferedContractInfo.Products.entries[0].Quantity, 0.6f); float num4 = Mathf.Lerp(0f, 2f, num3 * 0.5f); float num5 = Mathf.Lerp(1f, 0f, Mathf.Abs(num4 - 1f)); if (valueProposition2 * num5 > valueProposition) { return 1f; } if (valueProposition2 < 0.12f) { return 0f; } float num6 = productEnjoyment * valueProposition; float num7 = num2 * num5 * valueProposition2; if (num7 > num6) { return 1f; } float num8 = num6 - num7; float num9 = Mathf.Lerp(0f, 1f, num8 / 0.2f); float num10 = Mathf.Max(component.CurrentAddiction, nPC.RelationData.NormalizedRelationDelta); float num11 = Mathf.Lerp(0f, 0.2f, num10); if (num9 <= num11) { return 1f; } if (num9 - num11 >= 0.9f) { return 0f; } float num12 = (0.9f + num11 - num9) / 0.9f; return Mathf.Clamp(num12, 0f, 1f); } public static void CreateSuccessLabel(CounterofferInterface instance) { //IL_0082: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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_013c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)SuccessLabel != (Object)null)) { Text fairPriceLabel = instance.FairPriceLabel; Transform parent = ((Component)fairPriceLabel).transform.parent; GameObject val = Object.Instantiate<GameObject>(((Component)fairPriceLabel).gameObject, parent); ((Object)val).name = "SuccessChanceLabel"; SuccessLabel = val.GetComponent<Text>(); SuccessLabel.font = fairPriceLabel.font; SuccessLabel.fontSize = fairPriceLabel.fontSize; SuccessLabel.fontStyle = (FontStyle)1; SuccessLabel.alignment = fairPriceLabel.alignment; ((Graphic)SuccessLabel).color = Color.black; SuccessLabel.supportRichText = true; ((Behaviour)SuccessLabel).enabled = true; SuccessLabel.text = "Success chance: --%"; LayoutElement val2 = val.AddComponent<LayoutElement>(); val2.ignoreLayout = true; RectTransform rectTransform = ((Graphic)fairPriceLabel).rectTransform; RectTransform rectTransform2 = ((Graphic)SuccessLabel).rectTransform; rectTransform2.anchorMin = rectTransform.anchorMin; rectTransform2.anchorMax = rectTransform.anchorMax; rectTransform2.pivot = rectTransform.pivot; rectTransform2.sizeDelta = rectTransform.sizeDelta; rectTransform2.anchoredPosition = rectTransform.anchoredPosition + new Vector2(0f, -23f); val.transform.SetAsLastSibling(); } } public static void UpdateSuccessLabel(CounterofferInterface instance) { if (!((Object)(object)SuccessLabel == (Object)null)) { float num = CalculateSuccessChance(instance); string value = ((num >= 0.75f) ? "#4CAF50" : ((num >= 0.4f) ? "#FFC107" : "#F44336")); SuccessLabel.text = $"<color={value}>Success chance: {num * 100f:0}%</color>"; } } } public static class BetterDelivery { public static bool Add; } [HarmonyPatch(typeof(DeliveryManager), "SendDelivery")] public static class DeliveryTime_Patch { [HarmonyPrefix] public static void Prefix(ref DeliveryInstance delivery) { if (BetterDelivery.Add && delivery != null && delivery.TimeUntilArrival > 120) { int timeUntilArrival = delivery.TimeUntilArrival; float num = Mathf.InverseLerp(60f, 360f, (float)timeUntilArrival); int num2 = Mathf.RoundToInt(Mathf.Lerp(30f, 120f, num)); delivery.TimeUntilArrival = num2; MelonLogger.Msg($"[DeliverySkill] Delivery scaling adjusted. Original: {timeUntilArrival}m | New: {num2}m"); } } } } namespace SkillTree.SkillPatchSocial { public static class CustomerCache { public static Dictionary<string, float> OriginalMinSpend = new Dictionary<string, float>(); public static Dictionary<string, float> OriginalMaxSpend = new Dictionary<string, float>(); public static bool IsLoaded = false; public static void FillCache(List<Customer> customers) { if (IsLoaded) { return; } foreach (Customer customer in customers) { string name = ((Object)customer.CustomerData).name; if (!OriginalMinSpend.ContainsKey(name)) { OriginalMinSpend.Add(name, customer.CustomerData.MinWeeklySpend); OriginalMaxSpend.Add(name, customer.CustomerData.MaxWeeklySpend); } } IsLoaded = true; MelonLogger.Msg("Customer spending history successfully stored!"); } } public static class BusinessCache { public static Dictionary<string, float> LaunderCapacity = new Dictionary<string, float>(); public static bool IsLoaded = false; public static void FillCache(List<Business> business) { if (IsLoaded) { return; } foreach (Business item in business) { string propertyName = ((Property)item).PropertyName; if (!LaunderCapacity.ContainsKey(propertyName)) { LaunderCapacity.Add(propertyName, item.LaunderCapacity); } } IsLoaded = true; MelonLogger.Msg("Business Laundering Memory successfully stored!"); } } public static class ATMConfig { public static float MaxWeeklyLimit = 10000f; } [HarmonyPatch(typeof(ATMInterface))] public static class ATM_DynamicLimit_IL2CPP_Final_Patch { [HarmonyPatch("get_remainingAllowedDeposit")] [HarmonyPrefix] public static bool PrefixGetRemaining(ref float __result) { __result = Mathf.Max(0f, ATMConfig.MaxWeeklyLimit - ATM.WeeklyDepositSum); return false; } [HarmonyPatch("GetAmountFromIndex")] [HarmonyPrefix] public static bool PrefixGetAmount(int index, bool depositing, ref float __result) { if (index == -1 || index >= ((Il2CppArrayBase<int>)(object)ATMInterface.amounts).Length) { __result = 0f; return false; } if (depositing && index == ((Il2CppArrayBase<int>)(object)ATMInterface.amounts).Length - 1) { float num = Mathf.Max(0f, ATMConfig.MaxWeeklyLimit - ATM.WeeklyDepositSum); __result = Mathf.Min(NetworkSingleton<MoneyManager>.Instance.cashBalance, num); return false; } __result = ((Il2CppArrayBase<int>)(object)ATMInterface.amounts)[index]; return false; } [HarmonyPatch("SetSelectedAmount")] [HarmonyPrefix] public static bool PrefixSetSelected(ATMInterface __instance, float amount) { float num = Mathf.Max(0f, ATMConfig.MaxWeeklyLimit - ATM.WeeklyDepositSum); float num2 = NetworkSingleton<MoneyManager>.Instance.sync___get_value_onlineBalance(); float num3 = ((!__instance.depositing) ? num2 : Mathf.Min(NetworkSingleton<MoneyManager>.Instance.cashBalance, num)); __instance.selectedAmount = Mathf.Clamp(amount, 0f, num3); if ((Object)(object)__instance.amountLabelText != (Object)null) { __instance.amountLabelText.text = MoneyManager.FormatAmount(__instance.selectedAmount, false, false); } return false; } [HarmonyPatch("Update")] [HarmonyPostfix] public static void PostfixUpdate(ATMInterface __instance) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (__instance.isOpen) { bool flag = ATM.WeeklyDepositSum >= ATMConfig.MaxWeeklyLimit; if ((Object)(object)__instance.menu_DepositButton != (Object)null) { ((Selectable)__instance.menu_DepositButton).interactable = !flag; } if ((Object)(object)__instance.depositLimitText != (Object)null) { __instance.depositLimitText.text = MoneyManager.FormatAmount(ATM.WeeklyDepositSum, false, false) + " / " + MoneyManager.FormatAmount(ATMConfig.MaxWeeklyLimit, false, false); ((Graphic)__instance.depositLimitText).color = (flag ? Color32.op_Implicit(new Color32(byte.MaxValue, (byte)75, (byte)75, byte.MaxValue)) : Color.white); } } } [HarmonyPatch("UpdateAvailableAmounts")] [HarmonyPrefix] public static bool PrefixUpdateAmounts(ATMInterface __instance) { if (__instance.depositing) { float cashBalance = NetworkSingleton<MoneyManager>.Instance.cashBalance; float num = Mathf.Max(0f, ATMConfig.MaxWeeklyLimit - ATM.WeeklyDepositSum); List<Button> amountButtons = __instance.amountButtons; for (int i = 0; i < ((Il2CppArrayBase<int>)(object)ATMInterface.amounts).Length && i < amountButtons.Count; i++) { float num2 = ((Il2CppArrayBase<int>)(object)ATMInterface.amounts)[i]; if (i == ((Il2CppArrayBase<int>)(object)ATMInterface.amounts).Length - 1) { ((Selectable)amountButtons[i]).interactable = cashBalance > 0f && num > 0f; } else { ((Selectable)amountButtons[i]).interactable = cashBalance >= num2 && num2 <= num; } } return false; } return true; } } public static class CustomerSample { public static float AddSampleChance; } [HarmonyPatch(typeof(Customer), "GetSampleSuccess")] public class PatchSampleSuccessUI { private static int _depth; [HarmonyPrefix] public static void Prefix() { _depth++; } [HarmonyPostfix] public static void Postfix(ref float __result, float __state) { if (_depth == 1) { if (CustomerSample.AddSampleChance <= 0f) { return; } float value = __result; __result = Mathf.Clamp(__result + CustomerSample.AddSampleChance, 0f, 1f); MelonLogger.Msg($"[Skill] Chance de Sample alterada de: {value:P0} para {__result:P0}"); } _depth--; } } public static class DealerUpCustomer { public static int MaxCustomer = 8; } [HarmonyPatch(typeof(DealerManagementApp))] public class DealerManagementPatch { private static int GetDynamicLimit() { return DealerUpCustomer.MaxCustomer; } [HarmonyPatch("Awake")] [HarmonyPostfix] public static void Awake_Postfix(DealerManagementApp __instance) { CheckAndExpandUI(__instance); if ((Object)(object)__instance.AssignCustomerButton != (Object)null) { ((Component)__instance.AssignCustomerButton).transform.SetSiblingIndex(1); } if ((Object)(object)__instance.CustomerTitleLabel != (Object)null) { ((Component)__instance.CustomerTitleLabel).transform.SetAsFirstSibling(); } LayoutRebuilder.ForceRebuildLayoutImmediate(__instance.Content); } [HarmonyPatch("SetDisplayedDealer")] [HarmonyPostfix] public static void SetDisplayedDealer_Postfix(DealerManagementApp __instance, Dealer dealer) { CheckAndExpandUI(__instance); int dynamicLimit = GetDynamicLimit(); if ((Object)(object)__instance.CustomerTitleLabel != (Object)null) { __instance.CustomerTitleLabel.text = $"Assigned Customers ({dealer.AssignedCustomers.Count}/{dynamicLimit})"; } if ((Object)(object)__instance.AssignCustomerButton != (Object)null) { ((Component)__instance.AssignCustomerButton).gameObject.SetActive(dealer.AssignedCustomers.Count < dynamicLimit); ((Component)__instance.AssignCustomerButton).transform.SetSiblingIndex(1); } for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)__instance.CustomerEntries).Length; i++) { if (dealer.AssignedCustomers.Count > i) { Customer customer = dealer.AssignedCustomers[i]; RectTransform val = ((Il2CppArrayBase<RectTransform>)(object)__instance.CustomerEntries)[i]; ((Component)((Transform)val).Find("Mugshot")).GetComponent<Image>().sprite = customer.NPC.MugshotSprite; ((Component)((Transform)val).Find("Name")).GetComponent<Text>().text = customer.NPC.fullName; Button component = ((Component)((Transform)val).Find("Remove")).GetComponent<Button>(); ((UnityEventBase)component.onClick).RemoveAllListeners(); ((UnityEvent)component.onClick).AddListener(UnityAction.op_Implicit((Action)delegate { dealer.SendRemoveCustomer(customer.NPC.ID); __instance.SetDisplayedDealer(dealer); })); ((Component)val).gameObject.SetActive(true); } else { ((Component)((Il2CppArrayBase<RectTransform>)(object)__instance.CustomerEntries)[i]).gameObject.SetActive(false); } } } private static void CheckAndExpandUI(DealerManagementApp __instance) { int dynamicLimit = GetDynamicLimit(); if (((Il2CppArrayBase<RectTransform>)(object)__instance.CustomerEntries).Length < dynamicLimit) { List<RectTransform> list = ((IEnumerable<RectTransform>)__instance.CustomerEntries).ToList(); RectTransform val = list[0]; Transform parent = ((Transform)val).parent; while (list.Count < dynamicLimit) { RectTransform val2 = Object.Instantiate<RectTransform>(val, parent); ((Object)val2).name = "CustomerEntry_Mod_Slot_" + list.Count; list.Add(val2); } __instance.CustomerEntries = Il2CppReferenceArray<RectTransform>.op_Implicit(list.ToArray()); LayoutRebuilder.ForceRebuildLayoutImmediate(__instance.Content); } } } public static class SupplierUp { public static float SupplierInc = 1f; public static int SupplierLimit = 10; } [HarmonyPatch(typeof(PhoneShopInterface))] public class PhoneShopGlobalPatch { [HarmonyPatch("CartChanged")] [HarmonyPrefix] public static bool CartChanged_Prefix(PhoneShopInterface __instance) { MelonLogger.Msg(" 1 "); if ((Object)(object)__instance == (Object)null) { return true; } int num = default(int); float orderTotal = __instance.GetOrderTotal(ref num); __instance.UpdateOrderTotal(); MelonLogger.Msg($"Order Total: {orderTotal} | Items: {num}"); if (orderTotal > 0f && orderTotal <= __instance.orderLimit) { ((Selectable)__instance.ConfirmButton).interactable = num <= SupplierUp.SupplierLimit; MelonLogger.Msg($"Can Confirm: {((Selectable)__instance.ConfirmButton).interactable} (Limit: {10 + SupplierUp.SupplierLimit})"); } return false; } } [HarmonyPatch(typeof(Supplier), "GetDeadDropLimit")] public static class Supplier_GetDeadDropLimit_Patch { [HarmonyPrefix] public static bool Prefix(Supplier __instance, ref float __result) { if (SupplierUp.SupplierLimit == 10) { return true; } __result = __instance.MaxOrderLimit * SupplierUp.SupplierInc; return false; } } public static class BetterBusiness { public static float Add; } [HarmonyPatch] public static class BusinessLaunderingPatch { [HarmonyPatch(typeof(Business), "MinsPass")] [HarmonyPrefix] public static bool Prefix_MinsPass(Business __instance, int mins) { string propertyName = ((Property)__instance).propertyName; for (int i = 0; i < __instance.LaunderingOperations.Count; i++) { LaunderingOperation val = __instance.LaunderingOperations[i]; int minutesSinceStarted = val.minutesSinceStarted; val.minutesSinceStarted += mins; if (val.minutesSinceStarted < val.completionTime_Minutes) { int num = minutesSinceStarted / 240; int num2 = val.minutesSinceStarted / 240; if (num2 > num) { float num3 = Mathf.Ceil(val.amount / 6f); if (InstanceFinder.IsServer) { NetworkSingleton<MoneyManager>.Instance.CreateOnlineTransaction("Partial Laundering (" + propertyName + ")", num3, 1f, string.Empty); MelonLogger.Msg($"[LaunderingMod] Partial payout of {num3} processed for {propertyName}"); } Singleton<NotificationsManager>.Instance.SendNotification(propertyName, "<color=#16F01C>" + MoneyManager.FormatAmount(num3, false, false) + "</color> Laundered (Partial)", NetworkSingleton<MoneyManager>.Instance.LaunderingNotificationIcon, 5f, true); } } if (val.minutesSinceStarted >= val.completionTime_Minutes) { val.amount /= 6f; __instance.CompleteOperation(val); MelonLogger.Msg("[LaunderingMod] Operation completed for " + propertyName + ". Final installment paid."); i--; } } return false; } } } namespace SkillTree.SkillPatchOperations { public static class AbsorbentSoil { public static bool Add; } [HarmonyPatch(typeof(Pot), "OnPlantFullyHarvested")] public static class Pot_OnPlantFullyHarvested_Patch { private static bool Prefix(Pot __instance) { if (!AbsorbentSoil.Add) { return true; } try { Plant plant = __instance.Plant; if ((Object)(object)plant == (Object)null) { MelonLogger.Msg("OnPlantFullyHarvested skipped: Plant is null"); return false; } if (InstanceFinder.IsServer) { float value = NetworkSingleton<VariableDatabase>.Instance.GetValue<float>("HarvestedPlantCount"); NetworkSingleton<VariableDatabase>.Instance.SetVariableValue("HarvestedPlantCount", (value + 1f).ToString(), true); NetworkSingleton<LevelManager>.Instance.AddXP(5); MelonLogger.Msg("Server harvest processed"); } int num = ((GrowContainer)__instance)._remainingSoilUses - 1; ((GrowContainer)__instance).SetRemainingSoilUses(num); __instance.SetSoilState((ESoilState)0); if (num <= 0) { MelonLogger.Msg("Soil depleted: clearing soil and additives"); ((GrowContainer)__instance).ClearAdditives(); ((GrowContainer)__instance).ClearSoil(); } else { MelonLogger.Msg("Soil still usable: additives preserved"); } return false; } catch (Exception value2) { MelonLogger.Error($"OnPlantFullyHarvested patch failed: {value2}"); return true; } } } public static class CauldronOutputAdd { public static int Add = 10; } [HarmonyPatch(typeof(Cauldron), "RpcLogic___FinishCookOperation_2166136261")] public static class Cauldron_Finish_Patch { [HarmonyPrefix] public static void Prefix(Cauldron __instance) { } } [HarmonyPatch(typeof(QualityItemDefinition), "GetDefaultInstance", new Type[] { typeof(int) })] public static class Cauldron_Double_Output_Patch { [HarmonyPrefix] public static void Prefix(QualityItemDefinition __instance, ref int quantity) { if (CauldronOutputAdd.Add != 10 && ((Object)__instance).name.Contains("CocaineBase") && quantity == 10) { quantity = CauldronOutputAdd.Add; } } } public static class StationTimeLess { public static float TimeAjust = 1f; } [HarmonyPatch(typeof(Cauldron), "MinPass")] public static class Cauldron_Speed_Patch { [HarmonyPrefix] public static void Prefix(Cauldron __instance) { if (__instance.RemainingCookTime > 0 && StationTimeLess.TimeAjust > 1f) { int remainingCookTime = __instance.RemainingCookTime; __instance.RemainingCookTime = remainingCookTime - 1; } } } [HarmonyPatch(typeof(ChemistryStation), "MinPass")] public static class ChemistryStation_MinPass_IL2CPP_Patch { [HarmonyPrefix] public static void Prefix(ChemistryStation __instance) { if (StationTimeLess.TimeAjust > 1f && __instance.CurrentCookOperation != null) { __instance.CurrentCookOperation.Progress(1); } } } [HarmonyPatch(typeof(LabOven), "MinPass")] public static class Oven_FastProgress_IL2CPP_Patch { [HarmonyPostfix] public static void Prefix(LabOven __instance) { if (StationTimeLess.TimeAjust > 1f && __instance.CurrentOperation != null) { OvenCookOperation currentOperation = __instance.CurrentOperation; int cookProgress = currentOperation.CookProgress; currentOperation.CookProgress = cookProgress + 1; } } } public static class MixOutputAdd { public static int Add = 1; public static int TimeAjust = 1; } [HarmonyPatch(typeof(MixingStation))] public static class MixStationPatch { [HarmonyPatch("GetMixQuantity")] [HarmonyPostfix] public static void Postfix(MixingStation __instance, ref int __result) { if (__result > 0 && __instance.ProductSlot != null && __instance.MixerSlot != null) { int quantity = __instance.ProductSlot.Quantity; int quantity2 = __instance.MixerSlot.Quantity; int num = Mathf.Min(Mathf.Min(quantity, quantity2), __instance.MaxMixQuantity * MixOutputAdd.Add); __result = num; } } } [HarmonyPatch(typeof(MixingStation), "MinPass")] public static class MixStation_Time_Patch { [HarmonyPostfix] public static void Postfix(MixingStation __instance) { if (!((Object)(object)__instance == (Object)null) && __instance.CurrentMixTime < __instance.GetMixTimeForCurrentOperation() / 2) { __instance.CurrentMixTime = __instance.GetMixTimeForCurrentOperation() / 2; if (MixOutputAdd.Add == 2) { __instance.CurrentMixTime += __instance.GetMixTimeForCurrentOperation() / 4; } } } } public static class StackItem2xFix { private static bool _add; public static bool Add { get { return _add; } set { if (_add != value) { _add = value; UpdateAllRacks(); } } } public static void UpdateAllRacks() { DryingRack[] array = Il2CppArrayBase<DryingRack>.op_Implicit(Object.FindObjectsOfType<DryingRack>()); DryingRack[] array2 = array; foreach (DryingRack _instance in array2) { DryingRack_Patch.ApplyCapacityUpdate(_instance); } MelonLogger.Msg($"[DryingRack] Capacity updated for all active {array.Length} racks."); } } [HarmonyPatch(typeof(DryingRack), "InitializeGridItem")] public static class DryingRack_Patch { [HarmonyPostfix] public static void Postfix(DryingRack __instance) { ApplyCapacityUpdate(__instance); } public static void ApplyCapacityUpdate(DryingRack __instance) { int num2 = (__instance.ItemCapacity = (StackItem2xFix.Add ? 40 : 20)); if (__instance.HangAlignments != null && ((Il2CppArrayBase<Transform>)(object)__instance.HangAlignments).Length != num2) { Transform[] array = Il2CppArrayBase<Transform>.op_Implicit(((Component)__instance).GetComponentsInChildren<Transform>()); Transform[] array2 = (Transform[])(object)new Transform[num2]; for (int i = 0; i < num2; i++) { array2[i] = ((Il2CppArrayBase<Transform>)(object)__instance.HangAlignments)[i % ((Il2CppArrayBase<Transform>)(object)__instance.HangAlignments).Length]; } __instance.HangAlignments = Il2CppReferenceArray<Transform>.op_Implicit(array2); } Array array3 = Il2CppArrayBase<ItemSlot>.op_Implicit((Il2CppArrayBase<ItemSlot>)(object)__instance.hangSlots); if (array3 != null && array3.Length != num2) { Type elementType = array3.GetType().GetElementType(); Array array4 = Array.CreateInstance(elementType, num2); int length = Math.Min(array3.Length, num2); Array.Copy(array3, array4, length); if (num2 > array3.Length) { for (int j = array3.Length; j < num2; j++) { object value = Activator.CreateInstance(elementType); array4.SetValue(value, j); } } __instance.hangSlots = Il2CppReferenceArray<ItemSlot>.op_Implicit((ItemSlot[])array4); } __instance.RefreshHangingVisuals(); } } public static class GrowthSpeedUp { public static float Add; } [HarmonyPatch(typeof(Plant), "MinPass")] public static class Plant_MinPass_Patch { [HarmonyPrefix] public static bool Prefix(Plant __instance, int mins) { if (__instance.NormalizedGrowthProgress >= 1f || NetworkSingleton<TimeManager>.Instance.IsEndOfDay) { return true; } float num = 1f / ((float)__instance.GrowthTime * 60f) * (float)mins; num *= ((GrowContainer)__instance.Pot).GetTemperatureGrowthMultiplier(); float num2 = default(float); num *= ((GrowContainer)__instance.Pot).GetAverageLightExposure(ref num2); num *= __instance.Pot.GrowSpeedMultiplier; num *= num2; num += num * GrowthSpeedUp.Add; if (GameManager.IS_TUTORIAL) { num *= 0.3f; } if (((GrowContainer)__instance.Pot).NormalizedMoistureAmount <= 0f) { num *= 0f; } MelonLogger.Msg($" Before Growth Plant {__instance.NormalizedGrowthProgress}"); MelonLogger.Msg($" Add Growth Plant {__instance.NormalizedGrowthProgress}"); __instance.SetNormalizedGrowthProgress(__instance.NormalizedGrowthProgress + num); MelonLogger.Msg($" After Growth Plant {__instance.NormalizedGrowthProgress}"); return false; } } [HarmonyPatch(typeof(ShroomColony), "ChangeGrowthPercentage")] public static class MushroomGrowthSpeedPatch { [HarmonyPrefix] public static void Prefix(ShroomColony __instance, ref float change) { if (change > 0f && GrowthSpeedUp.Add > 0f) { MelonLogger.Msg($" Growth Shroom {__instance.GrowthProgress}"); MelonLogger.Msg($" Before Shroom change {change}"); change += change * GrowthSpeedUp.Add; MelonLogger.Msg($" After Shroom change {change}"); } } } public static class QualityMushroomUP { public static float Add; } [HarmonyPatch(typeof(ShroomColony), "GetHarvestedShroom")] public static class MushroomQualityPatch { [CompilerGenerated] private sealed class <CleanUp>d__2 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int id; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CleanUp>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(120f); <>1__state = 1; return true; case 1: <>1__state = -1; processedIds.Remove(id); 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 static readonly HashSet<int> processedIds = new HashSet<int>(); [HarmonyPostfix] public static void Postfix(ShroomColony __instance, ref ShroomInstance __result) { if (!(QualityMushroomUP.Add <= 0f) && __result != null) { int instanceID = ((Object)__instance).GetInstanceID(); if (!processedIds.Contains(instanceID)) { float normalizedQuality = __instance.NormalizedQuality; __instance.ChangeQuality(QualityMushroomUP.Add); processedIds.Add(instanceID); float normalizedQuality2 = __instance.NormalizedQuality; MelonCoroutines.Start(CleanUp(instanceID)); } } } [IteratorStateMachine(typeof(<CleanUp>d__2))] private static IEnumerator CleanUp(int id) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CleanUp>d__2(0) { id = id }; } } public static class QualityUP { public static float Add; } public static class BetterGrowTent { public static float Add; } [HarmonyPatch(typeof(Plant), "Initialize")] public static class PlantQualityPatch { [HarmonyPostfix] public static void Postfix(Plant __instance) { if (!((Object)(object)__instance.Pot != (Object)null)) { return; } string text = ((GrowContainer)__instance.Pot).Name.ToString(); float num = 0.5f; float qualityLevel = __instance.QualityLevel; num = (text.Equals("Grow Tent") ? (0.1f + BetterGrowTent.Add) : (text.Equals("Plastic Pot") ? 0.26f : (text.Equals("Moisture-Preserving Pot") ? 0.36f : ((!text.Equals("Air Pot")) ? 0.1f : 0.5f)))); float num2 = num + QualityUP.Add; if (AbsorbentSoil.Add) { if ((Object)(object)__instance.Pot == (Object)null) { MelonLogger.Warning("Plant.Initialize Postfix: Pot is null"); } else { List<AdditiveDefinition> appliedAdditives = ((GrowContainer)__instance.Pot).AppliedAdditives; if (appliedAdditives == null || appliedAdditives.Count == 0) { MelonLogger.Msg("No initial additives found for instant growth"); } else { float num3 = 0f; Enumerator<AdditiveDefinition> enumerator = appliedAdditives.GetEnumerator(); while (enumerator.MoveNext()) { AdditiveDefinition current = enumerator.Current; if (!((Object)(object)current == (Object)null)) { MelonLogger.Msg("Additive Name: " + ((ItemDefinition)current).Name.ToString().ToLower()); if (current.InstantGrowth > 0f && __instance.NormalizedGrowthProgress < 0.5f) { float normalizedGrowthProgress = __instance.NormalizedGrowthProgress; __instance.SetNormalizedGrowthProgress(normalizedGrowthProgress + current.InstantGrowth); MelonLogger.Msg($"Instant growth applied: +{current.InstantGrowth} (from {normalizedGrowthProgress} to {__instance.NormalizedGrowthProgress})"); } if (num2 < 0.27f && num2 > 0.17f) { num2 = 0.27f; } } } } } } __instance.QualityLevel = num2; MelonLogger.Msg($"[SkillTree] Plant Init: {text} | Final: {num2} | Skill: {QualityUP.Add} | Total: {__instance.QualityLevel}"); } } [HarmonyPatch(typeof(Plant), "Initialize")] public static class Plant_Initialize_Patch { private static void Postfix(Plant __instance) { try { if (!AbsorbentSoil.Add) { return; } if ((Object)(object)__instance.Pot == (Object)null) { MelonLogger.Warning("Plant.Initialize Postfix: Pot is null"); return; } List<AdditiveDefinition> appliedAdditives = ((GrowContainer)__instance.Pot).AppliedAdditives; if (appliedAdditives == null || appliedAdditives.Count == 0) { MelonLogger.Msg("No initial additives found for instant growth"); return; } Enumerator<AdditiveDefinition> enumerator = appliedAdditives.GetEnumerator(); while (enumerator.MoveNext()) { AdditiveDefinition current = enumerator.Current; if (!((Object)(object)current == (Object)null) && current.InstantGrowth > 0f && __instance.NormalizedGrowthProgress < 0.5f) { float normalizedGrowthProgress = __instance.NormalizedGrowthProgress; __instance.SetNormalizedGrowthProgress(normalizedGrowthProgress + current.InstantGrowth); MelonLogger.Msg($"Instant growth applied: +{current.InstantGrowth} (from {normalizedGrowthProgress} to {__instance.NormalizedGrowthProgress})"); } } } catch (Exception value) { MelonLogger.Error($"Plant.Initialize Postfix failed: {value}"); } } } public static class YieldAdd { public static int Add; } [HarmonyPatch(typeof(Plant), "GrowthDone")] public static class GrowthDone_SmartBasePatch { [HarmonyPrefix] public static void Prefix(Plant __instance) { if (InstanceFinder.IsServer) { float yieldMultiplier = __instance.YieldMultiplier; int baseYieldQuantity = __instance.BaseYieldQuantity; if (Mathf.Approximately(yieldMultiplier, 1f) && YieldAdd.Add != 0 && baseYieldQuantity == 12) { int value = (__instance.BaseYieldQuantity = baseYieldQuantity + YieldAdd.Add); MelonLogger.Msg($"[Skill More Yield] No additives detected. Skill applied. New Base: {value}"); } } } } public static class MethQualityAdd { public static bool Add; } [HarmonyPatch(typeof(LabOven), "Shatter")] public static class LabOven_QualityPatch { [CompilerGenerated] private sealed class <CleanUp>d__2 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public object id; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CleanUp>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; processedOperations.Remove(id); 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 static readonly HashSet<object> processedOperations = new HashSet<object>(); [HarmonyPrefix] public static void Prefix(LabOven __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_005e: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (__instance.CurrentOperation != null) { OvenCookOperation currentOperation = __instance.CurrentOperation; if (!processedOperations.Contains(currentOperation) && (int)currentOperation.IngredientQuality < 4) { MelonLogger.Msg($"__instance.CurrentOperation.IngredientQuality {__instance.CurrentOperation.IngredientQuality}"); OvenCookOperation currentOperation2 = __instance.CurrentOperation; currentOperation2.IngredientQuality = (EQuality)(currentOperation2.IngredientQuality + 1); processedOperations.Add(currentOperation); MelonLogger.Msg($"__instance.CurrentOperation.IngredientQuality {__instance.CurrentOperation.IngredientQuality}"); MelonCoroutines.Start(CleanUp(currentOperation)); } } } [IteratorStateMachine(typeof(<CleanUp>d__2))] private static IEnumerator CleanUp(object id) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CleanUp>d__2(0) { id = id }; } } } namespace SkillTree.SkillEffect { public static class SkillSystem { private static Player localPlayer; private static PlayerMovement playerMovement; private static Customer[] customerList; private static Business[] businessList; private static Dealer[] dealerList; private static Registry registry; public static void ApplySkill(string skillId, SkillTreeData data) { localPlayer = Player.Local; playerMovement = PlayerSingleton<PlayerMovement>.Instance; registry = Singleton<Registry>.Instance; customerList = Il2CppArrayBase<Customer>.op_Implicit(Object.FindObjectsOfType<Customer>()); dealerList = Il2CppArrayBase<Dealer>.op_Implicit(Object.FindObjectsOfType<Dealer>()); businessList = Il2CppArrayBase<Business>.op_Implicit(Object.FindObjectsOfType<Business>()); List<ItemDefinition> allItems = registry.GetAllItems(); switch (skillId) { case "Stats": MelonLogger.Msg("Player Health Before: " + localPlayer.Health.CurrentHealth); PlayerHealthConfig.MaxHealth = 100f + (float)data.Stats * 20f; localPlayer.Health.SetHealth(PlayerHealthConfig.MaxHealth); localPlayer.Health.RecoverHealth(PlayerHealthConfig.MaxHealth); MelonLogger.Msg("Player Health Now: " + localPlayer.Health.CurrentHealth); break; case "MoreMovespeed": MelonLogger.Msg("MoveSpeed Before: " + playerMovement.MoveSpeedMultiplier); PlayerMovespeed.MovespeedBase = 1f + (float)data.MoreMovespeed * 0.1f; playerMovement.MoveSpeedMultiplier = PlayerMovespeed.MovespeedBase; MelonLogger.Msg("MoveSpeed Now: " + playerMovement.MoveSpeedMultiplier); break; case "MoreStackItem": { QuickPackagers.Add = true; if ((Object)(object)registry == (Object)null) { break; } StackCache.FillCache(allItems); int num = 1 + data.MoreStackItem; Enumerator<ItemDefinition> enumerator = allItems.GetEnumerator(); while (enumerator.MoveNext()) { ItemDefinition current = enumerator.Current; string name = ((Object)current).name; if (StackCache.ItemStack.TryGetValue(name, out var value)) { int stackLimit = current.StackLimit; current.StackLimit = value * num; MelonLogger.Msg($"[MoreStackItem] {name}: {value} -> {current.StackLimit}"); } } MelonLogger.Msg("Skill Item Stack x2 Active"); break; } case "MoreXP": PlayerXPConfig.XpBase = 100f + (float)data.MoreXP * 5f; MelonLogger.Msg($"XP Base updated for: {PlayerXPConfig.XpBase}%"); break; case "MoreXP2": PlayerXPConfig.XpBase = 100f + (float)(data.MoreXP + data.MoreXP2) * 5f; MelonLogger.Msg($"XP Base updated for: {PlayerXPConfig.XpBase}%"); break; case "BetterDelivery": BetterDelivery.Add = data.BetterDelivery == 1; break; case "AllowSleepAthEne": AllowSleepAthEne.Add = data.AllowSleepAthEne == 1; break; case "AllowSeeCounteroffChance": CounterofferHelper.Counteroffer = data.AllowSeeCounteroffChance == 1; break; case "SkipSchedule": SkipSchedule.Add = data.SkipSchedule == 1; break; case "MoreXPWhenEarnMoney": PlayerXpMoney.XpMoney = true; break; case "Operations": BetterGrowTent.Add = (float)data.Operations * 0.16f; break; case "GrowthSpeed": GrowthSpeedUp.Add = (float)data.GrowthSpeed * 0.025f; break; case "GrowthSpeed2": GrowthSpeedUp.Add = (float)(data.GrowthSpeed + data.GrowthSpeed2) * 0.025f; break; case "MoreYield": YieldAdd.Add = data.MoreYield; break; case "MoreQuality": QualityUP.Add = (float)data.MoreQuality * 0.15f; break; case "MoreQualityMeth": MethQualityAdd.Add = data.MoreQualityMeth == 1; break; case "MoreQualityMushroom": QualityMushroomUP.Add = ((data.MoreQualityMushroom == 1) ? 0.3f : 0f); break; case "AbsorbentSoil": AbsorbentSoil.Add = data.AbsorbentSoil == 1; break; case "MoreMixAndDryingRackOutput": StackItem2xFix.Add = true; MixOutputAdd.Add = ((data.MoreMixAndDryingRackOutput * 2 == 0) ? 1 : (data.MoreMixAndDryingRackOutput * 2)); break; case "ChemistStationQuick": StationTimeLess.TimeAjust = (((float)data.ChemistStationQuick * 1.5f == 0f) ? 1 : (data.ChemistStationQuick * 2)); MixOutputAdd.TimeAjust = ((data.ChemistStationQuick * 2 == 0) ? 1 : (data.ChemistStationQuick * 2)); break; case "MoreCauldronOutput": { int add = CauldronOutputAdd.Add; int num4 = Mathf.FloorToInt((float)add * 1f * (float)data.MoreCauldronOutput); CauldronOutputAdd.Add = add + num4; break; } case "Social": CustomerSample.AddSampleChance = (float)data.Social * 0.05f; break; case "CityEvolving": { CustomerCache.FillCache(customerList.ToList()); float num3 = 1f + (float)data.CityEvolving * 0.1f; Customer[] array4 = customerList; foreach (Customer val4 in array4) { string name2 = ((Object)val4.CustomerData).name; if (CustomerCache.OriginalMinSpend.TryGetValue(name2, out var value3) && CustomerCache.OriginalMaxSpend.TryGetValue(name2, out var value4)) { val4.CustomerData.MinWeeklySpend = value3 * num3; val4.CustomerData.MaxWeeklySpend = value4 * num3; } } MelonLogger.Msg($"Weekly spend incresed by {1f + (float)data.CityEvolving * 0.15f}%"); break; } case "BusinessEvolving": { BusinessCache.FillCache(businessList.ToList()); float num2 = 1f + (float)data.BusinessEvolving * 0.2f; Business[] array3 = businessList; foreach (Business val3 in array3) { string propertyName = ((Property)val3).PropertyName; if (BusinessCache.LaunderCapacity.TryGetValue(propertyName, out var value2)) { float launderCapacity = val3.LaunderCapacity; val3.LaunderCapacity = value2 * num2; MelonLogger.Msg($"[BusinessEvolving] {propertyName}: {value2} -> {val3.LaunderCapacity}"); } } MelonLogger.Msg($"LaunderCapacity incresed by {1f + (float)data.BusinessEvolving * 0.2f}%"); break; } case "MoreATMLimit": ATMConfig.MaxWeeklyLimit = 10000f + (float)(data.MoreATMLimit * 1500); MelonLogger.Msg($"ATM Deposit Weekly Limit: ${ATMConfig.MaxWeeklyLimit}"); break; case "DealerCutLess": { Dealer[] array2 = dealerList; foreach (Dealer val2 in array2) { if (ValidDealer(val2)) { float cut = val2.Cut; val2.Cut = 0.2f - (float)data.DealerCutLess * 0.05f; MelonLogger.Msg($"Dealer: {((Object)val2).name} decrease cut from {cut}% to {val2.Cut}"); } } break; } case "DealerSpeedUp": { Dealer[] array = dealerList; foreach (Dealer val in array) { if (ValidDealer(val)) { float moveSpeedMultiplier = ((NPC)val).Movement.MoveSpeedMultiplier; ((NPC)val).Movement.MoveSpeedMultiplier = 1f + (float)data.DealerSpeedUp; MelonLogger.Msg($"Dealer: {((Object)val).name} movespeed increase from {moveSpeedMultiplier}% to {((NPC)val).Movement.MoveSpeedMultiplier}"); } } break; } case "DealerMoreCustomer": DealerUpCustomer.MaxCustomer += data.DealerMoreCustomer * 2; MelonLogger.Msg($"Dealer MaxCustomer: {DealerUpCustomer.MaxCustomer}"); break; case "BetterSupplier": SupplierUp.SupplierInc = 1f + 1f * ((float)data.BetterSupplier * 0.675f); SupplierUp.SupplierLimit = (int)(10f + 10f * ((float)data.BetterSupplier * 0.5f)); break; } } public static void ApplyAll(SkillTreeData data) { FieldInfo[] fields = typeof(SkillTreeData).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { ApplySkill(fieldInfo.Name, data); } } private static bool ValidDealer(Dealer dealer) { if (((Object)dealer).name.ToLower().Contains("carteldealer")) { return false; } return true; } } }