Decompiled source of BetterCasinoV2 v2.0.0

BetterCasino.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BetterCasino.Core;
using BetterCasino.Features;
using HarmonyLib;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.Casino;
using Il2CppScheduleOne.Casino.UI;
using Il2CppScheduleOne.Map;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Main), "BetterCasino", "2.0.0", "Zyhloh", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Zyhloh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Better Casino mod for Schedule I")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("BetterCasino")]
[assembly: AssemblyTitle("BetterCasino")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BetterCasino.Features
{
	public static class AlwaysOpen
	{
		[HarmonyPatch(typeof(TimedAccessZone), "GetIsOpen")]
		public static class TimedAccessZone_GetIsOpen_Patch
		{
			public static bool Prefix(TimedAccessZone __instance, ref bool __result)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				if (((Object)((Component)__instance).gameObject).name.Contains("Casino"))
				{
					__result = true;
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(TimedAccessZone), "MinPass")]
		public static class TimedAccessZone_MinPass_Patch
		{
			public static void Postfix(TimedAccessZone __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				string name = ((Object)((Component)__instance).gameObject).name;
				if (!name.Contains("Casino"))
				{
					return;
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!((AccessZone)__instance).IsOpen && InstanceFinder.IsHost)
				{
					((AccessZone)__instance).SetIsOpen(true);
					((MelonBase)Main.Instance).LoggerInstance.Msg("[HOST] Forced Casino open: " + name);
				}
				if (!_openedZones.Contains(instanceID) && InstanceFinder.IsHost)
				{
					_openedZones.Add(instanceID);
					if (((AccessZone)__instance).onOpen != null)
					{
						((AccessZone)__instance).onOpen.Invoke();
						((MelonBase)Main.Instance).LoggerInstance.Msg("[HOST] Invoked onOpen for Casino: " + name);
					}
				}
			}
		}

		[HarmonyPatch(typeof(AccessZone), "SetIsOpen")]
		public static class AccessZone_SetIsOpen_Patch
		{
			public static void Prefix(AccessZone __instance, ref bool open)
			{
				if (!((Object)(object)__instance == (Object)null) && InstanceFinder.IsHost && ((Object)((Component)__instance).gameObject).name.Contains("Casino"))
				{
					open = true;
				}
			}
		}

		private static readonly HashSet<int> _openedZones = new HashSet<int>();

		public static void Initialize()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("AlwaysOpen feature initialized.");
		}

		public static void OnSceneLoaded()
		{
			_openedZones.Clear();
		}
	}
	public static class BetterSlots
	{
		[HarmonyPatch(typeof(SlotMachine), "RpcLogic___SetBetIndex_2681120339")]
		public static class SlotMachine_SetBetIndex_Patch
		{
			public static void Postfix(SlotMachine __instance, int index)
			{
				UpdateSlotLabel(__instance, index);
			}
		}

		[HarmonyPatch(typeof(SlotMachine), "UpInteracted")]
		public static class SlotMachine_UpInteracted_Patch
		{
			public static void Postfix(SlotMachine __instance)
			{
				UpdateSlotLabelFromCurrent(__instance);
			}
		}

		[HarmonyPatch(typeof(SlotMachine), "DownInteracted")]
		public static class SlotMachine_DownInteracted_Patch
		{
			public static void Postfix(SlotMachine __instance)
			{
				UpdateSlotLabelFromCurrent(__instance);
			}
		}

		[HarmonyPatch(typeof(BlackjackInterface), "Open")]
		public static class Blackjack_Open_Patch
		{
			public static void Postfix(BlackjackInterface __instance)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetSlider != (Object)null)
				{
					__instance.BetSlider.minValue = 0f;
					__instance.BetSlider.maxValue = 100f;
					__instance.BetSlider.value = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(BlackjackInterface), "BetSliderChanged")]
		public static class Blackjack_BetSliderChanged_Patch
		{
			public static void Postfix(BlackjackInterface __instance, float newValue)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetSlider != (Object)null)
				{
					__instance.BetSlider.SetValueWithoutNotify(newValue);
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetAmount != (Object)null)
				{
					int amount = (int)(newValue * 1000f);
					((TMP_Text)__instance.BetAmount).text = FormatMoney(amount);
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.CurrentGame != (Object)null)
				{
					float localPlayerBet = newValue * 1000f;
					__instance.CurrentGame.LocalPlayerBet = localPlayerBet;
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.ReadyButton != (Object)null)
				{
					((Selectable)__instance.ReadyButton).interactable = true;
				}
			}
		}

		[HarmonyPatch(typeof(BlackjackInterface), "RefreshReadyButton")]
		public static class Blackjack_RefreshReadyButton_Patch
		{
			public static void Postfix(BlackjackInterface __instance)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.ReadyButton != (Object)null)
				{
					((Selectable)__instance.ReadyButton).interactable = true;
				}
			}
		}

		[HarmonyPatch(typeof(RTBInterface), "Open")]
		public static class RTB_Open_Patch
		{
			public static void Postfix(RTBInterface __instance)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetSlider != (Object)null)
				{
					__instance.BetSlider.minValue = 0f;
					__instance.BetSlider.maxValue = 100f;
					__instance.BetSlider.value = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(RTBInterface), "BetSliderChanged")]
		public static class RTB_BetSliderChanged_Patch
		{
			public static void Postfix(RTBInterface __instance, float newValue)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetSlider != (Object)null)
				{
					__instance.BetSlider.SetValueWithoutNotify(newValue);
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.BetAmount != (Object)null)
				{
					int amount = (int)(newValue * 1000f);
					((TMP_Text)__instance.BetAmount).text = FormatMoney(amount);
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.CurrentGame != (Object)null)
				{
					float localPlayerBet = newValue * 1000f;
					__instance.CurrentGame.LocalPlayerBet = localPlayerBet;
				}
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.ReadyButton != (Object)null)
				{
					((Selectable)__instance.ReadyButton).interactable = true;
				}
			}
		}

		[HarmonyPatch(typeof(RTBInterface), "RefreshReadyButton")]
		public static class RTB_RefreshReadyButton_Patch
		{
			public static void Postfix(RTBInterface __instance)
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.ReadyButton != (Object)null)
				{
					((Selectable)__instance.ReadyButton).interactable = true;
				}
			}
		}

		private static bool _betAmountsSet = false;

		public static int TABLE_BET_MINIMUM = 1;

		public static int TABLE_BET_MAXIMUM = 100000;

		private static readonly int[] BaseBetIncrements = new int[19]
		{
			0, 1, 5, 10, 25, 50, 100, 250, 500, 1000,
			2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000
		};

		public static void Initialize()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("BetterSlots feature initialized.");
		}

		public static void OnSceneLoaded()
		{
			_betAmountsSet = false;
		}

		public static void OnUpdate()
		{
			if (!_betAmountsSet)
			{
				TrySetBetAmounts();
			}
		}

		private static void TrySetBetAmounts()
		{
			try
			{
				int value = Settings.SlotMaxBet.Value;
				bool value2 = Settings.FreeBetEnabled.Value;
				List<int> list = new List<int>();
				int[] baseBetIncrements = BaseBetIncrements;
				foreach (int num in baseBetIncrements)
				{
					if ((num != 0 || value2) && num <= value)
					{
						list.Add(num);
					}
				}
				if ((list.Count == 0 || list[list.Count - 1] < value) && !list.Contains(value))
				{
					list.Add(value);
				}
				Il2CppStructArray<int> val = new Il2CppStructArray<int>((long)list.Count);
				for (int j = 0; j < list.Count; j++)
				{
					((Il2CppArrayBase<int>)(object)val)[j] = list[j];
				}
				SlotMachine.BetAmounts = val;
				_betAmountsSet = true;
				string value3 = (value2 ? "FREE" : "$1");
				((MelonBase)Main.Instance).LoggerInstance.Msg($"Set slot machine bet amounts: {value3} to {FormatMoney(value)} ({list.Count} increments)");
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Msg("Failed to set bet amounts: " + ex.Message);
				_betAmountsSet = true;
			}
		}

		public static string FormatMoney(int amount)
		{
			if (amount == 0)
			{
				return "FREE";
			}
			if (amount >= 1000000)
			{
				float num = (float)amount / 1000000f;
				if (num == (float)(int)num)
				{
					return $"${(int)num}M";
				}
				return $"${num:0.#}M";
			}
			if (amount >= 1000)
			{
				float num2 = (float)amount / 1000f;
				if (num2 == (float)(int)num2)
				{
					return $"${(int)num2}k";
				}
				return $"${num2:0.#}k";
			}
			return $"${amount}";
		}

		private static void UpdateSlotLabel(SlotMachine instance, int index)
		{
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.BetAmountLabel == (Object)null) && SlotMachine.BetAmounts != null && index >= 0 && index < ((Il2CppArrayBase<int>)(object)SlotMachine.BetAmounts).Length)
			{
				int amount = ((Il2CppArrayBase<int>)(object)SlotMachine.BetAmounts)[index];
				((TMP_Text)instance.BetAmountLabel).text = FormatMoney(amount);
				((TMP_Text)instance.BetAmountLabel).enableWordWrapping = false;
				((TMP_Text)instance.BetAmountLabel).overflowMode = (TextOverflowModes)0;
			}
		}

		private static void UpdateSlotLabelFromCurrent(SlotMachine instance)
		{
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.BetAmountLabel == (Object)null))
			{
				int currentBetAmount = instance.currentBetAmount;
				((TMP_Text)instance.BetAmountLabel).text = FormatMoney(currentBetAmount);
				((TMP_Text)instance.BetAmountLabel).enableWordWrapping = false;
				((TMP_Text)instance.BetAmountLabel).overflowMode = (TextOverflowModes)0;
			}
		}
	}
	public static class CasinoSafehouse
	{
		private static readonly HashSet<int> _clearedPlayers = new HashSet<int>();

		private static float _lastCheckTime = 0f;

		private const float CHECK_INTERVAL = 2f;

		private static Vector3 _casinoPosition = Vector3.zero;

		private static bool _casinoFound = false;

		private static bool _searchedForCasino = false;

		public static bool Enabled = true;

		public static void Initialize()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("CasinoSafehouse feature initialized.");
		}

		public static void OnSceneLoaded()
		{
			//IL_000a: 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)
			_clearedPlayers.Clear();
			_casinoPosition = Vector3.zero;
			_casinoFound = false;
			_searchedForCasino = false;
		}

		public static void OnUpdate()
		{
			if (Enabled && InstanceFinder.IsHost && !(Time.time - _lastCheckTime < 2f))
			{
				_lastCheckTime = Time.time;
				if (!_searchedForCasino)
				{
					FindCasinoPosition();
					_searchedForCasino = true;
				}
				if (_casinoFound)
				{
					CheckPlayersInCasino();
				}
			}
		}

		private static void FindCasinoPosition()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			try
			{
				Il2CppArrayBase<AccessZone> val = Object.FindObjectsOfType<AccessZone>();
				if (val == null)
				{
					return;
				}
				foreach (AccessZone item in val)
				{
					if ((Object)(object)item != (Object)null && ((Object)((Component)item).gameObject).name.Contains("Casino"))
					{
						_casinoPosition = ((Component)item).transform.position;
						_casinoFound = true;
						((MelonBase)Main.Instance).LoggerInstance.Msg($"Casino Safehouse: Found casino at {_casinoPosition}");
						break;
					}
				}
			}
			catch
			{
			}
		}

		private static void CheckPlayersInCasino()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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)
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return;
				}
				float x = _casinoPosition.x;
				float y = _casinoPosition.y;
				float z = _casinoPosition.z;
				Enumerator<Player> enumerator = playerList.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Player current = enumerator.Current;
					if ((Object)(object)current == (Object)null || (Object)(object)((Component)current).transform == (Object)null)
					{
						continue;
					}
					int instanceID = ((Object)current).GetInstanceID();
					Vector3 position = ((Component)current).transform.position;
					float num = position.x - x;
					float num2 = position.y - y;
					float num3 = position.z - z;
					if (num * num + num2 * num2 + num3 * num3 < 2500f)
					{
						if (!_clearedPlayers.Contains(instanceID))
						{
							ClearPlayerWanted(current);
							_clearedPlayers.Add(instanceID);
						}
					}
					else
					{
						_clearedPlayers.Remove(instanceID);
					}
				}
			}
			catch
			{
			}
		}

		private static void ClearPlayerWanted(Player player)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)player == (Object)null))
				{
					PlayerCrimeData crimeData = player.CrimeData;
					if (!((Object)(object)crimeData == (Object)null) && (int)crimeData.CurrentPursuitLevel != 0)
					{
						crimeData.SetPursuitLevel((EPursuitLevel)0);
						crimeData.ClearCrimes();
						string text = ((Object)player).name ?? "Unknown";
						((MelonBase)Main.Instance).LoggerInstance.Msg("[HOST] Cleared wanted status for player entering Casino: " + text);
					}
				}
			}
			catch
			{
			}
		}
	}
	public static class SignChanger
	{
		private static int _signsChanged;

		private const int EXPECTED_SIGN_COUNT = 2;

		public static void Initialize()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("SignChanger feature initialized.");
		}

		public static void OnSceneLoaded()
		{
			_signsChanged = 0;
		}

		public static void OnUpdate()
		{
			if (_signsChanged < 2)
			{
				TryChangeSign();
			}
		}

		private static void TryChangeSign()
		{
			foreach (TextMeshPro item in Object.FindObjectsOfType<TextMeshPro>())
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				string text = ((TMP_Text)item).text;
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				bool flag = false;
				if (text.Contains("OPENING HOURS") || text.Contains("Opening Hours") || text.Contains("opening hours"))
				{
					Transform val = item.transform;
					while ((Object)(object)val != (Object)null)
					{
						if (((Object)val).name.Contains("Casino", StringComparison.OrdinalIgnoreCase))
						{
							flag = true;
							break;
						}
						val = val.parent;
					}
					if (!flag && ((Object)((Component)item).gameObject).name.Contains("Casino", StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
					}
				}
				if (text.Contains("4PM") || text.Contains("5AM") || text.Contains("4 PM") || text.Contains("5 AM"))
				{
					Transform val2 = item.transform;
					while ((Object)(object)val2 != (Object)null)
					{
						if (((Object)val2).name.Contains("Casino", StringComparison.OrdinalIgnoreCase))
						{
							flag = true;
							break;
						}
						val2 = val2.parent;
					}
				}
				if (flag)
				{
					string text2 = ((TMP_Text)item).text;
					((TMP_Text)item).text = "24/7";
					_signsChanged++;
					((MelonBase)Main.Instance).LoggerInstance.Msg($"Changed Casino sign #{_signsChanged} from '{text2.Replace("\n", "\\n")}' to '24/7'");
					((MelonBase)Main.Instance).LoggerInstance.Msg("Sign GameObject: " + ((Object)((Component)item).gameObject).name);
				}
			}
		}
	}
	public static class SlotControl
	{
		private class PlayerSpinData
		{
			public Dictionary<int, float> MachineLastSpinTime = new Dictionary<int, float>();

			public Dictionary<int, int> MachineWinStreaks = new Dictionary<int, int>();

			public float LastActivityTime;
		}

		[HarmonyPatch(typeof(SlotMachine), "RpcLogic___SendStartSpin_2681120339")]
		public static class SlotMachine_SendStartSpin_Patch
		{
			public static void Prefix(SlotMachine __instance, NetworkConnection spinner, ref int betAmount)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if (InstanceFinder.IsHost)
				{
					int num = ((spinner != (NetworkConnection)null) ? spinner.ClientId : 0);
					int instanceID = ((Object)__instance).GetInstanceID();
					SlotMachine_GetRandomSymbol_Patch.SetSymbols(GenerateSymbolsForOutcome(DetermineOutcome(num, instanceID)));
					if (LogSpins)
					{
						((MelonBase)Main.Instance).LoggerInstance.Msg($"[HOST] Slot outcome determined for player {num}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(SlotMachine), "GetRandomSymbol")]
		public static class SlotMachine_GetRandomSymbol_Patch
		{
			private static int _symbolIndex;

			private static Il2CppStructArray<ESymbol> _currentSymbols;

			public static void SetSymbols(Il2CppStructArray<ESymbol> symbols)
			{
				_currentSymbols = symbols;
				_symbolIndex = 0;
			}

			public static bool Prefix(ref ESymbol __result)
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Expected I4, but got Unknown
				if (!InstanceFinder.IsHost)
				{
					return true;
				}
				if (_currentSymbols != null && _symbolIndex < ((Il2CppArrayBase<ESymbol>)(object)_currentSymbols).Length)
				{
					__result = (ESymbol)(int)((Il2CppArrayBase<ESymbol>)(object)_currentSymbols)[_symbolIndex];
					_symbolIndex++;
					if (_symbolIndex >= ((Il2CppArrayBase<ESymbol>)(object)_currentSymbols).Length)
					{
						_currentSymbols = null;
						_symbolIndex = 0;
					}
					return false;
				}
				return true;
			}
		}

		private static readonly Dictionary<int, PlayerSpinData> _playerData = new Dictionary<int, PlayerSpinData>();

		private static float _lastCleanupTime = 0f;

		public static float BaseJackpotChance = 0.01f;

		public static float BaseBigWinChance = 0.05f;

		public static float BaseSmallWinChance = 0.15f;

		public static float BaseMiniWinChance = 0.25f;

		public static float WinStreakPenaltyPerWin = 0.15f;

		public static int WinStreakThreshold = 2;

		public static float MultiMachinePenalty = 0.5f;

		public static float MultiMachineTimeWindow = 5f;

		public static bool EnableAntiAbuse = true;

		public static bool LogSpins = false;

		public static void Initialize()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("SlotControl feature initialized.");
			((MelonBase)Main.Instance).LoggerInstance.Msg($"  Base chances - Jackpot: {BaseJackpotChance * 100f}%, Big: {BaseBigWinChance * 100f}%, Small: {BaseSmallWinChance * 100f}%, Mini: {BaseMiniWinChance * 100f}%");
			((MelonBase)Main.Instance).LoggerInstance.Msg("  Anti-abuse: " + (EnableAntiAbuse ? "Enabled" : "Disabled"));
		}

		public static void OnSceneLoaded()
		{
			_playerData.Clear();
		}

		public static void OnUpdate()
		{
			if (Time.time - _lastCleanupTime > 30f)
			{
				_lastCleanupTime = Time.time;
				CleanupOldPlayerData();
			}
		}

		private static void CleanupOldPlayerData()
		{
			List<int> list = new List<int>();
			float time = Time.time;
			foreach (KeyValuePair<int, PlayerSpinData> playerDatum in _playerData)
			{
				if (time - playerDatum.Value.LastActivityTime > 120f)
				{
					list.Add(playerDatum.Key);
				}
			}
			foreach (int item in list)
			{
				_playerData.Remove(item);
			}
		}

		private static PlayerSpinData GetPlayerData(int playerId)
		{
			if (!_playerData.ContainsKey(playerId))
			{
				_playerData[playerId] = new PlayerSpinData();
			}
			return _playerData[playerId];
		}

		private static int CountActiveMachinesForPlayer(PlayerSpinData data)
		{
			float time = Time.time;
			int num = 0;
			foreach (KeyValuePair<int, float> item in data.MachineLastSpinTime)
			{
				if (time - item.Value < MultiMachineTimeWindow)
				{
					num++;
				}
			}
			return num;
		}

		private static float GetWinChanceMultiplier(int playerId, int machineId)
		{
			float num = 1f;
			if (!EnableAntiAbuse)
			{
				return num;
			}
			PlayerSpinData playerData = GetPlayerData(playerId);
			int num2 = CountActiveMachinesForPlayer(playerData);
			if (num2 > 1)
			{
				float val = 1f - MultiMachinePenalty * (float)(num2 - 1);
				num *= Math.Max(0.1f, val);
				if (LogSpins)
				{
					((MelonBase)Main.Instance).LoggerInstance.Msg($"Player {playerId} multi-machine penalty: {num2} machines, multiplier: {num:F2}");
				}
			}
			if (playerData.MachineWinStreaks.TryGetValue(machineId, out var value) && value >= WinStreakThreshold)
			{
				float val2 = 1f - WinStreakPenaltyPerWin * (float)(value - WinStreakThreshold + 1);
				num *= Math.Max(0.05f, val2);
				if (LogSpins)
				{
					((MelonBase)Main.Instance).LoggerInstance.Msg($"Player {playerId} win streak penalty: {value} wins, multiplier: {num:F2}");
				}
			}
			return num;
		}

		private static void RecordSpin(int playerId, int machineId, bool isWin)
		{
			PlayerSpinData playerData = GetPlayerData(playerId);
			playerData.LastActivityTime = Time.time;
			playerData.MachineLastSpinTime[machineId] = Time.time;
			if (isWin)
			{
				if (!playerData.MachineWinStreaks.ContainsKey(machineId))
				{
					playerData.MachineWinStreaks[machineId] = 0;
				}
				playerData.MachineWinStreaks[machineId]++;
			}
			else
			{
				playerData.MachineWinStreaks[machineId] = 0;
			}
		}

		private static EOutcome DetermineOutcome(int playerId, int machineId)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			float winChanceMultiplier = GetWinChanceMultiplier(playerId, machineId);
			float value = Random.value;
			float num = BaseJackpotChance * winChanceMultiplier;
			float num2 = num + BaseBigWinChance * winChanceMultiplier;
			float num3 = num2 + BaseSmallWinChance * winChanceMultiplier;
			float num4 = num3 + BaseMiniWinChance * winChanceMultiplier;
			EOutcome val = ((value < num) ? ((EOutcome)0) : ((value < num2) ? ((EOutcome)1) : ((value < num3) ? ((EOutcome)2) : ((!(value < num4)) ? ((EOutcome)4) : ((EOutcome)3)))));
			bool isWin = (int)val != 4;
			RecordSpin(playerId, machineId, isWin);
			if (LogSpins)
			{
				((MelonBase)Main.Instance).LoggerInstance.Msg($"Slot spin: roll={value:F3}, multiplier={winChanceMultiplier:F2}, outcome={val}");
			}
			return val;
		}

		private static Il2CppStructArray<ESymbol> GenerateSymbolsForOutcome(EOutcome outcome)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected I4, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			Il2CppStructArray<ESymbol> val = new Il2CppStructArray<ESymbol>(3L);
			switch ((int)outcome)
			{
			case 0:
				((Il2CppArrayBase<ESymbol>)(object)val)[0] = (ESymbol)5;
				((Il2CppArrayBase<ESymbol>)(object)val)[1] = (ESymbol)5;
				((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)5;
				break;
			case 1:
			{
				ESymbol val7 = (((Il2CppArrayBase<ESymbol>)(object)val)[1] = (((Il2CppArrayBase<ESymbol>)(object)val)[0] = (ESymbol)Random.Range(4, 6)));
				((Il2CppArrayBase<ESymbol>)(object)val)[2] = val7;
				break;
			}
			case 2:
			{
				ESymbol val4 = (((Il2CppArrayBase<ESymbol>)(object)val)[1] = (((Il2CppArrayBase<ESymbol>)(object)val)[0] = (ESymbol)Random.Range(0, 4)));
				((Il2CppArrayBase<ESymbol>)(object)val)[2] = val4;
				break;
			}
			case 3:
				((Il2CppArrayBase<ESymbol>)(object)val)[0] = (ESymbol)Random.Range(0, 4);
				((Il2CppArrayBase<ESymbol>)(object)val)[1] = (ESymbol)Random.Range(0, 4);
				((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)Random.Range(0, 4);
				while (((Il2CppArrayBase<ESymbol>)(object)val)[0] == ((Il2CppArrayBase<ESymbol>)(object)val)[1] && ((Il2CppArrayBase<ESymbol>)(object)val)[1] == ((Il2CppArrayBase<ESymbol>)(object)val)[2])
				{
					((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)Random.Range(0, 4);
				}
				break;
			default:
				((Il2CppArrayBase<ESymbol>)(object)val)[0] = (ESymbol)Random.Range(0, 6);
				((Il2CppArrayBase<ESymbol>)(object)val)[1] = (ESymbol)Random.Range(0, 6);
				((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)Random.Range(0, 6);
				while (((Il2CppArrayBase<ESymbol>)(object)val)[0] == ((Il2CppArrayBase<ESymbol>)(object)val)[1] && ((Il2CppArrayBase<ESymbol>)(object)val)[1] == ((Il2CppArrayBase<ESymbol>)(object)val)[2])
				{
					((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)Random.Range(0, 6);
				}
				while (IsFruitCombo(val))
				{
					((Il2CppArrayBase<ESymbol>)(object)val)[2] = (ESymbol)Random.Range(0, 6);
				}
				break;
			}
			return val;
		}

		private static bool IsFruitCombo(Il2CppStructArray<ESymbol> symbols)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if ((int)((Il2CppArrayBase<ESymbol>)(object)symbols)[0] <= 3 && (int)((Il2CppArrayBase<ESymbol>)(object)symbols)[1] <= 3)
			{
				return (int)((Il2CppArrayBase<ESymbol>)(object)symbols)[2] <= 3;
			}
			return false;
		}
	}
}
namespace BetterCasino.Core
{
	public static class ConfigFile
	{
		public const int MIN_BET = 1;

		public const int MAX_SLOT_BET = 1000000;

		public const int MAX_TABLE_BET = 1000000;

		public const float MIN_CHANCE = 0f;

		public const float MAX_CHANCE = 1f;

		public const int MIN_STREAK_THRESHOLD = 1;

		public const int MAX_STREAK_THRESHOLD = 100;

		public const float MIN_TIME_WINDOW = 1f;

		public const float MAX_TIME_WINDOW = 60f;

		private static string ConfigPath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "..", "UserData", "BetterCasino.cfg");

		private static int ClampInt(int value, int min, int max, string name)
		{
			if (value < min)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to minimum {min}");
				return min;
			}
			if (value > max)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to maximum {max}");
				return max;
			}
			return value;
		}

		private static float ClampFloat(float value, float min, float max, string name)
		{
			if (value < min)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to minimum {min}");
				return min;
			}
			if (value > max)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to maximum {max}");
				return max;
			}
			return value;
		}

		private static bool TryParseBool(string value, out bool result)
		{
			value = value.ToLower().Trim();
			switch (value)
			{
			case "true":
			case "1":
			case "yes":
			case "on":
				result = true;
				return true;
			case "false":
			case "0":
			case "no":
			case "off":
				result = false;
				return true;
			default:
				result = false;
				return false;
			}
		}

		private static bool TryParseInt(string value, out int result)
		{
			return int.TryParse(value.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
		}

		private static bool TryParseFloat(string value, out float result)
		{
			return float.TryParse(value.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result);
		}

		public static void CreateConfigFileIfNotExists()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(ConfigPath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				if (!File.Exists(ConfigPath))
				{
					SaveConfigFile();
					((MelonBase)Main.Instance).LoggerInstance.Msg("Config file created at: " + ConfigPath);
				}
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Error("Failed to create config file: " + ex.Message);
			}
		}

		public static void SaveConfigFile()
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# ═══════════════════════════════════════════════════════════════════════════════");
				stringBuilder.AppendLine("# BetterCasino Configuration File");
				stringBuilder.AppendLine("# ═══════════════════════════════════════════════════════════════════════════════");
				stringBuilder.AppendLine("#");
				stringBuilder.AppendLine("# This file is auto-generated by BetterCasino.");
				stringBuilder.AppendLine("# Edit the values below to customize the mod.");
				stringBuilder.AppendLine("# Changes take effect after restarting the game.");
				stringBuilder.AppendLine("#");
				stringBuilder.AppendLine("# If you have Mod Manager & Phone App installed, you can also");
				stringBuilder.AppendLine("# change these settings in-game through the phone app or main menu.");
				stringBuilder.AppendLine("#");
				stringBuilder.AppendLine("# ═══════════════════════════════════════════════════════════════════════════════");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine("# GENERAL SETTINGS");
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Keep the casino open 24/7 (true/false)");
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
				handler.AppendLiteral("AlwaysOpen = ");
				handler.AppendFormatted(Settings.AlwaysOpenEnabled.Value.ToString().ToLower());
				stringBuilder3.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Change casino signs to show \"24/7\" (true/false)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
				handler.AppendLiteral("SignChanger = ");
				handler.AppendFormatted(Settings.SignChangerEnabled.Value.ToString().ToLower());
				stringBuilder4.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Clear wanted status when entering the casino (true/false)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder2);
				handler.AppendLiteral("CasinoSafehouse = ");
				handler.AppendFormatted(Settings.CasinoSafehouseEnabled.Value.ToString().ToLower());
				stringBuilder5.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine("# SLOT MACHINE SETTINGS");
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Enable FREE ($0) bet option for slot machines (true/false)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder6 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
				handler.AppendLiteral("FreeBetEnabled = ");
				handler.AppendFormatted(Settings.FreeBetEnabled.Value.ToString().ToLower());
				stringBuilder6.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Maximum bet amount for slot machines (in dollars, max: 1000000)");
				stringBuilder.AppendLine("# Bet increments are automatically generated: FREE, $1, $5, $10, $25, $50, $100,");
				stringBuilder.AppendLine("# $250, $500, $1k, $2.5k, $5k, $10k, $25k, $50k, $100k, $250k, $500k, $1M");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder7 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2);
				handler.AppendLiteral("SlotMaxBet = ");
				handler.AppendFormatted(Settings.SlotMaxBet.Value);
				stringBuilder7.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine("# TABLE GAME SETTINGS (Blackjack & Ride The Bus)");
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Minimum bet for table games (in dollars, min: 1)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder8 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
				handler.AppendLiteral("TableMinBet = ");
				handler.AppendFormatted(Settings.TableMinBet.Value);
				stringBuilder8.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Maximum bet for table games (in dollars, max: 1000000)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder9 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
				handler.AppendLiteral("TableMaxBet = ");
				handler.AppendFormatted(Settings.TableMaxBet.Value);
				stringBuilder9.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine("# ANTI-ABUSE SYSTEM (Slot Machines)");
				stringBuilder.AppendLine("# ───────────────────────────────────────────────────────────────────────────────");
				stringBuilder.AppendLine("# Prevents players from exploiting slot machines by playing multiple machines");
				stringBuilder.AppendLine("# at once or farming win streaks.");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Enable the anti-abuse system (true/false)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder10 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
				handler.AppendLiteral("AntiAbuseEnabled = ");
				handler.AppendFormatted(Settings.AntiAbuseEnabled.Value.ToString().ToLower());
				stringBuilder10.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ─── Win Chances (0.0 to 1.0, where 0.01 = 1%, max total should be < 1.0) ───");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Base chance for JACKPOT (three 7s)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder11 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2);
				handler.AppendLiteral("JackpotChance = ");
				handler.AppendFormatted(Settings.JackpotChance.Value);
				stringBuilder11.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Base chance for BIG WIN (three bells or sevens)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder12 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
				handler.AppendLiteral("BigWinChance = ");
				handler.AppendFormatted(Settings.BigWinChance.Value);
				stringBuilder12.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Base chance for SMALL WIN (three matching fruits)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder13 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
				handler.AppendLiteral("SmallWinChance = ");
				handler.AppendFormatted(Settings.SmallWinChance.Value);
				stringBuilder13.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Base chance for MINI WIN (all fruits, not matching)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder14 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder2);
				handler.AppendLiteral("MiniWinChance = ");
				handler.AppendFormatted(Settings.MiniWinChance.Value);
				stringBuilder14.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ─── Win Streak Penalty ───");
				stringBuilder.AppendLine("# Reduces win chances when a player wins multiple times in a row.");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Number of consecutive wins before penalty kicks in");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder15 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(21, 1, stringBuilder2);
				handler.AppendLiteral("WinStreakThreshold = ");
				handler.AppendFormatted(Settings.WinStreakThreshold.Value);
				stringBuilder15.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Win chance reduction per consecutive win after threshold (0.15 = 15%)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder16 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
				handler.AppendLiteral("WinStreakPenalty = ");
				handler.AppendFormatted(Settings.WinStreakPenalty.Value);
				stringBuilder16.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ─── Multi-Machine Penalty ───");
				stringBuilder.AppendLine("# Reduces win chances when a player uses multiple machines at once.");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Time window to track multi-machine usage (in seconds)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder17 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder2);
				handler.AppendLiteral("MultiMachineTimeWindow = ");
				handler.AppendFormatted(Settings.MultiMachineTimeWindow.Value);
				stringBuilder17.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Win chance reduction per extra machine (0.5 = 50%)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder18 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
				handler.AppendLiteral("MultiMachinePenalty = ");
				handler.AppendFormatted(Settings.MultiMachinePenalty.Value);
				stringBuilder18.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ─── Debug ───");
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# Log slot spin results to console (true/false)");
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder19 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2);
				handler.AppendLiteral("LogSpins = ");
				handler.AppendFormatted(Settings.LogSpins.Value.ToString().ToLower());
				stringBuilder19.AppendLine(ref handler);
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("# ═══════════════════════════════════════════════════════════════════════════════");
				stringBuilder.AppendLine("# END OF CONFIGURATION");
				stringBuilder.AppendLine("# ═══════════════════════════════════════════════════════════════════════════════");
				File.WriteAllText(ConfigPath, stringBuilder.ToString());
				((MelonBase)Main.Instance).LoggerInstance.Msg("Config file saved to: " + ConfigPath);
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Error("Failed to create config file: " + ex.Message);
			}
		}

		public static void LoadConfigFile()
		{
			if (!File.Exists(ConfigPath))
			{
				((MelonBase)Main.Instance).LoggerInstance.Msg("No config file found. Using default settings.");
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(ConfigPath);
				foreach (string text in array)
				{
					if (string.IsNullOrWhiteSpace(text) || text.TrimStart().StartsWith("#"))
					{
						continue;
					}
					string[] array2 = text.Split(new char[1] { '=' }, 2);
					if (array2.Length != 2)
					{
						continue;
					}
					string text2 = array2[0].Trim();
					string text3 = array2[1].Trim();
					try
					{
						if (text2 == null)
						{
							continue;
						}
						switch (text2.Length)
						{
						case 10:
							switch (text2[0])
							{
							case 'A':
								if (text2 == "AlwaysOpen")
								{
									if (TryParseBool(text3, out var result15))
									{
										Settings.AlwaysOpenEnabled.Value = result15;
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for AlwaysOpen: '" + text3 + "', using default");
									}
								}
								break;
							case 'S':
								if (text2 == "SlotMaxBet")
								{
									if (TryParseInt(text3, out var result14))
									{
										Settings.SlotMaxBet.Value = ClampInt(result14, 1, 1000000, "SlotMaxBet");
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for SlotMaxBet: '" + text3 + "', using default");
									}
								}
								break;
							}
							break;
						case 11:
							switch (text2[0])
							{
							case 'S':
								if (text2 == "SignChanger")
								{
									if (TryParseBool(text3, out var result11))
									{
										Settings.SignChangerEnabled.Value = result11;
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for SignChanger: '" + text3 + "', using default");
									}
								}
								break;
							case 'T':
							{
								int result10;
								if (!(text2 == "TableMinBet"))
								{
									if (text2 == "TableMaxBet")
									{
										if (TryParseInt(text3, out var result9))
										{
											Settings.TableMaxBet.Value = ClampInt(result9, 1, 1000000, "TableMaxBet");
										}
										else
										{
											((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for TableMaxBet: '" + text3 + "', using default");
										}
									}
								}
								else if (TryParseInt(text3, out result10))
								{
									Settings.TableMinBet.Value = ClampInt(result10, 1, 1000000, "TableMinBet");
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for TableMinBet: '" + text3 + "', using default");
								}
								break;
							}
							}
							break;
						case 14:
							switch (text2[0])
							{
							case 'F':
								if (text2 == "FreeBetEnabled")
								{
									if (TryParseBool(text3, out var result8))
									{
										Settings.FreeBetEnabled.Value = result8;
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for FreeBetEnabled: '" + text3 + "', using default");
									}
								}
								break;
							case 'S':
								if (text2 == "SmallWinChance")
								{
									if (TryParseFloat(text3, out var result7))
									{
										Settings.SmallWinChance.Value = ClampFloat(result7, 0f, 1f, "SmallWinChance");
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for SmallWinChance: '" + text3 + "', using default");
									}
								}
								break;
							}
							break;
						case 16:
							switch (text2[0])
							{
							case 'A':
								if (text2 == "AntiAbuseEnabled")
								{
									if (TryParseBool(text3, out var result3))
									{
										Settings.AntiAbuseEnabled.Value = result3;
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for AntiAbuseEnabled: '" + text3 + "', using default");
									}
								}
								break;
							case 'W':
								if (text2 == "WinStreakPenalty")
								{
									if (TryParseFloat(text3, out var result2))
									{
										Settings.WinStreakPenalty.Value = ClampFloat(result2, 0f, 1f, "WinStreakPenalty");
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for WinStreakPenalty: '" + text3 + "', using default");
									}
								}
								break;
							}
							break;
						case 13:
							switch (text2[0])
							{
							case 'J':
								if (text2 == "JackpotChance")
								{
									if (TryParseFloat(text3, out var result17))
									{
										Settings.JackpotChance.Value = ClampFloat(result17, 0f, 1f, "JackpotChance");
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for JackpotChance: '" + text3 + "', using default");
									}
								}
								break;
							case 'M':
								if (text2 == "MiniWinChance")
								{
									if (TryParseFloat(text3, out var result16))
									{
										Settings.MiniWinChance.Value = ClampFloat(result16, 0f, 1f, "MiniWinChance");
									}
									else
									{
										((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for MiniWinChance: '" + text3 + "', using default");
									}
								}
								break;
							}
							break;
						case 15:
							if (text2 == "CasinoSafehouse")
							{
								if (TryParseBool(text3, out var result5))
								{
									Settings.CasinoSafehouseEnabled.Value = result5;
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for CasinoSafehouse: '" + text3 + "', using default");
								}
							}
							break;
						case 12:
							if (text2 == "BigWinChance")
							{
								if (TryParseFloat(text3, out var result12))
								{
									Settings.BigWinChance.Value = ClampFloat(result12, 0f, 1f, "BigWinChance");
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for BigWinChance: '" + text3 + "', using default");
								}
							}
							break;
						case 18:
							if (text2 == "WinStreakThreshold")
							{
								if (TryParseInt(text3, out var result4))
								{
									Settings.WinStreakThreshold.Value = ClampInt(result4, 1, 100, "WinStreakThreshold");
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for WinStreakThreshold: '" + text3 + "', using default");
								}
							}
							break;
						case 22:
							if (text2 == "MultiMachineTimeWindow")
							{
								if (TryParseFloat(text3, out var result13))
								{
									Settings.MultiMachineTimeWindow.Value = ClampFloat(result13, 1f, 60f, "MultiMachineTimeWindow");
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for MultiMachineTimeWindow: '" + text3 + "', using default");
								}
							}
							break;
						case 19:
							if (text2 == "MultiMachinePenalty")
							{
								if (TryParseFloat(text3, out var result6))
								{
									Settings.MultiMachinePenalty.Value = ClampFloat(result6, 0f, 1f, "MultiMachinePenalty");
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid number for MultiMachinePenalty: '" + text3 + "', using default");
								}
							}
							break;
						case 8:
							if (text2 == "LogSpins")
							{
								if (TryParseBool(text3, out var result))
								{
									Settings.LogSpins.Value = result;
								}
								else
								{
									((MelonBase)Main.Instance).LoggerInstance.Warning("Invalid boolean for LogSpins: '" + text3 + "', using default");
								}
							}
							break;
						case 9:
						case 17:
						case 20:
						case 21:
							break;
						}
					}
					catch (Exception ex)
					{
						((MelonBase)Main.Instance).LoggerInstance.Warning("Failed to parse config value '" + text2 + "': " + ex.Message);
					}
				}
				((MelonBase)Main.Instance).LoggerInstance.Msg("Config file loaded successfully.");
			}
			catch (Exception ex2)
			{
				((MelonBase)Main.Instance).LoggerInstance.Error("Failed to load config file: " + ex2.Message);
			}
		}
	}
	public class Main : MelonMod
	{
		public static Main Instance { get; private set; }

		public override void OnInitializeMelon()
		{
			Instance = this;
			((MelonBase)this).LoggerInstance.Msg("BetterCasino v2.0.0 initialized!");
			Settings.Initialize();
			ConfigFile.LoadConfigFile();
			AlwaysOpen.Initialize();
			SignChanger.Initialize();
			BetterSlots.Initialize();
			SlotControl.Initialize();
			CasinoSafehouse.Initialize();
			Settings.ApplySettings();
			ConfigFile.CreateConfigFileIfNotExists();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			((MelonBase)this).LoggerInstance.Msg("Scene loaded: " + sceneName);
			AlwaysOpen.OnSceneLoaded();
			SignChanger.OnSceneLoaded();
			BetterSlots.OnSceneLoaded();
			SlotControl.OnSceneLoaded();
			CasinoSafehouse.OnSceneLoaded();
		}

		public override void OnUpdate()
		{
			SignChanger.OnUpdate();
			BetterSlots.OnUpdate();
			SlotControl.OnUpdate();
			CasinoSafehouse.OnUpdate();
		}

		public override void OnLateUpdate()
		{
		}

		public override void OnGUI()
		{
		}

		public override void OnApplicationQuit()
		{
			Settings.Unsubscribe();
			((MelonBase)this).LoggerInstance.Msg("BetterCasino shutting down.");
		}
	}
	public static class Settings
	{
		private static MelonPreferences_Category _generalCategory;

		private static MelonPreferences_Category _slotsCategory;

		private static MelonPreferences_Category _tableGamesCategory;

		private static MelonPreferences_Category _antiAbuseCategory;

		public static MelonPreferences_Entry<bool> AlwaysOpenEnabled;

		public static MelonPreferences_Entry<bool> SignChangerEnabled;

		public static MelonPreferences_Entry<bool> FreeBetEnabled;

		public static MelonPreferences_Entry<int> SlotMaxBet;

		public static MelonPreferences_Entry<int> TableMinBet;

		public static MelonPreferences_Entry<int> TableMaxBet;

		public static MelonPreferences_Entry<bool> AntiAbuseEnabled;

		public static MelonPreferences_Entry<float> JackpotChance;

		public static MelonPreferences_Entry<float> BigWinChance;

		public static MelonPreferences_Entry<float> SmallWinChance;

		public static MelonPreferences_Entry<float> MiniWinChance;

		public static MelonPreferences_Entry<float> WinStreakPenalty;

		public static MelonPreferences_Entry<int> WinStreakThreshold;

		public static MelonPreferences_Entry<float> MultiMachinePenalty;

		public static MelonPreferences_Entry<float> MultiMachineTimeWindow;

		public static MelonPreferences_Entry<bool> LogSpins;

		public static MelonPreferences_Entry<bool> CasinoSafehouseEnabled;

		private static bool _modManagerFound;

		private static object _onPhoneEvent;

		private static object _onMenuEvent;

		private static Delegate _phoneHandler;

		private static Delegate _menuHandler;

		public static void Initialize()
		{
			_generalCategory = MelonPreferences.CreateCategory("BetterCasino_01_General", "General Settings");
			_slotsCategory = MelonPreferences.CreateCategory("BetterCasino_02_SlotMachines", "Slot Machines");
			_tableGamesCategory = MelonPreferences.CreateCategory("BetterCasino_03_TableGames", "Table Games");
			_antiAbuseCategory = MelonPreferences.CreateCategory("BetterCasino_04_AntiAbuse", "Anti-Abuse System");
			AlwaysOpenEnabled = _generalCategory.CreateEntry<bool>("AlwaysOpen", true, "Casino Always Open", "Keep the casino open 24/7", false, false, (ValueValidator)null, (string)null);
			SignChangerEnabled = _generalCategory.CreateEntry<bool>("SignChanger", true, "Change Signs to 24/7", "Update casino signs to show 24/7", false, false, (ValueValidator)null, (string)null);
			FreeBetEnabled = _slotsCategory.CreateEntry<bool>("FreeBetEnabled", true, "Enable FREE Bet Option", "Add a $0 FREE bet option to slot machines", false, false, (ValueValidator)null, (string)null);
			SlotMaxBet = _slotsCategory.CreateEntry<int>("MaxBet", 100000, "Maximum Bet Amount", "Maximum bet amount for slot machines", false, false, (ValueValidator)null, (string)null);
			TableMinBet = _tableGamesCategory.CreateEntry<int>("MinBet", 1, "Minimum Bet", "Minimum bet for Blackjack and RTB", false, false, (ValueValidator)null, (string)null);
			TableMaxBet = _tableGamesCategory.CreateEntry<int>("MaxBet", 100000, "Maximum Bet", "Maximum bet for Blackjack and RTB", false, false, (ValueValidator)null, (string)null);
			AntiAbuseEnabled = _antiAbuseCategory.CreateEntry<bool>("Enabled", true, "Enable Anti-Abuse", "Enable penalties for slot machine abuse", false, false, (ValueValidator)null, (string)null);
			JackpotChance = _antiAbuseCategory.CreateEntry<float>("JackpotChance", 0.01f, "Jackpot Chance", "Base chance for jackpot (0.01 = 1%)", false, false, (ValueValidator)null, (string)null);
			BigWinChance = _antiAbuseCategory.CreateEntry<float>("BigWinChance", 0.05f, "Big Win Chance", "Base chance for big win (0.05 = 5%)", false, false, (ValueValidator)null, (string)null);
			SmallWinChance = _antiAbuseCategory.CreateEntry<float>("SmallWinChance", 0.15f, "Small Win Chance", "Base chance for small win (0.15 = 15%)", false, false, (ValueValidator)null, (string)null);
			MiniWinChance = _antiAbuseCategory.CreateEntry<float>("MiniWinChance", 0.25f, "Mini Win Chance", "Base chance for mini win (0.25 = 25%)", false, false, (ValueValidator)null, (string)null);
			WinStreakPenalty = _antiAbuseCategory.CreateEntry<float>("WinStreakPenalty", 0.15f, "Win Streak Penalty", "Chance reduction per consecutive win (0.15 = 15%)", false, false, (ValueValidator)null, (string)null);
			WinStreakThreshold = _antiAbuseCategory.CreateEntry<int>("WinStreakThreshold", 2, "Win Streak Threshold", "Number of wins before penalty applies", false, false, (ValueValidator)null, (string)null);
			MultiMachinePenalty = _antiAbuseCategory.CreateEntry<float>("MultiMachinePenalty", 0.5f, "Multi-Machine Penalty", "Chance reduction per extra machine (0.5 = 50%)", false, false, (ValueValidator)null, (string)null);
			MultiMachineTimeWindow = _antiAbuseCategory.CreateEntry<float>("MultiMachineTimeWindow", 5f, "Multi-Machine Time Window", "Seconds to track multi-machine usage", false, false, (ValueValidator)null, (string)null);
			LogSpins = _antiAbuseCategory.CreateEntry<bool>("LogSpins", false, "Log Spin Results", "Log slot spin results to console for debugging", false, false, (ValueValidator)null, (string)null);
			CasinoSafehouseEnabled = _generalCategory.CreateEntry<bool>("CasinoSafehouse", true, "Casino Safehouse", "Clear wanted status when entering the casino", false, false, (ValueValidator)null, (string)null);
			((MelonBase)Main.Instance).LoggerInstance.Msg("Settings initialized.");
			TrySubscribeToModManager();
		}

		private static void TrySubscribeToModManager()
		{
			try
			{
				_modManagerFound = MelonBase.RegisteredMelons.Any(delegate(MelonBase mod)
				{
					object obj;
					if (mod == null)
					{
						obj = null;
					}
					else
					{
						MelonInfoAttribute info = mod.Info;
						obj = ((info != null) ? info.Name : null);
					}
					return (string?)obj == "Mod Manager & Phone App";
				});
				if (_modManagerFound)
				{
					((MelonBase)Main.Instance).LoggerInstance.Msg("Mod Manager found. Subscribing to events...");
					SubscribeToModManagerEvents_Helper();
				}
				else
				{
					((MelonBase)Main.Instance).LoggerInstance.Msg("Mod Manager not found. Settings will be loaded from config file.");
				}
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Error("Error checking for Mod Manager: " + ex.Message);
				_modManagerFound = false;
			}
		}

		private static void SubscribeToModManagerEvents_Helper()
		{
			try
			{
				Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ModManager&PhoneApp");
				if (assembly == null)
				{
					((MelonBase)Main.Instance).LoggerInstance.Warning("Mod Manager assembly not found.");
					_modManagerFound = false;
					return;
				}
				Type type = assembly.GetType("ModManagerPhoneApp.ModSettingsEvents");
				if (type == null)
				{
					((MelonBase)Main.Instance).LoggerInstance.Warning("ModSettingsEvents type not found.");
					_modManagerFound = false;
					return;
				}
				EventInfo @event = type.GetEvent("OnPhonePreferencesSaved");
				EventInfo event2 = type.GetEvent("OnMenuPreferencesSaved");
				if (@event != null)
				{
					_phoneHandler = Delegate.CreateDelegate(@event.EventHandlerType, typeof(Settings).GetMethod("HandleSettingsUpdate", BindingFlags.Static | BindingFlags.NonPublic));
					@event.AddEventHandler(null, _phoneHandler);
					((MelonBase)Main.Instance).LoggerInstance.Msg("Subscribed to OnPhonePreferencesSaved.");
				}
				if (event2 != null)
				{
					_menuHandler = Delegate.CreateDelegate(event2.EventHandlerType, typeof(Settings).GetMethod("HandleSettingsUpdate", BindingFlags.Static | BindingFlags.NonPublic));
					event2.AddEventHandler(null, _menuHandler);
					((MelonBase)Main.Instance).LoggerInstance.Msg("Subscribed to OnMenuPreferencesSaved.");
				}
				_onPhoneEvent = @event;
				_onMenuEvent = event2;
				((MelonBase)Main.Instance).LoggerInstance.Msg("Successfully subscribed to Mod Manager save events.");
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Error("Error subscribing to Mod Manager events: " + ex.Message);
				_modManagerFound = false;
			}
		}

		private static void HandleSettingsUpdate()
		{
			((MelonBase)Main.Instance).LoggerInstance.Msg("Settings updated via Mod Manager. Applying changes...");
			ApplySettings();
			ConfigFile.SaveConfigFile();
		}

		public static void ApplySettings()
		{
			SlotMaxBet.Value = ClampInt(SlotMaxBet.Value, 1, 1000000, "SlotMaxBet");
			TableMinBet.Value = ClampInt(TableMinBet.Value, 1, 1000000, "TableMinBet");
			TableMaxBet.Value = ClampInt(TableMaxBet.Value, 1, 1000000, "TableMaxBet");
			JackpotChance.Value = ClampFloat(JackpotChance.Value, 0f, 1f, "JackpotChance");
			BigWinChance.Value = ClampFloat(BigWinChance.Value, 0f, 1f, "BigWinChance");
			SmallWinChance.Value = ClampFloat(SmallWinChance.Value, 0f, 1f, "SmallWinChance");
			MiniWinChance.Value = ClampFloat(MiniWinChance.Value, 0f, 1f, "MiniWinChance");
			WinStreakPenalty.Value = ClampFloat(WinStreakPenalty.Value, 0f, 1f, "WinStreakPenalty");
			WinStreakThreshold.Value = ClampInt(WinStreakThreshold.Value, 1, 100, "WinStreakThreshold");
			MultiMachinePenalty.Value = ClampFloat(MultiMachinePenalty.Value, 0f, 1f, "MultiMachinePenalty");
			MultiMachineTimeWindow.Value = ClampFloat(MultiMachineTimeWindow.Value, 1f, 60f, "MultiMachineTimeWindow");
			SlotControl.EnableAntiAbuse = AntiAbuseEnabled.Value;
			SlotControl.BaseJackpotChance = JackpotChance.Value;
			SlotControl.BaseBigWinChance = BigWinChance.Value;
			SlotControl.BaseSmallWinChance = SmallWinChance.Value;
			SlotControl.BaseMiniWinChance = MiniWinChance.Value;
			SlotControl.WinStreakPenaltyPerWin = WinStreakPenalty.Value;
			SlotControl.WinStreakThreshold = WinStreakThreshold.Value;
			SlotControl.MultiMachinePenalty = MultiMachinePenalty.Value;
			SlotControl.MultiMachineTimeWindow = MultiMachineTimeWindow.Value;
			SlotControl.LogSpins = LogSpins.Value;
			BetterSlots.TABLE_BET_MINIMUM = TableMinBet.Value;
			BetterSlots.TABLE_BET_MAXIMUM = TableMaxBet.Value;
			CasinoSafehouse.Enabled = CasinoSafehouseEnabled.Value;
			((MelonBase)Main.Instance).LoggerInstance.Msg("Settings applied successfully.");
		}

		private static int ClampInt(int value, int min, int max, string name)
		{
			if (value < min)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to minimum {min}");
				return min;
			}
			if (value > max)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to maximum {max}");
				return max;
			}
			return value;
		}

		private static float ClampFloat(float value, float min, float max, string name)
		{
			if (value < min)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to minimum {min}");
				return min;
			}
			if (value > max)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning($"{name} was {value}, clamped to maximum {max}");
				return max;
			}
			return value;
		}

		public static void Unsubscribe()
		{
			if (!_modManagerFound)
			{
				return;
			}
			try
			{
				if (_onPhoneEvent is EventInfo eventInfo && (object)_phoneHandler != null)
				{
					eventInfo.RemoveEventHandler(null, _phoneHandler);
				}
				if (_onMenuEvent is EventInfo eventInfo2 && (object)_menuHandler != null)
				{
					eventInfo2.RemoveEventHandler(null, _menuHandler);
				}
				((MelonBase)Main.Instance).LoggerInstance.Msg("Unsubscribed from Mod Manager events.");
			}
			catch (Exception ex)
			{
				((MelonBase)Main.Instance).LoggerInstance.Warning("Error during unsubscribe: " + ex.Message);
			}
		}
	}
}