

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