Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of OverTheCounter v1.3.0
OverTheCounter.Il2Cpp.dll
Decompiled 5 days 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.Permissions; using System.Text; using System.Threading; using HarmonyLib; using Il2Cpp; using Il2CppFishNet; using Il2CppFishNet.Connection; using Il2CppFishNet.Managing; using Il2CppFishNet.Managing.Object; using Il2CppFishNet.Object; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.AvatarFramework.Animation; using Il2CppScheduleOne.AvatarFramework.Equipping; using Il2CppScheduleOne.AvatarFramework.Impostors; using Il2CppScheduleOne.Combat; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Dialogue; using Il2CppScheduleOne.Doors; using Il2CppScheduleOne.Economy; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.EntityFramework; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.Interaction; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Law; 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.ObjectScripts; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.Persistence.Datas; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Police; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Product.Packaging; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.Quests; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Tools; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Compass; using Il2CppScheduleOne.UI.Handover; using Il2CppScheduleOne.UI.Management; using Il2CppScheduleOne.UI.Phone; using Il2CppScheduleOne.UI.Phone.ContactsApp; using Il2CppScheduleOne.UI.Phone.Map; using Il2CppScheduleOne.UI.Shop; using Il2CppScheduleOne.Variables; using Il2CppScheduleOne.VoiceOver; using Il2CppSteamworks; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using OverTheCounter; using OverTheCounter.Apps; using OverTheCounter.Logic; 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.Messaging; using S1API.Money; using S1API.PhoneApp; using S1API.Products; using S1API.Quests; using S1API.Quests.Identifiers; using S1API.Saveables; using S1API.UI; using S1API.Utils; using SteamNetworkLib; 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", "1.3.0", "hdlmrell", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonOptionalDependencies(new string[] { "SteamNetworkLib" })] [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+de565dbb2b56dd5e21f645dc57046918064cb34f")] [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; public override void OnInitializeMelon() { Config.Initialize(); NpcTypeDiscoveryPatch.Apply(((MelonBase)this).HarmonyInstance); ConfigSyncPatch.TryApply(((MelonBase)this).HarmonyInstance); ManagerClipboardPatch.Apply(((MelonBase)this).HarmonyInstance); if (!ConfigSyncData.IsNetworkLibAvailable) { ((MelonBase)this).LoggerInstance.Warning("SteamNetworkLib not installed — multiplayer sync disabled. Single-player works fine. Install SteamNetworkLib for co-op support."); } ((MelonBase)this).LoggerInstance.Msg("OverTheCounter Initialized."); ImmediateQuestWindowConfig.Register(); MinimapOverlay.Register(); ExtractIcons(); _notificationManager = new NotificationManager(((MelonBase)this).LoggerInstance); _desperationManager = new DesperationManager(((MelonBase)this).LoggerInstance); _drifterManager = new DrifterManager(((MelonBase)this).LoggerInstance); _managerManager = new ManagerController(((MelonBase)this).LoggerInstance); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown StaticSaveData.ResetInstance(); VicSaveData.ResetInstance(); BellaSaveData.ResetInstance(); StaticIntroQuest.ResetInstance(); StaticUpgrade1Quest.ResetInstance(); StaticUpgrade2Quest.ResetInstance(); VicIntroQuest.ResetInstance(); BellaProtocolQuest.ResetInstance(); BellaSummonPatch.Reset(); ContactsAppFix.Reset(); DrifterInstance.CleanupAll(); DrifterSpawner.ResetCache(); 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); } } public override void OnLateUpdate() { try { ConfigSyncData.EnsureNetworkReady(); ConfigSyncData.ProcessMessages(); _notificationManager.ProcessContractState(); VicSaveData.Instance?.Tick(); StaticSaveData.Instance?.Tick(); BellaSaveData.Instance?.Tick(); ManagerSaveData.Instance?.Tick(); ContactsAppFix.Tick(); _drifterManager?.RetryPendingAdoptions(); ManagerInstance.RetryPendingAdoptions(); _managerManager?.CheckImmediateWages(); foreach (ManagerInstance value in ManagerInstance.Active.Values) { value.EnsureMoving(); } if (NetworkHelper.IsHost) { foreach (ManagerInstance value2 in ManagerInstance.Active.Values) { value2.SupplyBehaviour?.Tick(); value2.DistributionBehaviour?.Tick(); } if (ManagerInstance.HasPendingMessages) { ConfigSyncData.Instance?.PublishManagerMessages(); } if (DrifterManager.HasPendingDrifterMessages) { ConfigSyncData.Instance?.PublishDrifterMessages(); } if (ManagerInstance.StatePublishNeeded) { ManagerInstance.StatePublishNeeded = false; ConfigSyncData.Instance?.PublishManagerState(); } } _drifterManager?.ClientQuestTick(); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("Error in OnLateUpdate: " + ex.Message + "\n" + ex.StackTrace); } } public override void OnDeinitializeMelon() { ConfigSyncData.Cleanup(); _notificationManager?.Cleanup(); _desperationManager?.Cleanup(); _drifterManager?.Cleanup(); _managerManager?.Cleanup(); } private void ExtractIcons() { string text = Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } ExtractResource(text, "CustomersIcon.png"); ExtractResource(text, "DrifterQuestIcon.png"); ExtractResource(text, "DrifterProfileIcon.png"); ExtractResource(text, "RinseCycle.png"); ExtractResource(text, "CrimeWareQuest.png"); ExtractResource(text, "ExecutivePrivilege.png"); ExtractResource(text, "ManagerIcon.png"); } private void ExtractResource(string directory, string fileName) { string path = Path.Combine(directory, fileName); if (File.Exists(path)) { return; } ((MelonBase)this).LoggerInstance.Msg("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); } ((MelonBase)this).LoggerInstance.Msg(fileName + " extracted successfully."); } else { ((MelonBase)this).LoggerInstance.Error("Could not find embedded resource '" + text + "'."); } } } public static class Config { 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 _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; private static MelonPreferences_Category _subscription; public static ConfigEntry<float> SaasWeeklyCost; public static ConfigEntry<int> SaasCycleDays; public static ConfigEntry<float> AtmDepositTrigger; 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 _notifications; public static ConfigEntry<bool> ConsolidationEnabled; public static ConfigEntry<int> ConsolidationThreshold; private static MelonPreferences_Category _managers; public static ConfigEntry<float> ManagerDailyWage; public static ConfigEntry<float> ManagerSigningFee; public static ConfigEntry<bool> ManagerVerboseLogging; public static ConfigEntry<bool> AlternateHire; private static MelonPreferences_Category _debug; public static ConfigEntry<bool> VerboseLogging; private static MelonPreferences_Category _bella; public static ConfigEntry<float> BellaWeedValue; public static ConfigEntry<float> BellaMethValue; public static ConfigEntry<float> BellaCokeValue; 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 _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 MelonPreferences_Entry<string> MinimapPosition; 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; 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; 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", "VerboseLogging", "MinimapEnabled", "MinimapSize", "MinimapRotateWithPlayer", "MinimapCircle", "MinimapDefaultZoom", "MinimapIconScale", "MinimapBorderWidth", "MinimapShowTime", "MinimapShowDay", "MinimapUse24HourClock", "MinimapShowPotentialCustomers", "MinimapShowCustomers", "MinimapShowDealers", "MinimapShowDeadDrops", "MinimapShowContracts", "MinimapShowQuests", "MinimapShowProperties", "MinimapShowManagers" }; public static void Initialize() { //IL_09b5: Unknown result type (might be due to invalid IL or missing references) _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)); _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)); _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)); AtmDepositTrigger = Register(_subscription.CreateEntry<float>("AtmDepositTrigger", 5000f, "ATM Deposit Trigger", "Weekly ATM deposit sum that triggers Static's intro quest", 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)); _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)); _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)); ManagerVerboseLogging = Register(_managers.CreateEntry<bool>("ManagerVerboseLogging", false, "Verbose Logging", "Enable detailed manager logging for troubleshooting (shopping list breakdowns, per-item details)", 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)); _debug = MelonPreferences.CreateCategory("OverTheCounter_Debug", "Debug"); VerboseLogging = Register(_debug.CreateEntry<bool>("VerboseLogging", false, "Verbose Logging", "Enable detailed logging for troubleshooting (drifters, quests, sync, NPCs)", 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)); _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)); _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); MinimapPosition = _minimap.CreateEntry<string>("MinimapPosition", "TopRight", "Position", "TopLeft, TopRight, BottomLeft, BottomRight", 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)); _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)); } 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(); } } } } namespace OverTheCounter.Quests { public class VicIntroQuest : Quest { private static readonly Instance Logger = new Instance("OTC:VicIntroQuest"); [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 => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "RinseCycle.png")); public static VicIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); } catch (Exception ex) { Logger.Error("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) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Complete(); } } catch (Exception ex) { Logger.Error("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(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticIntroQuest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticIntroQuest"); [SaveableField("static_quest_stage")] private int _stage; private QuestEntry _talkToStaticEntry; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Crimeware as a Service"; protected override string Description => "Someone at the casino noticed your deposits. Find Static after 4 PM when the casino opens."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _talkToStaticEntry = ((Quest)this).AddEntry("Talk to Static in the casino after 4 PM", (Vector3?)StaticPosition); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier1BankCost.Value:N0} and {Config.StaticTier1WeedGrams.Value} grams of weed"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 3) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Complete(); } QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj2 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0062: 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 { if (StaticSaveData.Instance != null) { int num = ((StaticSaveData.Instance.CrmTier >= 1) ? 3 : (StaticSaveData.Instance.IntroCompleted ? 2 : (StaticSaveData.Instance.QuestTriggered ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _talkToStaticEntry = ((Quest)this).AddEntry("Talk to Static in the casino after 4 PM", (Vector3?)StaticPosition); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Begin(); } } if (_stage >= 2) { QuestEntry talkToStaticEntry2 = _talkToStaticEntry; if (talkToStaticEntry2 != null) { talkToStaticEntry2.Complete(); } QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 3) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade1Quest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticUpgrade1Quest"); [SaveableField("static_upgrade1_stage")] private int _stage; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Premium Tier"; protected override string Description => "Static has the premium tier upgrade available. Check your texts and bring him what he needs."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticUpgrade1Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier2BankCost.Value:N0} and {Config.StaticTier2MethGrams.Value} grams of meth"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 2) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 2) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade2Quest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticUpgrade2Quest"); [SaveableField("static_upgrade2_stage")] private int _stage; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Full Scale"; protected override string Description => "Static has the final tier-3 enterprise upgrade available. Bring premium meth and go all in."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticUpgrade2Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier3BankCost.Value:N0} and {Config.StaticTier3PremiumMethGrams.Value} grams of premium meth"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 2) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 2) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class DrifterDealQuest : Quest { private static readonly Instance Logger = new Instance("OTC:DrifterDealQuest"); 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 => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "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) { Logger.Error("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) { Logger.Error("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) { Logger.Warning("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) { Logger.Warning("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) { Logger.Error("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) { Logger.Error("FailDeal failed: " + ex.Message); } } public void CancelDeal() { try { ((Quest)this).Cancel(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { Logger.Error("CancelDeal failed: " + ex.Message); } } } public class BellaProtocolQuest : Quest { private static readonly Instance Logger = new Instance("OTC:BellaProtocolQuest"); [SaveableField("bella_quest_stage")] private int _stage; private QuestEntry _visitEntry; private QuestEntry _weedEntry; private QuestEntry _methEntry; private QuestEntry _cokeEntry; private static readonly Vector3 BellaBuilding = new Vector3(74.1f, 1f, 57.2f); protected override string Title => "Executive Privilege"; protected override string Description => "Someone at the Fixer's mentioned a contact who can help with warehouse access."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "ExecutivePrivilege.png")); public static BellaProtocolQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _visitEntry = ((Quest)this).AddEntry("Visit Bella at the downtown apartment", (Vector3?)BellaBuilding); _weedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)BellaBuilding); _methEntry = ((Quest)this).AddEntry(GetMethText(), (Vector3?)BellaBuilding); _cokeEntry = ((Quest)this).AddEntry(GetCokeText(), (Vector3?)BellaBuilding); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetWeedText() { return $"Bring Bella a weed mix worth ${Config.BellaWeedValue.Value:N0}+"; } private static string GetMethText() { return $"Bring Bella a meth mix worth ${Config.BellaMethValue.Value:N0}+"; } private static string GetCokeText() { return $"Bring Bella a cocaine mix worth ${Config.BellaCokeValue.Value:N0}+"; } public void RefreshEntryText() { if (_weedEntry != null && _stage == 2) { _weedEntry.Title = GetWeedText(); } if (_methEntry != null && _stage == 3) { _methEntry.Title = GetMethText(); } if (_cokeEntry != null && _stage == 4) { _cokeEntry.Title = GetCokeText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void AdvanceToWeedRequest() { try { _stage = 2; QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Complete(); } QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToWeedRequest failed: " + ex.Message); } } public void AdvanceToMethRequest() { try { _stage = 3; QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Complete(); } QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToMethRequest failed: " + ex.Message); } } public void AdvanceToCocaineRequest() { try { _stage = 4; QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Complete(); } QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToCocaineRequest failed: " + ex.Message); } } public void CompleteQuest() { try { _stage = 5; QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteQuest failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { int stage = _stage; int value = BellaSaveData.Instance?.Stage ?? (-1); if (Config.VerboseLogging.Value) { Logger.Msg($"OnLoaded: save _stage={stage}, BellaSaveData.Stage={value}"); } if (BellaSaveData.Instance != null && BellaSaveData.Instance.Stage > _stage) { _stage = BellaSaveData.Instance.Stage; } if (Config.VerboseLogging.Value) { Logger.Msg($"OnLoaded: rebuilding entries at _stage={_stage}"); } base.QuestEntries.Clear(); _visitEntry = ((Quest)this).AddEntry("Visit Bella at the downtown apartment", (Vector3?)BellaBuilding); _weedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)BellaBuilding); _methEntry = ((Quest)this).AddEntry(GetMethText(), (Vector3?)BellaBuilding); _cokeEntry = ((Quest)this).AddEntry(GetCokeText(), (Vector3?)BellaBuilding); if (_stage >= 1) { QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Begin(); } } if (_stage >= 2) { QuestEntry visitEntry2 = _visitEntry; if (visitEntry2 != null) { visitEntry2.Complete(); } QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Begin(); } } if (_stage >= 3) { QuestEntry weedEntry2 = _weedEntry; if (weedEntry2 != null) { weedEntry2.Complete(); } QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Begin(); } } if (_stage >= 4) { QuestEntry methEntry2 = _methEntry; if (methEntry2 != null) { methEntry2.Complete(); } QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Begin(); } } if (_stage >= 5) { QuestEntry cokeEntry2 = _cokeEntry; if (cokeEntry2 != null) { cokeEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } } namespace OverTheCounter.SaveData { public class VicSaveData : Saveable { private static readonly Instance Logger = new Instance("OTC:VicSaveData"); [SaveableField("vic_unlocked")] private bool _unlocked; [SaveableField("vic_has_been_texted")] private bool _hasBeenTexted; [SaveableField("vic_trust_level")] private int _trustLevel; [SaveableField("vic_quest_accepted")] private bool _questAccepted; [SaveableField("vic_trigger_pending_day")] private int _triggerPendingDay = -1; [SaveableField("vic_last_deposit_day")] private int _lastDepositDay = -1; [SaveableField("vic_last_trust_increment_day")] private int _lastTrustIncrementDay = -1; [SaveableField("vic_tier2_intro_shown")] private bool _tier2IntroShown; private bool _needsIntroText; private bool _questCreated; private bool _fireOnNextTick; private bool _staleCheckDone; private bool _needsStatePublish; private bool _questReconciled; private int _tickCounter; private const int TICK_INTERVAL = 300; private bool _positionFixed; internal bool _dialogueStale; private bool _wasInDialogue; private static bool _sleepEndSubscribed; public static VicSaveData Instance { get; private set; } public bool Unlocked => _unlocked; public bool QuestAccepted => _questAccepted; public int TrustLevel => _trustLevel; public int LastDepositDay => _lastDepositDay; public bool Tier2IntroShown => _tier2IntroShown; public bool HasBeenTexted { get { return _hasBeenTexted; } set { if (!_hasBeenTexted && value) { _hasBeenTexted = true; TrySendIntroText(); CreateOrResumeQuest(); _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } } internal static void ResetInstance() { Instance = null; } public VicSaveData() { Instance = this; if (!_sleepEndSubscribed) { TimeManager.OnSleepEnd = (Action<int>)Delegate.Combine(TimeManager.OnSleepEnd, (Action<int>)delegate { Instance?.OnPlayerWokeUp(); }); _sleepEndSubscribed = true; } } protected override void OnLoaded() { Instance = this; if (_questAccepted) { _questCreated = true; } _dialogueStale = true; if (_hasBeenTexted) { _questCreated = true; if (NetworkHelper.IsHost) { _needsStatePublish = true; } ConfigSyncData.ApplyPendingGameState(); ReconcileQuest(); } else { ConfigSyncData.ApplyPendingGameState(); if (_triggerPendingDay < 0 && IsCleanCashQuestStarted()) { _triggerPendingDay = 0; } } } private void ReconcileQuest() { if (VicIntroQuest.Instance == null) { return; } int num = (_unlocked ? 3 : (_questAccepted ? 2 : (_hasBeenTexted ? 1 : 0))); if (num > VicIntroQuest.Instance.Stage) { if (num >= 2 && VicIntroQuest.Instance.Stage < 2) { VicIntroQuest.Instance.CompleteObj1(); } if (num >= 3 && VicIntroQuest.Instance.Stage < 3) { VicIntroQuest.Instance.CompleteObj2(); } } } public void OnVicSpawned() { if (NetworkHelper.IsHost) { _positionFixed = false; } if (_needsIntroText) { _needsIntroText = false; TrySendIntroText(); } } private void OnPlayerWokeUp() { if (NetworkHelper.IsHost) { _positionFixed = false; if (!_hasBeenTexted && (_triggerPendingDay >= 0 || IsCleanCashQuestStarted())) { _triggerPendingDay = 0; _fireOnNextTick = true; } } } public void Tick() { if (!_questReconciled && _hasBeenTexted && VicIntroQuest.Instance != null) { _questReconciled = true; int num = (_unlocked ? 3 : ((!_questAccepted) ? 1 : 2)); if (VicIntroQuest.Instance.Stage < num) { if (Config.VerboseLogging.Value) { Logger.Msg($"Tick reconciliation: quest stage {VicIntroQuest.Instance.Stage} → {num}"); } ReconcileQuest(); } } bool flag = VicNPC.Instance != null && VicNPC.Instance.IsInDialogue; if (_wasInDialogue && !flag) { _dialogueStale = true; } _wasInDialogue = flag; if (_dialogueStale && VicNPC.Instance != null && VicNPC.Instance.DialogueReady && !flag) { _dialogueStale = false; try { VicNPC.Instance.RefreshDialogue(); } catch (Exception) { } } if (_needsStatePublish && NetworkHelper.IsHost) { _needsStatePublish = false; ConfigSyncData.Instance?.PublishGameState(); } if (NetworkHelper.IsHost && !_staleCheckDone && _hasBeenTexted) { _staleCheckDone = true; if (!_unlocked && !IsCleanCashQuestStarted()) { _hasBeenTexted = false; _triggerPendingDay = -1; _questCreated = false; _needsIntroText = false; _fireOnNextTick = false; } } else if (_fireOnNextTick) { _fireOnNextTick = false; if (!_hasBeenTexted) { HasBeenTexted = true; } } else { if (++_tickCounter < 300) { return; } _tickCounter = 0; if (NetworkHelper.IsHost && !_positionFixed && VicNPC.Instance != null) { _positionFixed = true; try { VicNPC.Instance.WarpToSpawn(); } catch (Exception) { } } if (_hasBeenTexted) { try { if (VicNPC.Instance != null && VicNPC.Instance.DialogueReady) { VicNPC.Instance.RefreshDialogue(); } return; } catch (Exception) { return; } } if (NetworkHelper.IsHost && _triggerPendingDay < 0 && IsCleanCashQuestStarted()) { _triggerPendingDay = 0; } } } public void CreateOrResumeQuest() { if (_questCreated) { return; } _questCreated = true; try { if (VicIntroQuest.Instance == null) { VicIntroQuest vicIntroQuest = (VicIntroQuest)(object)QuestManager.CreateQuest<VicIntroQuest>((string)null); if (vicIntroQuest != null) { vicIntroQuest.Initialize(); vicIntroQuest.StartQuest(); } else { Logger.Error("QuestManager.CreateQuest<VicIntroQuest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateOrResumeQuest failed: " + ex.Message); } } public void ApplyHostState(bool hasBeenTexted = false, bool questAccepted = false, bool unlocked = false, int trustLevel = -1) { bool flag = false; bool flag2 = unlocked; if (hasBeenTexted && !_hasBeenTexted) { _hasBeenTexted = true; if (!flag2) { CreateOrResumeQuest(); } flag = true; } if (questAccepted && !_questAccepted) { _questAccepted = true; _questCreated = true; if (!flag2) { try { VicIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Client VicIntroQuest CompleteObj1 failed: " + ex.Message); } } flag = true; } if (unlocked && !_unlocked) { _unlocked = true; try { VicIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Client VicIntroQuest CompleteObj2 failed: " + ex2.Message); } flag = true; } if (trustLevel >= 0 && trustLevel != _trustLevel) { _trustLevel = trustLevel; flag = true; } if (flag) { _dialogueStale = true; } } public void OnQuestComplete() { _unlocked = true; ConfigSyncData.Instance?.PublishGameState(); } public void OnLaunderComplete(int currentDay) { _lastDepositDay = currentDay; if (_lastTrustIncrementDay < currentDay) { _lastTrustIncrementDay = currentDay; _trustLevel++; } ConfigSyncData.Instance?.PublishGameState(); } public void HandleRemoteAction(string action) { switch (action) { case "VIC_QUEST_ACCEPTED": _questAccepted = true; _questCreated = true; try { VicIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Remote VicIntroQuest CompleteObj1 failed: " + ex.Message); } break; case "VIC_QUEST_COMPLETE": _unlocked = true; try { VicIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Remote VicIntroQuest CompleteObj2 failed: " + ex2.Message); } break; case "VIC_LAUNDER": { int num = (_lastDepositDay = TimeManager.ElapsedDays); if (_lastTrustIncrementDay < num) { _lastTrustIncrementDay = num; _trustLevel++; } break; } default: Logger.Warning("VicSaveData: unknown remote action '" + action + "'"); return; } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public void MarkTier2IntroShown() { _tier2IntroShown = true; } private void TrySendIntroText() { if (!NetworkHelper.IsHost) { return; } try { NPC val = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "vic_bank_teller")); if (val != null) { val.SendTextMessage("Hey, I noticed you've been hitting your weekly deposit limits. Meet me in the alley behind the bank. I might be able to help.", (Response[])null, 1f, true); _needsIntroText = false; } else { Logger.Warning("Vic NPC not found — deferring intro text until spawn."); _needsIntroText = true; } } catch (Exception ex) { Logger.Error("TrySendIntroText failed: " + ex.Message); _needsIntroText = true; } } private bool IsCleanCashQuestStarted() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 try { QuestWrapper val = QuestManager.Get<CleanCash>(); if (val == null) { return false; } List<QuestEntry> questEntries = val.QuestEntries; if (questEntries == null || questEntries.Count == 0) { return false; } foreach (QuestEntry item in questEntries) { if ((int)item.State == 1 || (int)item.State == 2) { return true; } } } catch (Exception ex) { Logger.Warning("Could not check Clean Cash quest: " + ex.Message); } return false; } } public class StaticSaveData : Saveable { private static readonly Instance Logger = new Instance("OTC:StaticSaveData"); [SaveableField("static_intro_completed")] private bool _introCompleted; [SaveableField("static_quest_triggered")] private bool _questTriggered; [SaveableField("static_crm_tier")] private int _crmTier; [SaveableField("static_saas_active")] private bool _saasActive; [SaveableField("static_saas_next_payment_day")] private int _saasNextPaymentDay; [SaveableField("static_saas_day_pass_count")] private int _dayPassCount; [SaveableField("static_upgrade_available")] private bool _upgradeAvailable; [SaveableField("static_early_visit_seen")] private bool _earlyVisitSeen; private int _tickCounter; private const int TICK_INTERVAL = 300; private bool _positionFixed; private bool _dialogueStale; private bool _wasInDialogue; private bool _questCreated; private bool _needsStatePublish; private bool _questReconciled; private bool _needsIntroText; private static bool _dayPassSubscribed; public static StaticSaveData Instance { get; private set; } public bool IntroCompleted => _introCompleted; public bool QuestTriggered => _questTriggered; public int CrmTier => _crmTier; public bool SaasActive => _saasActive; public int SaasNextPaymentDay => _saasNextPaymentDay; public int DayPassCount => _dayPassCount; public bool UpgradeAvailable => _upgradeAvailable; public bool EarlyVisitSeen => _earlyVisitSeen; internal static void ResetInstance() { Instance = null; } public StaticSaveData() { Instance = this; if (!_dayPassSubscribed) { TimeManager.OnDayPass = (Action)Delegate.Combine(TimeManager.OnDayPass, (Action)delegate { Instance?.OnDayPass(); }); _dayPassSubscribed = true; } } protected override void OnLoaded() { Instance = this; if (_questTriggered) { _questCreated = true; if (NetworkHelper.IsHost) { _needsStatePublish = true; } } _dialogueStale = true; ConfigSyncData.ApplyPendingGameState(); ReconcileQuest(); } private void ReconcileQuest() { if (StaticIntroQuest.Instance == null) { return; } int num = ((_crmTier >= 1) ? 3 : (_introCompleted ? 2 : (_questTriggered ? 1 : 0))); if (num > StaticIntroQuest.Instance.Stage) { if (num >= 2 && StaticIntroQuest.Instance.Stage < 2) { StaticIntroQuest.Instance.CompleteObj1(); } if (num >= 3 && StaticIntroQuest.Instance.Stage < 3) { StaticIntroQuest.Instance.CompleteObj2(); } } } public void Tick() { if (!_questReconciled && _questTriggered && StaticIntroQuest.Instance != null) { _questReconciled = true; int num = ((_crmTier >= 1) ? 3 : ((!_introCompleted) ? 1 : 2)); if (StaticIntroQuest.Instance.Stage < num) { if (Config.VerboseLogging.Value) { Logger.Msg($"Tick reconciliation: quest stage {StaticIntroQuest.Instance.Stage} → {num}"); } ReconcileQuest(); } } bool flag = StaticNPC.Instance != null && StaticNPC.Instance.IsInDialogue; if (_wasInDialogue && !flag) { _dialogueStale = true; } _wasInDialogue = flag; if (_needsStatePublish && NetworkHelper.IsHost) { _needsStatePublish = false; ConfigSyncData.Instance?.PublishGameState(); } if (_dialogueStale && StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady && !flag) { _dialogueStale = false; try { StaticNPC.Instance.RefreshDialogue(); } catch (Exception) { } } if (++_tickCounter < 300) { return; } _tickCounter = 0; if (NetworkHelper.IsHost && !_positionFixed && StaticNPC.Instance != null) { _positionFixed = true; try { StaticNPC.Instance.WarpToSpawn(); } catch (Exception) { } } if (!_questTriggered) { try { if (ATM.WeeklyDepositSum >= Config.AtmDepositTrigger.Value) { _questTriggered = true; CreateOrResumeQuest(); if (NetworkHelper.IsHost) { TrySendIntroText(); ConfigSyncData.Instance?.PublishGameState(); } else { ConfigSyncData.SendQuestAction("STATIC_ATM_TRIGGERED"); } } return; } catch (Exception ex3) { Logger.Warning("ATM check failed: " + ex3.Message); return; } } try { if (StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady) { StaticNPC.Instance.RefreshDialogue(); } } catch (Exception) { } } public void CreateOrResumeQuest() { if (_questCreated) { return; } _questCreated = true; try { if (StaticIntroQuest.Instance == null) { StaticIntroQuest staticIntroQuest = (StaticIntroQuest)(object)QuestManager.CreateQuest<StaticIntroQuest>((string)null); if (staticIntroQuest != null) { staticIntroQuest.Initialize(); staticIntroQuest.StartQuest(); } else { Logger.Error("QuestManager.CreateQuest<StaticIntroQuest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateOrResumeQuest failed: " + ex.Message); } } public void ApplyHostState(bool questTriggered = false, bool introCompleted = false, int crmTier = -1, bool? saasActive = null, bool? upgradeAvailable = null, int saasNextPaymentDay = -1, int dayPassCount = -1) { bool flag = false; bool flag2 = crmTier >= 1; if (questTriggered && !_questTriggered) { _questTriggered = true; if (!flag2) { CreateOrResumeQuest(); } flag = true; } if (introCompleted && !_introCompleted) { _introCompleted = true; if (!flag2) { try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Client CompleteObj1 failed: " + ex.Message); } } flag = true; } if (crmTier >= 0 && crmTier != _crmTier) { int crmTier2 = _crmTier; _crmTier = crmTier; if (crmTier2 == 0 && crmTier == 1) { try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Client CompleteObj2 failed: " + ex2.Message); } } if (crmTier2 == 1 && crmTier == 2) { try { StaticUpgrade1Quest.Instance?.CompleteObj1(); } catch (Exception ex3) { Logger.Warning("Client Upgrade1 CompleteObj1 failed: " + ex3.Message); } } if (crmTier2 == 2 && crmTier == 3) { try { StaticUpgrade2Quest.Instance?.CompleteObj1(); } catch (Exception ex4) { Logger.Warning("Client Upgrade2 CompleteObj1 failed: " + ex4.Message); } } flag = true; } if (saasActive.HasValue && saasActive.Value != _saasActive) { _saasActive = saasActive.Value; flag = true; } if (upgradeAvailable.HasValue && upgradeAvailable.Value != _upgradeAvailable) { _upgradeAvailable = upgradeAvailable.Value; if (_upgradeAvailable) { CreateUpgradeQuest(); } flag = true; } if (saasNextPaymentDay >= 0 && saasNextPaymentDay != _saasNextPaymentDay) { _saasNextPaymentDay = saasNextPaymentDay; flag = true; } if (dayPassCount >= 0 && dayPassCount != _dayPassCount) { _dayPassCount = dayPassCount; flag = true; } if (flag && StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady) { StaticNPC.Instance.RefreshDialogue(); } } public void OnStaticSpawned() { if (NetworkHelper.IsHost) { _positionFixed = false; } if (_needsIntroText) { _needsIntroText = false; TrySendIntroText(); } } private void TrySendIntroText() { if (!NetworkHelper.IsHost) { return; } try { NPC val = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "static_casino_fixer")); if (val != null) { val.SendTextMessage("[0x4E72] d1g1t4l f00tpr1nt fl4gg3d. unencrypt3d ch4nn3l. vuln: CR1T1C4L.\n\nc4s1n0. t0p fl00r. 4ft3r 4. c0m3 4l0n3.\n\n— ST4T1C", (Response[])null, 1f, true); _needsIntroText = false; } else { Logger.Warning("Static NPC not found — deferring intro text until spawn."); _needsIntroText = true; } } catch (Exception ex) { Logger.Error("TrySendIntroText failed: " + ex.Message); _needsIntroText = true; } } public void OnEarlyVisitSeen() { _earlyVisitSeen = true; } public void OnIntroCompleted() { if (!_introCompleted) { _introCompleted = true; try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Error("OnIntroCompleted quest completion failed: " + ex.Message); } SendStaticText($"[0x7A3F] s0ftw4r3 p4ck4g3 r34dy. c0st: ${Config.StaticTier1BankCost.Value:N0} + {Config.StaticTier1WeedGrams.Value}g w33d.\n\nbr1ng t0 c4s1n0.\n\n— ST4T1C_SYS"); _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } public void PurchaseInitial() { if (_crmTier < 1) { _crmTier = 1; _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex) { Logger.Error("PurchaseInitial quest completion failed: " + ex.Message); } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } public void PurchaseUpgrade() { if (_crmTier >= 3) { return; } int crmTier = _crmTier; _crmTier++; _upgradeAvailable = false; try { switch (crmTier) { case 1: StaticUpgrade1Quest.Instance?.CompleteObj1(); break; case 2: StaticUpgrade2Quest.Instance?.CompleteObj1(); break; } } catch (Exception ex) { Logger.Error("PurchaseUpgrade quest completion failed: " + ex.Message); } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public bool ReactivateSubscription() { try { if (Money.GetOnlineBalance() < Config.SaasWeeklyCost.Value) { return false; } Money.CreateOnlineTransaction("OTC Back-Rent", 0f - Config.SaasWeeklyCost.Value, 1f, "Static Services"); _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); return true; } catch (Exception ex) { Logger.Error("ReactivateSubscription failed: " + ex.Message); return false; } } public void CancelSubscription() { _saasActive = false; _upgradeAvailable = false; _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public void HandleRemoteAction(string action) { switch (action) { case "STATIC_ATM_TRIGGERED": if (!_questTriggered) { _questTriggered = true; TrySendIntroText(); CreateOrResumeQuest(); } break; case "STATIC_INTRO_COMPLETED": _introCompleted = true; try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex3) { Logger.Warning("Remote CompleteObj1 failed: " + ex3.Message); } break; case "STATIC_PURCHASE_INITIAL": _crmTier = 1; _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Remote CompleteObj2 failed: " + ex2.Message); } break; case "STATIC_PURCHASE_UPGRADE": { if (_crmTier >= 3) { return; } int crmTier = _crmTier; _crmTier++; _upgradeAvailable = false; try { switch (crmTier) { case 1: StaticUpgrade1Quest.Instance?.CompleteObj1(); break; case 2: StaticUpgrade2Quest.Instance?.CompleteObj1(); break; } } catch (Exception ex) { Logger.Warning("Remote PurchaseUpgrade quest failed: " + ex.Message); } break; } case "STATIC_REACTIVATE": _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; break; case "STATIC_CANCEL": _saasActive = false; _upgradeAvailable = false; break; default: Logger.Warning("StaticSaveData: unknown remote action '" + action + "'"); return; } ConfigSyncData.Instance?.PublishGameState(); } private void OnDayPass() { if (NetworkHelper.IsHost) { _positionFixed = false; _dayPassCount++; CheckSubscriptionStatus(); } } public void CheckSubscriptionStatus() { if (!_saasActive || _dayPassCount < _saasNextPaymentDay) { return; } try { if (Money.GetOnlineBalance() >= Config.SaasWeeklyCost.Value) { Money.CreateOnlineTransaction("OTC Server Rent", 0f - Config.SaasWeeklyCost.Value, 1f, "Static Services"); _saasNextPaymentDay += Config.SaasCycleDays.Value; SendStaticText("[0x52E1] server r3nt cleared. nod3s onl1ne.\n\n— ST4T1C_SYS"); if (_crmTier < 3 && !_upgradeAvailable) { _upgradeAvailable = true; SendUpgradeOfferText(); CreateUpgradeQuest(); } } else { _saasActive = false; SendStaticText("[0xDEAD] paym3nt fa1led. serv1ce suspended. r3store in p3rson.\n\n— ST4T1C_SYS"); } ConfigSyncData.Instance?.PublishGameState(); } catch (Exception ex) { Logger.Error("CheckSubscriptionStatus failed: " + ex.Message); } } private void CreateUpgradeQuest() { try { if (_crmTier == 1) { if (StaticUpgrade1Quest.Instance == null) { StaticUpgrade1Quest staticUpgrade1Quest = (StaticUpgrade1Quest)(object)QuestManager.CreateQuest<StaticUpgrade1Quest>((string)null); if (staticUpgrade1Quest != null) { staticUpgrade1Quest.Initialize(); staticUpgrade1Quest.StartQuest(); } else { Logger.Error("CreateQuest<StaticUpgrade1Quest> returned null."); } } } else if (_crmTier == 2 && StaticUpgrade2Quest.Instance == null) { StaticUpgrade2Quest staticUpgrade2Quest = (StaticUpgrade2Quest)(object)QuestManager.CreateQuest<StaticUpgrade2Quest>((string)null); if (staticUpgrade2Quest != null) { staticUpgrade2Quest.Initialize(); staticUpgrade2Quest.StartQuest(); } else { Logger.Error("CreateQuest<StaticUpgrade2Quest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateUpgradeQuest failed: " + ex.Message); } } private void SendUpgradeOfferText() { if (_crmTier == 1) { SendStaticText($"[0x9FA1] pr1v4t3 s3rv3r r34dy. c0st: ${Config.StaticTier2BankCost.Value:N0} + {Config.StaticTier2MethGrams.Value}g m3th.\nfull r3g10n c0v3r4g3. s4m3 sp0t.\n\n— ST4T1C_SYS"); } else if (_crmTier == 2) { SendStaticText($"[0xB2D8] 3nt3rpr1s3 t13r. GPS tr4ck1ng. c0st: ${Config.StaticTier3BankCost.Value:N0} + {Config.StaticTier3PremiumMethGrams.Value}g pr3m1um m3th.\nl4st upgr4d3. c4s1n0.\n\n— ST4T1C_SYS"); } } private void SendStaticText(string message) { try { NPC? obj = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "static_casino_fixer")); if (obj != null) { obj.SendTextMessage(message, (Response[])null, 1f, true); } } catch (Exception ex) { Logger.Error("SendStaticText failed: " + ex.Message); } } } public class ConfigSyncData : Saveable { private static readonly Instance Logger = new Instance("OTC:ConfigSync"); [SaveableField("config_sync_payload")] private string _payload = ""; private static Dictionary<string, string> _pendingGameState; private static int _msgSeq; private static int _actionSeq; private static bool? _networkLibAvailable; public static ConfigSyncData Instance { get; private set; } internal static bool IsNetworkLibAvailable { get { bool valueOrDefault = _networkLibAvailable.GetValueOrDefault(); if (!_networkLibAvailable.HasValue) { valueOrDefault = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name.Contains("SteamNetworkLib")); _networkLibAvailable = valueOrDefault; return valueOrDefault; } return valueOrDefault; } } public ConfigSyncData() { Instance = this; } protected override void OnLoaded() { Instance = this; _pendingGameState = null; Config.ClearAllOverrides(); if (IsNetworkLibAvailable) { OnLoadedNetworkPush(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void OnLoadedNetworkPush() { NetworkSyncBridge.PushOnLoaded(Config.SerializeAll(), SerializeGameState(), DrifterManager.Instance?.SerializeDrifterState() ?? ""); } public static void EnsureNetworkReady() { if (IsNetworkLibAvailable) { EnsureNetworkReadyImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void EnsureNetworkReadyImpl() { NetworkSyncBridge.EnsureNetworkReady(); } public static void ProcessMessages() { if (IsNetworkLibAvailable) { ProcessMessagesImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ProcessMessagesImpl() { NetworkSyncBridge.ProcessMessages(); } public static void Cleanup() { _pendingGameState = null; if (IsNetworkLibAvailable) { CleanupImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void CleanupImpl() { NetworkSyncBridge.Cleanup(); } public void RefreshFromConfig() { if (NetworkHelper.IsHost) { _payload = Config.SerializeAll(); if (IsNetworkLibAvailable) { RefreshFromConfigImpl(_payload); } RefreshQuestText(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RefreshFromConfigImpl(string payload) { NetworkSyncBridge.PushConfig(payload); } public void PublishGameState() { if (!NetworkHelper.IsHost) { return; } try { string text = SerializeGameState(); if (Config.VerboseLogging.Value) { Logger.Msg($"PublishGameState: payload length={text?.Length ?? 0}"); } if (IsNetworkLibAvailable) { PublishGameStateImpl(text); } } catch (Exception ex) { Logger.Warning("PublishGameState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishGameStateImpl(string payload) { NetworkSyncBridge.PushState(payload); } public void PublishDrifterState() { if (!NetworkHelper.IsHost) { return; } try { string payload = DrifterManager.Instance?.SerializeDrifterState() ?? ""; if (IsNetworkLibAvailable) { PublishDrifterStateImpl(payload); } } catch (Exception ex) { Logger.Warning("PublishDrifterState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishDrifterStateImpl(string payload) { NetworkSyncBridge.PushDrifterState(payload); } public void PublishManagerState() { if (!NetworkHelper.IsHost) { return; } ManagerSaveData.Instance?.CaptureState(); try { if (IsNetworkLibAvailable) { PublishManagerStateImpl(); } } catch (Exception ex) { Logger.Warning("PublishManagerState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishManagerStateImpl() { ManagerInstance.PublishAllSlots(); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void WriteInitialManagerSlots() { ManagerInstance.PublishAllSlots(); } public void PublishManagerMessages() { if (!NetworkHelper.IsHost) { return; } try { List<string> list = new List<string>(); list.Add(_msgSeq++.ToString()); foreach (ManagerInstance value in ManagerInstance.Active.Values) { if (!string.IsNullOrEmpty(value.PendingClientMessage)) { list.Add(value.Id + "|" + value.PendingClientMessage); value.PendingClientMessage = null; } } ManagerInstance.HasPendingMessages = false; if (list.Count > 1 && IsNetworkLibAvailable) { string text = string.Join(";", list); PublishManagerMessagesImpl(text); if (Config.VerboseLogging.Value) { Logger.Msg($"PublishManagerMessages: {text.Length} chars, {list.Count - 1} messages"); } } } catch (Exception ex) { Logger.Warning("PublishManagerMessages failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishManagerMessagesImpl(string payload) { NetworkSyncBridge.PushManagerMessages(payload); } public void PublishDrifterMessages() { if (!NetworkHelper.IsHost) { return; } try { List<string> list = new List<string>(); list.Add(_msgSeq++.ToString()); DrifterManager instance = DrifterManager.Instance; if (instance != null) { foreach (DrifterEvent value in instance.ActiveEvents.Values) { if (!string.IsNullOrEmpty(value.PendingClientMessage)) { list.Add(value.DrifterId + "|" + value.PendingClientMessage); value.PendingClientMessage = null; } } } DrifterManager.HasPendingDrifterMessages = false; if (list.Count > 1 && IsNetworkLibAvailable) { string text = string.Join(";", list); PublishDrifterMessagesImpl(text); if (Config.VerboseLogging.Value) { Logger.Msg($"PublishDrifterMessages: {text.Length} chars, {list.Count - 1} messages"); } } } catch (Exception ex) { Logger.Warning("PublishDrifterMessages failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishDrifterMessagesImpl(string payload) { NetworkSyncBridge.PushDrifterMessages(payload); } public static void SendQuestAction(string action) { if (!NetworkHelper.IsHost && IsNetworkLibAvailable) { SendQuestActionImpl(action); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void SendQuestActionImpl(string action) { NetworkSyncBridge.SendAction($"{++_actionSeq}:{action}"); } internal static string GetSerializedConfig() { return Config.SerializeAll(); } internal static string GetSerializedGameState() { return SerializeGameState(); } internal static string GetSerializedDrifterState() { return DrifterManager.Instance?.SerializeDrifterState() ?? ""; } internal static void ClearOverridesForHost() { Config.ClearAllOverrides(); } internal static void HandleConfigChanged(string newValue) { try { Dictionary<string, string> dictionary = ParsePayload(newValue); Config.ApplyOverrides(dictionary); RefreshQuestText(); Logger.Msg($"Client applied {dictionary.Count} config overrides from SyncVar."); } catch (Exception ex) { Logger.Warning("HandleConfigChanged failed: " + ex.Message); } } internal static void HandleStateChanged(string newValue) { try { Dictionary<string, string> dictionary = (_pendingGameState = ParsePayload(newValue)); ApplyGameState(dictionary); Logger.Msg($"Client applied {dictionary.Count} game state values from SyncVar."); } catch (Exception ex) { Logger.Warning("HandleStateChanged failed: " + ex.Message); } } internal static void HandleDrifterStateChanged(string newValue) { try { DrifterManager.Instance?.ApplyDrifterState(newValue); Logger.Msg($"Client applied drifter state from SyncVar ({newValue.Length} chars)."); } catch (Exception ex) { Logger.Warning("HandleDrifterStateChanged failed: " + ex.Message); } } internal static void HandleManagerSlotChanged(int slot, string newValue) { try { ManagerInstance.ApplyManagerSlot(slot, newValue); Logger.Msg($"Client applied manager slot {slot} from SyncVar ({newValue?.Length ?? 0} chars)."); } catch (Exception ex) { Logger.Warning($"HandleManagerSlotChanged[{slot}] failed: {ex.Message}"); } } internal static void HandleManagerMessageChanged(string newValue) { try { string[] array = newValue.Split(';'); for (int i = 1; i < array.Length; i++) { string text = array[i]; int num = text.IndexOf('|'); if (num <= 0) { continue; } string text2 = text.Substring(0, num); string message = text.Substring(num + 1); if (ManagerInstance.Active.TryGetValue(text2, out var value)) { value.SendTextMessage(m
OverTheCounter.Mono.dll
Decompiled 5 days 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.Permissions; using System.Text; using System.Threading; using FishNet; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using OverTheCounter; using OverTheCounter.Apps; using OverTheCounter.Logic; 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.Messaging; using S1API.Money; using S1API.PhoneApp; using S1API.Products; using S1API.Quests; using S1API.Quests.Identifiers; using S1API.Saveables; using S1API.UI; using S1API.Utils; using ScheduleOne; using ScheduleOne.AvatarFramework; using ScheduleOne.AvatarFramework.Animation; using ScheduleOne.AvatarFramework.Equipping; using ScheduleOne.AvatarFramework.Impostors; using ScheduleOne.Combat; using ScheduleOne.DevUtilities; using ScheduleOne.Dialogue; using ScheduleOne.Doors; using ScheduleOne.Economy; using ScheduleOne.Employees; using ScheduleOne.EntityFramework; using ScheduleOne.GameTime; using ScheduleOne.Interaction; using ScheduleOne.ItemFramework; using ScheduleOne.Law; 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.ObjectScripts; using ScheduleOne.Persistence; using ScheduleOne.Persistence.Datas; using ScheduleOne.PlayerScripts; using ScheduleOne.Police; using ScheduleOne.Product; using ScheduleOne.Product.Packaging; using ScheduleOne.Property; using ScheduleOne.Quests; using ScheduleOne.Storage; using ScheduleOne.Tools; using ScheduleOne.UI; using ScheduleOne.UI.Compass; using ScheduleOne.UI.Handover; using ScheduleOne.UI.Management; using ScheduleOne.UI.Phone; using ScheduleOne.UI.Phone.ContactsApp; using ScheduleOne.UI.Phone.Map; using ScheduleOne.UI.Shop; using ScheduleOne.Variables; using ScheduleOne.VoiceOver; using SteamNetworkLib; 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", "1.3.0", "hdlmrell", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonOptionalDependencies(new string[] { "SteamNetworkLib" })] [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+de565dbb2b56dd5e21f645dc57046918064cb34f")] [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 { private NotificationManager _notificationManager; private DesperationManager _desperationManager; private DrifterManager _drifterManager; private ManagerController _managerManager; public override void OnInitializeMelon() { Config.Initialize(); NpcTypeDiscoveryPatch.Apply(((MelonBase)this).HarmonyInstance); ConfigSyncPatch.TryApply(((MelonBase)this).HarmonyInstance); ManagerClipboardPatch.Apply(((MelonBase)this).HarmonyInstance); if (!ConfigSyncData.IsNetworkLibAvailable) { ((MelonBase)this).LoggerInstance.Warning("SteamNetworkLib not installed — multiplayer sync disabled. Single-player works fine. Install SteamNetworkLib for co-op support."); } ((MelonBase)this).LoggerInstance.Msg("OverTheCounter Initialized."); ImmediateQuestWindowConfig.Register(); MinimapOverlay.Register(); ExtractIcons(); _notificationManager = new NotificationManager(((MelonBase)this).LoggerInstance); _desperationManager = new DesperationManager(((MelonBase)this).LoggerInstance); _drifterManager = new DrifterManager(((MelonBase)this).LoggerInstance); _managerManager = new ManagerController(((MelonBase)this).LoggerInstance); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown StaticSaveData.ResetInstance(); VicSaveData.ResetInstance(); BellaSaveData.ResetInstance(); StaticIntroQuest.ResetInstance(); StaticUpgrade1Quest.ResetInstance(); StaticUpgrade2Quest.ResetInstance(); VicIntroQuest.ResetInstance(); BellaProtocolQuest.ResetInstance(); BellaSummonPatch.Reset(); ContactsAppFix.Reset(); DrifterInstance.CleanupAll(); DrifterSpawner.ResetCache(); 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); } } public override void OnLateUpdate() { try { ConfigSyncData.EnsureNetworkReady(); ConfigSyncData.ProcessMessages(); _notificationManager.ProcessContractState(); VicSaveData.Instance?.Tick(); StaticSaveData.Instance?.Tick(); BellaSaveData.Instance?.Tick(); ManagerSaveData.Instance?.Tick(); ContactsAppFix.Tick(); _drifterManager?.RetryPendingAdoptions(); ManagerInstance.RetryPendingAdoptions(); _managerManager?.CheckImmediateWages(); foreach (ManagerInstance value in ManagerInstance.Active.Values) { value.EnsureMoving(); } if (NetworkHelper.IsHost) { foreach (ManagerInstance value2 in ManagerInstance.Active.Values) { value2.SupplyBehaviour?.Tick(); value2.DistributionBehaviour?.Tick(); } if (ManagerInstance.HasPendingMessages) { ConfigSyncData.Instance?.PublishManagerMessages(); } if (DrifterManager.HasPendingDrifterMessages) { ConfigSyncData.Instance?.PublishDrifterMessages(); } if (ManagerInstance.StatePublishNeeded) { ManagerInstance.StatePublishNeeded = false; ConfigSyncData.Instance?.PublishManagerState(); } } _drifterManager?.ClientQuestTick(); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("Error in OnLateUpdate: " + ex.Message + "\n" + ex.StackTrace); } } public override void OnDeinitializeMelon() { ConfigSyncData.Cleanup(); _notificationManager?.Cleanup(); _desperationManager?.Cleanup(); _drifterManager?.Cleanup(); _managerManager?.Cleanup(); } private void ExtractIcons() { string text = Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } ExtractResource(text, "CustomersIcon.png"); ExtractResource(text, "DrifterQuestIcon.png"); ExtractResource(text, "DrifterProfileIcon.png"); ExtractResource(text, "RinseCycle.png"); ExtractResource(text, "CrimeWareQuest.png"); ExtractResource(text, "ExecutivePrivilege.png"); ExtractResource(text, "ManagerIcon.png"); } private void ExtractResource(string directory, string fileName) { string path = Path.Combine(directory, fileName); if (File.Exists(path)) { return; } ((MelonBase)this).LoggerInstance.Msg("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); } ((MelonBase)this).LoggerInstance.Msg(fileName + " extracted successfully."); } else { ((MelonBase)this).LoggerInstance.Error("Could not find embedded resource '" + text + "'."); } } } public static class Config { 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 _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; private static MelonPreferences_Category _subscription; public static ConfigEntry<float> SaasWeeklyCost; public static ConfigEntry<int> SaasCycleDays; public static ConfigEntry<float> AtmDepositTrigger; 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 _notifications; public static ConfigEntry<bool> ConsolidationEnabled; public static ConfigEntry<int> ConsolidationThreshold; private static MelonPreferences_Category _managers; public static ConfigEntry<float> ManagerDailyWage; public static ConfigEntry<float> ManagerSigningFee; public static ConfigEntry<bool> ManagerVerboseLogging; public static ConfigEntry<bool> AlternateHire; private static MelonPreferences_Category _debug; public static ConfigEntry<bool> VerboseLogging; private static MelonPreferences_Category _bella; public static ConfigEntry<float> BellaWeedValue; public static ConfigEntry<float> BellaMethValue; public static ConfigEntry<float> BellaCokeValue; 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 _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 MelonPreferences_Entry<string> MinimapPosition; 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; 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; 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", "VerboseLogging", "MinimapEnabled", "MinimapSize", "MinimapRotateWithPlayer", "MinimapCircle", "MinimapDefaultZoom", "MinimapIconScale", "MinimapBorderWidth", "MinimapShowTime", "MinimapShowDay", "MinimapUse24HourClock", "MinimapShowPotentialCustomers", "MinimapShowCustomers", "MinimapShowDealers", "MinimapShowDeadDrops", "MinimapShowContracts", "MinimapShowQuests", "MinimapShowProperties", "MinimapShowManagers" }; public static void Initialize() { //IL_09b6: Unknown result type (might be due to invalid IL or missing references) _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)); _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)); _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)); AtmDepositTrigger = Register(_subscription.CreateEntry<float>("AtmDepositTrigger", 5000f, "ATM Deposit Trigger", "Weekly ATM deposit sum that triggers Static's intro quest", 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)); _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)); _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)); ManagerVerboseLogging = Register(_managers.CreateEntry<bool>("ManagerVerboseLogging", false, "Verbose Logging", "Enable detailed manager logging for troubleshooting (shopping list breakdowns, per-item details)", 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)); _debug = MelonPreferences.CreateCategory("OverTheCounter_Debug", "Debug"); VerboseLogging = Register(_debug.CreateEntry<bool>("VerboseLogging", false, "Verbose Logging", "Enable detailed logging for troubleshooting (drifters, quests, sync, NPCs)", 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)); _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)); _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); MinimapPosition = _minimap.CreateEntry<string>("MinimapPosition", "TopRight", "Position", "TopLeft, TopRight, BottomLeft, BottomRight", 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)); _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)); } 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(); } } } } namespace OverTheCounter.Quests { public class VicIntroQuest : Quest { private static readonly Instance Logger = new Instance("OTC:VicIntroQuest"); [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 => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "RinseCycle.png")); public static VicIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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, Array.Empty<QuestEntryData>(), val.StaticGUID); } } } catch (Exception ex) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _meetVicEntry = ((Quest)this).AddEntry("Meet Vic in the alleyway behind the bank", (Vector3?)VicPosition); _bringWeedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)VicPosition); } catch (Exception ex) { Logger.Error("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) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry meetVicEntry = _meetVicEntry; if (meetVicEntry != null) { meetVicEntry.Complete(); } QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Begin(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringWeedEntry = _bringWeedEntry; if (bringWeedEntry != null) { bringWeedEntry.Complete(); } } catch (Exception ex) { Logger.Error("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(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticIntroQuest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticIntroQuest"); [SaveableField("static_quest_stage")] private int _stage; private QuestEntry _talkToStaticEntry; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Crimeware as a Service"; protected override string Description => "Someone at the casino noticed your deposits. Find Static after 4 PM when the casino opens."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticIntroQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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, Array.Empty<QuestEntryData>(), val.StaticGUID); } } } catch (Exception ex) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _talkToStaticEntry = ((Quest)this).AddEntry("Talk to Static in the casino after 4 PM", (Vector3?)StaticPosition); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier1BankCost.Value:N0} and {Config.StaticTier1WeedGrams.Value} grams of weed"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 3) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Complete(); } QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } public void CompleteObj2() { try { _stage = 3; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj2 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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) ? 3 : (StaticSaveData.Instance.IntroCompleted ? 2 : (StaticSaveData.Instance.QuestTriggered ? 1 : 0))); if (num > _stage) { _stage = num; } } base.QuestEntries.Clear(); _talkToStaticEntry = ((Quest)this).AddEntry("Talk to Static in the casino after 4 PM", (Vector3?)StaticPosition); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry talkToStaticEntry = _talkToStaticEntry; if (talkToStaticEntry != null) { talkToStaticEntry.Begin(); } } if (_stage >= 2) { QuestEntry talkToStaticEntry2 = _talkToStaticEntry; if (talkToStaticEntry2 != null) { talkToStaticEntry2.Complete(); } QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 3) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade1Quest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticUpgrade1Quest"); [SaveableField("static_upgrade1_stage")] private int _stage; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Premium Tier"; protected override string Description => "Static has the premium tier upgrade available. Check your texts and bring him what he needs."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticUpgrade1Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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, Array.Empty<QuestEntryData>(), val.StaticGUID); } } } catch (Exception ex) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier2BankCost.Value:N0} and {Config.StaticTier2MethGrams.Value} grams of meth"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 2) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 2) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class StaticUpgrade2Quest : Quest { private static readonly Instance Logger = new Instance("OTC:StaticUpgrade2Quest"); [SaveableField("static_upgrade2_stage")] private int _stage; private QuestEntry _bringSuppliesEntry; private static readonly Vector3 StaticPosition = new Vector3(13.72f, 5.16f, 95.96f); protected override string Title => "Full Scale"; protected override string Description => "Static has the final tier-3 enterprise upgrade available. Bring premium meth and go all in."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "CrimeWareQuest.png")); public static StaticUpgrade2Quest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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, Array.Empty<QuestEntryData>(), val.StaticGUID); } } } catch (Exception ex) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetSuppliesText() { return $"Bring Static ${Config.StaticTier3BankCost.Value:N0} and {Config.StaticTier3PremiumMethGrams.Value} grams of premium meth"; } public void RefreshEntryText() { if (_bringSuppliesEntry != null && _stage >= 1 && _stage < 2) { _bringSuppliesEntry.Title = GetSuppliesText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void CompleteObj1() { try { _stage = 2; QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteObj1 failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { base.QuestEntries.Clear(); _bringSuppliesEntry = ((Quest)this).AddEntry(GetSuppliesText(), (Vector3?)StaticPosition); if (_stage >= 1) { QuestEntry bringSuppliesEntry = _bringSuppliesEntry; if (bringSuppliesEntry != null) { bringSuppliesEntry.Begin(); } } if (_stage >= 2) { QuestEntry bringSuppliesEntry2 = _bringSuppliesEntry; if (bringSuppliesEntry2 != null) { bringSuppliesEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } public class DrifterDealQuest : Quest { private static readonly Instance Logger = new Instance("OTC:DrifterDealQuest"); 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 => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "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, Array.Empty<QuestEntryData>(), s1Quest.StaticGUID); } } catch (Exception ex) { Logger.Error("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) { Logger.Error("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) { Logger.Warning("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) { Logger.Warning("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) { Logger.Error("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) { Logger.Error("FailDeal failed: " + ex.Message); } } public void CancelDeal() { try { ((Quest)this).Cancel(); ActiveQuests.Remove(DrifterId); } catch (Exception ex) { Logger.Error("CancelDeal failed: " + ex.Message); } } } public class BellaProtocolQuest : Quest { private static readonly Instance Logger = new Instance("OTC:BellaProtocolQuest"); [SaveableField("bella_quest_stage")] private int _stage; private QuestEntry _visitEntry; private QuestEntry _weedEntry; private QuestEntry _methEntry; private QuestEntry _cokeEntry; private static readonly Vector3 BellaBuilding = new Vector3(74.1f, 1f, 57.2f); protected override string Title => "Executive Privilege"; protected override string Description => "Someone at the Fixer's mentioned a contact who can help with warehouse access."; protected override bool AutoBegin => false; protected override Sprite QuestIcon => ImageUtils.LoadImage(Path.Combine(MelonEnvironment.UserDataDirectory, "S1API", "Icons", "ExecutivePrivilege.png")); public static BellaProtocolQuest Instance { get; private set; } public int Stage => _stage; internal static void ResetInstance() { Instance = null; } 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, Array.Empty<QuestEntryData>(), val.StaticGUID); } } } catch (Exception ex) { Logger.Error("TriggerInternalInit failed: " + ex.Message); } } public void Initialize() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { TriggerInternalInit(); _visitEntry = ((Quest)this).AddEntry("Visit Bella at the downtown apartment", (Vector3?)BellaBuilding); _weedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)BellaBuilding); _methEntry = ((Quest)this).AddEntry(GetMethText(), (Vector3?)BellaBuilding); _cokeEntry = ((Quest)this).AddEntry(GetCokeText(), (Vector3?)BellaBuilding); } catch (Exception ex) { Logger.Error("Initialize failed: " + ex.Message); } } private static string GetWeedText() { return $"Bring Bella a weed mix worth ${Config.BellaWeedValue.Value:N0}+"; } private static string GetMethText() { return $"Bring Bella a meth mix worth ${Config.BellaMethValue.Value:N0}+"; } private static string GetCokeText() { return $"Bring Bella a cocaine mix worth ${Config.BellaCokeValue.Value:N0}+"; } public void RefreshEntryText() { if (_weedEntry != null && _stage == 2) { _weedEntry.Title = GetWeedText(); } if (_methEntry != null && _stage == 3) { _methEntry.Title = GetMethText(); } if (_cokeEntry != null && _stage == 4) { _cokeEntry.Title = GetCokeText(); } } public void StartQuest() { try { _stage = 1; ((Quest)this).Begin(); QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Begin(); } } catch (Exception ex) { Logger.Error("StartQuest failed: " + ex.Message); } } public void AdvanceToWeedRequest() { try { _stage = 2; QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Complete(); } QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToWeedRequest failed: " + ex.Message); } } public void AdvanceToMethRequest() { try { _stage = 3; QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Complete(); } QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToMethRequest failed: " + ex.Message); } } public void AdvanceToCocaineRequest() { try { _stage = 4; QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Complete(); } QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Begin(); } } catch (Exception ex) { Logger.Error("AdvanceToCocaineRequest failed: " + ex.Message); } } public void CompleteQuest() { try { _stage = 5; QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Complete(); } } catch (Exception ex) { Logger.Error("CompleteQuest failed: " + ex.Message); } } protected override void OnCreated() { ((Registerable)this).OnCreated(); Instance = this; } protected override void OnLoaded() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) ((Saveable)this).OnLoaded(); Instance = this; try { int stage = _stage; int num = BellaSaveData.Instance?.Stage ?? (-1); if (Config.VerboseLogging.Value) { Logger.Msg($"OnLoaded: save _stage={stage}, BellaSaveData.Stage={num}"); } if (BellaSaveData.Instance != null && BellaSaveData.Instance.Stage > _stage) { _stage = BellaSaveData.Instance.Stage; } if (Config.VerboseLogging.Value) { Logger.Msg($"OnLoaded: rebuilding entries at _stage={_stage}"); } base.QuestEntries.Clear(); _visitEntry = ((Quest)this).AddEntry("Visit Bella at the downtown apartment", (Vector3?)BellaBuilding); _weedEntry = ((Quest)this).AddEntry(GetWeedText(), (Vector3?)BellaBuilding); _methEntry = ((Quest)this).AddEntry(GetMethText(), (Vector3?)BellaBuilding); _cokeEntry = ((Quest)this).AddEntry(GetCokeText(), (Vector3?)BellaBuilding); if (_stage >= 1) { QuestEntry visitEntry = _visitEntry; if (visitEntry != null) { visitEntry.Begin(); } } if (_stage >= 2) { QuestEntry visitEntry2 = _visitEntry; if (visitEntry2 != null) { visitEntry2.Complete(); } QuestEntry weedEntry = _weedEntry; if (weedEntry != null) { weedEntry.Begin(); } } if (_stage >= 3) { QuestEntry weedEntry2 = _weedEntry; if (weedEntry2 != null) { weedEntry2.Complete(); } QuestEntry methEntry = _methEntry; if (methEntry != null) { methEntry.Begin(); } } if (_stage >= 4) { QuestEntry methEntry2 = _methEntry; if (methEntry2 != null) { methEntry2.Complete(); } QuestEntry cokeEntry = _cokeEntry; if (cokeEntry != null) { cokeEntry.Begin(); } } if (_stage >= 5) { QuestEntry cokeEntry2 = _cokeEntry; if (cokeEntry2 != null) { cokeEntry2.Complete(); } } } catch (Exception ex) { Logger.Warning("OnLoaded rebuild failed: " + ex.Message); } } } } namespace OverTheCounter.SaveData { public class VicSaveData : Saveable { private static readonly Instance Logger = new Instance("OTC:VicSaveData"); [SaveableField("vic_unlocked")] private bool _unlocked; [SaveableField("vic_has_been_texted")] private bool _hasBeenTexted; [SaveableField("vic_trust_level")] private int _trustLevel; [SaveableField("vic_quest_accepted")] private bool _questAccepted; [SaveableField("vic_trigger_pending_day")] private int _triggerPendingDay = -1; [SaveableField("vic_last_deposit_day")] private int _lastDepositDay = -1; [SaveableField("vic_last_trust_increment_day")] private int _lastTrustIncrementDay = -1; [SaveableField("vic_tier2_intro_shown")] private bool _tier2IntroShown; private bool _needsIntroText; private bool _questCreated; private bool _fireOnNextTick; private bool _staleCheckDone; private bool _needsStatePublish; private bool _questReconciled; private int _tickCounter; private const int TICK_INTERVAL = 300; private bool _positionFixed; internal bool _dialogueStale; private bool _wasInDialogue; private static bool _sleepEndSubscribed; public static VicSaveData Instance { get; private set; } public bool Unlocked => _unlocked; public bool QuestAccepted => _questAccepted; public int TrustLevel => _trustLevel; public int LastDepositDay => _lastDepositDay; public bool Tier2IntroShown => _tier2IntroShown; public bool HasBeenTexted { get { return _hasBeenTexted; } set { if (!_hasBeenTexted && value) { _hasBeenTexted = true; TrySendIntroText(); CreateOrResumeQuest(); _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } } internal static void ResetInstance() { Instance = null; } public VicSaveData() { Instance = this; if (!_sleepEndSubscribed) { TimeManager.OnSleepEnd = (Action<int>)Delegate.Combine(TimeManager.OnSleepEnd, (Action<int>)delegate { Instance?.OnPlayerWokeUp(); }); _sleepEndSubscribed = true; } } protected override void OnLoaded() { Instance = this; if (_questAccepted) { _questCreated = true; } _dialogueStale = true; if (_hasBeenTexted) { _questCreated = true; if (NetworkHelper.IsHost) { _needsStatePublish = true; } ConfigSyncData.ApplyPendingGameState(); ReconcileQuest(); } else { ConfigSyncData.ApplyPendingGameState(); if (_triggerPendingDay < 0 && IsCleanCashQuestStarted()) { _triggerPendingDay = 0; } } } private void ReconcileQuest() { if (VicIntroQuest.Instance == null) { return; } int num = (_unlocked ? 3 : (_questAccepted ? 2 : (_hasBeenTexted ? 1 : 0))); if (num > VicIntroQuest.Instance.Stage) { if (num >= 2 && VicIntroQuest.Instance.Stage < 2) { VicIntroQuest.Instance.CompleteObj1(); } if (num >= 3 && VicIntroQuest.Instance.Stage < 3) { VicIntroQuest.Instance.CompleteObj2(); } } } public void OnVicSpawned() { if (NetworkHelper.IsHost) { _positionFixed = false; } if (_needsIntroText) { _needsIntroText = false; TrySendIntroText(); } } private void OnPlayerWokeUp() { if (NetworkHelper.IsHost) { _positionFixed = false; if (!_hasBeenTexted && (_triggerPendingDay >= 0 || IsCleanCashQuestStarted())) { _triggerPendingDay = 0; _fireOnNextTick = true; } } } public void Tick() { if (!_questReconciled && _hasBeenTexted && VicIntroQuest.Instance != null) { _questReconciled = true; int num = (_unlocked ? 3 : ((!_questAccepted) ? 1 : 2)); if (VicIntroQuest.Instance.Stage < num) { if (Config.VerboseLogging.Value) { Logger.Msg($"Tick reconciliation: quest stage {VicIntroQuest.Instance.Stage} → {num}"); } ReconcileQuest(); } } bool flag = VicNPC.Instance != null && VicNPC.Instance.IsInDialogue; if (_wasInDialogue && !flag) { _dialogueStale = true; } _wasInDialogue = flag; if (_dialogueStale && VicNPC.Instance != null && VicNPC.Instance.DialogueReady && !flag) { _dialogueStale = false; try { VicNPC.Instance.RefreshDialogue(); } catch (Exception) { } } if (_needsStatePublish && NetworkHelper.IsHost) { _needsStatePublish = false; ConfigSyncData.Instance?.PublishGameState(); } if (NetworkHelper.IsHost && !_staleCheckDone && _hasBeenTexted) { _staleCheckDone = true; if (!_unlocked && !IsCleanCashQuestStarted()) { _hasBeenTexted = false; _triggerPendingDay = -1; _questCreated = false; _needsIntroText = false; _fireOnNextTick = false; } } else if (_fireOnNextTick) { _fireOnNextTick = false; if (!_hasBeenTexted) { HasBeenTexted = true; } } else { if (++_tickCounter < 300) { return; } _tickCounter = 0; if (NetworkHelper.IsHost && !_positionFixed && VicNPC.Instance != null) { _positionFixed = true; try { VicNPC.Instance.WarpToSpawn(); } catch (Exception) { } } if (_hasBeenTexted) { try { if (VicNPC.Instance != null && VicNPC.Instance.DialogueReady) { VicNPC.Instance.RefreshDialogue(); } return; } catch (Exception) { return; } } if (NetworkHelper.IsHost && _triggerPendingDay < 0 && IsCleanCashQuestStarted()) { _triggerPendingDay = 0; } } } public void CreateOrResumeQuest() { if (_questCreated) { return; } _questCreated = true; try { if (VicIntroQuest.Instance == null) { VicIntroQuest vicIntroQuest = (VicIntroQuest)(object)QuestManager.CreateQuest<VicIntroQuest>((string)null); if (vicIntroQuest != null) { vicIntroQuest.Initialize(); vicIntroQuest.StartQuest(); } else { Logger.Error("QuestManager.CreateQuest<VicIntroQuest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateOrResumeQuest failed: " + ex.Message); } } public void ApplyHostState(bool hasBeenTexted = false, bool questAccepted = false, bool unlocked = false, int trustLevel = -1) { bool flag = false; bool flag2 = unlocked; if (hasBeenTexted && !_hasBeenTexted) { _hasBeenTexted = true; if (!flag2) { CreateOrResumeQuest(); } flag = true; } if (questAccepted && !_questAccepted) { _questAccepted = true; _questCreated = true; if (!flag2) { try { VicIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Client VicIntroQuest CompleteObj1 failed: " + ex.Message); } } flag = true; } if (unlocked && !_unlocked) { _unlocked = true; try { VicIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Client VicIntroQuest CompleteObj2 failed: " + ex2.Message); } flag = true; } if (trustLevel >= 0 && trustLevel != _trustLevel) { _trustLevel = trustLevel; flag = true; } if (flag) { _dialogueStale = true; } } public void OnQuestComplete() { _unlocked = true; ConfigSyncData.Instance?.PublishGameState(); } public void OnLaunderComplete(int currentDay) { _lastDepositDay = currentDay; if (_lastTrustIncrementDay < currentDay) { _lastTrustIncrementDay = currentDay; _trustLevel++; } ConfigSyncData.Instance?.PublishGameState(); } public void HandleRemoteAction(string action) { switch (action) { case "VIC_QUEST_ACCEPTED": _questAccepted = true; _questCreated = true; try { VicIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Remote VicIntroQuest CompleteObj1 failed: " + ex.Message); } break; case "VIC_QUEST_COMPLETE": _unlocked = true; try { VicIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Remote VicIntroQuest CompleteObj2 failed: " + ex2.Message); } break; case "VIC_LAUNDER": { int num = (_lastDepositDay = TimeManager.ElapsedDays); if (_lastTrustIncrementDay < num) { _lastTrustIncrementDay = num; _trustLevel++; } break; } default: Logger.Warning("VicSaveData: unknown remote action '" + action + "'"); return; } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public void MarkTier2IntroShown() { _tier2IntroShown = true; } private void TrySendIntroText() { if (!NetworkHelper.IsHost) { return; } try { NPC val = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "vic_bank_teller")); if (val != null) { val.SendTextMessage("Hey, I noticed you've been hitting your weekly deposit limits. Meet me in the alley behind the bank. I might be able to help.", (Response[])null, 1f, true); _needsIntroText = false; } else { Logger.Warning("Vic NPC not found — deferring intro text until spawn."); _needsIntroText = true; } } catch (Exception ex) { Logger.Error("TrySendIntroText failed: " + ex.Message); _needsIntroText = true; } } private bool IsCleanCashQuestStarted() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 try { QuestWrapper val = QuestManager.Get<CleanCash>(); if (val == null) { return false; } List<QuestEntry> questEntries = val.QuestEntries; if (questEntries == null || questEntries.Count == 0) { return false; } foreach (QuestEntry item in questEntries) { if ((int)item.State == 1 || (int)item.State == 2) { return true; } } } catch (Exception ex) { Logger.Warning("Could not check Clean Cash quest: " + ex.Message); } return false; } } public class StaticSaveData : Saveable { private static readonly Instance Logger = new Instance("OTC:StaticSaveData"); [SaveableField("static_intro_completed")] private bool _introCompleted; [SaveableField("static_quest_triggered")] private bool _questTriggered; [SaveableField("static_crm_tier")] private int _crmTier; [SaveableField("static_saas_active")] private bool _saasActive; [SaveableField("static_saas_next_payment_day")] private int _saasNextPaymentDay; [SaveableField("static_saas_day_pass_count")] private int _dayPassCount; [SaveableField("static_upgrade_available")] private bool _upgradeAvailable; [SaveableField("static_early_visit_seen")] private bool _earlyVisitSeen; private int _tickCounter; private const int TICK_INTERVAL = 300; private bool _positionFixed; private bool _dialogueStale; private bool _wasInDialogue; private bool _questCreated; private bool _needsStatePublish; private bool _questReconciled; private bool _needsIntroText; private static bool _dayPassSubscribed; public static StaticSaveData Instance { get; private set; } public bool IntroCompleted => _introCompleted; public bool QuestTriggered => _questTriggered; public int CrmTier => _crmTier; public bool SaasActive => _saasActive; public int SaasNextPaymentDay => _saasNextPaymentDay; public int DayPassCount => _dayPassCount; public bool UpgradeAvailable => _upgradeAvailable; public bool EarlyVisitSeen => _earlyVisitSeen; internal static void ResetInstance() { Instance = null; } public StaticSaveData() { Instance = this; if (!_dayPassSubscribed) { TimeManager.OnDayPass = (Action)Delegate.Combine(TimeManager.OnDayPass, (Action)delegate { Instance?.OnDayPass(); }); _dayPassSubscribed = true; } } protected override void OnLoaded() { Instance = this; if (_questTriggered) { _questCreated = true; if (NetworkHelper.IsHost) { _needsStatePublish = true; } } _dialogueStale = true; ConfigSyncData.ApplyPendingGameState(); ReconcileQuest(); } private void ReconcileQuest() { if (StaticIntroQuest.Instance == null) { return; } int num = ((_crmTier >= 1) ? 3 : (_introCompleted ? 2 : (_questTriggered ? 1 : 0))); if (num > StaticIntroQuest.Instance.Stage) { if (num >= 2 && StaticIntroQuest.Instance.Stage < 2) { StaticIntroQuest.Instance.CompleteObj1(); } if (num >= 3 && StaticIntroQuest.Instance.Stage < 3) { StaticIntroQuest.Instance.CompleteObj2(); } } } public void Tick() { if (!_questReconciled && _questTriggered && StaticIntroQuest.Instance != null) { _questReconciled = true; int num = ((_crmTier >= 1) ? 3 : ((!_introCompleted) ? 1 : 2)); if (StaticIntroQuest.Instance.Stage < num) { if (Config.VerboseLogging.Value) { Logger.Msg($"Tick reconciliation: quest stage {StaticIntroQuest.Instance.Stage} → {num}"); } ReconcileQuest(); } } bool flag = StaticNPC.Instance != null && StaticNPC.Instance.IsInDialogue; if (_wasInDialogue && !flag) { _dialogueStale = true; } _wasInDialogue = flag; if (_needsStatePublish && NetworkHelper.IsHost) { _needsStatePublish = false; ConfigSyncData.Instance?.PublishGameState(); } if (_dialogueStale && StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady && !flag) { _dialogueStale = false; try { StaticNPC.Instance.RefreshDialogue(); } catch (Exception) { } } if (++_tickCounter < 300) { return; } _tickCounter = 0; if (NetworkHelper.IsHost && !_positionFixed && StaticNPC.Instance != null) { _positionFixed = true; try { StaticNPC.Instance.WarpToSpawn(); } catch (Exception) { } } if (!_questTriggered) { try { if (ATM.WeeklyDepositSum >= Config.AtmDepositTrigger.Value) { _questTriggered = true; CreateOrResumeQuest(); if (NetworkHelper.IsHost) { TrySendIntroText(); ConfigSyncData.Instance?.PublishGameState(); } else { ConfigSyncData.SendQuestAction("STATIC_ATM_TRIGGERED"); } } return; } catch (Exception ex3) { Logger.Warning("ATM check failed: " + ex3.Message); return; } } try { if (StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady) { StaticNPC.Instance.RefreshDialogue(); } } catch (Exception) { } } public void CreateOrResumeQuest() { if (_questCreated) { return; } _questCreated = true; try { if (StaticIntroQuest.Instance == null) { StaticIntroQuest staticIntroQuest = (StaticIntroQuest)(object)QuestManager.CreateQuest<StaticIntroQuest>((string)null); if (staticIntroQuest != null) { staticIntroQuest.Initialize(); staticIntroQuest.StartQuest(); } else { Logger.Error("QuestManager.CreateQuest<StaticIntroQuest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateOrResumeQuest failed: " + ex.Message); } } public void ApplyHostState(bool questTriggered = false, bool introCompleted = false, int crmTier = -1, bool? saasActive = null, bool? upgradeAvailable = null, int saasNextPaymentDay = -1, int dayPassCount = -1) { bool flag = false; bool flag2 = crmTier >= 1; if (questTriggered && !_questTriggered) { _questTriggered = true; if (!flag2) { CreateOrResumeQuest(); } flag = true; } if (introCompleted && !_introCompleted) { _introCompleted = true; if (!flag2) { try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Warning("Client CompleteObj1 failed: " + ex.Message); } } flag = true; } if (crmTier >= 0 && crmTier != _crmTier) { int crmTier2 = _crmTier; _crmTier = crmTier; if (crmTier2 == 0 && crmTier == 1) { try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Client CompleteObj2 failed: " + ex2.Message); } } if (crmTier2 == 1 && crmTier == 2) { try { StaticUpgrade1Quest.Instance?.CompleteObj1(); } catch (Exception ex3) { Logger.Warning("Client Upgrade1 CompleteObj1 failed: " + ex3.Message); } } if (crmTier2 == 2 && crmTier == 3) { try { StaticUpgrade2Quest.Instance?.CompleteObj1(); } catch (Exception ex4) { Logger.Warning("Client Upgrade2 CompleteObj1 failed: " + ex4.Message); } } flag = true; } if (saasActive.HasValue && saasActive.Value != _saasActive) { _saasActive = saasActive.Value; flag = true; } if (upgradeAvailable.HasValue && upgradeAvailable.Value != _upgradeAvailable) { _upgradeAvailable = upgradeAvailable.Value; if (_upgradeAvailable) { CreateUpgradeQuest(); } flag = true; } if (saasNextPaymentDay >= 0 && saasNextPaymentDay != _saasNextPaymentDay) { _saasNextPaymentDay = saasNextPaymentDay; flag = true; } if (dayPassCount >= 0 && dayPassCount != _dayPassCount) { _dayPassCount = dayPassCount; flag = true; } if (flag && StaticNPC.Instance != null && StaticNPC.Instance.DialogueReady) { StaticNPC.Instance.RefreshDialogue(); } } public void OnStaticSpawned() { if (NetworkHelper.IsHost) { _positionFixed = false; } if (_needsIntroText) { _needsIntroText = false; TrySendIntroText(); } } private void TrySendIntroText() { if (!NetworkHelper.IsHost) { return; } try { NPC val = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "static_casino_fixer")); if (val != null) { val.SendTextMessage("[0x4E72] d1g1t4l f00tpr1nt fl4gg3d. unencrypt3d ch4nn3l. vuln: CR1T1C4L.\n\nc4s1n0. t0p fl00r. 4ft3r 4. c0m3 4l0n3.\n\n— ST4T1C", (Response[])null, 1f, true); _needsIntroText = false; } else { Logger.Warning("Static NPC not found — deferring intro text until spawn."); _needsIntroText = true; } } catch (Exception ex) { Logger.Error("TrySendIntroText failed: " + ex.Message); _needsIntroText = true; } } public void OnEarlyVisitSeen() { _earlyVisitSeen = true; } public void OnIntroCompleted() { if (!_introCompleted) { _introCompleted = true; try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex) { Logger.Error("OnIntroCompleted quest completion failed: " + ex.Message); } SendStaticText($"[0x7A3F] s0ftw4r3 p4ck4g3 r34dy. c0st: ${Config.StaticTier1BankCost.Value:N0} + {Config.StaticTier1WeedGrams.Value}g w33d.\n\nbr1ng t0 c4s1n0.\n\n— ST4T1C_SYS"); _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } public void PurchaseInitial() { if (_crmTier < 1) { _crmTier = 1; _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex) { Logger.Error("PurchaseInitial quest completion failed: " + ex.Message); } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } } public void PurchaseUpgrade() { if (_crmTier >= 3) { return; } int crmTier = _crmTier; _crmTier++; _upgradeAvailable = false; try { switch (crmTier) { case 1: StaticUpgrade1Quest.Instance?.CompleteObj1(); break; case 2: StaticUpgrade2Quest.Instance?.CompleteObj1(); break; } } catch (Exception ex) { Logger.Error("PurchaseUpgrade quest completion failed: " + ex.Message); } _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public bool ReactivateSubscription() { try { if (Money.GetOnlineBalance() < Config.SaasWeeklyCost.Value) { return false; } Money.CreateOnlineTransaction("OTC Back-Rent", 0f - Config.SaasWeeklyCost.Value, 1f, "Static Services"); _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); return true; } catch (Exception ex) { Logger.Error("ReactivateSubscription failed: " + ex.Message); return false; } } public void CancelSubscription() { _saasActive = false; _upgradeAvailable = false; _dialogueStale = true; ConfigSyncData.Instance?.PublishGameState(); } public void HandleRemoteAction(string action) { switch (action) { case "STATIC_ATM_TRIGGERED": if (!_questTriggered) { _questTriggered = true; TrySendIntroText(); CreateOrResumeQuest(); } break; case "STATIC_INTRO_COMPLETED": _introCompleted = true; try { StaticIntroQuest.Instance?.CompleteObj1(); } catch (Exception ex3) { Logger.Warning("Remote CompleteObj1 failed: " + ex3.Message); } break; case "STATIC_PURCHASE_INITIAL": _crmTier = 1; _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; try { StaticIntroQuest.Instance?.CompleteObj2(); } catch (Exception ex2) { Logger.Warning("Remote CompleteObj2 failed: " + ex2.Message); } break; case "STATIC_PURCHASE_UPGRADE": { if (_crmTier >= 3) { return; } int crmTier = _crmTier; _crmTier++; _upgradeAvailable = false; try { switch (crmTier) { case 1: StaticUpgrade1Quest.Instance?.CompleteObj1(); break; case 2: StaticUpgrade2Quest.Instance?.CompleteObj1(); break; } } catch (Exception ex) { Logger.Warning("Remote PurchaseUpgrade quest failed: " + ex.Message); } break; } case "STATIC_REACTIVATE": _saasActive = true; _saasNextPaymentDay = _dayPassCount + Config.SaasCycleDays.Value; break; case "STATIC_CANCEL": _saasActive = false; _upgradeAvailable = false; break; default: Logger.Warning("StaticSaveData: unknown remote action '" + action + "'"); return; } ConfigSyncData.Instance?.PublishGameState(); } private void OnDayPass() { if (NetworkHelper.IsHost) { _positionFixed = false; _dayPassCount++; CheckSubscriptionStatus(); } } public void CheckSubscriptionStatus() { if (!_saasActive || _dayPassCount < _saasNextPaymentDay) { return; } try { if (Money.GetOnlineBalance() >= Config.SaasWeeklyCost.Value) { Money.CreateOnlineTransaction("OTC Server Rent", 0f - Config.SaasWeeklyCost.Value, 1f, "Static Services"); _saasNextPaymentDay += Config.SaasCycleDays.Value; SendStaticText("[0x52E1] server r3nt cleared. nod3s onl1ne.\n\n— ST4T1C_SYS"); if (_crmTier < 3 && !_upgradeAvailable) { _upgradeAvailable = true; SendUpgradeOfferText(); CreateUpgradeQuest(); } } else { _saasActive = false; SendStaticText("[0xDEAD] paym3nt fa1led. serv1ce suspended. r3store in p3rson.\n\n— ST4T1C_SYS"); } ConfigSyncData.Instance?.PublishGameState(); } catch (Exception ex) { Logger.Error("CheckSubscriptionStatus failed: " + ex.Message); } } private void CreateUpgradeQuest() { try { if (_crmTier == 1) { if (StaticUpgrade1Quest.Instance == null) { StaticUpgrade1Quest staticUpgrade1Quest = (StaticUpgrade1Quest)(object)QuestManager.CreateQuest<StaticUpgrade1Quest>((string)null); if (staticUpgrade1Quest != null) { staticUpgrade1Quest.Initialize(); staticUpgrade1Quest.StartQuest(); } else { Logger.Error("CreateQuest<StaticUpgrade1Quest> returned null."); } } } else if (_crmTier == 2 && StaticUpgrade2Quest.Instance == null) { StaticUpgrade2Quest staticUpgrade2Quest = (StaticUpgrade2Quest)(object)QuestManager.CreateQuest<StaticUpgrade2Quest>((string)null); if (staticUpgrade2Quest != null) { staticUpgrade2Quest.Initialize(); staticUpgrade2Quest.StartQuest(); } else { Logger.Error("CreateQuest<StaticUpgrade2Quest> returned null."); } } } catch (Exception ex) { Logger.Error("CreateUpgradeQuest failed: " + ex.Message); } } private void SendUpgradeOfferText() { if (_crmTier == 1) { SendStaticText($"[0x9FA1] pr1v4t3 s3rv3r r34dy. c0st: ${Config.StaticTier2BankCost.Value:N0} + {Config.StaticTier2MethGrams.Value}g m3th.\nfull r3g10n c0v3r4g3. s4m3 sp0t.\n\n— ST4T1C_SYS"); } else if (_crmTier == 2) { SendStaticText($"[0xB2D8] 3nt3rpr1s3 t13r. GPS tr4ck1ng. c0st: ${Config.StaticTier3BankCost.Value:N0} + {Config.StaticTier3PremiumMethGrams.Value}g pr3m1um m3th.\nl4st upgr4d3. c4s1n0.\n\n— ST4T1C_SYS"); } } private void SendStaticText(string message) { try { NPC val = NPC.All?.FirstOrDefault((Func<NPC, bool>)((NPC n) => n.ID == "static_casino_fixer")); if (val != null) { val.SendTextMessage(message, (Response[])null, 1f, true); } } catch (Exception ex) { Logger.Error("SendStaticText failed: " + ex.Message); } } } public class ConfigSyncData : Saveable { private static readonly Instance Logger = new Instance("OTC:ConfigSync"); [SaveableField("config_sync_payload")] private string _payload = ""; private static Dictionary<string, string> _pendingGameState; private static int _msgSeq; private static int _actionSeq; private static bool? _networkLibAvailable; public static ConfigSyncData Instance { get; private set; } internal static bool IsNetworkLibAvailable { get { bool valueOrDefault = _networkLibAvailable.GetValueOrDefault(); bool result; if (!_networkLibAvailable.HasValue) { valueOrDefault = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name.Contains("SteamNetworkLib")); _networkLibAvailable = valueOrDefault; result = valueOrDefault; } else { result = valueOrDefault; } return result; } } public ConfigSyncData() { Instance = this; } protected override void OnLoaded() { Instance = this; _pendingGameState = null; Config.ClearAllOverrides(); if (IsNetworkLibAvailable) { OnLoadedNetworkPush(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void OnLoadedNetworkPush() { NetworkSyncBridge.PushOnLoaded(Config.SerializeAll(), SerializeGameState(), DrifterManager.Instance?.SerializeDrifterState() ?? ""); } public static void EnsureNetworkReady() { if (IsNetworkLibAvailable) { EnsureNetworkReadyImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void EnsureNetworkReadyImpl() { NetworkSyncBridge.EnsureNetworkReady(); } public static void ProcessMessages() { if (IsNetworkLibAvailable) { ProcessMessagesImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ProcessMessagesImpl() { NetworkSyncBridge.ProcessMessages(); } public static void Cleanup() { _pendingGameState = null; if (IsNetworkLibAvailable) { CleanupImpl(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void CleanupImpl() { NetworkSyncBridge.Cleanup(); } public void RefreshFromConfig() { if (NetworkHelper.IsHost) { _payload = Config.SerializeAll(); if (IsNetworkLibAvailable) { RefreshFromConfigImpl(_payload); } RefreshQuestText(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RefreshFromConfigImpl(string payload) { NetworkSyncBridge.PushConfig(payload); } public void PublishGameState() { if (!NetworkHelper.IsHost) { return; } try { string text = SerializeGameState(); if (Config.VerboseLogging.Value) { Logger.Msg($"PublishGameState: payload length={text?.Length ?? 0}"); } if (IsNetworkLibAvailable) { PublishGameStateImpl(text); } } catch (Exception ex) { Logger.Warning("PublishGameState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishGameStateImpl(string payload) { NetworkSyncBridge.PushState(payload); } public void PublishDrifterState() { if (!NetworkHelper.IsHost) { return; } try { string payload = DrifterManager.Instance?.SerializeDrifterState() ?? ""; if (IsNetworkLibAvailable) { PublishDrifterStateImpl(payload); } } catch (Exception ex) { Logger.Warning("PublishDrifterState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishDrifterStateImpl(string payload) { NetworkSyncBridge.PushDrifterState(payload); } public void PublishManagerState() { if (!NetworkHelper.IsHost) { return; } ManagerSaveData.Instance?.CaptureState(); try { if (IsNetworkLibAvailable) { PublishManagerStateImpl(); } } catch (Exception ex) { Logger.Warning("PublishManagerState failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishManagerStateImpl() { ManagerInstance.PublishAllSlots(); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void WriteInitialManagerSlots() { ManagerInstance.PublishAllSlots(); } public void PublishManagerMessages() { if (!NetworkHelper.IsHost) { return; } try { List<string> list = new List<string>(); list.Add(_msgSeq++.ToString()); foreach (ManagerInstance value in ManagerInstance.Active.Values) { if (!string.IsNullOrEmpty(value.PendingClientMessage)) { list.Add(value.Id + "|" + value.PendingClientMessage); value.PendingClientMessage = null; } } ManagerInstance.HasPendingMessages = false; if (list.Count > 1 && IsNetworkLibAvailable) { string text = string.Join(";", list); PublishManagerMessagesImpl(text); if (Config.VerboseLogging.Value) { Logger.Msg($"PublishManagerMessages: {text.Length} chars, {list.Count - 1} messages"); } } } catch (Exception ex) { Logger.Warning("PublishManagerMessages failed: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void PublishManagerMessagesImpl(string payload) { NetworkSyncBridge.PushManagerMessages(payload); } public void PublishDrifterMessages() { if (!NetworkHelper.IsHost) { return; } try { List<string> list = new List<string>(); list.Add(_msgSeq++.ToString()); DrifterManager instance = DrifterManager.Instance; if (instance != null) { foreach (Drif