Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of OverTheCounter v2.0.10
OverTheCounter.Il2Cpp.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using HarmonyLib; using Il2Cpp; using Il2CppEPOOutline; using Il2CppFishNet; using Il2CppFishNet.Component.Ownership; using Il2CppFishNet.Connection; using Il2CppFishNet.Managing; using Il2CppFishNet.Managing.Object; using Il2CppFishNet.Object; using Il2CppFishNet.Observing; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.Audio; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.AvatarFramework.Animation; using Il2CppScheduleOne.AvatarFramework.Equipping; using Il2CppScheduleOne.AvatarFramework.Impostors; using Il2CppScheduleOne.Building; using Il2CppScheduleOne.Cartel; using Il2CppScheduleOne.Combat; using Il2CppScheduleOne.Core.Items.Framework; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Dialogue; using Il2CppScheduleOne.Doors; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.Effects; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.EntityFramework; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.Graffiti; using Il2CppScheduleOne.Interaction; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Law; using Il2CppScheduleOne.Levelling; using Il2CppScheduleOne.Lighting; using Il2CppScheduleOne.Management; using Il2CppScheduleOne.Map; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Behaviour; using Il2CppScheduleOne.NPCs.Relation; using Il2CppScheduleOne.Networking; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.ObjectScripts.Cash; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.Persistence.Datas; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.PlayerScripts.Health; using Il2CppScheduleOne.Police; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Product.Packaging; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.Quests; using Il2CppScheduleOne.StationFramework; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Tiles; using Il2CppScheduleOne.Tools; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Compass; using Il2CppScheduleOne.UI.Handover; using Il2CppScheduleOne.UI.Items; using Il2CppScheduleOne.UI.Management; using Il2CppScheduleOne.UI.Phone; using Il2CppScheduleOne.UI.Phone.ContactsApp; using Il2CppScheduleOne.UI.Phone.Map; using Il2CppScheduleOne.UI.Phone.ProductManagerApp; using Il2CppScheduleOne.UI.Relations; using Il2CppScheduleOne.UI.Shop; using Il2CppScheduleOne.Variables; using Il2CppScheduleOne.Vehicles; using Il2CppScheduleOne.VoiceOver; using Il2CppScheduleOne.Weather; using Il2CppSteamworks; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using MeshVault; using Microsoft.CodeAnalysis; using OverTheCounter; using OverTheCounter.Apps; using OverTheCounter.Logic; using OverTheCounter.Logic.Placement; using OverTheCounter.NPCs; using OverTheCounter.Patches; using OverTheCounter.Quests; using OverTheCounter.SaveData; using OverTheCounter.UI; using OverTheCounter.Utilities; using S1API.Entities; using S1API.Entities.Appearances.AccessoryFields; using S1API.Entities.Appearances.BodyLayerFields; using S1API.Entities.Appearances.CustomizationFields; using S1API.Entities.Appearances.FaceLayerFields; using S1API.Entities.Dialogue; using S1API.Entities.Schedule; using S1API.GameTime; using S1API.Internal.Abstraction; using S1API.Items; using S1API.Leveling; using S1API.Messaging; using S1API.Misc; using S1API.Money; using S1API.PhoneApp; using S1API.Products; using S1API.Quests; using S1API.Saveables; using S1API.Shops; using S1API.UI; using S1API.Utils; using S1MAPI.Building; using S1MAPI.Building.Components; using S1MAPI.Building.Config; using S1MAPI.Building.Structural; using S1MAPI.Core; using S1MAPI.Gltf; using S1MAPI.ProceduralMesh; using S1MAPI.S1; using S1MAPI.Utils; using SteamNetworkLib; using SteamNetworkLib.Models; using SteamNetworkLib.Sync; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "OverTheCounter", "2.0.10", "hdlmrell", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonOptionalDependencies(new string[] { "SteamNetworkLib" })] [assembly: HarmonyDontPatchAll] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("OverTheCounter.Il2Cpp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6b7caa4bc824a2bf8fc9dcdc200bf94491a1a140")] [assembly: AssemblyProduct("OverTheCounter.Il2Cpp")] [assembly: AssemblyTitle("OverTheCounter.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 OverTheCounter { internal static class PrivateAccess { public static VODatabase GetDatabase(this VOEmitter emitter) { return emitter.Database; } public static CustomerData GetCustData(this Customer customer) { return customer.customerData; } public static void SetCustData(this Customer customer, CustomerData data) { customer.customerData = data; } public static string GetTitle(this Quest quest) { return quest.title; } public static void SetTitle(this Quest quest, string value) { quest.title = value; } public static DialogueHandler GetHandler(this DialogueController dc) { return dc.handler; } public static ConfigurableTypePanel[] GetConfigPanelPrefabs(this ManagementInterface mi) { return Il2CppArrayBase<ConfigurableTypePanel>.op_Implicit((Il2CppArrayBase<ConfigurableTypePanel>)(object)mi.ConfigPanelPrefabs); } public static MSGConversation GetMSGConversation(this NPC npc) { return npc.MSGConversation; } public static void SetMSGConversation(this NPC npc, MSGConversation conv) { npc.MSGConversation = conv; } public static void SetCurrentBuilding(this NPC npc, NPCEnterableBuilding building) { npc.CurrentBuilding = building; } public static void SetTimeSinceLastDealCompleted(this Customer customer, int value) { customer.TimeSinceLastDealCompleted = value; } public static void SetTimeSinceLastDealOffered(this Customer customer, int value) { customer.TimeSinceLastDealOffered = value; } public static ContractInfo GetOfferedContractInfo(this Customer customer) { return customer.OfferedContractInfo; } public static void SetOfferedContractInfo(this Customer customer, ContractInfo info) { customer.OfferedContractInfo = info; } public static NPCPoI GetPotentialCustomerPoI(this Customer customer) { return customer.potentialCustomerPoI; } public static void SetPotentialCustomerPoI(this Customer customer, NPCPoI poi) { customer.potentialCustomerPoI = poi; } public static QuestEntryHUDUI GetEntryUI(this QuestEntry entry) { return entry.entryUI; } public static void SetShouldShowCheck(this DialogueChoice choice, Func<bool, bool> func) { choice.shouldShowCheck = ShouldShowCheck.op_Implicit(func); } public static ItemSlot[] GetCustomerSlots(this HandoverScreen hs) { return Il2CppArrayBase<ItemSlot>.op_Implicit((Il2CppArrayBase<ItemSlot>)(object)hs.CustomerSlots); } public static void TrackItemAsPlayer(this HandoverScreen hs, ItemInstance item) { hs.OriginalItemLocations[item] = (EItemSource)0; } } public class Core : MelonMod { private NotificationManager _notificationManager; private DesperationManager _desperationManager; private DrifterManager _drifterManager; private ManagerController _managerManager; private CustomerManager _customerManager; private bool _multiplayerDepChecked; private static bool _meshVaultRegistered; private static bool _loadHooked; private static bool _budtendersRestored; private static UnityAction _onGameLoadedAction; private static bool _gameLoadedRan; internal static string OtcIconDir { get; private set; } public override void OnInitializeMelon() { DependencyChecker.RunChecks(); if (DependencyChecker.HasMissingDeps) { ((MelonBase)this).LoggerInstance.Warning("Missing dependencies — mod features disabled. Check the main menu for details."); } else { OnInitializeMelonImpl(); } } private void OnInitializeMelonImpl() { Config.Initialize(); Config.SubscribeToChanges(); CustomersApp.ApplyHireMeDefaults(); SafeTypeLoadPatch.Apply(((MelonBase)this).HarmonyInstance); foreach (Type validType in MelonUtils.GetValidTypes(typeof(Core).Assembly)) { try { ((MelonBase)this).HarmonyInstance.CreateClassProcessor(validType).Patch(); } catch (Exception ex) { OTCLog.Error("Patch", "Failed to patch " + validType.FullName + ": " + ex.Message); } } NpcTypeDiscoveryPatch.Apply(((MelonBase)this).HarmonyInstance); StackSizePatch.Apply(((MelonBase)this).HarmonyInstance); ManagerClipboardPatch.Apply(((MelonBase)this).HarmonyInstance); try { BuildingPlacementPatch.Apply(((MelonBase)this).HarmonyInstance); } catch (Exception value) { OTCLog.Error("Patch", $"BuildingPlacementPatch.Apply failed: {value}"); } try { ConfigReplicatorPatch.Apply(((MelonBase)this).HarmonyInstance); } catch (Exception value2) { OTCLog.Error("Patch", $"ConfigReplicatorPatch.Apply failed: {value2}"); } ContactsAppFix.Apply(((MelonBase)this).HarmonyInstance); GraffitiPatch.Apply(((MelonBase)this).HarmonyInstance); RecipePinPatch.Apply(((MelonBase)this).HarmonyInstance); SupplierWarehousePatch.Apply(((MelonBase)this).HarmonyInstance); SupplierFleePatch.Apply(((MelonBase)this).HarmonyInstance); SaveManagerPatch.Apply(((MelonBase)this).HarmonyInstance); GameProfilerPatches.Apply(((MelonBase)this).HarmonyInstance); WeatherPatches.Apply(((MelonBase)this).HarmonyInstance); CustomerCheckoutInterceptPatch.Apply(((MelonBase)this).HarmonyInstance); TimeManager.OnSleepEnd = (Action<int>)Delegate.Combine(TimeManager.OnSleepEnd, new Action<int>(OnSleepEnd)); TimeManager.OnDayPass = (Action)Delegate.Combine(TimeManager.OnDayPass, new Action(OnDayPass)); if (!ConfigSyncData.IsNetworkLibAvailable) { OTCLog.Warning("Network", "SteamNetworkLib not installed — multiplayer sync disabled. Single-player works fine. Install SteamNetworkLib for co-op support."); } OTCLog.Msg("Patch", "OverTheCounter Initialized."); ImmediateQuestWindowConfig.Register(); MinimapOverlay.Register(); HUDOverlay.Register(); StoreAlertOverlay.Register(); RecipeOverlay.Register(); ExtractIcons(); _notificationManager = new NotificationManager(); _desperationManager = new DesperationManager(); _drifterManager = new DrifterManager(); _managerManager = new ManagerController(); _customerManager = new CustomerManager(); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (DependencyChecker.HasMissingDeps) { if (sceneName == "Menu") { DependencyChecker.ShowPopup(); } } else { OnSceneWasLoadedImpl(buildIndex, sceneName); } } private void OnSceneWasLoadedImpl(int buildIndex, string sceneName) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown StaticSaveData.ResetInstance(); StaticThreadSaveData.ResetInstance(); PropertySaveData.ResetInstance(); PricingSaveData.ResetInstance(); VicSaveData.ResetInstance(); BellaSaveData.ResetInstance(); StaticIntroQuest.ResetInstance(); StaticUpgrade1Quest.ResetInstance(); StaticUpgrade2Quest.ResetInstance(); VicIntroQuest.ResetInstance(); BellaProtocolQuest.ResetInstance(); StorefrontGrowthQuest.ResetInstance(); StorefrontExpansionQuest.ResetInstance(); BellaSummonPatch.Reset(); try { (typeof(Saveable).Assembly.GetType("S1API.Saveables.SaveableAutoRegistry")?.GetMethod("ClearCache", BindingFlags.Static | BindingFlags.NonPublic))?.Invoke(null, null); OTCLog.Msg("Patch", "Cleared S1API SaveableAutoRegistry cache"); } catch (Exception ex) { OTCLog.Warning("Patch", "Failed to clear SaveableAutoRegistry: " + ex.Message); } DrifterInstance.CleanupAll(); CustomerInstance.CleanupAll(); DrifterSpawner.ResetCache(); BudtenderInstance.CleanupAll(); _budtendersRestored = false; ManagerSaveData.ResetInstance(); ManagerInstance.CleanupAll(); ManagerSpawner.ResetCache(); MugshotUtility.ResetSession(); if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_MinimapController"))) { GameObject val = new GameObject("OTC_MinimapController"); val.AddComponent<MinimapOverlay>(); Object.DontDestroyOnLoad((Object)val); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_HUDOverlay"))) { GameObject val2 = new GameObject("OTC_HUDOverlay"); val2.AddComponent<HUDOverlay>(); Object.DontDestroyOnLoad((Object)val2); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_RecipeOverlay"))) { GameObject val3 = new GameObject("OTC_RecipeOverlay"); val3.AddComponent<RecipeOverlay>(); Object.DontDestroyOnLoad((Object)val3); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_StoreAlertOverlay"))) { GameObject val4 = new GameObject("OTC_StoreAlertOverlay"); val4.AddComponent<StoreAlertOverlay>(); Object.DontDestroyOnLoad((Object)val4); } WeatherPatches.Cleanup(); MapBuildingOverlay.Clear(); CheckoutCounter.Cleanup(); WestvilleShack.Cleanup(); Dispensary.Cleanup(); OTCWarehouse.Cleanup(); OTCSupplierArea.Cleanup(); CasinoDeadDrop.Cleanup(); CheckoutProcess.ResetStatic(); CustomerSpawnPoints.Cleanup(); BuildingGridFactory.Cleanup(); _loadHooked = false; _gameLoadedRan = false; } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if (!DependencyChecker.HasMissingDeps) { OnSceneWasInitializedImpl(buildIndex, sceneName); } } private void OnSceneWasInitializedImpl(int buildIndex, string sceneName) { if (!(sceneName == "Main")) { return; } MeshVaultAPI.Init(); if (!_meshVaultRegistered) { bool flag = false; bool flag2 = false; try { byte[] array = EmbeddedResourceLoader.LoadBytes("OverTheCounter.Resources.MeshDatabase.json", Assembly.GetExecutingAssembly()); if (array != null) { MeshVaultAPI.RegisterMeshes("otc", "OverTheCounter", Encoding.UTF8.GetString(array)); flag = true; } } catch (Exception ex) { OTCLog.Warning("Patch", "OTC mesh registration failed: " + ex.Message); } try { MeshVaultAPI.RegisterDecals("otc", "OverTheCounter", Assembly.GetExecutingAssembly(), "OverTheCounter.Resources.MeshVaultDecals."); flag2 = true; } catch (Exception ex2) { OTCLog.Warning("Patch", "OTC decal registration failed: " + ex2.Message); } _meshVaultRegistered = flag || flag2; } CheckoutCounter.Register(); WestvilleShack.SpawnBuilding(); Dispensary.SpawnBuilding(); OTCWarehouse.Initialize(); OTCSupplierArea.Initialize(OTCWarehouse.BuildingTransform); HookLoadComplete(); CheckoutCounter.AddToShop(); } private static void HookLoadComplete() { if (_loadHooked) { return; } try { if ((Delegate)(object)_onGameLoadedAction == (Delegate)null) { _onGameLoadedAction = UnityAction.op_Implicit((Action)OnGameLoaded); } LoadManager instance = Singleton<LoadManager>.Instance; if ((Object)(object)instance != (Object)null) { instance.onLoadComplete.RemoveListener(_onGameLoadedAction); instance.onLoadComplete.AddListener(_onGameLoadedAction); _loadHooked = true; OTCLog.Msg("Patch", "Hooked LoadManager.onLoadComplete"); } else { OTCLog.Warning("Patch", "LoadManager.Instance is null — cannot hook onLoadComplete"); } } catch (Exception ex) { OTCLog.Error("Patch", "Failed to hook LoadManager.onLoadComplete: " + ex.Message); } } private static void OnGameLoaded() { if (_gameLoadedRan) { OTCLog.Warning("Patch", "OnGameLoaded fired more than once this session (stale listener?) — ignoring duplicate."); return; } _gameLoadedRan = true; try { WestvilleShack.ClearTerrain(); Dispensary.ClearTerrain(); OTCWarehouse.ClearTerrain(); WestvilleShack.SpawnNetworkedObjects(); Dispensary.SpawnNetworkedObjects(); OTCWarehouse.SpawnNetworkedObjects(); CheckoutCounter.AddToShop(); CasinoDeadDrop.Initialize(); CheckoutProcess.InitP2P(); CheckoutProcess.RequestSalesLog(); BuildingGridFactory.SuppressNavigationRebuild = true; if (PropertySaveData.Instance != null) { foreach (KeyValuePair<Grid, OtcGridInfo> item in BuildingGridFactory.GridRegistry) { PropertySaveData.Instance.RestorePlacedItems(item.Value.BuildingId, item.Key); } } else { Grid shackGrid = WestvilleShack.ShackGrid; if ((Object)(object)shackGrid != (Object)null) { CheckoutCounter.SpawnOnGrid(shackGrid); } } BuildingGridFactory.SuppressNavigationRebuild = false; WestvilleShack.RebuildNavigation(); Dispensary.RebuildNavigation(); OTCWarehouse.RebuildNavigation(); if (!MapBuildingOverlay.PaintBuildings()) { OTCLog.Warning("Patch", "MapBuildingOverlay.PaintBuildings failed — MapApp or MapPositionUtility not ready"); } } catch (Exception ex) { BuildingGridFactory.SuppressNavigationRebuild = false; OTCLog.Error("General", "OnGameLoaded restore failed: " + ex.Message + "\n" + ex.StackTrace); } } public override void OnLateUpdate() { if (!DependencyChecker.HasMissingDeps) { OnLateUpdateImpl(); } } private void OnLateUpdateImpl() { PerfTracker.BeginFrame(); try { PerfTracker.Begin("NetworkInit"); ConfigSyncData.EnsureNetworkReady(); PerfTracker.End("NetworkInit"); PerfTracker.Begin("SyncMessages"); ConfigSyncData.ProcessMessages(); PerfTracker.End("SyncMessages"); if (!_multiplayerDepChecked && !ConfigSyncData.IsNetworkLibAvailable) { Lobby instance = Singleton<Lobby>.Instance; if ((Object)(object)instance != (Object)null && instance.IsInLobby && instance.PlayerCount > 1) { _multiplayerDepChecked = true; DependencyChecker.RunMultiplayerChecks(); if (DependencyChecker.HasMultiplayerIssues) { DependencyChecker.ShowMultiplayerPopup(); } } } PerfTracker.Begin("SaveDataTicks"); _notificationManager.ProcessContractState(); VicSaveData.Instance?.Tick(); StaticSaveData.Instance?.Tick(); BellaSaveData.Instance?.Tick(); ManagerSaveData.Instance?.Tick(); PerfTracker.End("SaveDataTicks"); PerfTracker.Begin("AdoptionRetries"); _drifterManager?.RetryPendingAdoptions(); _customerManager?.RetryPendingAdoptions(); ManagerInstance.RetryPendingAdoptions(); PerfTracker.End("AdoptionRetries"); PerfTracker.Begin("ManagerAI"); PerfTracker.Begin("ManagerAI.Wages"); _managerManager?.CheckImmediateWages(); PerfTracker.End("ManagerAI.Wages"); PerfTracker.Begin("ManagerAI.EnsureMoving"); foreach (ManagerInstance value in ManagerInstance.Active.Values) { value.EnsureMoving(); } PerfTracker.End("ManagerAI.EnsureMoving"); PerfTracker.Begin("ManagerAI.SupplyDistribution"); if (NetworkHelper.IsHost) { foreach (ManagerInstance value2 in ManagerInstance.Active.Values) { value2.SupplyBehaviour?.Tick(); value2.DistributionBehaviour?.Tick(); } } PerfTracker.End("ManagerAI.SupplyDistribution"); PerfTracker.End("ManagerAI"); PerfTracker.Begin("NetworkPublish"); if (NetworkHelper.IsHost) { ConfigSyncData.FlushDirtyState(); if (ManagerInstance.HasPendingMessages) { ConfigSyncData.Instance?.PublishManagerMessages(); } if (DrifterManager.HasPendingDrifterMessages) { ConfigSyncData.Instance?.PublishDrifterMessages(); } _customerManager?.PublishIfNeeded(); if (ManagerInstance.StatePublishNeeded) { ManagerInstance.StatePublishNeeded = false; ConfigSyncData.Instance?.PublishManagerState(); } } PerfTracker.End("NetworkPublish"); PerfTracker.Begin("ClientDoorSetup"); if (!NetworkHelper.IsHost) { WestvilleShack.TickClientDoorSetup(); Dispensary.TickClientDoorSetup(); } PerfTracker.End("ClientDoorSetup"); if (!_budtendersRestored && NetworkHelper.IsHost && CheckoutCounter.AllCounters.Count > 0 && PropertySaveData.Instance != null) { _budtendersRestored = true; string budtenderSaveState = PropertySaveData.Instance.BudtenderSaveState; if (!string.IsNullOrEmpty(budtenderSaveState)) { BudtenderController.Deserialize(budtenderSaveState); } } PerfTracker.Begin("BudtenderAI"); if (NetworkHelper.IsHost) { BudtenderController.Tick(); } PerfTracker.End("BudtenderAI"); PerfTracker.Begin("Checkout"); CheckoutProcess.Instance?.Tick(); CheckoutProcess.TryStartCheckout(); CheckoutProcess.PollLockGrant(); if (CheckoutProcess.Instance == null) { CheckoutCounter.TryCollectRegister(); } PerfTracker.End("Checkout"); PerfTracker.Begin("ScreenTicks"); foreach (CheckoutCounterInstance allCounter in CheckoutCounter.AllCounters) { allCounter.Screen?.Tick(); } PerfTracker.End("ScreenTicks"); Dispensary.UpdateLightBrightness(); WestvilleShack.UpdateLightBrightness(); PerfTracker.Begin("QuestTicks"); _drifterManager?.ClientQuestTick(); StorefrontGrowthQuest.Instance?.Tick(); StorefrontExpansionQuest.Instance?.Tick(); PerfTracker.End("QuestTicks"); } catch (Exception ex) { OTCLog.Error("Patch", "Error in OnLateUpdate: " + ex.Message + "\n" + ex.StackTrace); } PerfTracker.EndFrame(); } private static void OnSleepEnd(int minutesSkipped) { if (NetworkHelper.IsHost) { LoadManager instance = Singleton<LoadManager>.Instance; if (!((Object)(object)instance == (Object)null) && instance.IsGameLoaded) { StaticNPC.Instance?.WarpToSpawn(); BellaNPC.Instance?.ReInjectIntoBuilding(); } } } public override void OnDeinitializeMelon() { if (!DependencyChecker.HasMissingDeps) { OnDeinitializeMelonImpl(); } } private static void OnDayPass() { if (!NetworkHelper.IsHost) { return; } PropertySaveData instance = PropertySaveData.Instance; if (instance != null) { int num = 0; if (instance.IsPropertyOwned("westville_shack")) { num += PropertyInventory.GetTotalProductCount(WestvilleShack.ShackGrid); } if (instance.IsPropertyOwned("big_dispensary")) { num += PropertyInventory.GetTotalProductCount(Dispensary.DispensaryGrid); } instance.RecordInventorySnapshot(TimeManager.ElapsedDays, num); instance.TrimSalesLog(TimeManager.ElapsedDays); } } private void OnDeinitializeMelonImpl() { PerfTracker.WriteReport(); TimeManager.OnSleepEnd = (Action<int>)Delegate.Remove(TimeManager.OnSleepEnd, new Action<int>(OnSleepEnd)); TimeManager.OnDayPass = (Action)Delegate.Remove(TimeManager.OnDayPass, new Action(OnDayPass)); ConfigSyncData.Cleanup(); _notificationManager?.Cleanup(); _desperationManager?.Cleanup(); _drifterManager?.Cleanup(); _managerManager?.Cleanup(); _customerManager?.Cleanup(); } private void ExtractIcons() { OtcIconDir = Path.Combine(MelonEnvironment.UserDataDirectory, "OverTheCounter", "Icons"); if (!Directory.Exists(OtcIconDir)) { Directory.CreateDirectory(OtcIconDir); } ExtractResource(OtcIconDir, "CustomersIcon.png"); ExtractResource(OtcIconDir, "DrifterQuestIcon.png"); ExtractResource(OtcIconDir, "DrifterProfileIcon.png"); ExtractResource(OtcIconDir, "RinseCycle.png"); ExtractResource(OtcIconDir, "CrimeWareQuest.png"); ExtractResource(OtcIconDir, "ExecutivePrivilege.png"); ExtractResource(OtcIconDir, "ManagerIcon.png"); ExtractResource(OtcIconDir, "CheckoutCounter.png"); ExtractResource(OtcIconDir, "StoreAlertIcon.png"); } private void ExtractResource(string directory, string fileName) { string path = Path.Combine(directory, fileName); if (File.Exists(path)) { return; } OTCLog.Msg("Patch", "Extracting " + fileName + "..."); string text = "OverTheCounter.Resources." + fileName; using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text); if (stream != null) { using (FileStream destination = new FileStream(path, FileMode.Create, FileAccess.Write)) { stream.CopyTo(destination); } OTCLog.Msg("Patch", fileName + " extracted successfully."); } else { OTCLog.Error("Patch", "Could not find embedded resource '" + text + "'."); } } } public static class Config { private static MelonPreferences_Category _managers; public static ConfigEntry<float> ManagerDailyWage; public static ConfigEntry<float> ManagerSigningFee; public static ConfigEntry<bool> AlternateHire; private static MelonPreferences_Category _laundering; public static ConfigEntry<float> VicTier1Cost; public static ConfigEntry<float> VicTier1Return; public static ConfigEntry<int> VicTier2TrustUnlock; public static ConfigEntry<float> VicTier2Cost; public static ConfigEntry<float> VicTier2Return; public static ConfigEntry<int> VicIntroWeedGrams; public static ConfigEntry<float> VicDepositTrigger; private static MelonPreferences_Category _bella; public static ConfigEntry<float> BellaWeedValue; public static ConfigEntry<float> BellaMethValue; public static ConfigEntry<float> BellaCokeValue; private static MelonPreferences_Category _notifications; public static ConfigEntry<bool> ConsolidationEnabled; public static ConfigEntry<int> ConsolidationThreshold; private static MelonPreferences_Category _subscription; public static ConfigEntry<float> SaasWeeklyCost; public static ConfigEntry<int> SaasCycleDays; public static ConfigEntry<float> StaticTier1BankCost; public static ConfigEntry<int> StaticTier1WeedGrams; public static ConfigEntry<float> StaticTier2BankCost; public static ConfigEntry<int> StaticTier2MethGrams; public static ConfigEntry<float> StaticTier3BankCost; public static ConfigEntry<int> StaticTier3PremiumMethGrams; private static MelonPreferences_Category _world; public static ConfigEntry<float> ShackPurchasePrice; public static ConfigEntry<float> WarehousePurchasePrice; public static ConfigEntry<float> DispensaryPurchasePrice; public static ConfigEntry<int> StackSizeMultiplier; public static ConfigEntry<bool> GraffitiReEdit; public static ConfigEntry<bool> RecipePinEnabled; public static ConfigEntry<int> ShackDailyCustomerCap; public static ConfigEntry<bool> PreserveVanillaDeals; public static ConfigEntry<float> WalkInMirrorRate; private static MelonPreferences_Category _desperation; public static ConfigEntry<bool> DesperationEnabled; public static ConfigEntry<float> FiendAddictionThreshold; public static ConfigEntry<float> TriggerChancePerHour; public static ConfigEntry<int> MaxEventsPerDay; public static ConfigEntry<int> ResponseDeadlineMinutes; public static ConfigEntry<int> DeadlineMinutes; public static ConfigEntry<float> BonusMultiplier; public static ConfigEntry<float> RelationshipPenalty; public static ConfigEntry<int> CooldownMinutes; public static ConfigEntry<int> DayStartHour; public static ConfigEntry<int> DayEndHour; private static MelonPreferences_Category _drifters; public static ConfigEntry<bool> DrifterEnabled; public static ConfigEntry<float> DrifterSpawnChancePerHour; public static ConfigEntry<int> MaxActiveDrifters; public static ConfigEntry<int> DrifterDayStartHour; public static ConfigEntry<int> DrifterDayEndHour; public static ConfigEntry<int> DrifterOfferWindowMin; public static ConfigEntry<int> DrifterDeliveryDeadlineMin; public static ConfigEntry<int> DrifterLingerMinMin; public static ConfigEntry<int> DrifterLingerMaxMin; public static ConfigEntry<float> DrifterMinDealValue; private static MelonPreferences_Category _debug; public static ConfigEntry<bool> VerboseLogging; public static ConfigEntry<bool> ManagerVerboseLogging; public static ConfigEntry<bool> DrifterVerboseLogging; public static ConfigEntry<bool> DesperationVerboseLogging; public static ConfigEntry<bool> NpcVerboseLogging; public static ConfigEntry<bool> NetworkVerboseLogging; public static ConfigEntry<bool> QuestVerboseLogging; public static ConfigEntry<bool> NotificationVerboseLogging; public static ConfigEntry<bool> PatchVerboseLogging; public static ConfigEntry<bool> ProfilingEnabled; private static MelonPreferences_Category _minimap; public static ConfigEntry<bool> MinimapEnabled; public static ConfigEntry<int> MinimapSize; public static ConfigEntry<bool> MinimapRotateWithPlayer; public static ConfigEntry<bool> MinimapCircle; public static ConfigEntry<int> MinimapDefaultZoom; public static ConfigEntry<float> MinimapIconScale; public static MelonPreferences_Entry<KeyCode> MinimapToggleKey; public static ConfigEntry<int> MinimapHorizontalOffset; public static ConfigEntry<int> MinimapVerticalOffset; public static ConfigEntry<bool> MinimapInfoOnTop; public static MelonPreferences_Entry<Color> MinimapBorderColor; public static ConfigEntry<int> MinimapBorderWidth; public static ConfigEntry<bool> MinimapShowTime; public static ConfigEntry<bool> MinimapShowDay; public static ConfigEntry<bool> MinimapUse24HourClock; public static ConfigEntry<bool> MinimapShowCompass; public static ConfigEntry<bool> MinimapShowEdgeIndicators; public static ConfigEntry<bool> MinimapPerfLimit; private static MelonPreferences_Category _hud; public static ConfigEntry<bool> HUDShowRankXP; public static ConfigEntry<bool> HUDShowHealth; public static ConfigEntry<bool> HUDShowStamina; public static ConfigEntry<bool> StoreAlertEnabled; private static MelonPreferences_Category _minimapPoi; public static ConfigEntry<bool> MinimapShowPotentialCustomers; public static ConfigEntry<bool> MinimapShowCustomers; public static ConfigEntry<bool> MinimapShowDealers; public static ConfigEntry<bool> MinimapShowDeadDrops; public static ConfigEntry<bool> MinimapShowContracts; public static ConfigEntry<bool> MinimapShowQuests; public static ConfigEntry<bool> MinimapShowProperties; public static ConfigEntry<bool> MinimapShowManagers; public static ConfigEntry<bool> MinimapShowModdedNPCs; private static readonly Dictionary<string, ConfigEntry<float>> _floatEntries = new Dictionary<string, ConfigEntry<float>>(); private static readonly Dictionary<string, ConfigEntry<int>> _intEntries = new Dictionary<string, ConfigEntry<int>>(); private static readonly Dictionary<string, ConfigEntry<bool>> _boolEntries = new Dictionary<string, ConfigEntry<bool>>(); private static readonly HashSet<string> _localOnlyKeys = new HashSet<string> { "ConsolidationEnabled", "ConsolidationThreshold", "ManagerVerboseLogging", "DrifterVerboseLogging", "DesperationVerboseLogging", "NpcVerboseLogging", "NetworkVerboseLogging", "QuestVerboseLogging", "NotificationVerboseLogging", "PatchVerboseLogging", "ProfilingEnabled", "VerboseLogging", "MinimapEnabled", "MinimapSize", "MinimapRotateWithPlayer", "MinimapCircle", "MinimapDefaultZoom", "MinimapIconScale", "MinimapHorizontalOffset", "MinimapVerticalOffset", "MinimapInfoOnTop", "MinimapBorderWidth", "MinimapShowTime", "MinimapShowDay", "MinimapUse24HourClock", "MinimapShowPotentialCustomers", "MinimapShowCustomers", "MinimapShowDealers", "MinimapShowDeadDrops", "MinimapShowContracts", "MinimapShowQuests", "MinimapShowProperties", "MinimapShowManagers", "MinimapShowModdedNPCs", "MinimapShowCompass", "MinimapShowEdgeIndicators", "MinimapPerfLimit", "HUDShowRankXP", "HUDShowHealth", "HUDShowStamina", "StoreAlertEnabled", "RecipePinEnabled" }; public static void Initialize() { //IL_0e73: Unknown result type (might be due to invalid IL or missing references) _managers = MelonPreferences.CreateCategory("OverTheCounter_Managers", "Manager System"); ManagerDailyWage = Register(_managers.CreateEntry<float>("ManagerDailyWage", 350f, "Base Daily Wage", "Base daily wage before upgrade fees are added", false, false, (ValueValidator)null, (string)null)); ManagerSigningFee = Register(_managers.CreateEntry<float>("ManagerSigningFee", 3000f, "Signing Fee", "One-time fee deducted from player cash when hiring a manager", false, false, (ValueValidator)null, (string)null)); AlternateHire = Register(_managers.CreateEntry<bool>("AlternateHire", false, "Alternate Hire", "Show hire buttons in the OTC app instead of using Manny's dialogue. Enable if another mod conflicts with Manny.", false, false, (ValueValidator)null, (string)null)); _laundering = MelonPreferences.CreateCategory("OverTheCounter_Laundering", "Vic Laundering"); VicTier1Cost = Register(_laundering.CreateEntry<float>("VicTier1Cost", 500f, "Tier 1 Cost", "Cash required for tier-1 laundering", false, false, (ValueValidator)null, (string)null)); VicTier1Return = Register(_laundering.CreateEntry<float>("VicTier1Return", 400f, "Tier 1 Return", "Clean money returned for tier-1 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2TrustUnlock = Register(_laundering.CreateEntry<int>("VicTier2TrustUnlock", 7, "Tier 2 Trust Unlock", "Trust level required to unlock tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2Cost = Register(_laundering.CreateEntry<float>("VicTier2Cost", 900f, "Tier 2 Cost", "Cash required for tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2Return = Register(_laundering.CreateEntry<float>("VicTier2Return", 750f, "Tier 2 Return", "Clean money returned for tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicIntroWeedGrams = Register(_laundering.CreateEntry<int>("VicIntroWeedGrams", 40, "Intro Quest Weed Grams", "Grams of weed required to complete Vic's intro quest", false, false, (ValueValidator)null, (string)null)); VicDepositTrigger = Register(_laundering.CreateEntry<float>("VicDepositTrigger", 10000f, "Deposit Trigger Amount", "Weekly deposit total that triggers Vic's intro quest", false, false, (ValueValidator)null, (string)null)); _bella = MelonPreferences.CreateCategory("OverTheCounter_Bella", "Bella Protocol"); BellaWeedValue = Register(_bella.CreateEntry<float>("BellaWeedValue", 105f, "Weed Mix Value", "Minimum base price for the weed mix Bella requires", false, false, (ValueValidator)null, (string)null)); BellaMethValue = Register(_bella.CreateEntry<float>("BellaMethValue", 200f, "Meth Mix Value", "Minimum base price for the meth mix Bella requires", false, false, (ValueValidator)null, (string)null)); BellaCokeValue = Register(_bella.CreateEntry<float>("BellaCokeValue", 400f, "Cocaine Mix Value", "Minimum base price for the cocaine mix Bella requires", false, false, (ValueValidator)null, (string)null)); _notifications = MelonPreferences.CreateCategory("OverTheCounter_Notifications", "Contract Notifications"); ConsolidationEnabled = Register(_notifications.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable contract consolidation (groups same-window deliveries into one HUD entry)", false, false, (ValueValidator)null, (string)null)); ConsolidationThreshold = Register(_notifications.CreateEntry<int>("ConsolidationThreshold", 5, "Consolidation Threshold", "Minimum contracts in a window before consolidation kicks in", false, false, (ValueValidator)null, (string)null)); _subscription = MelonPreferences.CreateCategory("OverTheCounter_Subscription", "Static Subscription"); SaasWeeklyCost = Register(_subscription.CreateEntry<float>("SaasWeeklyCost", 1000f, "Weekly Cost", "Bank balance deducted each billing cycle", false, false, (ValueValidator)null, (string)null)); SaasCycleDays = Register(_subscription.CreateEntry<int>("SaasCycleDays", 7, "Cycle Days", "Number of days between subscription payments", false, false, (ValueValidator)null, (string)null)); StaticTier1BankCost = Register(_subscription.CreateEntry<float>("StaticTier1BankCost", 3000f, "Tier 1 Bank Cost", "Bank transfer cost for the initial software package", false, false, (ValueValidator)null, (string)null)); StaticTier1WeedGrams = Register(_subscription.CreateEntry<int>("StaticTier1WeedGrams", 20, "Tier 1 Weed Grams", "Grams of weed required for the initial package", false, false, (ValueValidator)null, (string)null)); StaticTier2BankCost = Register(_subscription.CreateEntry<float>("StaticTier2BankCost", 6000f, "Tier 2 Bank Cost", "Bank transfer cost for the Premium upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier2MethGrams = Register(_subscription.CreateEntry<int>("StaticTier2MethGrams", 5, "Tier 2 Meth Grams", "Grams of meth required for the Premium upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier3BankCost = Register(_subscription.CreateEntry<float>("StaticTier3BankCost", 12000f, "Tier 3 Bank Cost", "Bank transfer cost for the Enterprise upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier3PremiumMethGrams = Register(_subscription.CreateEntry<int>("StaticTier3PremiumMethGrams", 10, "Tier 3 Premium Meth Grams", "Grams of premium meth required for Enterprise upgrade", false, false, (ValueValidator)null, (string)null)); _world = MelonPreferences.CreateCategory("OverTheCounter_World", "World"); ShackPurchasePrice = Register(_world.CreateEntry<float>("ShackPurchasePrice", 5000f, "Shack Purchase Price", "Bank transfer cost for the Westville Shack property", false, false, (ValueValidator)null, (string)null)); WarehousePurchasePrice = Register(_world.CreateEntry<float>("WarehousePurchasePrice", 18000f, "Warehouse Purchase Price", "Bank transfer cost for the Warehouse property", false, false, (ValueValidator)null, (string)null)); DispensaryPurchasePrice = Register(_world.CreateEntry<float>("DispensaryPurchasePrice", 30000f, "Dispensary Purchase Price", "Bank transfer cost for the Big Dispensary property", false, false, (ValueValidator)null, (string)null)); StackSizeMultiplier = Register(_world.CreateEntry<int>("StackSizeMultiplier", 1, "Stack Size Multiplier", "Multiplies the stack limit of all stackable items by this value. 1 = vanilla stacks (default). 2 = double stacks. Affects all inventories. Host value is used in multiplayer. Changing mid-save does not retroactively adjust existing item quantities.", false, false, (ValueValidator)(object)new ValueRange<int>(1, 10), (string)null)); GraffitiReEdit = Register(_world.CreateEntry<bool>("GraffitiReEdit", true, "Graffiti Re-Edit", "Allow re-editing spray paint surfaces without consuming spray cans. Spray can must still be equipped to interact.", false, false, (ValueValidator)null, (string)null)); RecipePinEnabled = Register(_world.CreateEntry<bool>("RecipePinEnabled", true, "Recipe Pin", "Show a Pin Recipe button in the Product Manager app. Pins a draggable overlay showing the full mixing chain for a product.", false, false, (ValueValidator)null, (string)null)); ShackDailyCustomerCap = Register(_world.CreateEntry<int>("ShackDailyCustomerCap", 12, "Shack Daily Customer Cap", "Maximum customers redirected to the Westville Shack per day", false, false, (ValueValidator)null, (string)null)); PreserveVanillaDeals = Register(_world.CreateEntry<bool>("PreserveVanillaDeals", false, "Preserve Vanilla Deals", "When enabled, vanilla NPCs keep their normal deal behavior instead of being redirected to the dispensary. Each redirected deal has a chance (set by Mirror Spawn Rate) to also spawn a random walk-in customer. Off by default because keeping both vanilla deals AND dispensary sales effectively doubles income.", false, false, (ValueValidator)null, (string)null)); WalkInMirrorRate = Register(_world.CreateEntry<float>("WalkInMirrorRate", 0.4f, "Mirror Spawn Rate", "Only used when Preserve Vanilla Deals is enabled. Chance (0-1) that each vanilla deal that would have been redirected also spawns a random store customer. Has no effect when Preserve Vanilla Deals is off. 0.4 = 40% of deals spawn one. 1.0 = every deal spawns one.", false, false, (ValueValidator)(object)new ValueRange<float>(0f, 1f), (string)null)); _desperation = MelonPreferences.CreateCategory("OverTheCounter", "Desperation System"); DesperationEnabled = Register(_desperation.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable the desperation system (urgent fiend requests)", false, false, (ValueValidator)null, (string)null)); FiendAddictionThreshold = Register(_desperation.CreateEntry<float>("FiendAddictionThreshold", 0.67f, "Fiend Addiction Threshold", "Addiction level required to qualify as a Fiend (0.0–1.0)", false, false, (ValueValidator)null, (string)null)); TriggerChancePerHour = Register(_desperation.CreateEntry<float>("TriggerChancePerHour", 0.12f, "Trigger Chance Per Hour", "Probability of a desperation event each hour (0.0–1.0)", false, false, (ValueValidator)null, (string)null)); MaxEventsPerDay = Register(_desperation.CreateEntry<int>("MaxEventsPerDay", 3, "Max Events Per Day", "Hard cap on desperation events per day", false, false, (ValueValidator)null, (string)null)); ResponseDeadlineMinutes = Register(_desperation.CreateEntry<int>("ResponseDeadlineMinutes", 60, "Response Deadline (min)", "In-game minutes the player has to respond to a desperation offer", false, false, (ValueValidator)null, (string)null)); DeadlineMinutes = Register(_desperation.CreateEntry<int>("DeadlineMinutes", 120, "Delivery Deadline (min)", "In-game minutes to deliver after accepting a desperation contract", false, false, (ValueValidator)null, (string)null)); BonusMultiplier = Register(_desperation.CreateEntry<float>("BonusMultiplier", 0.45f, "Bonus Multiplier", "Extra payment multiplier for desperation deliveries (0.45 = 45%)", false, false, (ValueValidator)null, (string)null)); RelationshipPenalty = Register(_desperation.CreateEntry<float>("RelationshipPenalty", -15f, "Relationship Penalty", "Relationship change on failed desperation event", false, false, (ValueValidator)null, (string)null)); CooldownMinutes = Register(_desperation.CreateEntry<int>("CooldownMinutes", 1440, "Cooldown (min)", "Minutes a customer is locked out after a failed event (1440 = 24h)", false, false, (ValueValidator)null, (string)null)); DayStartHour = Register(_desperation.CreateEntry<int>("DayStartHour", 800, "Day Start Hour", "Earliest 24h time for desperation rolls (800 = 8:00 AM)", false, false, (ValueValidator)null, (string)null)); DayEndHour = Register(_desperation.CreateEntry<int>("DayEndHour", 2100, "Day End Hour", "Latest 24h time for desperation rolls (2100 = 9:00 PM)", false, false, (ValueValidator)null, (string)null)); _drifters = MelonPreferences.CreateCategory("OverTheCounter_Drifters", "Drifter System"); DrifterEnabled = Register(_drifters.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable the drifter system (random street NPCs offering one-time deals)", false, false, (ValueValidator)null, (string)null)); DrifterSpawnChancePerHour = Register(_drifters.CreateEntry<float>("DrifterSpawnChancePerHour", 0.38f, "Spawn Chance Per Hour", "Base spawn chance per hour at max regions. Scaled down by unlocked region count (0.0-1.0)", false, false, (ValueValidator)null, (string)null)); MaxActiveDrifters = Register(_drifters.CreateEntry<int>("MaxActiveDrifters", 3, "Max Active Drifters", "Maximum number of drifters that can be active at once", false, false, (ValueValidator)null, (string)null)); DrifterDayStartHour = Register(_drifters.CreateEntry<int>("DrifterDayStartHour", 800, "Day Start Hour", "Earliest 24h time for drifter spawns (800 = 8:00 AM)", false, false, (ValueValidator)null, (string)null)); DrifterDayEndHour = Register(_drifters.CreateEntry<int>("DrifterDayEndHour", 2100, "Day End Hour", "Latest 24h time for drifter spawns (2100 = 9:00 PM)", false, false, (ValueValidator)null, (string)null)); DrifterOfferWindowMin = Register(_drifters.CreateEntry<int>("DrifterOfferWindowMin", 120, "Offer Window (min)", "Minutes player has to respond to a drifter offer (120 = 2 hours)", false, false, (ValueValidator)null, (string)null)); DrifterDeliveryDeadlineMin = Register(_drifters.CreateEntry<int>("DrifterDeliveryDeadlineMin", 240, "Delivery Deadline (min)", "Minutes to deliver after accepting a drifter deal (240 = 4 hours)", false, false, (ValueValidator)null, (string)null)); DrifterLingerMinMin = Register(_drifters.CreateEntry<int>("DrifterLingerMinMin", 30, "Linger Min (min)", "Minimum minutes a drifter lingers after deal completion/expiry", false, false, (ValueValidator)null, (string)null)); DrifterLingerMaxMin = Register(_drifters.CreateEntry<int>("DrifterLingerMaxMin", 60, "Linger Max (min)", "Maximum minutes a drifter lingers after deal completion/expiry", false, false, (ValueValidator)null, (string)null)); DrifterMinDealValue = Register(_drifters.CreateEntry<float>("DrifterMinDealValue", 90f, "Min Deal Value ($)", "Soft minimum deal value - drifters ask for more quantity until the deal reaches this threshold", false, false, (ValueValidator)null, (string)null)); _debug = MelonPreferences.CreateCategory("OverTheCounter_Debug", "Debug"); VerboseLogging = Register(_debug.CreateEntry<bool>("VerboseLogging", false, "Verbose Logging (General)", "Catch-all verbose logging for systems without a dedicated toggle", false, false, (ValueValidator)null, (string)null)); ManagerVerboseLogging = Register(_debug.CreateEntry<bool>("ManagerVerboseLogging", false, "Verbose: Manager", "Enable detailed manager logging (shopping list breakdowns, per-item details)", false, false, (ValueValidator)null, (string)null)); DrifterVerboseLogging = Register(_debug.CreateEntry<bool>("DrifterVerboseLogging", false, "Verbose: Drifter", "Enable detailed drifter system logging", false, false, (ValueValidator)null, (string)null)); DesperationVerboseLogging = Register(_debug.CreateEntry<bool>("DesperationVerboseLogging", false, "Verbose: Desperation", "Enable detailed desperation system logging", false, false, (ValueValidator)null, (string)null)); NpcVerboseLogging = Register(_debug.CreateEntry<bool>("NpcVerboseLogging", false, "Verbose: NPC", "Enable detailed NPC logging (Vic, Bella, Static)", false, false, (ValueValidator)null, (string)null)); NetworkVerboseLogging = Register(_debug.CreateEntry<bool>("NetworkVerboseLogging", false, "Verbose: Network", "Enable detailed network sync logging", false, false, (ValueValidator)null, (string)null)); QuestVerboseLogging = Register(_debug.CreateEntry<bool>("QuestVerboseLogging", false, "Verbose: Quest", "Enable detailed quest logging", false, false, (ValueValidator)null, (string)null)); NotificationVerboseLogging = Register(_debug.CreateEntry<bool>("NotificationVerboseLogging", false, "Verbose: Notification", "Enable detailed notification system logging", false, false, (ValueValidator)null, (string)null)); PatchVerboseLogging = Register(_debug.CreateEntry<bool>("PatchVerboseLogging", false, "Verbose: Patch", "Enable detailed Harmony patch logging", false, false, (ValueValidator)null, (string)null)); ProfilingEnabled = Register(_debug.CreateEntry<bool>("ProfilingEnabled", false, "Performance Profiling", "Write periodic performance reports to UserData/OTC_PerfReport.txt", false, false, (ValueValidator)null, (string)null)); _minimapPoi = MelonPreferences.CreateCategory("OverTheCounter_MinimapPOI", "Minimap POIs"); MinimapShowPotentialCustomers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowPotentialCustomers", true, "Show Potential Customers", "Show potential customer icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowCustomers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowCustomers", false, "Show Customers", "Show unlocked customer icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowDealers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowDealers", true, "Show Dealers", "Show dealer icons on the minimap (potential and active)", false, false, (ValueValidator)null, (string)null)); MinimapShowDeadDrops = Register(_minimapPoi.CreateEntry<bool>("MinimapShowDeadDrops", true, "Show Dead Drops", "Show dead drop icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowContracts = Register(_minimapPoi.CreateEntry<bool>("MinimapShowContracts", true, "Show Contracts", "Show contract delivery icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowQuests = Register(_minimapPoi.CreateEntry<bool>("MinimapShowQuests", true, "Show Quests", "Show quest objective icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowProperties = Register(_minimapPoi.CreateEntry<bool>("MinimapShowProperties", true, "Show Properties", "Show owned property icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowManagers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowManagers", true, "Show Managers", "Show manager icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowModdedNPCs = Register(_minimapPoi.CreateEntry<bool>("MinimapShowModdedNPCs", true, "Show Modded NPCs", "Show NPC icons added by other mods (e.g. police, cartel) on the minimap", false, false, (ValueValidator)null, (string)null)); _minimap = MelonPreferences.CreateCategory("OverTheCounter_Minimap", "Minimap"); MinimapEnabled = Register(_minimap.CreateEntry<bool>("MinimapEnabled", false, "Enabled", "Show the minimap overlay", false, false, (ValueValidator)null, (string)null)); MinimapSize = Register(_minimap.CreateEntry<int>("MinimapSize", 250, "Size (px)", "Minimap size in pixels", false, false, (ValueValidator)null, (string)null)); MinimapRotateWithPlayer = Register(_minimap.CreateEntry<bool>("MinimapRotateWithPlayer", false, "Rotate With Player", "Rotate minimap to match player facing direction", false, false, (ValueValidator)null, (string)null)); MinimapCircle = Register(_minimap.CreateEntry<bool>("MinimapCircle", false, "Circle Shape", "Use circular minimap shape instead of square", false, false, (ValueValidator)null, (string)null)); MinimapDefaultZoom = Register(_minimap.CreateEntry<int>("MinimapDefaultZoom", 2, "Default Zoom", "Starting zoom level, 1=closest, 3=farthest (1-3)", false, false, (ValueValidator)null, (string)null)); MinimapIconScale = Register(_minimap.CreateEntry<float>("MinimapIconScale", 0.7f, "Icon Scale", "POI icon scale on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapToggleKey = _minimap.CreateEntry<KeyCode>("MinimapToggleKey", (KeyCode)110, "Toggle Key", "Hotkey to cycle minimap zoom", false, false, (ValueValidator)null, (string)null); MinimapHorizontalOffset = Register(_minimap.CreateEntry<int>("MinimapHorizontalOffset", 100, "Horizontal Offset", "Horizontal position (0=left, 100=right)", false, false, (ValueValidator)(object)new ValueRange<int>(0, 100), (string)null)); MinimapVerticalOffset = Register(_minimap.CreateEntry<int>("MinimapVerticalOffset", 0, "Vertical Offset", "Vertical position (0=top, 100=bottom)", false, false, (ValueValidator)(object)new ValueRange<int>(0, 100), (string)null)); MinimapInfoOnTop = Register(_minimap.CreateEntry<bool>("MinimapInfoOnTop", false, "Info Panels On Top", "Place clock and day display above the minimap instead of below", false, false, (ValueValidator)null, (string)null)); MinimapBorderColor = _minimap.CreateEntry<Color>("MinimapBorderColor", new Color(0.2f, 0.2f, 0.2f, 0.9f), "Border Color", "Minimap border color", false, false, (ValueValidator)null, (string)null); MinimapBorderWidth = Register(_minimap.CreateEntry<int>("MinimapBorderWidth", 4, "Border Width", "Border thickness in pixels per side (2-10)", false, false, (ValueValidator)null, (string)null)); MinimapShowTime = Register(_minimap.CreateEntry<bool>("MinimapShowTime", true, "Show Time", "Display the current time near the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowDay = Register(_minimap.CreateEntry<bool>("MinimapShowDay", true, "Show Day", "Display the current day near the minimap", false, false, (ValueValidator)null, (string)null)); MinimapUse24HourClock = Register(_minimap.CreateEntry<bool>("MinimapUse24HourClock", false, "24-Hour Clock", "Use 24-hour time format instead of 12-hour AM/PM", false, false, (ValueValidator)null, (string)null)); MinimapShowCompass = Register(_minimap.CreateEntry<bool>("MinimapShowCompass", true, "Show Compass", "Display N/S/E/W cardinal direction labels on the minimap edge", false, false, (ValueValidator)null, (string)null)); MinimapShowEdgeIndicators = Register(_minimap.CreateEntry<bool>("MinimapShowEdgeIndicators", true, "Edge Indicators", "Show POI icons pinned to the minimap edge for off-screen points of interest", false, false, (ValueValidator)null, (string)null)); MinimapPerfLimit = Register(_minimap.CreateEntry<bool>("MinimapPerfLimit", true, "Performance Limiting", "Adaptively reduce minimap update rate to limit CPU usage", false, false, (ValueValidator)null, (string)null)); _hud = MelonPreferences.CreateCategory("OverTheCounter_HUD", "HUD Overlay"); HUDShowRankXP = Register(_hud.CreateEntry<bool>("HUDShowRankXP", false, "Show Rank/XP", "Display rank and XP progress bar above the hotbar", false, false, (ValueValidator)null, (string)null)); HUDShowHealth = Register(_hud.CreateEntry<bool>("HUDShowHealth", false, "Show Health", "Display health bar above the hotbar", false, false, (ValueValidator)null, (string)null)); HUDShowStamina = Register(_hud.CreateEntry<bool>("HUDShowStamina", false, "Show Stamina", "Display stamina bar above the hotbar", false, false, (ValueValidator)null, (string)null)); StoreAlertEnabled = Register(_hud.CreateEntry<bool>("StoreAlertEnabled", true, "Show Store Alerts", "Show checkout queue alerts on the right side of the screen", false, false, (ValueValidator)null, (string)null)); } private static ConfigEntry<float> Register(MelonPreferences_Entry<float> entry) { ConfigEntry<float> configEntry = new ConfigEntry<float>(entry); _floatEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } private static ConfigEntry<int> Register(MelonPreferences_Entry<int> entry) { ConfigEntry<int> configEntry = new ConfigEntry<int>(entry); _intEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } private static ConfigEntry<bool> Register(MelonPreferences_Entry<bool> entry) { ConfigEntry<bool> configEntry = new ConfigEntry<bool>(entry); _boolEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } public static string SerializeAll() { List<string> list = new List<string>(); foreach (KeyValuePair<string, ConfigEntry<float>> floatEntry in _floatEntries) { if (!_localOnlyKeys.Contains(floatEntry.Key)) { list.Add(floatEntry.Key + "=" + floatEntry.Value.RawEntry.Value.ToString(CultureInfo.InvariantCulture)); } } foreach (KeyValuePair<string, ConfigEntry<int>> intEntry in _intEntries) { if (!_localOnlyKeys.Contains(intEntry.Key)) { list.Add(intEntry.Key + "=" + intEntry.Value.RawEntry.Value.ToString(CultureInfo.InvariantCulture)); } } foreach (KeyValuePair<string, ConfigEntry<bool>> boolEntry in _boolEntries) { if (!_localOnlyKeys.Contains(boolEntry.Key)) { list.Add($"{boolEntry.Key}={boolEntry.Value.RawEntry.Value}"); } } return string.Join("|", list); } public static void ApplyOverrides(Dictionary<string, string> data) { foreach (KeyValuePair<string, string> datum in data) { if (_localOnlyKeys.Contains(datum.Key)) { continue; } ConfigEntry<int> value2; ConfigEntry<bool> value3; bool result3; if (_floatEntries.TryGetValue(datum.Key, out var value)) { if (float.TryParse(datum.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { value.SetOverride(result); } } else if (_intEntries.TryGetValue(datum.Key, out value2)) { if (int.TryParse(datum.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { value2.SetOverride(result2); } } else if (_boolEntries.TryGetValue(datum.Key, out value3) && bool.TryParse(datum.Value, out result3)) { value3.SetOverride(result3); } } } public static void ClearAllOverrides() { foreach (ConfigEntry<float> value in _floatEntries.Values) { value.ClearOverride(); } foreach (ConfigEntry<int> value2 in _intEntries.Values) { value2.ClearOverride(); } foreach (ConfigEntry<bool> value3 in _boolEntries.Values) { value3.ClearOverride(); } } public static void SubscribeToChanges() { foreach (KeyValuePair<string, ConfigEntry<float>> floatEntry in _floatEntries) { if (!_localOnlyKeys.Contains(floatEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)floatEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } foreach (KeyValuePair<string, ConfigEntry<int>> intEntry in _intEntries) { if (!_localOnlyKeys.Contains(intEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)intEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } foreach (KeyValuePair<string, ConfigEntry<bool>> boolEntry in _boolEntries) { if (!_localOnlyKeys.Contains(boolEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)boolEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } } private static void OnSyncableEntryChanged(object oldValue, object newValue) { if (NetworkHelper.IsHost) { ConfigSyncData.Instance?.RefreshFromConfig(); } } } } namespace OverTheCounter.Quests { internal static class QuestHelper { public static string StableGuid(string key) { if (string.IsNullOrEmpty(key)) { throw new ArgumentException("StableGuid key cannot be null/empty", "key"); } using MD5 mD = MD5.Create(); return new Guid(mD.ComputeHash(Encoding.UTF8.GetBytes("otc-quest:" + key))).ToString(); } public static T CreateWithGuid<T>(string guid) where T : Quest { T val = (T)(object)QuestManager.CreateQuest<T>((string)null); if (val == null) { OTCLog.Error("Quest", "QuestManager.CreateQuest<" + typeof(T).Name + "> returned null."); return default(T); } TryForceInit((Quest)(object)val, guid); return val; } public static string GetCurrentGuid(Quest quest) { if (quest == null) { return string.Empty; } Quest s1Quest = GetS1Quest(quest); return ((s1Quest != null) ? s1Quest.StaticGUID : null) ?? string.Empty; } private static void TryForceInit(Quest quest, string guid) { try { Quest s1Quest = GetS1Quest(quest); if ((Object)(object)s1Quest == (Object)null) { OTCLog.Warning("Quest", "TryForceInit: S1Quest field not found on " + ((object)quest).GetType().Name + "."); return; } s1Quest.StaticGUID = guid; string protectedString = GetProtectedString(quest, "Title"); string protectedString2 = GetProtectedString(quest, "Description"); Il2CppReferenceArray<QuestEntryData> val = new Il2CppReferenceArray<QuestEntryData>(0L); s1Quest.InitializeQuest(protectedString ?? string.Empty, protectedString2 ?? string.Empty, val, guid); } catch (Exception ex) { OTCLog.Error("Quest", "TryForceInit failed for " + ((object)quest).GetType().Name + ": " + ex.Message); } } private static Quest GetS1Quest(Quest quest) { object? obj = typeof(Quest).GetField("S1Quest", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(quest); return (Quest)((obj is Quest) ? obj : null); } private static string GetProtectedString(Quest quest, string propertyName) { return ((object)quest).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(quest) as string; } } public class VicIntroQuest : Quest { [SaveableField("vic_quest_stage")] private int _stage; private QuestEntry _meetVicEntry; private QuestEntry _bringWeedEntry; private static readonly Vector3 VicPosition = new Vector3(67.75f, 0.97f, 32.36f); protected override string Title => "Rinse Cycle"; protected override string Description => "Help Vic with his party supplies and he'll help you clean some cash."; protected override bool AutoBegin => false; protected override Sprite QuestIcon { get { if (Core.OtcIconDir == null) { return null; } return ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "RinseCycle.png")); } } public static VicIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) try { _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetWeedText() { return $"Bring Vic {Config.VicIntroWeedGrams.Value} grams of weed"; } public void RefreshEntryText() { if (_bringWeedEntry != null && _stage >= 1 && _stage < 3) { _bringWeedEntry.Title = GetWeedText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } QuestEntry meetVicEntry2 = _meetVicEntry; if (meetVicEntry2 != null) { meetVicEntry2.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } QuestEntry bringWeedEntry2 = _bringWeedEntry; if (bringWeedEntry2 != null) { bringWeedEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj2 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { if (VicSaveData.Instance != null) { int num = (VicSaveData.Instance.Unlocked ? 3 : (VicSaveData.Instance.QuestAccepted ? 2 : (VicSaveData.Instance.HasBeenTexted ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); if (_stage >= 1) { QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } } if (_stage >= 2) { QuestEntry meetVicEntry2 = _meetVicEntry; if (meetVicEntry2 != null) { meetVicEntry2.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } if (_stage >= 3) { QuestEntry bringWeedEntry2 = _bringWeedEntry; if (bringWeedEntry2 != null) { bringWeedEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } internal static class QuestIconHelper { private static readonly Dictionary<int, Sprite> _cache = new Dictionary<int, Sprite>(); private static string IconPath { get { if (Core.OtcIconDir == null) { return null; } return Path.Combine(Core.OtcIconDir, "CrimeWareQuest.png"); } } internal static Sprite Load() { if (IconPath == null) { return null; } return ImageUtils.LoadImage(IconPath); } internal static Sprite LoadTinted(Color tint) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) int hashCode = ((object)(Color)(ref tint)).GetHashCode(); if (_cache.TryGetValue(hashCode, out var value) && (Object)(object)value != (Object)null) { return value; } try { byte[] array = File.ReadAllBytes(IconPath); Texture2D val = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array))) { return Load(); } Il2CppStructArray<Color> pixels = val.GetPixels(); for (int i = 0; i < ((Il2CppArrayBase<Color>)(object)pixels).Length; i++) { ((Il2CppArrayBase<Color>)(object)pixels)[i] = new Color(((Il2CppArrayBase<Color>)(object)pixels)[i].r * tint.r, ((Il2CppArrayBase<Color>)(object)pixels)[i].g * tint.g, ((Il2CppArrayBase<Color>)(object)pixels)[i].b * tint.b, ((Il2CppArrayBase<Color>)(object)pixels)[i].a); } val.SetPixels(pixels); val.Apply(); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); _cache[hashCode] = val2; return val2; } catch { return Load(); } } } internal static class QuestPoiFixer { [CompilerGenerated] private sealed class <FixPositionDelayed>d__2 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Vector3 worldPos; public QuestEntry entry; private int <i>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FixPositionDelayed>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0180: 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_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; OTCLog.Msg("Quest", $"QuestPoiFixer: starting, target={worldPos}"); <i>5__2 = 0; break; case 1: <>1__state = -1; <i>5__2++; break; } if (<i>5__2 < 5) { <>2__current = null; <>1__state = 1; return true; } try { if (_s1EntryField == null) { _s1EntryField = typeof(QuestEntry).GetField("S1QuestEntry", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } OTCLog.Msg("Quest", $"QuestPoiFixer: field={_s1EntryField != null}"); object? obj = _s1EntryField?.GetValue(entry); QuestEntry val = (QuestEntry)((obj is QuestEntry) ? obj : null); if ((Object)(object)val == (Object)null) { OTCLog.Warning("Quest", "QuestPoiFixer: s1Entry is null"); return false; } Transform poILocation = val.PoILocation; POI poI = val.PoI; OTCLog.Msg("Quest", $"QuestPoiFixer: PoILocation={(Object)(object)poILocation != (Object)null} pos={((poILocation != null) ? new Vector3?(poILocation.position) : null)} PoI={(Object)(object)poI != (Object)null} poiPos={((poI != null) ? new Vector3?(((Component)poI).transform.position) : null)}"); val.SetPoILocation(worldPos); DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(63, 2); defaultInterpolatedStringHandler.AppendLiteral("QuestPoiFixer: AFTER SetPoILocation → PoILocation.pos="); Transform poILocation2 = val.PoILocation; defaultInterpolatedStringHandler.AppendFormatted((poILocation2 != null) ? new Vector3?(poILocation2.position) : null); defaultInterpolatedStringHandler.AppendLiteral(" PoI.pos="); POI poI2 = val.PoI; defaultInterpolatedStringHandler.AppendFormatted((poI2 != null) ? new Vector3?(((Component)poI2).transform.position) : null); OTCLog.Msg("Quest", defaultInterpolatedStringHandler.ToStringAndClear()); } catch (Exception ex) { OTCLog.Warning("Quest", "QuestPoiFixer failed: " + ex.Message); } 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 FieldInfo _s1EntryField; public static void FixPosition(QuestEntry entry, Vector3 worldPos) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (entry != null) { MelonCoroutines.Start(FixPositionDelayed(entry, worldPos)); } } [IteratorStateMachine(typeof(<FixPositionDelayed>d__2))] private static IEnumerator FixPositionDelayed(QuestEntry entry, Vector3 worldPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FixPositionDelayed>d__2(0) { entry = entry, worldPos = worldPos }; } } public class StaticIntroQuest : Quest { [SaveableField("static_quest_stage")] private int _stage; private QuestEntry _checkMessagesEntry; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Crimeware as a Service"; protected override string Description => "Someone noticed your operation. Check the OTC app for a new message."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticIntroQuest Instance { get; private set; } public int Stage => _stage; private static Vector3 DeadDropPosition => CasinoDeadDrop.Position; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) try { _checkMessagesEntry = ((Quest)this).AddEntry("Check your messages in the OTC app", (Vector3?)null); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)DeadDropPosition); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier1BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier1WeedGrams.Value}g weed at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 2 && _stage < 4) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 2 && _stage < 4) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) try { _stage = 2; QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } QuestEntry checkMessagesEntry2 = _checkMessagesEntry; if (checkMessagesEntry2 != null) { checkMessagesEntry2.Complete(); } QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, DeadDropPosition); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj2 failed: " + ex.Message); } } public void CompleteObj3() { try { _stage = 4; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj3 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { if (StaticSaveData.Instance != null) { int num = ((StaticSaveData.Instance.CrmTier >= 1) ? 4 : (StaticSaveData.Instance.IntroCompleted ? 2 : (StaticSaveData.Instance.QuestTriggered ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _checkMessagesEntry = ((Quest)this).AddEntry("Check your messages in the OTC app", (Vector3?)null); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)DeadDropPosition); if (_stage >= 1) { QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } } if (_stage >= 2) { QuestEntry checkMessagesEntry2 = _checkMessagesEntry; if (checkMessagesEntry2 != null) { checkMessagesEntry2.Complete(); } QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, DeadDropPosition); } if (_stage >= 2 && _stage < 4 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.Tier1MoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.Tier1ProductDelivered) { CompleteDropOff(); } } if (_stage >= 4) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade1Quest : Quest { [SaveableField("static_upgrade1_stage")] private int _stage; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Premium Tier"; protected override string Description => "Static has the premium tier upgrade available. Pay and deliver via the OTC app."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticUpgrade1Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) try { _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier2BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier2MethGrams.Value}g meth at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 1 && _stage < 2) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 1 && _stage < 2) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) try { _stage = 1; ((Quest)this).Begin(); QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0038: 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) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); if (_stage >= 1) { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } if (_stage >= 1 && _stage < 2 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.UpgradeMoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.UpgradeProductDelivered) { CompleteDropOff(); } } if (_stage >= 2) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade2Quest : Quest { [SaveableField("static_upgrade2_stage")] private int _stage; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Full Scale"; protected override string Description => "Static has the final tier-3 enterprise upgrade available. Pay and deliver via the OTC app."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticUpgrade2Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) try { _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier3BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier3PremiumMethGrams.Value}g premium meth at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 1 && _stage < 2) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 1 && _stage < 2) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) try { _stage = 1; ((Quest)this).Begin(); QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0038: 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) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); if (_stage >= 1) { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } if (_stage >= 1 && _stage < 2 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.UpgradeMoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.UpgradeProductDelivered) { CompleteDropOff(); } } if (_stage >= 2) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class DrifterDealQuest : Quest { private string _title; private string _description; private QuestEntry _deliverEntry; private int _deadlineElapsedMinutes; protected override string Title => _title ?? "Drifter Deal"; protected override string Description => _description ?? "Complete a deal with a drifter."; protected override bool AutoBegin => false; protected override Sprite QuestIcon { get { if (Core.OtcIconDir == null) { return null; } return ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "DrifterQuestIcon.png")); } } public string DrifterId { get; private set; } public static Dictionary<string, DrifterDealQuest> ActiveQuests { get; } = new Dictionary<string, DrifterDealQuest>(); private Quest GetS1Quest() { object? obj = typeof(Quest).GetField("S1Quest", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(this); return (Quest)((obj is Quest) ? obj : null); } private void TriggerInternalInit() { try { Quest s1Quest = GetS1Quest(); if (!((Object)(object)s1Quest == (Object)null)) { s1Quest.InitializeQuest(((Quest)this).Title, ((Quest)this).Description, Il2CppReferenceArray<QuestEntryData>.op_Implicit(Array.Empty<QuestEntryData>()), s1Quest.StaticGUID); } } catch (Exception ex) { OTCLog.Error("Quest", "TriggerInternalInit failed: " + ex.Message); } } public void Initialize(string drifterId, string productName, int quantity, float payment, Vector3 destination, string locationDesc, int deadlineElapsedMinutes) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) DrifterId = drifterId; _title = "Drifter Deal"; _description = $"Deliver {quantity} {productName} for ${payment:F0}"; _deadlineElapsedMinutes = deadlineElapsedMinutes; TriggerInternalInit(); _deliverEntry = ((Quest)this).AddEntry($"Deliver {quantity} {productName} to the drifter {locationDesc}", (Vector3?)destination); ActiveQuests[drifterId] = this; } public void StartQuest() { try { ((Quest)this).Begin(); QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void UpdateTiming() { try { if (_deadlineElapsedMinutes > 0) { int currentElapsedMinutes = GetCurrentElapsedMinutes(); int num = _deadlineElapsedMinutes - currentElapsedMinutes; if (num < 0) { num = 0; } int num2 = num / 60; int value = num % 60; string subtitleViaReflection = ((num >= 120) ? $"<color=green> (Expires in {num2}h {value}m)</color>" : ((num2 <= 0) ? $"<color=#ff6b6b> (Expires in {num} min)</color>" : $"<color=#ff6b6b> (Expires in {num2}h {value}m)</color>")); SetSubtitleViaReflection(subtitleViaReflection); } } catch (Exception ex) { OTCLog.Warning("Quest", "UpdateTiming failed: " + ex.Message); } } private void SetSubtitleViaReflection(string subtitle) { try { Quest s1Quest = GetS1Quest(); if (!((Object)(object)s1Quest == (Object)null)) { s1Quest.SetSubtitle(subtitle); if ((Object)(object)s1Quest.hudUI != (Object)null) { s1Quest.hudUI.UpdateMainLabel(); } } } catch (Exception ex) { OTCLog.Warning("Quest", "SetSubtitleViaReflection failed: " + ex.Message); } } private static int GetCurrentElapsedMinutes() { int elapsedDays = TimeManager.ElapsedDays; int currentTime = TimeManager.CurrentTime; int num = currentTime / 100; int num2 = currentTime % 100; return elapsedDays * 1440 + num * 60 + num2; } public void CompleteDeal() { try { QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Complete(); } ((Quest)this).Complete(); ((Quest)this).End(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteDeal failed: " + ex.Message); } } public void FailDeal() { try { QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Complete(); } ((Quest)this).Fail(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "FailDeal failed: " + ex.Message); } } public void CancelDeal() { try { ((Quest)this).Cancel(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "CancelDeal failed: " + ex.Message); } } } public enum QuestHighlight { None, InventoryNav, PricingArea, ProductRows, OverviewNav, StoreToggle } public class StorefrontGrowthQuest : Quest { [SaveableField("storefront_quest_stage")] private int _stage; [SaveableField("storefront_quest_touched_pricing")] private bool _hasTouchedPricing; [SaveableField("storefront_quest_viewed_product")] private bool _hasViewedProduct; private QuestEntry _placeStorageEntry; private QuestEntry _stockProductEntry; private QuestEntry _setPricesEntry; private QuestEntry _viewProductEntry; private QuestEntry _turnOnLightsEntry; private QuestEntry _openStoreEntry; private QuestEntry _makeSaleEntry; private static readonly Vector3 ShackPosition = new Vector3(-164.4f, -3f, 76f); private float _lastTickTime; private const float TickInterval = 3f; private TutorialCustomerHelper _tutorialCustomer; protected override string Title => "Storefront Growth"; protected override string Description => "You've got the keys. Now turn this place into a working storefront."; protected override bool AutoBegin => false; protected override Sprite QuestIcon { get { if (Core.OtcIconDir == null) { return null; } return ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "StoreAlertIcon.png")); } } public static StorefrontGrowthQuest Instance { get; private set; } public int Stage => _stage; public static QuestHighlight ActiveHighlight { get { if (Instance == null) { return QuestHighlight.None; } return Instance._stage switch { 3 => QuestHighlight.InventoryNav, 4 => QuestHighlight.InventoryNav, 6 => QuestHighlight.OverviewNav, _ => QuestHighlight.None, }; } } internal static void ResetInstance() { Instance = null; } private TutorialCustomerHelper GetTutorialCustomer() { return _tutorialCustomer ?? (_tutorialCustomer = new TutorialCustomerHelper("westville_shack", () => WestvilleShack.IsStoreOpen, () => WestvilleShack.Target)); } private void TriggerInternalInit() { try { FieldInfo field = typeof(Quest).GetField("S1Quest", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object? value = field.GetValue(this); Quest val = (Quest)((value is Quest) ? value : null); if (!((Object)(object)val == (Object)null)) { val.InitializeQuest(((Quest)this).Title, ((Quest)this).Description, Il2CppReferenceArray<QuestEntryData>.op_Implicit(Array.Empty<QuestEntryData>()), val.StaticGUID); } } } catch (Exception ex) { OTCLog.Error("Quest", "StorefrontGrowth TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { try { TriggerInternalInit(); BuildEntries(); } catch (Exception ex) { OTCLog.Error("Quest", "StorefrontGrowth Initialize failed: " + ex.Message); } } private void BuildEntries() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) _placeStorageEntry = ((Quest)this).AddEntry("Place a Display Cabinet or any storage in your new dispensary", (Vector3?)ShackPosition); _stockProductEntry = ((Quest)this).AddEntry("Stock your shelves with packaged weed", (Vector3?)ShackPosition); _setPricesEntry = ((Quest)this).AddEntry("Open the GreenTab app and set your product prices", (Vector3?)ShackPosition); _viewProductEntry = ((Quest)this).AddEntry("Click on a product in the Inventory tab to view its details", (Vector3?)ShackPosition); _turnOnLightsEntry = ((Quest)this).AddEntry("Turn on the lights using the light switch on the wall", (Vector3?)ShackPosition); _openStoreEntry = ((Quest)this).AddEntry("Open the store using the GreenTab app on your phone", (Vector3?)ShackPosition); _makeSaleEntry = ((Quest)this).AddEntry("Make your first sale. A customer is on their way!", (Vector3?)ShackPosition); } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry placeStorageEntry = _placeStorageEntry; if (placeStorageEntry != null) { placeStorageEntry.Begin(); } SubscribeSaleEvent(); } catch (Exception ex) { OTCLog.Error("Quest", "StorefrontGrowth StartQuest failed: " + ex.Message); } } public void OnPricingTouched() { if (_stage == 3) { _hasTouchedPricing = true; } } public void OnProductViewed() { if (_stage == 4) { _hasViewedProduct = true; }
OverTheCounter.Mono.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using EPOOutline; using FishNet; using FishNet.Component.Ownership; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using FishNet.Observing; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using MeshVault; using Microsoft.CodeAnalysis; using OverTheCounter; using OverTheCounter.Apps; using OverTheCounter.Logic; using OverTheCounter.Logic.Placement; using OverTheCounter.NPCs; using OverTheCounter.Patches; using OverTheCounter.Quests; using OverTheCounter.SaveData; using OverTheCounter.UI; using OverTheCounter.Utilities; using S1API.Entities; using S1API.Entities.Appearances.AccessoryFields; using S1API.Entities.Appearances.BodyLayerFields; using S1API.Entities.Appearances.CustomizationFields; using S1API.Entities.Appearances.FaceLayerFields; using S1API.Entities.Dialogue; using S1API.Entities.Schedule; using S1API.GameTime; using S1API.Internal.Abstraction; using S1API.Items; using S1API.Leveling; using S1API.Messaging; using S1API.Misc; using S1API.Money; using S1API.PhoneApp; using S1API.Products; using S1API.Quests; using S1API.Saveables; using S1API.Shops; using S1API.UI; using S1API.Utils; using S1MAPI.Building; using S1MAPI.Building.Components; using S1MAPI.Building.Config; using S1MAPI.Building.Structural; using S1MAPI.Core; using S1MAPI.Gltf; using S1MAPI.ProceduralMesh; using S1MAPI.S1; using S1MAPI.Utils; using ScheduleOne; using ScheduleOne.Audio; using ScheduleOne.AvatarFramework; using ScheduleOne.AvatarFramework.Animation; using ScheduleOne.AvatarFramework.Equipping; using ScheduleOne.AvatarFramework.Impostors; using ScheduleOne.Building; using ScheduleOne.Cartel; using ScheduleOne.Combat; using ScheduleOne.Core.Items.Framework; using ScheduleOne.DevUtilities; using ScheduleOne.Dialogue; using ScheduleOne.Doors; using ScheduleOne.Economy; using ScheduleOne.Effects; using ScheduleOne.Employees; using ScheduleOne.EntityFramework; using ScheduleOne.GameTime; using ScheduleOne.Graffiti; using ScheduleOne.Interaction; using ScheduleOne.ItemFramework; using ScheduleOne.Law; using ScheduleOne.Levelling; using ScheduleOne.Lighting; using ScheduleOne.Management; using ScheduleOne.Map; using ScheduleOne.Messaging; using ScheduleOne.Money; using ScheduleOne.NPCs; using ScheduleOne.NPCs.Behaviour; using ScheduleOne.NPCs.Relation; using ScheduleOne.Networking; using ScheduleOne.ObjectScripts; using ScheduleOne.ObjectScripts.Cash; using ScheduleOne.Persistence; using ScheduleOne.Persistence.Datas; using ScheduleOne.PlayerScripts; using ScheduleOne.PlayerScripts.Health; using ScheduleOne.Police; using ScheduleOne.Product; using ScheduleOne.Product.Packaging; using ScheduleOne.Property; using ScheduleOne.Quests; using ScheduleOne.StationFramework; using ScheduleOne.Storage; using ScheduleOne.Tiles; using ScheduleOne.Tools; using ScheduleOne.UI; using ScheduleOne.UI.Compass; using ScheduleOne.UI.Handover; using ScheduleOne.UI.Items; using ScheduleOne.UI.Management; using ScheduleOne.UI.Phone; using ScheduleOne.UI.Phone.ContactsApp; using ScheduleOne.UI.Phone.Map; using ScheduleOne.UI.Phone.ProductManagerApp; using ScheduleOne.UI.Relations; using ScheduleOne.UI.Shop; using ScheduleOne.Variables; using ScheduleOne.Vehicles; using ScheduleOne.VoiceOver; using ScheduleOne.Weather; using SteamNetworkLib; using SteamNetworkLib.Models; using SteamNetworkLib.Sync; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; 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), "OverTheCounter", "2.0.10", "hdlmrell", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonOptionalDependencies(new string[] { "SteamNetworkLib" })] [assembly: HarmonyDontPatchAll] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("OverTheCounter.Mono")] [assembly: AssemblyConfiguration("MonoRelease")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6b7caa4bc824a2bf8fc9dcdc200bf94491a1a140")] [assembly: AssemblyProduct("OverTheCounter.Mono")] [assembly: AssemblyTitle("OverTheCounter.Mono")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 OverTheCounter { public static class Il2CppCompat { public static T TryCast<T>(this object obj) where T : class { return obj as T; } public static T Cast<T>(this object obj) where T : class { return (T)obj; } } public static class UnityEventCompat { public static void AddListener(this UnityEvent ev, Action action) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown ev.AddListener(new UnityAction(action.Invoke)); } public static void RemoveListener(this UnityEvent ev, Action action) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown ev.RemoveListener(new UnityAction(action.Invoke)); } public static void AddListener<T0>(this UnityEvent<T0> ev, Action<T0> action) { ev.AddListener((UnityAction<T0>)action.Invoke); } public static void RemoveListener<T0>(this UnityEvent<T0> ev, Action<T0> action) { ev.RemoveListener((UnityAction<T0>)action.Invoke); } } internal static class PrivateAccess { private static readonly FieldInfo _voeDatabase = AccessTools.Field(typeof(VOEmitter), "Database"); private static readonly FieldInfo _customerData = AccessTools.Field(typeof(Customer), "customerData"); private static readonly FieldInfo _questTitle = AccessTools.Field(typeof(Quest), "title"); private static readonly FieldInfo _dcHandler = AccessTools.Field(typeof(DialogueController), "handler"); private static readonly FieldInfo _questEntryUI = AccessTools.Field(typeof(QuestEntry), "entryUI"); private static readonly FieldInfo _miConfigPanels = AccessTools.Field(typeof(ManagementInterface), "ConfigPanelPrefabs"); private static readonly PropertyInfo _npcMsgConv = AccessTools.Property(typeof(NPC), "MSGConversation"); private static readonly PropertyInfo _npcCurrentBuilding = AccessTools.Property(typeof(NPC), "CurrentBuilding"); private static readonly PropertyInfo _custTimeDealCompleted = AccessTools.Property(typeof(Customer), "TimeSinceLastDealCompleted"); private static readonly PropertyInfo _custTimeDealOffered = AccessTools.Property(typeof(Customer), "TimeSinceLastDealOffered"); private static readonly PropertyInfo _custOfferedContract = AccessTools.Property(typeof(Customer), "OfferedContractInfo"); private static readonly PropertyInfo _custPoI = AccessTools.Property(typeof(Customer), "potentialCustomerPoI"); private static readonly FieldInfo _hsCustomerSlots = AccessTools.Field(typeof(HandoverScreen), "CustomerSlots"); private static readonly FieldInfo _hsOriginalItemLocations = AccessTools.Field(typeof(HandoverScreen), "OriginalItemLocations"); private static readonly Type _hsEItemSource = typeof(HandoverScreen).GetNestedType("EItemSource", BindingFlags.NonPublic); private static readonly object _hsEItemSourcePlayer = ((_hsEItemSource != null) ? Enum.Parse(_hsEItemSource, "Player") : null); public static VODatabase GetDatabase(this VOEmitter emitter) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (VODatabase)(_voeDatabase?.GetValue(emitter)); } public static CustomerData GetCustData(this Customer customer) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (CustomerData)(_customerData?.GetValue(customer)); } public static void SetCustData(this Customer customer, CustomerData data) { _customerData?.SetValue(customer, data); } public static string GetTitle(this Quest quest) { return (string)_questTitle?.GetValue(quest); } public static void SetTitle(this Quest quest, string value) { _questTitle?.SetValue(quest, value); } public static DialogueHandler GetHandler(this DialogueController dc) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (DialogueHandler)(_dcHandler?.GetValue(dc)); } public static ConfigurableTypePanel[] GetConfigPanelPrefabs(this ManagementInterface mi) { return (ConfigurableTypePanel[])_miConfigPanels?.GetValue(mi); } public static MSGConversation GetMSGConversation(this NPC npc) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (MSGConversation)(_npcMsgConv?.GetValue(npc)); } public static void SetMSGConversation(this NPC npc, MSGConversation conv) { _npcMsgConv?.SetValue(npc, conv); } public static void SetCurrentBuilding(this NPC npc, NPCEnterableBuilding building) { _npcCurrentBuilding?.SetValue(npc, building); } public static void SetTimeSinceLastDealCompleted(this Customer customer, int value) { _custTimeDealCompleted?.SetValue(customer, value); } public static void SetTimeSinceLastDealOffered(this Customer customer, int value) { _custTimeDealOffered?.SetValue(customer, value); } public static ContractInfo GetOfferedContractInfo(this Customer customer) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (ContractInfo)(_custOfferedContract?.GetValue(customer)); } public static void SetOfferedContractInfo(this Customer customer, ContractInfo info) { _custOfferedContract?.SetValue(customer, info); } public static NPCPoI GetPotentialCustomerPoI(this Customer customer) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (NPCPoI)(_custPoI?.GetValue(customer)); } public static void SetPotentialCustomerPoI(this Customer customer, NPCPoI poi) { _custPoI?.SetValue(customer, poi); } public static QuestEntryHUDUI GetEntryUI(this QuestEntry entry) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return (QuestEntryHUDUI)(_questEntryUI?.GetValue(entry)); } public static void SetShouldShowCheck(this DialogueChoice choice, Func<bool, bool> func) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown choice.shouldShowCheck = new ShouldShowCheck(func.Invoke); } public static ItemSlot[] GetCustomerSlots(this HandoverScreen hs) { return (ItemSlot[])_hsCustomerSlots?.GetValue(hs); } public static void TrackItemAsPlayer(this HandoverScreen hs, ItemInstance item) { object obj = _hsOriginalItemLocations?.GetValue(hs); if (obj != null && _hsEItemSourcePlayer != null) { obj.GetType().GetMethod("set_Item")?.Invoke(obj, new object[2] { item, _hsEItemSourcePlayer }); } } } public class Core : MelonMod { [CompilerGenerated] private static class <>O { public static Action<int> <0>__OnSleepEnd; public static Action <1>__OnDayPass; public static UnityAction <2>__OnGameLoaded; } private NotificationManager _notificationManager; private DesperationManager _desperationManager; private DrifterManager _drifterManager; private ManagerController _managerManager; private CustomerManager _customerManager; private bool _multiplayerDepChecked; private static bool _meshVaultRegistered; private static bool _loadHooked; private static bool _budtendersRestored; private static UnityAction _onGameLoadedAction; private static bool _gameLoadedRan; internal static string OtcIconDir { get; private set; } public override void OnInitializeMelon() { DependencyChecker.RunChecks(); if (DependencyChecker.HasMissingDeps) { ((MelonBase)this).LoggerInstance.Warning("Missing dependencies — mod features disabled. Check the main menu for details."); } else { OnInitializeMelonImpl(); } } private void OnInitializeMelonImpl() { Config.Initialize(); Config.SubscribeToChanges(); CustomersApp.ApplyHireMeDefaults(); SafeTypeLoadPatch.Apply(((MelonBase)this).HarmonyInstance); foreach (Type validType in MelonUtils.GetValidTypes(typeof(Core).Assembly)) { try { ((MelonBase)this).HarmonyInstance.CreateClassProcessor(validType).Patch(); } catch (Exception ex) { OTCLog.Error("Patch", "Failed to patch " + validType.FullName + ": " + ex.Message); } } NpcTypeDiscoveryPatch.Apply(((MelonBase)this).HarmonyInstance); StackSizePatch.Apply(((MelonBase)this).HarmonyInstance); ManagerClipboardPatch.Apply(((MelonBase)this).HarmonyInstance); try { BuildingPlacementPatch.Apply(((MelonBase)this).HarmonyInstance); } catch (Exception arg) { OTCLog.Error("Patch", $"BuildingPlacementPatch.Apply failed: {arg}"); } try { ConfigReplicatorPatch.Apply(((MelonBase)this).HarmonyInstance); } catch (Exception arg2) { OTCLog.Error("Patch", $"ConfigReplicatorPatch.Apply failed: {arg2}"); } ContactsAppFix.Apply(((MelonBase)this).HarmonyInstance); GraffitiPatch.Apply(((MelonBase)this).HarmonyInstance); RecipePinPatch.Apply(((MelonBase)this).HarmonyInstance); SupplierWarehousePatch.Apply(((MelonBase)this).HarmonyInstance); SupplierFleePatch.Apply(((MelonBase)this).HarmonyInstance); SaveManagerPatch.Apply(((MelonBase)this).HarmonyInstance); GameProfilerPatches.Apply(((MelonBase)this).HarmonyInstance); WeatherPatches.Apply(((MelonBase)this).HarmonyInstance); CustomerCheckoutInterceptPatch.Apply(((MelonBase)this).HarmonyInstance); TimeManager.OnSleepEnd = (Action<int>)Delegate.Combine(TimeManager.OnSleepEnd, new Action<int>(OnSleepEnd)); TimeManager.OnDayPass = (Action)Delegate.Combine(TimeManager.OnDayPass, new Action(OnDayPass)); if (!ConfigSyncData.IsNetworkLibAvailable) { OTCLog.Warning("Network", "SteamNetworkLib not installed — multiplayer sync disabled. Single-player works fine. Install SteamNetworkLib for co-op support."); } OTCLog.Msg("Patch", "OverTheCounter Initialized."); ImmediateQuestWindowConfig.Register(); MinimapOverlay.Register(); HUDOverlay.Register(); StoreAlertOverlay.Register(); RecipeOverlay.Register(); ExtractIcons(); _notificationManager = new NotificationManager(); _desperationManager = new DesperationManager(); _drifterManager = new DrifterManager(); _managerManager = new ManagerController(); _customerManager = new CustomerManager(); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (DependencyChecker.HasMissingDeps) { if (sceneName == "Menu") { DependencyChecker.ShowPopup(); } } else { OnSceneWasLoadedImpl(buildIndex, sceneName); } } private void OnSceneWasLoadedImpl(int buildIndex, string sceneName) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown StaticSaveData.ResetInstance(); StaticThreadSaveData.ResetInstance(); PropertySaveData.ResetInstance(); PricingSaveData.ResetInstance(); VicSaveData.ResetInstance(); BellaSaveData.ResetInstance(); StaticIntroQuest.ResetInstance(); StaticUpgrade1Quest.ResetInstance(); StaticUpgrade2Quest.ResetInstance(); VicIntroQuest.ResetInstance(); BellaProtocolQuest.ResetInstance(); StorefrontGrowthQuest.ResetInstance(); StorefrontExpansionQuest.ResetInstance(); BellaSummonPatch.Reset(); try { (typeof(Saveable).Assembly.GetType("S1API.Saveables.SaveableAutoRegistry")?.GetMethod("ClearCache", BindingFlags.Static | BindingFlags.NonPublic))?.Invoke(null, null); OTCLog.Msg("Patch", "Cleared S1API SaveableAutoRegistry cache"); } catch (Exception ex) { OTCLog.Warning("Patch", "Failed to clear SaveableAutoRegistry: " + ex.Message); } DrifterInstance.CleanupAll(); CustomerInstance.CleanupAll(); DrifterSpawner.ResetCache(); BudtenderInstance.CleanupAll(); _budtendersRestored = false; ManagerSaveData.ResetInstance(); ManagerInstance.CleanupAll(); ManagerSpawner.ResetCache(); MugshotUtility.ResetSession(); if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_MinimapController"))) { GameObject val = new GameObject("OTC_MinimapController"); val.AddComponent<MinimapOverlay>(); Object.DontDestroyOnLoad((Object)(object)val); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_HUDOverlay"))) { GameObject val2 = new GameObject("OTC_HUDOverlay"); val2.AddComponent<HUDOverlay>(); Object.DontDestroyOnLoad((Object)(object)val2); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_RecipeOverlay"))) { GameObject val3 = new GameObject("OTC_RecipeOverlay"); val3.AddComponent<RecipeOverlay>(); Object.DontDestroyOnLoad((Object)(object)val3); } if (!Object.op_Implicit((Object)(object)GameObject.Find("OTC_StoreAlertOverlay"))) { GameObject val4 = new GameObject("OTC_StoreAlertOverlay"); val4.AddComponent<StoreAlertOverlay>(); Object.DontDestroyOnLoad((Object)(object)val4); } WeatherPatches.Cleanup(); MapBuildingOverlay.Clear(); CheckoutCounter.Cleanup(); WestvilleShack.Cleanup(); Dispensary.Cleanup(); OTCWarehouse.Cleanup(); OTCSupplierArea.Cleanup(); CasinoDeadDrop.Cleanup(); CheckoutProcess.ResetStatic(); CustomerSpawnPoints.Cleanup(); BuildingGridFactory.Cleanup(); _loadHooked = false; _gameLoadedRan = false; } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if (!DependencyChecker.HasMissingDeps) { OnSceneWasInitializedImpl(buildIndex, sceneName); } } private void OnSceneWasInitializedImpl(int buildIndex, string sceneName) { if (!(sceneName == "Main")) { return; } MeshVaultAPI.Init(); if (!_meshVaultRegistered) { bool flag = false; bool flag2 = false; try { byte[] array = EmbeddedResourceLoader.LoadBytes("OverTheCounter.Resources.MeshDatabase.json", Assembly.GetExecutingAssembly()); if (array != null) { MeshVaultAPI.RegisterMeshes("otc", "OverTheCounter", Encoding.UTF8.GetString(array)); flag = true; } } catch (Exception ex) { OTCLog.Warning("Patch", "OTC mesh registration failed: " + ex.Message); } try { MeshVaultAPI.RegisterDecals("otc", "OverTheCounter", Assembly.GetExecutingAssembly(), "OverTheCounter.Resources.MeshVaultDecals."); flag2 = true; } catch (Exception ex2) { OTCLog.Warning("Patch", "OTC decal registration failed: " + ex2.Message); } _meshVaultRegistered = flag || flag2; } CheckoutCounter.Register(); WestvilleShack.SpawnBuilding(); Dispensary.SpawnBuilding(); OTCWarehouse.Initialize(); OTCSupplierArea.Initialize(OTCWarehouse.BuildingTransform); HookLoadComplete(); CheckoutCounter.AddToShop(); } private static void HookLoadComplete() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (_loadHooked) { return; } try { if (_onGameLoadedAction == null) { object obj = <>O.<2>__OnGameLoaded; if (obj == null) { UnityAction val = OnGameLoaded; <>O.<2>__OnGameLoaded = val; obj = (object)val; } _onGameLoadedAction = (UnityAction)obj; } LoadManager instance = Singleton<LoadManager>.Instance; if ((Object)(object)instance != (Object)null) { instance.onLoadComplete.RemoveListener(_onGameLoadedAction); instance.onLoadComplete.AddListener(_onGameLoadedAction); _loadHooked = true; OTCLog.Msg("Patch", "Hooked LoadManager.onLoadComplete"); } else { OTCLog.Warning("Patch", "LoadManager.Instance is null — cannot hook onLoadComplete"); } } catch (Exception ex) { OTCLog.Error("Patch", "Failed to hook LoadManager.onLoadComplete: " + ex.Message); } } private static void OnGameLoaded() { if (_gameLoadedRan) { OTCLog.Warning("Patch", "OnGameLoaded fired more than once this session (stale listener?) — ignoring duplicate."); return; } _gameLoadedRan = true; try { WestvilleShack.ClearTerrain(); Dispensary.ClearTerrain(); OTCWarehouse.ClearTerrain(); WestvilleShack.SpawnNetworkedObjects(); Dispensary.SpawnNetworkedObjects(); OTCWarehouse.SpawnNetworkedObjects(); CheckoutCounter.AddToShop(); CasinoDeadDrop.Initialize(); CheckoutProcess.InitP2P(); CheckoutProcess.RequestSalesLog(); BuildingGridFactory.SuppressNavigationRebuild = true; if (PropertySaveData.Instance != null) { foreach (KeyValuePair<Grid, OtcGridInfo> item in BuildingGridFactory.GridRegistry) { PropertySaveData.Instance.RestorePlacedItems(item.Value.BuildingId, item.Key); } } else { Grid shackGrid = WestvilleShack.ShackGrid; if ((Object)(object)shackGrid != (Object)null) { CheckoutCounter.SpawnOnGrid(shackGrid); } } BuildingGridFactory.SuppressNavigationRebuild = false; WestvilleShack.RebuildNavigation(); Dispensary.RebuildNavigation(); OTCWarehouse.RebuildNavigation(); if (!MapBuildingOverlay.PaintBuildings()) { OTCLog.Warning("Patch", "MapBuildingOverlay.PaintBuildings failed — MapApp or MapPositionUtility not ready"); } } catch (Exception ex) { BuildingGridFactory.SuppressNavigationRebuild = false; OTCLog.Error("General", "OnGameLoaded restore failed: " + ex.Message + "\n" + ex.StackTrace); } } public override void OnLateUpdate() { if (!DependencyChecker.HasMissingDeps) { OnLateUpdateImpl(); } } private void OnLateUpdateImpl() { PerfTracker.BeginFrame(); try { PerfTracker.Begin("NetworkInit"); ConfigSyncData.EnsureNetworkReady(); PerfTracker.End("NetworkInit"); PerfTracker.Begin("SyncMessages"); ConfigSyncData.ProcessMessages(); PerfTracker.End("SyncMessages"); if (!_multiplayerDepChecked && !ConfigSyncData.IsNetworkLibAvailable) { Lobby instance = Singleton<Lobby>.Instance; if ((Object)(object)instance != (Object)null && instance.IsInLobby && instance.PlayerCount > 1) { _multiplayerDepChecked = true; DependencyChecker.RunMultiplayerChecks(); if (DependencyChecker.HasMultiplayerIssues) { DependencyChecker.ShowMultiplayerPopup(); } } } PerfTracker.Begin("SaveDataTicks"); _notificationManager.ProcessContractState(); VicSaveData.Instance?.Tick(); StaticSaveData.Instance?.Tick(); BellaSaveData.Instance?.Tick(); ManagerSaveData.Instance?.Tick(); PerfTracker.End("SaveDataTicks"); PerfTracker.Begin("AdoptionRetries"); _drifterManager?.RetryPendingAdoptions(); _customerManager?.RetryPendingAdoptions(); ManagerInstance.RetryPendingAdoptions(); PerfTracker.End("AdoptionRetries"); PerfTracker.Begin("ManagerAI"); PerfTracker.Begin("ManagerAI.Wages"); _managerManager?.CheckImmediateWages(); PerfTracker.End("ManagerAI.Wages"); PerfTracker.Begin("ManagerAI.EnsureMoving"); foreach (ManagerInstance value in ManagerInstance.Active.Values) { value.EnsureMoving(); } PerfTracker.End("ManagerAI.EnsureMoving"); PerfTracker.Begin("ManagerAI.SupplyDistribution"); if (NetworkHelper.IsHost) { foreach (ManagerInstance value2 in ManagerInstance.Active.Values) { value2.SupplyBehaviour?.Tick(); value2.DistributionBehaviour?.Tick(); } } PerfTracker.End("ManagerAI.SupplyDistribution"); PerfTracker.End("ManagerAI"); PerfTracker.Begin("NetworkPublish"); if (NetworkHelper.IsHost) { ConfigSyncData.FlushDirtyState(); if (ManagerInstance.HasPendingMessages) { ConfigSyncData.Instance?.PublishManagerMessages(); } if (DrifterManager.HasPendingDrifterMessages) { ConfigSyncData.Instance?.PublishDrifterMessages(); } _customerManager?.PublishIfNeeded(); if (ManagerInstance.StatePublishNeeded) { ManagerInstance.StatePublishNeeded = false; ConfigSyncData.Instance?.PublishManagerState(); } } PerfTracker.End("NetworkPublish"); PerfTracker.Begin("ClientDoorSetup"); if (!NetworkHelper.IsHost) { WestvilleShack.TickClientDoorSetup(); Dispensary.TickClientDoorSetup(); } PerfTracker.End("ClientDoorSetup"); if (!_budtendersRestored && NetworkHelper.IsHost && CheckoutCounter.AllCounters.Count > 0 && PropertySaveData.Instance != null) { _budtendersRestored = true; string budtenderSaveState = PropertySaveData.Instance.BudtenderSaveState; if (!string.IsNullOrEmpty(budtenderSaveState)) { BudtenderController.Deserialize(budtenderSaveState); } } PerfTracker.Begin("BudtenderAI"); if (NetworkHelper.IsHost) { BudtenderController.Tick(); } PerfTracker.End("BudtenderAI"); PerfTracker.Begin("Checkout"); CheckoutProcess.Instance?.Tick(); CheckoutProcess.TryStartCheckout(); CheckoutProcess.PollLockGrant(); if (CheckoutProcess.Instance == null) { CheckoutCounter.TryCollectRegister(); } PerfTracker.End("Checkout"); PerfTracker.Begin("ScreenTicks"); foreach (CheckoutCounterInstance allCounter in CheckoutCounter.AllCounters) { allCounter.Screen?.Tick(); } PerfTracker.End("ScreenTicks"); Dispensary.UpdateLightBrightness(); WestvilleShack.UpdateLightBrightness(); PerfTracker.Begin("QuestTicks"); _drifterManager?.ClientQuestTick(); StorefrontGrowthQuest.Instance?.Tick(); StorefrontExpansionQuest.Instance?.Tick(); PerfTracker.End("QuestTicks"); } catch (Exception ex) { OTCLog.Error("Patch", "Error in OnLateUpdate: " + ex.Message + "\n" + ex.StackTrace); } PerfTracker.EndFrame(); } private static void OnSleepEnd(int minutesSkipped) { if (NetworkHelper.IsHost) { LoadManager instance = Singleton<LoadManager>.Instance; if (!((Object)(object)instance == (Object)null) && instance.IsGameLoaded) { StaticNPC.Instance?.WarpToSpawn(); BellaNPC.Instance?.ReInjectIntoBuilding(); } } } public override void OnDeinitializeMelon() { if (!DependencyChecker.HasMissingDeps) { OnDeinitializeMelonImpl(); } } private static void OnDayPass() { if (!NetworkHelper.IsHost) { return; } PropertySaveData instance = PropertySaveData.Instance; if (instance != null) { int num = 0; if (instance.IsPropertyOwned("westville_shack")) { num += PropertyInventory.GetTotalProductCount(WestvilleShack.ShackGrid); } if (instance.IsPropertyOwned("big_dispensary")) { num += PropertyInventory.GetTotalProductCount(Dispensary.DispensaryGrid); } instance.RecordInventorySnapshot(TimeManager.ElapsedDays, num); instance.TrimSalesLog(TimeManager.ElapsedDays); } } private void OnDeinitializeMelonImpl() { PerfTracker.WriteReport(); TimeManager.OnSleepEnd = (Action<int>)Delegate.Remove(TimeManager.OnSleepEnd, new Action<int>(OnSleepEnd)); TimeManager.OnDayPass = (Action)Delegate.Remove(TimeManager.OnDayPass, new Action(OnDayPass)); ConfigSyncData.Cleanup(); _notificationManager?.Cleanup(); _desperationManager?.Cleanup(); _drifterManager?.Cleanup(); _managerManager?.Cleanup(); _customerManager?.Cleanup(); } private void ExtractIcons() { OtcIconDir = Path.Combine(MelonEnvironment.UserDataDirectory, "OverTheCounter", "Icons"); if (!Directory.Exists(OtcIconDir)) { Directory.CreateDirectory(OtcIconDir); } ExtractResource(OtcIconDir, "CustomersIcon.png"); ExtractResource(OtcIconDir, "DrifterQuestIcon.png"); ExtractResource(OtcIconDir, "DrifterProfileIcon.png"); ExtractResource(OtcIconDir, "RinseCycle.png"); ExtractResource(OtcIconDir, "CrimeWareQuest.png"); ExtractResource(OtcIconDir, "ExecutivePrivilege.png"); ExtractResource(OtcIconDir, "ManagerIcon.png"); ExtractResource(OtcIconDir, "CheckoutCounter.png"); ExtractResource(OtcIconDir, "StoreAlertIcon.png"); } private void ExtractResource(string directory, string fileName) { string path = Path.Combine(directory, fileName); if (File.Exists(path)) { return; } OTCLog.Msg("Patch", "Extracting " + fileName + "..."); string text = "OverTheCounter.Resources." + fileName; using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text); if (stream != null) { using (FileStream destination = new FileStream(path, FileMode.Create, FileAccess.Write)) { stream.CopyTo(destination); } OTCLog.Msg("Patch", fileName + " extracted successfully."); } else { OTCLog.Error("Patch", "Could not find embedded resource '" + text + "'."); } } } public static class Config { private static MelonPreferences_Category _managers; public static ConfigEntry<float> ManagerDailyWage; public static ConfigEntry<float> ManagerSigningFee; public static ConfigEntry<bool> AlternateHire; private static MelonPreferences_Category _laundering; public static ConfigEntry<float> VicTier1Cost; public static ConfigEntry<float> VicTier1Return; public static ConfigEntry<int> VicTier2TrustUnlock; public static ConfigEntry<float> VicTier2Cost; public static ConfigEntry<float> VicTier2Return; public static ConfigEntry<int> VicIntroWeedGrams; public static ConfigEntry<float> VicDepositTrigger; private static MelonPreferences_Category _bella; public static ConfigEntry<float> BellaWeedValue; public static ConfigEntry<float> BellaMethValue; public static ConfigEntry<float> BellaCokeValue; private static MelonPreferences_Category _notifications; public static ConfigEntry<bool> ConsolidationEnabled; public static ConfigEntry<int> ConsolidationThreshold; private static MelonPreferences_Category _subscription; public static ConfigEntry<float> SaasWeeklyCost; public static ConfigEntry<int> SaasCycleDays; public static ConfigEntry<float> StaticTier1BankCost; public static ConfigEntry<int> StaticTier1WeedGrams; public static ConfigEntry<float> StaticTier2BankCost; public static ConfigEntry<int> StaticTier2MethGrams; public static ConfigEntry<float> StaticTier3BankCost; public static ConfigEntry<int> StaticTier3PremiumMethGrams; private static MelonPreferences_Category _world; public static ConfigEntry<float> ShackPurchasePrice; public static ConfigEntry<float> WarehousePurchasePrice; public static ConfigEntry<float> DispensaryPurchasePrice; public static ConfigEntry<int> StackSizeMultiplier; public static ConfigEntry<bool> GraffitiReEdit; public static ConfigEntry<bool> RecipePinEnabled; public static ConfigEntry<int> ShackDailyCustomerCap; public static ConfigEntry<bool> PreserveVanillaDeals; public static ConfigEntry<float> WalkInMirrorRate; private static MelonPreferences_Category _desperation; public static ConfigEntry<bool> DesperationEnabled; public static ConfigEntry<float> FiendAddictionThreshold; public static ConfigEntry<float> TriggerChancePerHour; public static ConfigEntry<int> MaxEventsPerDay; public static ConfigEntry<int> ResponseDeadlineMinutes; public static ConfigEntry<int> DeadlineMinutes; public static ConfigEntry<float> BonusMultiplier; public static ConfigEntry<float> RelationshipPenalty; public static ConfigEntry<int> CooldownMinutes; public static ConfigEntry<int> DayStartHour; public static ConfigEntry<int> DayEndHour; private static MelonPreferences_Category _drifters; public static ConfigEntry<bool> DrifterEnabled; public static ConfigEntry<float> DrifterSpawnChancePerHour; public static ConfigEntry<int> MaxActiveDrifters; public static ConfigEntry<int> DrifterDayStartHour; public static ConfigEntry<int> DrifterDayEndHour; public static ConfigEntry<int> DrifterOfferWindowMin; public static ConfigEntry<int> DrifterDeliveryDeadlineMin; public static ConfigEntry<int> DrifterLingerMinMin; public static ConfigEntry<int> DrifterLingerMaxMin; public static ConfigEntry<float> DrifterMinDealValue; private static MelonPreferences_Category _debug; public static ConfigEntry<bool> VerboseLogging; public static ConfigEntry<bool> ManagerVerboseLogging; public static ConfigEntry<bool> DrifterVerboseLogging; public static ConfigEntry<bool> DesperationVerboseLogging; public static ConfigEntry<bool> NpcVerboseLogging; public static ConfigEntry<bool> NetworkVerboseLogging; public static ConfigEntry<bool> QuestVerboseLogging; public static ConfigEntry<bool> NotificationVerboseLogging; public static ConfigEntry<bool> PatchVerboseLogging; public static ConfigEntry<bool> ProfilingEnabled; private static MelonPreferences_Category _minimap; public static ConfigEntry<bool> MinimapEnabled; public static ConfigEntry<int> MinimapSize; public static ConfigEntry<bool> MinimapRotateWithPlayer; public static ConfigEntry<bool> MinimapCircle; public static ConfigEntry<int> MinimapDefaultZoom; public static ConfigEntry<float> MinimapIconScale; public static MelonPreferences_Entry<KeyCode> MinimapToggleKey; public static ConfigEntry<int> MinimapHorizontalOffset; public static ConfigEntry<int> MinimapVerticalOffset; public static ConfigEntry<bool> MinimapInfoOnTop; public static MelonPreferences_Entry<Color> MinimapBorderColor; public static ConfigEntry<int> MinimapBorderWidth; public static ConfigEntry<bool> MinimapShowTime; public static ConfigEntry<bool> MinimapShowDay; public static ConfigEntry<bool> MinimapUse24HourClock; public static ConfigEntry<bool> MinimapShowCompass; public static ConfigEntry<bool> MinimapShowEdgeIndicators; public static ConfigEntry<bool> MinimapPerfLimit; private static MelonPreferences_Category _hud; public static ConfigEntry<bool> HUDShowRankXP; public static ConfigEntry<bool> HUDShowHealth; public static ConfigEntry<bool> HUDShowStamina; public static ConfigEntry<bool> StoreAlertEnabled; private static MelonPreferences_Category _minimapPoi; public static ConfigEntry<bool> MinimapShowPotentialCustomers; public static ConfigEntry<bool> MinimapShowCustomers; public static ConfigEntry<bool> MinimapShowDealers; public static ConfigEntry<bool> MinimapShowDeadDrops; public static ConfigEntry<bool> MinimapShowContracts; public static ConfigEntry<bool> MinimapShowQuests; public static ConfigEntry<bool> MinimapShowProperties; public static ConfigEntry<bool> MinimapShowManagers; public static ConfigEntry<bool> MinimapShowModdedNPCs; private static readonly Dictionary<string, ConfigEntry<float>> _floatEntries = new Dictionary<string, ConfigEntry<float>>(); private static readonly Dictionary<string, ConfigEntry<int>> _intEntries = new Dictionary<string, ConfigEntry<int>>(); private static readonly Dictionary<string, ConfigEntry<bool>> _boolEntries = new Dictionary<string, ConfigEntry<bool>>(); private static readonly HashSet<string> _localOnlyKeys = new HashSet<string> { "ConsolidationEnabled", "ConsolidationThreshold", "ManagerVerboseLogging", "DrifterVerboseLogging", "DesperationVerboseLogging", "NpcVerboseLogging", "NetworkVerboseLogging", "QuestVerboseLogging", "NotificationVerboseLogging", "PatchVerboseLogging", "ProfilingEnabled", "VerboseLogging", "MinimapEnabled", "MinimapSize", "MinimapRotateWithPlayer", "MinimapCircle", "MinimapDefaultZoom", "MinimapIconScale", "MinimapHorizontalOffset", "MinimapVerticalOffset", "MinimapInfoOnTop", "MinimapBorderWidth", "MinimapShowTime", "MinimapShowDay", "MinimapUse24HourClock", "MinimapShowPotentialCustomers", "MinimapShowCustomers", "MinimapShowDealers", "MinimapShowDeadDrops", "MinimapShowContracts", "MinimapShowQuests", "MinimapShowProperties", "MinimapShowManagers", "MinimapShowModdedNPCs", "MinimapShowCompass", "MinimapShowEdgeIndicators", "MinimapPerfLimit", "HUDShowRankXP", "HUDShowHealth", "HUDShowStamina", "StoreAlertEnabled", "RecipePinEnabled" }; public static void Initialize() { //IL_0e74: Unknown result type (might be due to invalid IL or missing references) _managers = MelonPreferences.CreateCategory("OverTheCounter_Managers", "Manager System"); ManagerDailyWage = Register(_managers.CreateEntry<float>("ManagerDailyWage", 350f, "Base Daily Wage", "Base daily wage before upgrade fees are added", false, false, (ValueValidator)null, (string)null)); ManagerSigningFee = Register(_managers.CreateEntry<float>("ManagerSigningFee", 3000f, "Signing Fee", "One-time fee deducted from player cash when hiring a manager", false, false, (ValueValidator)null, (string)null)); AlternateHire = Register(_managers.CreateEntry<bool>("AlternateHire", false, "Alternate Hire", "Show hire buttons in the OTC app instead of using Manny's dialogue. Enable if another mod conflicts with Manny.", false, false, (ValueValidator)null, (string)null)); _laundering = MelonPreferences.CreateCategory("OverTheCounter_Laundering", "Vic Laundering"); VicTier1Cost = Register(_laundering.CreateEntry<float>("VicTier1Cost", 500f, "Tier 1 Cost", "Cash required for tier-1 laundering", false, false, (ValueValidator)null, (string)null)); VicTier1Return = Register(_laundering.CreateEntry<float>("VicTier1Return", 400f, "Tier 1 Return", "Clean money returned for tier-1 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2TrustUnlock = Register(_laundering.CreateEntry<int>("VicTier2TrustUnlock", 7, "Tier 2 Trust Unlock", "Trust level required to unlock tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2Cost = Register(_laundering.CreateEntry<float>("VicTier2Cost", 900f, "Tier 2 Cost", "Cash required for tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicTier2Return = Register(_laundering.CreateEntry<float>("VicTier2Return", 750f, "Tier 2 Return", "Clean money returned for tier-2 laundering", false, false, (ValueValidator)null, (string)null)); VicIntroWeedGrams = Register(_laundering.CreateEntry<int>("VicIntroWeedGrams", 40, "Intro Quest Weed Grams", "Grams of weed required to complete Vic's intro quest", false, false, (ValueValidator)null, (string)null)); VicDepositTrigger = Register(_laundering.CreateEntry<float>("VicDepositTrigger", 10000f, "Deposit Trigger Amount", "Weekly deposit total that triggers Vic's intro quest", false, false, (ValueValidator)null, (string)null)); _bella = MelonPreferences.CreateCategory("OverTheCounter_Bella", "Bella Protocol"); BellaWeedValue = Register(_bella.CreateEntry<float>("BellaWeedValue", 105f, "Weed Mix Value", "Minimum base price for the weed mix Bella requires", false, false, (ValueValidator)null, (string)null)); BellaMethValue = Register(_bella.CreateEntry<float>("BellaMethValue", 200f, "Meth Mix Value", "Minimum base price for the meth mix Bella requires", false, false, (ValueValidator)null, (string)null)); BellaCokeValue = Register(_bella.CreateEntry<float>("BellaCokeValue", 400f, "Cocaine Mix Value", "Minimum base price for the cocaine mix Bella requires", false, false, (ValueValidator)null, (string)null)); _notifications = MelonPreferences.CreateCategory("OverTheCounter_Notifications", "Contract Notifications"); ConsolidationEnabled = Register(_notifications.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable contract consolidation (groups same-window deliveries into one HUD entry)", false, false, (ValueValidator)null, (string)null)); ConsolidationThreshold = Register(_notifications.CreateEntry<int>("ConsolidationThreshold", 5, "Consolidation Threshold", "Minimum contracts in a window before consolidation kicks in", false, false, (ValueValidator)null, (string)null)); _subscription = MelonPreferences.CreateCategory("OverTheCounter_Subscription", "Static Subscription"); SaasWeeklyCost = Register(_subscription.CreateEntry<float>("SaasWeeklyCost", 1000f, "Weekly Cost", "Bank balance deducted each billing cycle", false, false, (ValueValidator)null, (string)null)); SaasCycleDays = Register(_subscription.CreateEntry<int>("SaasCycleDays", 7, "Cycle Days", "Number of days between subscription payments", false, false, (ValueValidator)null, (string)null)); StaticTier1BankCost = Register(_subscription.CreateEntry<float>("StaticTier1BankCost", 3000f, "Tier 1 Bank Cost", "Bank transfer cost for the initial software package", false, false, (ValueValidator)null, (string)null)); StaticTier1WeedGrams = Register(_subscription.CreateEntry<int>("StaticTier1WeedGrams", 20, "Tier 1 Weed Grams", "Grams of weed required for the initial package", false, false, (ValueValidator)null, (string)null)); StaticTier2BankCost = Register(_subscription.CreateEntry<float>("StaticTier2BankCost", 6000f, "Tier 2 Bank Cost", "Bank transfer cost for the Premium upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier2MethGrams = Register(_subscription.CreateEntry<int>("StaticTier2MethGrams", 5, "Tier 2 Meth Grams", "Grams of meth required for the Premium upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier3BankCost = Register(_subscription.CreateEntry<float>("StaticTier3BankCost", 12000f, "Tier 3 Bank Cost", "Bank transfer cost for the Enterprise upgrade", false, false, (ValueValidator)null, (string)null)); StaticTier3PremiumMethGrams = Register(_subscription.CreateEntry<int>("StaticTier3PremiumMethGrams", 10, "Tier 3 Premium Meth Grams", "Grams of premium meth required for Enterprise upgrade", false, false, (ValueValidator)null, (string)null)); _world = MelonPreferences.CreateCategory("OverTheCounter_World", "World"); ShackPurchasePrice = Register(_world.CreateEntry<float>("ShackPurchasePrice", 5000f, "Shack Purchase Price", "Bank transfer cost for the Westville Shack property", false, false, (ValueValidator)null, (string)null)); WarehousePurchasePrice = Register(_world.CreateEntry<float>("WarehousePurchasePrice", 18000f, "Warehouse Purchase Price", "Bank transfer cost for the Warehouse property", false, false, (ValueValidator)null, (string)null)); DispensaryPurchasePrice = Register(_world.CreateEntry<float>("DispensaryPurchasePrice", 30000f, "Dispensary Purchase Price", "Bank transfer cost for the Big Dispensary property", false, false, (ValueValidator)null, (string)null)); StackSizeMultiplier = Register(_world.CreateEntry<int>("StackSizeMultiplier", 1, "Stack Size Multiplier", "Multiplies the stack limit of all stackable items by this value. 1 = vanilla stacks (default). 2 = double stacks. Affects all inventories. Host value is used in multiplayer. Changing mid-save does not retroactively adjust existing item quantities.", false, false, (ValueValidator)(object)new ValueRange<int>(1, 10), (string)null)); GraffitiReEdit = Register(_world.CreateEntry<bool>("GraffitiReEdit", true, "Graffiti Re-Edit", "Allow re-editing spray paint surfaces without consuming spray cans. Spray can must still be equipped to interact.", false, false, (ValueValidator)null, (string)null)); RecipePinEnabled = Register(_world.CreateEntry<bool>("RecipePinEnabled", true, "Recipe Pin", "Show a Pin Recipe button in the Product Manager app. Pins a draggable overlay showing the full mixing chain for a product.", false, false, (ValueValidator)null, (string)null)); ShackDailyCustomerCap = Register(_world.CreateEntry<int>("ShackDailyCustomerCap", 12, "Shack Daily Customer Cap", "Maximum customers redirected to the Westville Shack per day", false, false, (ValueValidator)null, (string)null)); PreserveVanillaDeals = Register(_world.CreateEntry<bool>("PreserveVanillaDeals", false, "Preserve Vanilla Deals", "When enabled, vanilla NPCs keep their normal deal behavior instead of being redirected to the dispensary. Each redirected deal has a chance (set by Mirror Spawn Rate) to also spawn a random walk-in customer. Off by default because keeping both vanilla deals AND dispensary sales effectively doubles income.", false, false, (ValueValidator)null, (string)null)); WalkInMirrorRate = Register(_world.CreateEntry<float>("WalkInMirrorRate", 0.4f, "Mirror Spawn Rate", "Only used when Preserve Vanilla Deals is enabled. Chance (0-1) that each vanilla deal that would have been redirected also spawns a random store customer. Has no effect when Preserve Vanilla Deals is off. 0.4 = 40% of deals spawn one. 1.0 = every deal spawns one.", false, false, (ValueValidator)(object)new ValueRange<float>(0f, 1f), (string)null)); _desperation = MelonPreferences.CreateCategory("OverTheCounter", "Desperation System"); DesperationEnabled = Register(_desperation.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable the desperation system (urgent fiend requests)", false, false, (ValueValidator)null, (string)null)); FiendAddictionThreshold = Register(_desperation.CreateEntry<float>("FiendAddictionThreshold", 0.67f, "Fiend Addiction Threshold", "Addiction level required to qualify as a Fiend (0.0–1.0)", false, false, (ValueValidator)null, (string)null)); TriggerChancePerHour = Register(_desperation.CreateEntry<float>("TriggerChancePerHour", 0.12f, "Trigger Chance Per Hour", "Probability of a desperation event each hour (0.0–1.0)", false, false, (ValueValidator)null, (string)null)); MaxEventsPerDay = Register(_desperation.CreateEntry<int>("MaxEventsPerDay", 3, "Max Events Per Day", "Hard cap on desperation events per day", false, false, (ValueValidator)null, (string)null)); ResponseDeadlineMinutes = Register(_desperation.CreateEntry<int>("ResponseDeadlineMinutes", 60, "Response Deadline (min)", "In-game minutes the player has to respond to a desperation offer", false, false, (ValueValidator)null, (string)null)); DeadlineMinutes = Register(_desperation.CreateEntry<int>("DeadlineMinutes", 120, "Delivery Deadline (min)", "In-game minutes to deliver after accepting a desperation contract", false, false, (ValueValidator)null, (string)null)); BonusMultiplier = Register(_desperation.CreateEntry<float>("BonusMultiplier", 0.45f, "Bonus Multiplier", "Extra payment multiplier for desperation deliveries (0.45 = 45%)", false, false, (ValueValidator)null, (string)null)); RelationshipPenalty = Register(_desperation.CreateEntry<float>("RelationshipPenalty", -15f, "Relationship Penalty", "Relationship change on failed desperation event", false, false, (ValueValidator)null, (string)null)); CooldownMinutes = Register(_desperation.CreateEntry<int>("CooldownMinutes", 1440, "Cooldown (min)", "Minutes a customer is locked out after a failed event (1440 = 24h)", false, false, (ValueValidator)null, (string)null)); DayStartHour = Register(_desperation.CreateEntry<int>("DayStartHour", 800, "Day Start Hour", "Earliest 24h time for desperation rolls (800 = 8:00 AM)", false, false, (ValueValidator)null, (string)null)); DayEndHour = Register(_desperation.CreateEntry<int>("DayEndHour", 2100, "Day End Hour", "Latest 24h time for desperation rolls (2100 = 9:00 PM)", false, false, (ValueValidator)null, (string)null)); _drifters = MelonPreferences.CreateCategory("OverTheCounter_Drifters", "Drifter System"); DrifterEnabled = Register(_drifters.CreateEntry<bool>("Enabled", true, "Enabled", "Enable/disable the drifter system (random street NPCs offering one-time deals)", false, false, (ValueValidator)null, (string)null)); DrifterSpawnChancePerHour = Register(_drifters.CreateEntry<float>("DrifterSpawnChancePerHour", 0.38f, "Spawn Chance Per Hour", "Base spawn chance per hour at max regions. Scaled down by unlocked region count (0.0-1.0)", false, false, (ValueValidator)null, (string)null)); MaxActiveDrifters = Register(_drifters.CreateEntry<int>("MaxActiveDrifters", 3, "Max Active Drifters", "Maximum number of drifters that can be active at once", false, false, (ValueValidator)null, (string)null)); DrifterDayStartHour = Register(_drifters.CreateEntry<int>("DrifterDayStartHour", 800, "Day Start Hour", "Earliest 24h time for drifter spawns (800 = 8:00 AM)", false, false, (ValueValidator)null, (string)null)); DrifterDayEndHour = Register(_drifters.CreateEntry<int>("DrifterDayEndHour", 2100, "Day End Hour", "Latest 24h time for drifter spawns (2100 = 9:00 PM)", false, false, (ValueValidator)null, (string)null)); DrifterOfferWindowMin = Register(_drifters.CreateEntry<int>("DrifterOfferWindowMin", 120, "Offer Window (min)", "Minutes player has to respond to a drifter offer (120 = 2 hours)", false, false, (ValueValidator)null, (string)null)); DrifterDeliveryDeadlineMin = Register(_drifters.CreateEntry<int>("DrifterDeliveryDeadlineMin", 240, "Delivery Deadline (min)", "Minutes to deliver after accepting a drifter deal (240 = 4 hours)", false, false, (ValueValidator)null, (string)null)); DrifterLingerMinMin = Register(_drifters.CreateEntry<int>("DrifterLingerMinMin", 30, "Linger Min (min)", "Minimum minutes a drifter lingers after deal completion/expiry", false, false, (ValueValidator)null, (string)null)); DrifterLingerMaxMin = Register(_drifters.CreateEntry<int>("DrifterLingerMaxMin", 60, "Linger Max (min)", "Maximum minutes a drifter lingers after deal completion/expiry", false, false, (ValueValidator)null, (string)null)); DrifterMinDealValue = Register(_drifters.CreateEntry<float>("DrifterMinDealValue", 90f, "Min Deal Value ($)", "Soft minimum deal value - drifters ask for more quantity until the deal reaches this threshold", false, false, (ValueValidator)null, (string)null)); _debug = MelonPreferences.CreateCategory("OverTheCounter_Debug", "Debug"); VerboseLogging = Register(_debug.CreateEntry<bool>("VerboseLogging", false, "Verbose Logging (General)", "Catch-all verbose logging for systems without a dedicated toggle", false, false, (ValueValidator)null, (string)null)); ManagerVerboseLogging = Register(_debug.CreateEntry<bool>("ManagerVerboseLogging", false, "Verbose: Manager", "Enable detailed manager logging (shopping list breakdowns, per-item details)", false, false, (ValueValidator)null, (string)null)); DrifterVerboseLogging = Register(_debug.CreateEntry<bool>("DrifterVerboseLogging", false, "Verbose: Drifter", "Enable detailed drifter system logging", false, false, (ValueValidator)null, (string)null)); DesperationVerboseLogging = Register(_debug.CreateEntry<bool>("DesperationVerboseLogging", false, "Verbose: Desperation", "Enable detailed desperation system logging", false, false, (ValueValidator)null, (string)null)); NpcVerboseLogging = Register(_debug.CreateEntry<bool>("NpcVerboseLogging", false, "Verbose: NPC", "Enable detailed NPC logging (Vic, Bella, Static)", false, false, (ValueValidator)null, (string)null)); NetworkVerboseLogging = Register(_debug.CreateEntry<bool>("NetworkVerboseLogging", false, "Verbose: Network", "Enable detailed network sync logging", false, false, (ValueValidator)null, (string)null)); QuestVerboseLogging = Register(_debug.CreateEntry<bool>("QuestVerboseLogging", false, "Verbose: Quest", "Enable detailed quest logging", false, false, (ValueValidator)null, (string)null)); NotificationVerboseLogging = Register(_debug.CreateEntry<bool>("NotificationVerboseLogging", false, "Verbose: Notification", "Enable detailed notification system logging", false, false, (ValueValidator)null, (string)null)); PatchVerboseLogging = Register(_debug.CreateEntry<bool>("PatchVerboseLogging", false, "Verbose: Patch", "Enable detailed Harmony patch logging", false, false, (ValueValidator)null, (string)null)); ProfilingEnabled = Register(_debug.CreateEntry<bool>("ProfilingEnabled", false, "Performance Profiling", "Write periodic performance reports to UserData/OTC_PerfReport.txt", false, false, (ValueValidator)null, (string)null)); _minimapPoi = MelonPreferences.CreateCategory("OverTheCounter_MinimapPOI", "Minimap POIs"); MinimapShowPotentialCustomers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowPotentialCustomers", true, "Show Potential Customers", "Show potential customer icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowCustomers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowCustomers", false, "Show Customers", "Show unlocked customer icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowDealers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowDealers", true, "Show Dealers", "Show dealer icons on the minimap (potential and active)", false, false, (ValueValidator)null, (string)null)); MinimapShowDeadDrops = Register(_minimapPoi.CreateEntry<bool>("MinimapShowDeadDrops", true, "Show Dead Drops", "Show dead drop icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowContracts = Register(_minimapPoi.CreateEntry<bool>("MinimapShowContracts", true, "Show Contracts", "Show contract delivery icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowQuests = Register(_minimapPoi.CreateEntry<bool>("MinimapShowQuests", true, "Show Quests", "Show quest objective icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowProperties = Register(_minimapPoi.CreateEntry<bool>("MinimapShowProperties", true, "Show Properties", "Show owned property icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowManagers = Register(_minimapPoi.CreateEntry<bool>("MinimapShowManagers", true, "Show Managers", "Show manager icons on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowModdedNPCs = Register(_minimapPoi.CreateEntry<bool>("MinimapShowModdedNPCs", true, "Show Modded NPCs", "Show NPC icons added by other mods (e.g. police, cartel) on the minimap", false, false, (ValueValidator)null, (string)null)); _minimap = MelonPreferences.CreateCategory("OverTheCounter_Minimap", "Minimap"); MinimapEnabled = Register(_minimap.CreateEntry<bool>("MinimapEnabled", false, "Enabled", "Show the minimap overlay", false, false, (ValueValidator)null, (string)null)); MinimapSize = Register(_minimap.CreateEntry<int>("MinimapSize", 250, "Size (px)", "Minimap size in pixels", false, false, (ValueValidator)null, (string)null)); MinimapRotateWithPlayer = Register(_minimap.CreateEntry<bool>("MinimapRotateWithPlayer", false, "Rotate With Player", "Rotate minimap to match player facing direction", false, false, (ValueValidator)null, (string)null)); MinimapCircle = Register(_minimap.CreateEntry<bool>("MinimapCircle", false, "Circle Shape", "Use circular minimap shape instead of square", false, false, (ValueValidator)null, (string)null)); MinimapDefaultZoom = Register(_minimap.CreateEntry<int>("MinimapDefaultZoom", 2, "Default Zoom", "Starting zoom level, 1=closest, 3=farthest (1-3)", false, false, (ValueValidator)null, (string)null)); MinimapIconScale = Register(_minimap.CreateEntry<float>("MinimapIconScale", 0.7f, "Icon Scale", "POI icon scale on the minimap", false, false, (ValueValidator)null, (string)null)); MinimapToggleKey = _minimap.CreateEntry<KeyCode>("MinimapToggleKey", (KeyCode)110, "Toggle Key", "Hotkey to cycle minimap zoom", false, false, (ValueValidator)null, (string)null); MinimapHorizontalOffset = Register(_minimap.CreateEntry<int>("MinimapHorizontalOffset", 100, "Horizontal Offset", "Horizontal position (0=left, 100=right)", false, false, (ValueValidator)(object)new ValueRange<int>(0, 100), (string)null)); MinimapVerticalOffset = Register(_minimap.CreateEntry<int>("MinimapVerticalOffset", 0, "Vertical Offset", "Vertical position (0=top, 100=bottom)", false, false, (ValueValidator)(object)new ValueRange<int>(0, 100), (string)null)); MinimapInfoOnTop = Register(_minimap.CreateEntry<bool>("MinimapInfoOnTop", false, "Info Panels On Top", "Place clock and day display above the minimap instead of below", false, false, (ValueValidator)null, (string)null)); MinimapBorderColor = _minimap.CreateEntry<Color>("MinimapBorderColor", new Color(0.2f, 0.2f, 0.2f, 0.9f), "Border Color", "Minimap border color", false, false, (ValueValidator)null, (string)null); MinimapBorderWidth = Register(_minimap.CreateEntry<int>("MinimapBorderWidth", 4, "Border Width", "Border thickness in pixels per side (2-10)", false, false, (ValueValidator)null, (string)null)); MinimapShowTime = Register(_minimap.CreateEntry<bool>("MinimapShowTime", true, "Show Time", "Display the current time near the minimap", false, false, (ValueValidator)null, (string)null)); MinimapShowDay = Register(_minimap.CreateEntry<bool>("MinimapShowDay", true, "Show Day", "Display the current day near the minimap", false, false, (ValueValidator)null, (string)null)); MinimapUse24HourClock = Register(_minimap.CreateEntry<bool>("MinimapUse24HourClock", false, "24-Hour Clock", "Use 24-hour time format instead of 12-hour AM/PM", false, false, (ValueValidator)null, (string)null)); MinimapShowCompass = Register(_minimap.CreateEntry<bool>("MinimapShowCompass", true, "Show Compass", "Display N/S/E/W cardinal direction labels on the minimap edge", false, false, (ValueValidator)null, (string)null)); MinimapShowEdgeIndicators = Register(_minimap.CreateEntry<bool>("MinimapShowEdgeIndicators", true, "Edge Indicators", "Show POI icons pinned to the minimap edge for off-screen points of interest", false, false, (ValueValidator)null, (string)null)); MinimapPerfLimit = Register(_minimap.CreateEntry<bool>("MinimapPerfLimit", true, "Performance Limiting", "Adaptively reduce minimap update rate to limit CPU usage", false, false, (ValueValidator)null, (string)null)); _hud = MelonPreferences.CreateCategory("OverTheCounter_HUD", "HUD Overlay"); HUDShowRankXP = Register(_hud.CreateEntry<bool>("HUDShowRankXP", false, "Show Rank/XP", "Display rank and XP progress bar above the hotbar", false, false, (ValueValidator)null, (string)null)); HUDShowHealth = Register(_hud.CreateEntry<bool>("HUDShowHealth", false, "Show Health", "Display health bar above the hotbar", false, false, (ValueValidator)null, (string)null)); HUDShowStamina = Register(_hud.CreateEntry<bool>("HUDShowStamina", false, "Show Stamina", "Display stamina bar above the hotbar", false, false, (ValueValidator)null, (string)null)); StoreAlertEnabled = Register(_hud.CreateEntry<bool>("StoreAlertEnabled", true, "Show Store Alerts", "Show checkout queue alerts on the right side of the screen", false, false, (ValueValidator)null, (string)null)); } private static ConfigEntry<float> Register(MelonPreferences_Entry<float> entry) { ConfigEntry<float> configEntry = new ConfigEntry<float>(entry); _floatEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } private static ConfigEntry<int> Register(MelonPreferences_Entry<int> entry) { ConfigEntry<int> configEntry = new ConfigEntry<int>(entry); _intEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } private static ConfigEntry<bool> Register(MelonPreferences_Entry<bool> entry) { ConfigEntry<bool> configEntry = new ConfigEntry<bool>(entry); _boolEntries[((MelonPreferences_Entry)entry).Identifier] = configEntry; return configEntry; } public static string SerializeAll() { List<string> list = new List<string>(); foreach (KeyValuePair<string, ConfigEntry<float>> floatEntry in _floatEntries) { if (!_localOnlyKeys.Contains(floatEntry.Key)) { list.Add(floatEntry.Key + "=" + floatEntry.Value.RawEntry.Value.ToString(CultureInfo.InvariantCulture)); } } foreach (KeyValuePair<string, ConfigEntry<int>> intEntry in _intEntries) { if (!_localOnlyKeys.Contains(intEntry.Key)) { list.Add(intEntry.Key + "=" + intEntry.Value.RawEntry.Value.ToString(CultureInfo.InvariantCulture)); } } foreach (KeyValuePair<string, ConfigEntry<bool>> boolEntry in _boolEntries) { if (!_localOnlyKeys.Contains(boolEntry.Key)) { list.Add($"{boolEntry.Key}={boolEntry.Value.RawEntry.Value}"); } } return string.Join("|", list); } public static void ApplyOverrides(Dictionary<string, string> data) { foreach (KeyValuePair<string, string> datum in data) { if (_localOnlyKeys.Contains(datum.Key)) { continue; } ConfigEntry<int> value2; ConfigEntry<bool> value3; bool result3; if (_floatEntries.TryGetValue(datum.Key, out var value)) { if (float.TryParse(datum.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { value.SetOverride(result); } } else if (_intEntries.TryGetValue(datum.Key, out value2)) { if (int.TryParse(datum.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { value2.SetOverride(result2); } } else if (_boolEntries.TryGetValue(datum.Key, out value3) && bool.TryParse(datum.Value, out result3)) { value3.SetOverride(result3); } } } public static void ClearAllOverrides() { foreach (ConfigEntry<float> value in _floatEntries.Values) { value.ClearOverride(); } foreach (ConfigEntry<int> value2 in _intEntries.Values) { value2.ClearOverride(); } foreach (ConfigEntry<bool> value3 in _boolEntries.Values) { value3.ClearOverride(); } } public static void SubscribeToChanges() { foreach (KeyValuePair<string, ConfigEntry<float>> floatEntry in _floatEntries) { if (!_localOnlyKeys.Contains(floatEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)floatEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } foreach (KeyValuePair<string, ConfigEntry<int>> intEntry in _intEntries) { if (!_localOnlyKeys.Contains(intEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)intEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } foreach (KeyValuePair<string, ConfigEntry<bool>> boolEntry in _boolEntries) { if (!_localOnlyKeys.Contains(boolEntry.Key)) { ((MelonEventBase<LemonAction<object, object>>)(object)((MelonPreferences_Entry)boolEntry.Value.RawEntry).OnEntryValueChangedUntyped).Subscribe((LemonAction<object, object>)OnSyncableEntryChanged, 0, false); } } } private static void OnSyncableEntryChanged(object oldValue, object newValue) { if (NetworkHelper.IsHost) { ConfigSyncData.Instance?.RefreshFromConfig(); } } } } namespace OverTheCounter.Quests { internal static class QuestHelper { public static string StableGuid(string key) { if (string.IsNullOrEmpty(key)) { throw new ArgumentException("StableGuid key cannot be null/empty", "key"); } using MD5 mD = MD5.Create(); byte[] b = mD.ComputeHash(Encoding.UTF8.GetBytes("otc-quest:" + key)); return new Guid(b).ToString(); } public static T CreateWithGuid<T>(string guid) where T : Quest { T val = (T)(object)QuestManager.CreateQuest<T>((string)null); if (val == null) { OTCLog.Error("Quest", "QuestManager.CreateQuest<" + typeof(T).Name + "> returned null."); return default(T); } TryForceInit((Quest)(object)val, guid); return val; } public static string GetCurrentGuid(Quest quest) { if (quest == null) { return string.Empty; } return GetS1Quest(quest)?.StaticGUID ?? string.Empty; } private static void TryForceInit(Quest quest, string guid) { try { Quest s1Quest = GetS1Quest(quest); if ((Object)(object)s1Quest == (Object)null) { OTCLog.Warning("Quest", "TryForceInit: S1Quest field not found on " + ((object)quest).GetType().Name + "."); return; } s1Quest.StaticGUID = guid; string protectedString = GetProtectedString(quest, "Title"); string protectedString2 = GetProtectedString(quest, "Description"); QuestEntryData[] array = Array.Empty<QuestEntryData>(); s1Quest.InitializeQuest(protectedString ?? string.Empty, protectedString2 ?? string.Empty, array, guid); } catch (Exception ex) { OTCLog.Error("Quest", "TryForceInit failed for " + ((object)quest).GetType().Name + ": " + ex.Message); } } private static Quest GetS1Quest(Quest quest) { object? obj = typeof(Quest).GetField("S1Quest", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(quest); return (Quest)((obj is Quest) ? obj : null); } private static string GetProtectedString(Quest quest, string propertyName) { return ((object)quest).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(quest) as string; } } public class VicIntroQuest : Quest { [SaveableField("vic_quest_stage")] private int _stage; private QuestEntry _meetVicEntry; private QuestEntry _bringWeedEntry; private static readonly Vector3 VicPosition = new Vector3(67.75f, 0.97f, 32.36f); protected override string Title => "Rinse Cycle"; protected override string Description => "Help Vic with his party supplies and he'll help you clean some cash."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => (Core.OtcIconDir != null) ? ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "RinseCycle.png")) : null; public static VicIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) try { _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetWeedText() { return $"Bring Vic {Config.VicIntroWeedGrams.Value} grams of weed"; } public void RefreshEntryText() { if (_bringWeedEntry != null && _stage >= 1 && _stage < 3) { _bringWeedEntry.Title = GetWeedText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } QuestEntry meetVicEntry2 = _meetVicEntry; if (meetVicEntry2 != null) { meetVicEntry2.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } QuestEntry bringWeedEntry2 = _bringWeedEntry; if (bringWeedEntry2 != null) { bringWeedEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj2 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { if (VicSaveData.Instance != null) { int num = (VicSaveData.Instance.Unlocked ? 3 : (VicSaveData.Instance.QuestAccepted ? 2 : (VicSaveData.Instance.HasBeenTexted ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); if (_stage >= 1) { QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Begin(); } } if (_stage >= 2) { QuestEntry meetVicEntry2 = _meetVicEntry; if (meetVicEntry2 != null) { meetVicEntry2.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } if (_stage >= 3) { QuestEntry bringWeedEntry2 = _bringWeedEntry; if (bringWeedEntry2 != null) { bringWeedEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } internal static class QuestIconHelper { private static readonly Dictionary<int, Sprite> _cache = new Dictionary<int, Sprite>(); private static string IconPath => (Core.OtcIconDir != null) ? Path.Combine(Core.OtcIconDir, "CrimeWareQuest.png") : null; internal static Sprite Load() { return (IconPath != null) ? ImageUtils.LoadImage(IconPath) : null; } internal static Sprite LoadTinted(Color tint) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) int hashCode = ((object)(Color)(ref tint)).GetHashCode(); if (_cache.TryGetValue(hashCode, out var value) && (Object)(object)value != (Object)null) { return value; } try { byte[] array = File.ReadAllBytes(IconPath); Texture2D val = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val, array)) { return Load(); } Color[] pixels = val.GetPixels(); for (int i = 0; i < pixels.Length; i++) { pixels[i] = new Color(pixels[i].r * tint.r, pixels[i].g * tint.g, pixels[i].b * tint.b, pixels[i].a); } val.SetPixels(pixels); val.Apply(); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); _cache[hashCode] = val2; return val2; } catch { return Load(); } } } internal static class QuestPoiFixer { [CompilerGenerated] private sealed class <FixPositionDelayed>d__2 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public QuestEntry entry; public Vector3 worldPos; private int <i>5__1; private QuestEntry <s1Entry>5__2; private Transform <poiLoc>5__3; private POI <poi>5__4; private Exception <ex>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FixPositionDelayed>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <s1Entry>5__2 = null; <poiLoc>5__3 = null; <poi>5__4 = null; <ex>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_017a: 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_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; OTCLog.Msg("Quest", $"QuestPoiFixer: starting, target={worldPos}"); <i>5__1 = 0; break; case 1: <>1__state = -1; <i>5__1++; break; } if (<i>5__1 < 5) { <>2__current = null; <>1__state = 1; return true; } try { if (_s1EntryField == null) { _s1EntryField = typeof(QuestEntry).GetField("S1QuestEntry", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } OTCLog.Msg("Quest", $"QuestPoiFixer: field={_s1EntryField != null}"); ref QuestEntry reference = ref <s1Entry>5__2; object? obj = _s1EntryField?.GetValue(entry); reference = (QuestEntry)((obj is QuestEntry) ? obj : null); if ((Object)(object)<s1Entry>5__2 == (Object)null) { OTCLog.Warning("Quest", "QuestPoiFixer: s1Entry is null"); return false; } <poiLoc>5__3 = <s1Entry>5__2.PoILocation; <poi>5__4 = <s1Entry>5__2.PoI; object[] obj2 = new object[4] { (Object)(object)<poiLoc>5__3 != (Object)null, null, null, null }; Transform obj3 = <poiLoc>5__3; obj2[1] = ((obj3 != null) ? new Vector3?(obj3.position) : null); obj2[2] = (Object)(object)<poi>5__4 != (Object)null; POI obj4 = <poi>5__4; obj2[3] = ((obj4 != null) ? new Vector3?(((Component)obj4).transform.position) : null); OTCLog.Msg("Quest", string.Format("QuestPoiFixer: PoILocation={0} pos={1} PoI={2} poiPos={3}", obj2)); <s1Entry>5__2.SetPoILocation(worldPos); Transform poILocation = <s1Entry>5__2.PoILocation; object arg = ((poILocation != null) ? new Vector3?(poILocation.position) : null); POI poI = <s1Entry>5__2.PoI; OTCLog.Msg("Quest", $"QuestPoiFixer: AFTER SetPoILocation → PoILocation.pos={arg} PoI.pos={((poI != null) ? new Vector3?(((Component)poI).transform.position) : null)}"); <s1Entry>5__2 = null; <poiLoc>5__3 = null; <poi>5__4 = null; } catch (Exception ex) { <ex>5__5 = ex; OTCLog.Warning("Quest", "QuestPoiFixer failed: " + <ex>5__5.Message); } 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 FieldInfo _s1EntryField; public static void FixPosition(QuestEntry entry, Vector3 worldPos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (entry != null) { MelonCoroutines.Start(FixPositionDelayed(entry, worldPos)); } } [IteratorStateMachine(typeof(<FixPositionDelayed>d__2))] private static IEnumerator FixPositionDelayed(QuestEntry entry, Vector3 worldPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FixPositionDelayed>d__2(0) { entry = entry, worldPos = worldPos }; } } public class StaticIntroQuest : Quest { [SaveableField("static_quest_stage")] private int _stage; private QuestEntry _checkMessagesEntry; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Crimeware as a Service"; protected override string Description => "Someone noticed your operation. Check the OTC app for a new message."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticIntroQuest Instance { get; private set; } public int Stage => _stage; private static Vector3 DeadDropPosition => CasinoDeadDrop.Position; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) try { _checkMessagesEntry = ((Quest)this).AddEntry("Check your messages in the OTC app", (Vector3?)null); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)DeadDropPosition); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier1BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier1WeedGrams.Value}g weed at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 2 && _stage < 4) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 2 && _stage < 4) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) try { _stage = 2; QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } QuestEntry checkMessagesEntry2 = _checkMessagesEntry; if (checkMessagesEntry2 != null) { checkMessagesEntry2.Complete(); } QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, DeadDropPosition); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj2 failed: " + ex.Message); } } public void CompleteObj3() { try { _stage = 4; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj3 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { if (StaticSaveData.Instance != null) { int num = ((StaticSaveData.Instance.CrmTier >= 1) ? 4 : (StaticSaveData.Instance.IntroCompleted ? 2 : (StaticSaveData.Instance.QuestTriggered ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _checkMessagesEntry = ((Quest)this).AddEntry("Check your messages in the OTC app", (Vector3?)null); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)DeadDropPosition); if (_stage >= 1) { QuestEntry checkMessagesEntry = _checkMessagesEntry; if (checkMessagesEntry != null) { checkMessagesEntry.Begin(); } } if (_stage >= 2) { QuestEntry checkMessagesEntry2 = _checkMessagesEntry; if (checkMessagesEntry2 != null) { checkMessagesEntry2.Complete(); } QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, DeadDropPosition); } if (_stage >= 2 && _stage < 4 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.Tier1MoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.Tier1ProductDelivered) { CompleteDropOff(); } } if (_stage >= 4) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade1Quest : Quest { [SaveableField("static_upgrade1_stage")] private int _stage; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Premium Tier"; protected override string Description => "Static has the premium tier upgrade available. Pay and deliver via the OTC app."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticUpgrade1Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) try { _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier2BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier2MethGrams.Value}g meth at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 1 && _stage < 2) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 1 && _stage < 2) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) try { _stage = 1; ((Quest)this).Begin(); QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); if (_stage >= 1) { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } if (_stage >= 1 && _stage < 2 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.UpgradeMoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.UpgradeProductDelivered) { CompleteDropOff(); } } if (_stage >= 2) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade2Quest : Quest { [SaveableField("static_upgrade2_stage")] private int _stage; private QuestEntry _payEntry; private QuestEntry _dropOffEntry; protected override string Title => "Full Scale"; protected override string Description => "Static has the final tier-3 enterprise upgrade available. Pay and deliver via the OTC app."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => QuestIconHelper.Load(); public static StaticUpgrade2Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } public void Initialize() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) try { _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "Initialize failed: " + ex.Message); } } private static string GetPayText() { return $"Pay ${Config.StaticTier3BankCost.Value:N0} via OTC app"; } private static string GetDropOffText() { return $"Drop off {Config.StaticTier3PremiumMethGrams.Value}g premium meth at the casino dead drop"; } public void RefreshEntryText() { if (_payEntry != null && _stage >= 1 && _stage < 2) { _payEntry.Title = GetPayText(); } if (_dropOffEntry != null && _stage >= 1 && _stage < 2) { _dropOffEntry.Title = GetDropOffText(); } } public void StartQuest() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) try { _stage = 1; ((Quest)this).Begin(); QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteObj1 failed: " + ex.Message); } } public void CompletePay() { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } } public void CompleteDropOff() { QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _payEntry = ((Quest)this).AddEntry(GetPayText(), (Vector3?)null); _dropOffEntry = ((Quest)this).AddEntry(GetDropOffText(), (Vector3?)CasinoDeadDrop.Position); if (_stage >= 1) { QuestEntry payEntry = _payEntry; if (payEntry != null) { payEntry.Begin(); } QuestEntry dropOffEntry = _dropOffEntry; if (dropOffEntry != null) { dropOffEntry.Begin(); } QuestPoiFixer.FixPosition(_dropOffEntry, CasinoDeadDrop.Position); } if (_stage >= 1 && _stage < 2 && StaticSaveData.Instance != null) { if (StaticSaveData.Instance.UpgradeMoneyPaid) { CompletePay(); } if (StaticSaveData.Instance.UpgradeProductDelivered) { CompleteDropOff(); } } if (_stage >= 2) { QuestEntry payEntry2 = _payEntry; if (payEntry2 != null) { payEntry2.Complete(); } QuestEntry dropOffEntry2 = _dropOffEntry; if (dropOffEntry2 != null) { dropOffEntry2.Complete(); } ((Quest)this).Complete(); } } catch (Exception ex) { OTCLog.Warning("Quest", "OnLoaded rebuild failed: " + ex.Message); } } } public class DrifterDealQuest : Quest { private string _title; private string _description; private QuestEntry _deliverEntry; private int _deadlineElapsedMinutes; protected override string Title => _title ?? "Drifter Deal"; protected override string Description => _description ?? "Complete a deal with a drifter."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => (Core.OtcIconDir != null) ? ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "DrifterQuestIcon.png")) : null; public string DrifterId { get; private set; } public static Dictionary<string, DrifterDealQuest> ActiveQuests { get; } = new Dictionary<string, DrifterDealQuest>(); private Quest GetS1Quest() { object? obj = typeof(Quest).GetField("S1Quest", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(this); return (Quest)((obj is Quest) ? obj : null); } private void TriggerInternalInit() { try { Quest s1Quest = GetS1Quest(); if (!((Object)(object)s1Quest == (Object)null)) { s1Quest.InitializeQuest(((Quest)this).Title, ((Quest)this).Description, Array.Empty<QuestEntryData>(), s1Quest.StaticGUID); } } catch (Exception ex) { OTCLog.Error("Quest", "TriggerInternalInit failed: " + ex.Message); } } public void Initialize(string drifterId, string productName, int quantity, float payment, Vector3 destination, string locationDesc, int deadlineElapsedMinutes) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) DrifterId = drifterId; _title = "Drifter Deal"; _description = $"Deliver {quantity} {productName} for ${payment:F0}"; _deadlineElapsedMinutes = deadlineElapsedMinutes; TriggerInternalInit(); _deliverEntry = ((Quest)this).AddEntry($"Deliver {quantity} {productName} to the drifter {locationDesc}", (Vector3?)destination); ActiveQuests[drifterId] = this; } public void StartQuest() { try { ((Quest)this).Begin(); QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Begin(); } } catch (Exception ex) { OTCLog.Error("Quest", "StartQuest failed: " + ex.Message); } } public void UpdateTiming() { try { if (_deadlineElapsedMinutes > 0) { int currentElapsedMinutes = GetCurrentElapsedMinutes(); int num = _deadlineElapsedMinutes - currentElapsedMinutes; if (num < 0) { num = 0; } int num2 = num / 60; int num3 = num % 60; string subtitleViaReflection = ((num >= 120) ? $"<color=green> (Expires in {num2}h {num3}m)</color>" : ((num2 <= 0) ? $"<color=#ff6b6b> (Expires in {num} min)</color>" : $"<color=#ff6b6b> (Expires in {num2}h {num3}m)</color>")); SetSubtitleViaReflection(subtitleViaReflection); } } catch (Exception ex) { OTCLog.Warning("Quest", "UpdateTiming failed: " + ex.Message); } } private void SetSubtitleViaReflection(string subtitle) { try { Quest s1Quest = GetS1Quest(); if (!((Object)(object)s1Quest == (Object)null)) { s1Quest.SetSubtitle(subtitle); if ((Object)(object)s1Quest.hudUI != (Object)null) { s1Quest.hudUI.UpdateMainLabel(); } } } catch (Exception ex) { OTCLog.Warning("Quest", "SetSubtitleViaReflection failed: " + ex.Message); } } private static int GetCurrentElapsedMinutes() { int elapsedDays = TimeManager.ElapsedDays; int currentTime = TimeManager.CurrentTime; int num = currentTime / 100; int num2 = currentTime % 100; return elapsedDays * 1440 + num * 60 + num2; } public void CompleteDeal() { try { QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Complete(); } ((Quest)this).Complete(); ((Quest)this).End(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "CompleteDeal failed: " + ex.Message); } } public void FailDeal() { try { QuestEntry deliverEntry = _deliverEntry; if (deliverEntry != null) { deliverEntry.Complete(); } ((Quest)this).Fail(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "FailDeal failed: " + ex.Message); } } public void CancelDeal() { try { ((Quest)this).Cancel(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { OTCLog.Error("Quest", "CancelDeal failed: " + ex.Message); } } } public enum QuestHighlight { None, InventoryNav, PricingArea, ProductRows, OverviewNav, StoreToggle } public class StorefrontGrowthQuest : Quest { [SaveableField("storefront_quest_stage")] private int _stage; [SaveableField("storefront_quest_touched_pricing")] private bool _hasTouchedPricing; [SaveableField("storefront_quest_viewed_product")] private bool _hasViewedProduct; private QuestEntry _placeStorageEntry; private QuestEntry _stockProductEntry; private QuestEntry _setPricesEntry; private QuestEntry _viewProductEntry; private QuestEntry _turnOnLightsEntry; private QuestEntry _openStoreEntry; private QuestEntry _makeSaleEntry; private static readonly Vector3 ShackPosition = new Vector3(-164.4f, -3f, 76f); private float _lastTickTime; private const float TickInterval = 3f; private TutorialCustomerHelper _tutorialCustomer; protected override string Title => "Storefront Growth"; protected override string Description => "You've got the keys. Now turn this place into a working storefront."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => (Core.OtcIconDir != null) ? ImageUtils.LoadImage(Path.Combine(Core.OtcIconDir, "StoreAlertIcon.png")) : null; public static StorefrontGrowthQuest Instance { get; private set; } public int Stage => _stage; public static QuestHighlight ActiveHighlight { get { if (Instance == null) { return QuestHighlight.None; } int stage = Instance._stage; if (1 == 0) { } QuestHighlight result = stage switch { 3 => QuestHighlight.InventoryNav,