Decompiled source of AtlyssCasino v1.0.1
AtlyssCasino.dll
Decompiled 10 minutes ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using AtlyssCasino.Blackjack; using AtlyssCasino.Blackjack.Netcode; using AtlyssCasino.Roulette; using AtlyssCasino.Roulette.Netcode; using BepInEx; using BepInEx.Logging; using CodeTalker; using CodeTalker.Networking; using CodeTalker.Packets; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AtlyssCasino")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AtlyssCasino")] [assembly: AssemblyTitle("AtlyssCasino")] [assembly: AssemblyVersion("1.0.0.0")] [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 AtlyssCasino { [HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")] public static class BlackjackDebugCommands { private static readonly List<GameObject> _spawnedCards = new List<GameObject>(); private static readonly FieldInfo MaxOnscreenField = typeof(ChatBehaviour).GetField("maxOnscreenMessages", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeof(ChatBehaviour).GetField("_maxOnscreenMessages", BindingFlags.Instance | BindingFlags.NonPublic); [HarmonyPrefix] public static bool Prefix(ChatBehaviour __instance, string _message) { try { if (string.IsNullOrEmpty(_message)) { return true; } if (!_message.StartsWith("/")) { return true; } string text = _message.Trim(); string[] array = text.Split(new char[1] { ' ' }, 2); string text2 = array[0].ToLower(); string args = ((array.Length > 1) ? array[1] : ""); switch (text2) { case "/spawncard": HandleSpawnCard(__instance, args); SetChatFocusFalse(__instance); return false; case "/clearcards": HandleClearCards(__instance); SetChatFocusFalse(__instance); return false; case "/deckdebug": HandleDeckDebug(__instance); SetChatFocusFalse(__instance); return false; case "/cleartable": HandleClearTable(__instance); SetChatFocusFalse(__instance); return false; default: return true; } } catch (Exception ex) { Plugin.Log.LogError((object)("[BJ-Debug] Command error: " + ex.Message)); return true; } } private static void HandleSpawnCard(ChatBehaviour chat, string args) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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) if ((Object)(object)Plugin.AssetsBundle == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> Assets bundle not loaded."); return; } if (string.IsNullOrWhiteSpace(args)) { SendLocalMessage(chat, "<color=#FFD700>[BJ-Debug]</color> Usage: /spawncard {suit}_{rank}"); return; } string text = NormalizeCardName(args.Trim()); string text2 = "Deck06_" + text; GameObject val = Plugin.AssetsBundle.LoadAsset<GameObject>(text2); if ((Object)(object)val == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> Card prefab not found: " + text2); return; } Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> Player not found."); return; } Vector3 val2 = ((Component)mainPlayer).transform.position + ((Component)mainPlayer).transform.forward * 2f + Vector3.up * 1.2f; Quaternion val3 = Quaternion.LookRotation(-((Component)mainPlayer).transform.forward); GameObject val4 = Object.Instantiate<GameObject>(val, val2, val3); ((Object)val4).name = "DebugCard_" + text; CardVisual cardVisual = val4.AddComponent<CardVisual>(); cardVisual.Init(null, faceUp: true); _spawnedCards.Add(val4); SendLocalMessage(chat, "<color=#FFD700>[BJ-Debug]</color> Spawned: " + text2); } private static void HandleClearCards(ChatBehaviour chat) { int num = 0; foreach (GameObject spawnedCard in _spawnedCards) { if ((Object)(object)spawnedCard != (Object)null) { Object.Destroy((Object)(object)spawnedCard); num++; } } _spawnedCards.Clear(); SendLocalMessage(chat, $"<color=#FFD700>[BJ-Debug]</color> Cleared {num} loose card(s)."); } private static void HandleDeckDebug(ChatBehaviour chat) { try { Deck deck = new Deck(); int count = deck.Count; if (count != 52) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> [FAIL] " + $"Fresh deck has {count} cards, expected 52."); return; } deck.Shuffle(); List<Card> list = new List<Card>(52); HashSet<string> hashSet = new HashSet<string>(); List<string> list2 = new List<string>(); while (!deck.IsEmpty) { Card card = deck.Draw(); list.Add(card); string item = $"{card.Suit}_{card.Rank}"; if (!hashSet.Add(item)) { list2.Add(item); } } SendLocalMessage(chat, $"<color=#FFD700>[BJ-Debug]</color> Drew {list.Count}, unique {hashSet.Count}, dupes {list2.Count}."); bool flag = list.Count == 52 && hashSet.Count == 52 && list2.Count == 0; SendLocalMessage(chat, flag ? "<color=#66FF66>[BJ-Debug]</color> [PASS] 52 unique cards." : "<color=#FF6666>[BJ-Debug]</color> [FAIL] deck invariants broken."); bool flag2 = false; try { deck.Draw(); } catch (InvalidOperationException) { flag2 = true; } SendLocalMessage(chat, "<color=#FFD700>[BJ-Debug]</color> Empty-draw: " + (flag2 ? "PASS" : "FAIL")); deck.ReshuffleAll(); SendLocalMessage(chat, $"<color=#FFD700>[BJ-Debug]</color> ReshuffleAll count: {deck.Count}"); } catch (Exception ex2) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> Deck test crashed: " + ex2.Message); } } private static void HandleClearTable(ChatBehaviour chat) { BlackjackTable blackjackTable = FindLocalPlayerTable(); if ((Object)(object)blackjackTable == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[BJ-Debug]</color> You must be seated."); return; } blackjackTable.ClearAllHands(); SendLocalMessage(chat, "<color=#FFD700>[BJ-Debug]</color> Table cleared."); } private static BlackjackTable? FindLocalPlayerTable() { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return null; } BlackjackTable[] array = Object.FindObjectsOfType<BlackjackTable>(); BlackjackTable[] array2 = array; foreach (BlackjackTable blackjackTable in array2) { if (blackjackTable.GetSeatForPlayer(mainPlayer) >= 0) { return blackjackTable; } } return null; } private static string NormalizeCardName(string input) { if (string.IsNullOrEmpty(input)) { return input; } string[] array = input.Split('_'); if (array.Length != 2) { return input; } string text = array[0]; string text2 = array[1]; if (text.Length >= 1) { text = char.ToUpper(text[0]) + text.Substring(1).ToLower(); } text2 = text2.ToUpper(); return text + "_" + text2; } private static void SendLocalMessage(ChatBehaviour chat, string message) { try { if (MaxOnscreenField != null) { try { MaxOnscreenField.SetValue(chat, 50); } catch { } } chat.Init_GameLogicMessage(message); } catch (Exception ex) { Plugin.Log.LogError((object)("[BJ-Debug] Chat failed: " + ex.Message)); } } private static void SetChatFocusFalse(ChatBehaviour chat) { try { typeof(ChatBehaviour).GetField("_focusedInChat", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(chat, false); } catch { } } } public static class BlackjackSceneWatcher { private const string CASINO_SCENE_NAME = "AtlyssCasino"; private static bool _wasInCasino; public static void Init() { SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; SceneManager.activeSceneChanged += OnActiveSceneChanged; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (((Scene)(ref scene)).name == "AtlyssCasino") { _wasInCasino = true; Plugin.Log.LogInfo((object)"[SceneWatcher] Entered casino scene."); } } private static void OnSceneUnloaded(Scene scene) { if (((Scene)(ref scene)).name == "AtlyssCasino" && _wasInCasino) { Plugin.Log.LogInfo((object)"[SceneWatcher] Casino scene unloaded — running cleanup."); CleanupOnLeave(); _wasInCasino = false; } } private static void OnActiveSceneChanged(Scene oldScene, Scene newScene) { if (_wasInCasino && ((Scene)(ref oldScene)).name == "AtlyssCasino" && ((Scene)(ref newScene)).name != "AtlyssCasino") { Plugin.Log.LogInfo((object)("[SceneWatcher] Active scene changed away from casino (" + ((Scene)(ref oldScene)).name + " -> " + ((Scene)(ref newScene)).name + ") — running cleanup.")); CleanupOnLeave(); _wasInCasino = false; } } private static void CleanupOnLeave() { try { ReleaseAnySeatedTable(); DestroyStrayCards(); Plugin.HasSetBlackjackBet = false; } catch (Exception ex) { Plugin.Log.LogError((object)("[SceneWatcher] Cleanup failed: " + ex.Message)); } } private static void ReleaseAnySeatedTable() { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { Plugin.Log.LogInfo((object)"[SceneWatcher] No local player — skipping seat release."); return; } BlackjackTable[] array = Object.FindObjectsOfType<BlackjackTable>(); BlackjackTable[] array2 = array; foreach (BlackjackTable blackjackTable in array2) { int seatForPlayer = blackjackTable.GetSeatForPlayer(mainPlayer); if (seatForPlayer >= 0) { string name = ((Object)blackjackTable).name; if (BJNetcode.AmHost()) { blackjackTable.ReleaseSeat(seatForPlayer); int hostSeatIndex = blackjackTable.HostSeatIndex; BJNetcode.BroadcastSeatReleased(name, seatForPlayer, hostSeatIndex); Plugin.Log.LogInfo((object)$"[SceneWatcher] Auto-released host seat {seatForPlayer} at '{name}'."); } else { BJNetcode.SendReleaseSeatRequest(name); blackjackTable.ApplySeatReleased(seatForPlayer, blackjackTable.HostSeatIndex); Plugin.Log.LogInfo((object)($"[SceneWatcher] Auto-released client seat {seatForPlayer} at '{name}' " + "(request sent + local mirror).")); } } } } private static void DestroyStrayCards() { CardVisual[] array = Object.FindObjectsOfType<CardVisual>(); int num = 0; CardVisual[] array2 = array; foreach (CardVisual cardVisual in array2) { if (!((Object)(object)cardVisual == (Object)null) && !((Object)(object)((Component)cardVisual).gameObject == (Object)null)) { Object.Destroy((Object)(object)((Component)cardVisual).gameObject); num++; } } if (num > 0) { Plugin.Log.LogInfo((object)$"[SceneWatcher] Destroyed {num} stray card object(s)."); } } } public class CasinoEntryFee : MonoBehaviour { [CompilerGenerated] private sealed class <BootPlayerToSanctum>d__16 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <BootPlayerToSanctum>d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1.5f); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = ((MonoBehaviour)Plugin.Instance).StartCoroutine(CasinoExitTrigger.ForceReturnToSanctum(player, "[EntryFee]")); <>1__state = 2; return true; case 2: <>1__state = -1; 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(); } } [CompilerGenerated] private sealed class <ShowBrokeMessageDelayed>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private int <i>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowBrokeMessageDelayed>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3.5f); <>1__state = 1; return true; case 1: <>1__state = -1; <i>5__1 = 0; break; case 2: <>1__state = -1; <i>5__1++; break; } if (<i>5__1 < 3) { try { ErrorPromptTextManager.current.Init_ErrorPrompt("Come back when you're a little... mmm... richer!"); } catch { } <>2__current = (object)new WaitForSeconds(3.8f); <>1__state = 2; return true; } Plugin.Log.LogInfo((object)"[EntryFee] Broke message shown."); 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(); } } public const int ENTRY_FEE = 100; private const float MESSAGE_DELAY = 3.5f; private const float MESSAGE_REPEAT_INTERVAL = 3.8f; private const int MESSAGE_REPEAT_COUNT = 3; private const string BROKE_MESSAGE = "Come back when you're a little... mmm... richer!"; private static readonly HashSet<ulong> _paidPlayers = new HashSet<ulong>(); private static bool _pendingBrokeMessage = false; private static bool _isBooting = false; private BoxCollider? _collider; private bool _playerWasInside = false; private void Awake() { _collider = ((Component)this).GetComponent<BoxCollider>(); _paidPlayers.Clear(); _pendingBrokeMessage = false; _isBooting = false; SceneManager.sceneUnloaded += OnSceneUnloaded; SceneManager.sceneLoaded += OnSceneLoaded; Plugin.Log.LogInfo((object)$"[EntryFee] Entry fee trigger active. Fee: {100} Crowns."); } private void OnDestroy() { SceneManager.sceneUnloaded -= OnSceneUnloaded; SceneManager.sceneLoaded -= OnSceneLoaded; } private static void OnSceneUnloaded(Scene scene) { if (!(((Scene)(ref scene)).name != "AtlyssCasino")) { _paidPlayers.Clear(); _pendingBrokeMessage = false; _isBooting = false; Plugin.Log.LogInfo((object)"[EntryFee] Casino unloaded — paid list cleared."); } } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (_pendingBrokeMessage && !(((Scene)(ref scene)).name == "AtlyssCasino")) { _pendingBrokeMessage = false; ((MonoBehaviour)Plugin.Instance).StartCoroutine(ShowBrokeMessageDelayed()); } } private void Update() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_collider == (Object)null || _isBooting) { return; } Player mainPlayer = Player._mainPlayer; if (!((Object)(object)mainPlayer == (Object)null)) { Bounds bounds = ((Collider)_collider).bounds; bool flag = ((Bounds)(ref bounds)).Contains(((Component)mainPlayer).transform.position); if (flag && !_playerWasInside) { HandlePlayerEntered(mainPlayer); } _playerWasInside = flag; } } private void HandlePlayerEntered(Player player) { ulong steam = GetSteam64(player); if (_paidPlayers.Contains(steam)) { Plugin.Log.LogInfo((object)"[EntryFee] Player already paid — welcome back."); return; } PlayerInventory component = ((Component)player).GetComponent<PlayerInventory>(); if (!((Object)(object)component == (Object)null)) { if (component._heldCurrency < 100) { ErrorPromptTextManager.current.Init_ErrorPrompt($"You need at least {100} Crowns to enter!"); Plugin.Log.LogInfo((object)($"[EntryFee] Player {steam} has {component._heldCurrency} Crowns " + "— insufficient. Sending back to Sanctum.")); _isBooting = true; _pendingBrokeMessage = true; ((MonoBehaviour)this).StartCoroutine(BootPlayerToSanctum(player)); } else { component.Network_heldCurrency -= 100; _paidPlayers.Add(steam); ErrorPromptTextManager.current.Init_ErrorPrompt("Welcome to AtlyssCasino! " + $"{100} Crown entry fee charged. Good luck!"); Plugin.Log.LogInfo((object)($"[EntryFee] Player {steam} paid {100} Crowns. " + $"Balance: {component.Network_heldCurrency}.")); } } } [IteratorStateMachine(typeof(<BootPlayerToSanctum>d__16))] private static IEnumerator BootPlayerToSanctum(Player player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <BootPlayerToSanctum>d__16(0) { player = player }; } [IteratorStateMachine(typeof(<ShowBrokeMessageDelayed>d__17))] private static IEnumerator ShowBrokeMessageDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowBrokeMessageDelayed>d__17(0); } private static void TeleportToStartPoint(Player player) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) GameObject[] array = GameObject.FindGameObjectsWithTag("spawnPoint"); GameObject[] array2 = array; foreach (GameObject val in array2) { if (((Object)val).name.Contains("startPoint")) { ((Component)player).transform.position = val.transform.position; break; } } } private static ulong GetSteam64(Player player) { if (ulong.TryParse(player.Network_steamID, out var result)) { return result; } return BJNetcode.GetLocalSteam64(); } } public static class CasinoPatch { [CompilerGenerated] private sealed class <SetupDelayed>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private GameObject[] <allObjects>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SetupDelayed>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <allObjects>5__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = null; <>1__state = 2; return true; case 2: { <>1__state = -1; _overlayShader = Shader.Find("Unlit/Texture"); if ((Object)(object)_overlayShader == (Object)null) { _overlayShader = Shader.Find("Standard"); } ManualLogSource log = Plugin.Log; Shader? overlayShader = _overlayShader; log.LogInfo((object)("[Casino] Overlay shader: " + (((overlayShader != null) ? ((Object)overlayShader).name : null) ?? "NULL"))); <allObjects>5__1 = Object.FindObjectsOfType<GameObject>(); HookSlotMachines(<allObjects>5__1); HookBlackjackTables(<allObjects>5__1); HookRouletteTables(<allObjects>5__1); HookEntryFee(); HookExitTrigger(); 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 Shader? _overlayShader; public static void Init() { SceneManager.sceneLoaded += OnSceneLoaded; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (!(((Scene)(ref scene)).name != "AtlyssCasino")) { Plugin.Log.LogInfo((object)"[Casino] Casino scene loaded!"); ((MonoBehaviour)Plugin.Instance).StartCoroutine(SetupDelayed()); } } [IteratorStateMachine(typeof(<SetupDelayed>d__3))] private static IEnumerator SetupDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SetupDelayed>d__3(0); } private static void HookSlotMachines(GameObject[] allObjects) { int num = 0; foreach (GameObject val in allObjects) { if (((Object)val).name != "SlotBet_Confirm") { continue; } Transform parent = val.transform.parent; GameObject val2 = ((parent != null) ? ((Component)parent).gameObject : null); if (!((Object)(object)val2 == (Object)null)) { ((Object)val2).name = $"SlotMachine_{num}"; num++; SlotMachine slotMachine = val2.GetComponent<SlotMachine>() ?? val2.AddComponent<SlotMachine>(); slotMachine.MatIdle = MakeMat("idle"); slotMachine.MatIdleBlank = MakeMat("idle_blank"); slotMachine.MatWin = MakeMat("win"); slotMachine.MatJackpot = MakeMat("jackpot"); slotMachine.MatCherry = MakeMat("cherry"); slotMachine.MatLemon = MakeMat("lemon"); slotMachine.MatOrange = MakeMat("orange"); slotMachine.MatStar = MakeMat("star"); slotMachine.MatDiamond = MakeMat("diamond"); slotMachine.MatSeven = MakeMat("seven"); slotMachine.Init(); SlotBetConfirm slotBetConfirm = val.GetComponent<SlotBetConfirm>() ?? val.AddComponent<SlotBetConfirm>(); slotBetConfirm.Setup(slotMachine); Transform val3 = val2.transform.Find("SlotBet_Selector"); if ((Object)(object)val3 != (Object)null) { Plugin.Log.LogInfo((object)"[Casino] Removing leftover SlotBet_Selector from old prefab instance."); Object.Destroy((Object)(object)((Component)val3).gameObject); } } } Plugin.Log.LogInfo((object)$"[Casino] Hooked {num} slot machine(s)."); } private static void HookBlackjackTables(GameObject[] allObjects) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (GameObject val in allObjects) { if (!((Object)val).name.StartsWith("Blackjack Table") || !HasAnyBlackjackWiring(val.transform)) { continue; } num++; BlackjackTable blackjackTable = val.GetComponent<BlackjackTable>() ?? val.AddComponent<BlackjackTable>(); int num5 = 0; Dictionary<int, BlackjackSeatTrigger> dictionary = new Dictionary<int, BlackjackSeatTrigger>(); Dictionary<int, Transform> dictionary2 = new Dictionary<int, Transform>(); foreach (Transform item in val.transform) { Transform val2 = item; string text = ((Object)val2).name.Trim(); if (text == "DealerAnchor") { blackjackTable.SetDealerAnchor(val2); num5++; continue; } int num6 = ParseIndexedName(text, "SeatAnchor"); if (num6 >= 0) { if (num6 >= 5) { Plugin.Log.LogWarning((object)($"[Casino] '{text}' index {num6} " + ">= MAX_PLAYERS; skipping.")); continue; } blackjackTable.SetSeatAnchor(num6, val2); num5++; continue; } int num7 = ParseIndexedName(text, "SeatTrigger"); if (num7 >= 0) { if (num7 >= 5) { Plugin.Log.LogWarning((object)($"[Casino] '{text}' index {num7} " + ">= MAX_PLAYERS; skipping.")); continue; } BlackjackSeatTrigger blackjackSeatTrigger = ((Component)val2).gameObject.GetComponent<BlackjackSeatTrigger>() ?? ((Component)val2).gameObject.AddComponent<BlackjackSeatTrigger>(); blackjackSeatTrigger.Setup(blackjackTable, num7); dictionary[num7] = blackjackSeatTrigger; continue; } int num8 = ParseIndexedName(text, "Stool"); if (num8 >= 0) { if (num8 >= 5) { Plugin.Log.LogWarning((object)($"[Casino] '{text}' index {num8} " + ">= MAX_PLAYERS; skipping.")); } else { dictionary2[num8] = val2; } } } int count = dictionary.Count; int num9 = 0; foreach (KeyValuePair<int, BlackjackSeatTrigger> item2 in dictionary) { if (dictionary2.TryGetValue(item2.Key, out var value)) { item2.Value.SetStool(value); num9++; } else { Plugin.Log.LogInfo((object)($"[Casino] No Stool with index {item2.Key} on " + "'" + ((Object)val).name + "' — seat color won't change.")); } } Plugin.Log.LogInfo((object)("[Casino] Hooked Blackjack table '" + ((Object)val).name + "' — " + $"{count} trigger(s), " + $"{num5} anchor(s), " + $"{num9} stool(s).")); num2 += count; num3 += num5; num4 += num9; } Plugin.Log.LogInfo((object)($"[Casino] Hooked {num} blackjack table(s), " + $"{num2} trigger(s), {num3} anchor(s), " + $"{num4} stool(s).")); } private static bool HasAnyBlackjackWiring(Transform parent) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; string text = ((Object)val).name.Trim(); if (text == "DealerAnchor") { return true; } if (ParseIndexedName(text, "SeatAnchor") >= 0) { return true; } if (ParseIndexedName(text, "SeatTrigger") >= 0) { return true; } } return false; } private static void HookRouletteTables(GameObject[] allObjects) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (GameObject val in allObjects) { if (((Object)val).name.StartsWith("Roulette Table") && (!((Object)(object)val.transform.parent != (Object)null) || !((Object)val.transform.parent).name.StartsWith("Roulette Table"))) { num++; RouletteTable rouletteTable = val.GetComponent<RouletteTable>() ?? val.AddComponent<RouletteTable>(); rouletteTable.Init(); Transform val2 = val.transform.Find("RouletteTrigger"); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("[Casino] Roulette table '" + ((Object)val).name + "' has no 'RouletteTrigger' child — players won't be able to join. Add an empty child GameObject named 'RouletteTrigger' in Unity.")); continue; } RouletteTrigger rouletteTrigger = ((Component)val2).gameObject.GetComponent<RouletteTrigger>() ?? ((Component)val2).gameObject.AddComponent<RouletteTrigger>(); rouletteTrigger.Setup(rouletteTable); Plugin.Log.LogInfo((object)("[Casino] Hooked roulette table '" + ((Object)val).name + "' " + $"with trigger at {val2.position}.")); } } Plugin.Log.LogInfo((object)$"[Casino] Hooked {num} roulette table(s)."); } private static void HookEntryFee() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("EntryFeeTrigger"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[Casino] No 'EntryFeeTrigger' GameObject found in scene. Add an empty GameObject with that name and a Box Collider (Is Trigger checked) near the casino entrance."); return; } if ((Object)(object)val.GetComponent<CasinoEntryFee>() == (Object)null) { val.AddComponent<CasinoEntryFee>(); } Plugin.Log.LogInfo((object)("[Casino] Entry fee trigger hooked at " + $"{val.transform.position}.")); } private static void HookExitTrigger() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("ExitTrigger"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[Casino] No 'ExitTrigger' GameObject found in scene. Add an empty GameObject named 'ExitTrigger' with a Box Collider (Is Trigger checked) near the exit."); return; } if ((Object)(object)val.GetComponent<CasinoExitTrigger>() == (Object)null) { val.AddComponent<CasinoExitTrigger>(); } Plugin.Log.LogInfo((object)("[Casino] Exit trigger hooked at " + $"{val.transform.position}.")); } private static int ParseIndexedName(string name, string prefix) { if (name == prefix) { return 0; } string text = prefix + " ("; if (!name.StartsWith(text)) { return -1; } if (!name.EndsWith(")")) { return -1; } int length = text.Length; int num = name.Length - text.Length - ")".Length; if (num <= 0) { return -1; } string s = name.Substring(length, num); if (!int.TryParse(s, out var result)) { return -1; } return result; } private static Material? MakeMat(string textureName) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.AssetsBundle == (Object)null) { Plugin.Log.LogWarning((object)"[Casino] AssetsBundle is null."); return null; } Texture2D val = Plugin.AssetsBundle.LoadAsset<Texture2D>(textureName); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("[Casino] Texture not found: " + textureName)); return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; if ((Object)(object)_overlayShader == (Object)null) { Plugin.Log.LogError((object)"[Casino] No shader available for overlay!"); return null; } Material val2 = new Material(_overlayShader) { name = "SlotMat_Runtime_" + textureName, mainTexture = (Texture)(object)val }; val2.mainTextureScale = Vector2.one; val2.mainTextureOffset = Vector2.zero; return val2; } } [HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")] public static class CommandHandler { private static readonly FieldInfo? MaxOnscreenField = typeof(ChatBehaviour).GetField("maxOnscreenMessages", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeof(ChatBehaviour).GetField("_maxOnscreenMessages", BindingFlags.Instance | BindingFlags.NonPublic); [HarmonyPrefix] public static bool Prefix(ChatBehaviour __instance, string _message) { try { if (string.IsNullOrEmpty(_message)) { return true; } if (!_message.StartsWith("/")) { return true; } string text = _message.Trim(); string[] array = text.Split(new char[1] { ' ' }, 2); string text2 = array[0].ToLower(); string args = ((array.Length > 1) ? array[1] : ""); switch (text2) { case "/slotbet": HandleSlotBet(__instance, args); SetChatFocusFalse(__instance); return false; case "/blackjackbet": case "/bjbet": HandleBlackjackBet(__instance, args); SetChatFocusFalse(__instance); return false; case "/ready": HandleReady(__instance); SetChatFocusFalse(__instance); return false; case "/start": HandleStart(__instance); SetChatFocusFalse(__instance); return false; case "/hit": HandleHit(__instance); SetChatFocusFalse(__instance); return false; case "/stand": HandleStand(__instance); SetChatFocusFalse(__instance); return false; case "/leave": HandleLeave(__instance); SetChatFocusFalse(__instance); return false; case "/tbet": HandleRouletteBet(__instance, args); SetChatFocusFalse(__instance); return false; case "/rbet": HandleRBet(__instance, args); SetChatFocusFalse(__instance); return false; case "/rclearbets": HandleRClearBets(__instance); SetChatFocusFalse(__instance); return false; case "/rstandby": HandleRReady(__instance); SetChatFocusFalse(__instance); return false; case "/rspin": HandleRSpin(__instance); SetChatFocusFalse(__instance); return false; case "/rleave": HandleRLeave(__instance); SetChatFocusFalse(__instance); return false; case "/casinohelp": HandleCasinoHelp(__instance); SetChatFocusFalse(__instance); return false; default: return true; } } catch (Exception ex) { Plugin.Log.LogError((object)("[Casino] Chat command error: " + ex.Message)); return true; } } private static void HandleSlotBet(ChatBehaviour chat, string args) { int result; if (string.IsNullOrWhiteSpace(args)) { if (Plugin.HasSetBet) { SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Current slot bet: " + $"<color=#FFFFFF>{Plugin.CurrentBet}</color> Crowns. " + "Usage: /slotbet <amount>"); return; } string text = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> No slot bet set yet. Usage: /slotbet <amount> — allowed: " + text); } else if (!int.TryParse(args.Trim(), out result)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Invalid amount '" + args + "'. Use a number."); } else if (!IsAllowedBet(result)) { string arg = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, $"<color=#FF6666>[Casino]</color> Bet {result} not allowed. Choose: {arg}"); } else { Plugin.CurrentBet = result; Plugin.HasSetBet = true; Plugin.Log.LogInfo((object)$"[Casino] Slot bet set to {result} via chat."); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Slot bet set to " + $"<color=#FFFFFF>{result}</color> Crowns."); } } private static void HandleBlackjackBet(ChatBehaviour chat, string args) { int result; if (string.IsNullOrWhiteSpace(args)) { if (Plugin.HasSetBlackjackBet) { SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Current blackjack bet: " + $"<color=#FFFFFF>{Plugin.BlackjackBet}</color> Crowns."); return; } string text = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> No blackjack bet set. Usage: /blackjackbet <amount> — allowed: " + text + ". Required before claiming a seat."); } else if (IsLocalPlayerSeatedAtAnyBlackjackTable()) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Can't change bet while seated. Use /leave first."); } else if (!int.TryParse(args.Trim(), out result)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Invalid amount '" + args + "'. Use a number."); } else if (!IsAllowedBet(result)) { string arg = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, $"<color=#FF6666>[Casino]</color> Bet {result} not allowed. Choose: {arg}"); } else { Plugin.BlackjackBet = result; Plugin.HasSetBlackjackBet = true; Plugin.Log.LogInfo((object)$"[Casino] Blackjack bet set to {result} via chat."); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Blackjack bet set to " + $"<color=#FFFFFF>{result}</color> Crowns. " + "Press F at a seat trigger to claim your spot."); } } private static void HandleReady(ChatBehaviour chat) { var (blackjackTable, num) = FindLocalSeat(); if ((Object)(object)blackjackTable == (Object)null || num < 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You must be seated at a blackjack table."); return; } if (blackjackTable.RoundInProgress) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Round in progress — can't change ready state."); return; } bool flag = blackjackTable.IsPlayerReady(num); bool flag2 = !flag; if (flag2) { int bet = blackjackTable.Hands[num].Bet; int localCrownBalance = GetLocalCrownBalance(); if (localCrownBalance < bet) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You can't afford your bet " + $"({localCrownBalance} < {bet}). Use /leave and /blackjackbet to lower it."); return; } } if (BJNetcode.AmHost()) { blackjackTable.SetPlayerReady(num, flag2); BJNetcode.BroadcastReadyChanged(((Object)blackjackTable).name, num, flag2); SendLocalMessage(chat, $"<color=#FFD700>[Casino]</color> Seat {num + 1}: " + (flag2 ? "<color=#66FF66>READY</color>" : "<color=#CCCCCC>not ready</color>") + ". " + ReadyCountSummary(blackjackTable)); } else { BJNetcode.SendReadyToggleRequest(((Object)blackjackTable).name, flag2); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Ready " + (flag2 ? "ON" : "OFF") + " request sent to host..."); } } private static void HandleStart(ChatBehaviour chat) { var (blackjackTable, num) = FindLocalSeat(); if ((Object)(object)blackjackTable == (Object)null || num < 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You must be seated to /start."); return; } if (!blackjackTable.IsHost(num)) { Player hostPlayer = blackjackTable.GetHostPlayer(); string text = (((Object)(object)hostPlayer == (Object)null) ? "(none)" : $"seat {blackjackTable.HostSeatIndex + 1}"); SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Only the host (" + text + ") can /start."); return; } if (blackjackTable.RoundInProgress) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Round already in progress."); return; } if (!blackjackTable.AllSeatedPlayersReady) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Not all seated players are /ready."); return; } if (!BJNetcode.AmHost()) { BJNetcode.SendStartRoundRequest(((Object)blackjackTable).name); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> /start request sent to lobby host..."); return; } BlackjackTable.StartRoundResult startRoundResult = blackjackTable.StartRound(); if (startRoundResult.KickedSeats != null && startRoundResult.KickedSeats.Count > 0) { foreach (int kickedSeat in startRoundResult.KickedSeats) { SendLocalMessage(chat, $"<color=#FF6666>[Casino]</color> Seat {kickedSeat + 1} auto-left (couldn't afford bet)."); } } if (!startRoundResult.Success) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Could not start: " + startRoundResult.Reason); return; } SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Round started. " + $"Seat {startRoundResult.FirstTurnSeat + 1}'s turn."); ShowLocalHandPrompt(blackjackTable, finalView: false); if (!blackjackTable.RoundInProgress) { ShowLocalHandPrompt(blackjackTable, finalView: true); } } private static void HandleHit(ChatBehaviour chat) { var (blackjackTable, num) = FindLocalSeat(); if ((Object)(object)blackjackTable == (Object)null || num < 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You must be seated to /hit."); return; } if (!BJNetcode.AmHost()) { BJNetcode.SendHitRequest(((Object)blackjackTable).name); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> /hit request sent..."); return; } BlackjackTable.HitResult hitResult = blackjackTable.PlayerHit(num); if (!hitResult.Success) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + hitResult.Reason); return; } BlackjackHand blackjackHand = blackjackTable.Hands[num]; SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Hit: " + blackjackHand.Describe()); ShowLocalHandPrompt(blackjackTable, hitResult.RoundResolved); if (hitResult.AutoStood && !hitResult.RoundResolved) { SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> " + (hitResult.Busted ? "Busted — turn ends." : "21 — turn ends.") + ((hitResult.NextTurnSeat >= 0) ? $" Seat {hitResult.NextTurnSeat + 1}'s turn." : "")); } } private static void HandleStand(ChatBehaviour chat) { var (blackjackTable, num) = FindLocalSeat(); if ((Object)(object)blackjackTable == (Object)null || num < 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You must be seated to /stand."); return; } if (!BJNetcode.AmHost()) { BJNetcode.SendStandRequest(((Object)blackjackTable).name); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> /stand request sent..."); return; } BlackjackTable.StandResult standResult = blackjackTable.PlayerStand(num); if (!standResult.Success) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + standResult.Reason); return; } SendLocalMessage(chat, $"<color=#FFD700>[Casino]</color> Stood on {blackjackTable.Hands[num].BestValue}."); ShowLocalHandPrompt(blackjackTable, standResult.RoundResolved); if (!standResult.RoundResolved && standResult.NextTurnSeat >= 0) { SendLocalMessage(chat, $"<color=#FFD700>[Casino]</color> Seat {standResult.NextTurnSeat + 1}'s turn."); } } private static void HandleLeave(ChatBehaviour chat) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Player not found."); return; } BlackjackTable[] array = Object.FindObjectsOfType<BlackjackTable>(); BlackjackTable[] array2 = array; foreach (BlackjackTable blackjackTable in array2) { int seatForPlayer = blackjackTable.GetSeatForPlayer(mainPlayer); if (seatForPlayer >= 0) { if (BJNetcode.AmHost()) { blackjackTable.ReleaseSeat(seatForPlayer); int hostSeatIndex = blackjackTable.HostSeatIndex; BJNetcode.BroadcastSeatReleased(((Object)blackjackTable).name, seatForPlayer, hostSeatIndex); Plugin.HasSetBlackjackBet = false; SendLocalMessage(chat, $"<color=#FFD700>[Casino]</color> Left seat {seatForPlayer + 1}. " + "Bet cleared — /blackjackbet to set a new one."); } else { BJNetcode.SendReleaseSeatRequest(((Object)blackjackTable).name); Plugin.HasSetBlackjackBet = false; SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Leave request sent " + $"for seat {seatForPlayer + 1}. Bet cleared — /blackjackbet to set a new one."); } return; } } SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> You're not seated at any blackjack table."); } private static void HandleRouletteBet(ChatBehaviour chat, string args) { if (string.IsNullOrWhiteSpace(args)) { if (Plugin.HasSetRouletteBet) { SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Current roulette bet amount: " + $"<color=#FFFFFF>{Plugin.RouletteBet}</color> Crowns per /rbet. " + "Usage: /tbet <amount>"); return; } string text = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> No roulette bet amount set. Usage: /tbet <amount> — allowed: " + text + ". Required before joining the table."); return; } if (!int.TryParse(args.Trim(), out var result)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Invalid amount '" + args + "'. Use a number."); return; } if (!IsAllowedBet(result)) { string arg = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, $"<color=#FF6666>[Casino]</color> Bet {result} not allowed. Choose: {arg}"); return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable != (Object)null) { List<PlacedBet> betsForPlayer = rouletteTable.GetBetsForPlayer(Player._mainPlayer); if (betsForPlayer.Count > 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Clear your bets first with /rclearbets before changing your bet amount."); return; } } Plugin.RouletteBet = result; Plugin.HasSetRouletteBet = true; Plugin.Log.LogInfo((object)$"[Casino] Roulette bet set to {result} via chat."); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Roulette bet amount set to " + $"<color=#FFFFFF>{result}</color> Crowns per /rbet. " + "Walk up to the table and press F to join."); } private static void HandleRBet(ChatBehaviour chat, string args) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You are not at a roulette table. Walk up and press F to join."); return; } if (!Plugin.HasSetRouletteBet) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Set a bet amount first: /tbet <amount>"); return; } if (!RouletteLogic.TryParseBet(args, out BetType betType, out int betTarget, out string errorMsg)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + errorMsg); return; } if (BJNetcode.AmHost()) { if (!rouletteTable.TryPlaceBet(mainPlayer, betType, betTarget, Plugin.RouletteBet, out string errorMsg2)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + errorMsg2); return; } RNNetcode.BroadcastBetPlaced(((Object)rouletteTable).name, BJNetcode.GetLocalSteam64(), betType, betTarget, Plugin.RouletteBet); } else { RNNetcode.SendPlaceBetRequest(((Object)rouletteTable).name, betType, betTarget, Plugin.RouletteBet); } string text = RouletteLogic.DescribeBet(betType, betTarget); List<PlacedBet> betsForPlayer = rouletteTable.GetBetsForPlayer(mainPlayer); string text2 = RouletteLogic.FormatBetSummary(betsForPlayer); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Bet placed: " + $"<color=#FFFFFF>{Plugin.RouletteBet}</color> on {text}. " + "All bets: " + text2); Plugin.Log.LogInfo((object)$"[Casino] /rbet {text} {Plugin.RouletteBet} crowns."); } private static void HandleRClearBets(ChatBehaviour chat) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You are not at a roulette table."); return; } if (BJNetcode.AmHost()) { if (!rouletteTable.TryClearBets(mainPlayer, out string errorMsg)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + errorMsg); return; } RNNetcode.BroadcastBetsCleared(((Object)rouletteTable).name, BJNetcode.GetLocalSteam64()); } else { RNNetcode.SendClearBetsRequest(((Object)rouletteTable).name); } SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> All bets cleared and refunded."); } private static void HandleRReady(ChatBehaviour chat) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You are not at a roulette table. Walk up and press F to join."); return; } bool flag = rouletteTable.IsPlayerReady(mainPlayer); bool flag2 = !flag; if (flag2 && rouletteTable.GetBetsForPlayer(mainPlayer).Count == 0) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> Place at least one bet first. Use /rbet <type> [number]."); return; } if (BJNetcode.AmHost()) { if (!rouletteTable.TrySetReady(mainPlayer, flag2, out string errorMsg)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + errorMsg); return; } RNNetcode.BroadcastReadyChanged(((Object)rouletteTable).name, BJNetcode.GetLocalSteam64(), flag2); } else { RNNetcode.SendReadyToggleRequest(((Object)rouletteTable).name, flag2); } string text = (flag2 ? "<color=#66FF66>READY</color>" : "<color=#CCCCCC>not ready</color>"); string text2 = ((rouletteTable.IsTableHost(mainPlayer) && flag2 && rouletteTable.AllPlayersReady()) ? " All players ready — use /rspin to spin the wheel!" : ((rouletteTable.IsTableHost(mainPlayer) && flag2) ? " Waiting for other players to /rstandby." : (flag2 ? " Waiting for host to /rspin." : ""))); SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> You are " + text + "." + text2); } private static void HandleRSpin(ChatBehaviour chat) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable == (Object)null) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> You are not at a roulette table."); } else if (BJNetcode.AmHost()) { if (!rouletteTable.TryStartSpin(mainPlayer, out string errorMsg)) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> " + errorMsg); } } else { RNNetcode.SendSpinRequest(((Object)rouletteTable).name); } } private static void HandleRLeave(ChatBehaviour chat) { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } RouletteTable rouletteTable = FindLocalRouletteTable(); if ((Object)(object)rouletteTable == (Object)null) { SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> You are not at a roulette table."); return; } if (rouletteTable.IsSpinning) { SendLocalMessage(chat, "<color=#FF6666>[Casino]</color> The wheel is spinning — wait for the round to finish before leaving."); return; } if (BJNetcode.AmHost()) { ulong localSteam = BJNetcode.GetLocalSteam64(); rouletteTable.Leave(mainPlayer); RNNetcode.BroadcastPlayerLeft(((Object)rouletteTable).name, localSteam, 0uL, rouletteTable.PlayerCount); } else { RNNetcode.SendLeaveTableRequest(((Object)rouletteTable).name); rouletteTable.Leave(mainPlayer); } Plugin.HasSetRouletteBet = false; SendLocalMessage(chat, "<color=#FFD700>[Casino]</color> Left the roulette table. Any unplaced bet amounts have been refunded. Use /tbet to set a new bet amount."); Plugin.Log.LogInfo((object)"[Casino] Local player left roulette table via /rleave."); } private static void HandleCasinoHelp(ChatBehaviour chat) { string text = string.Join(", ", Plugin.AllowedBets); SendLocalMessage(chat, "<color=#FFD700>[Casino Commands]</color>"); SendLocalMessage(chat, "<color=#AAAAAA>-- SLOTS --</color>"); SendLocalMessage(chat, "<color=#FFFFFF>/slotbet <amount></color> - Set slot bet (" + text + ")"); SendLocalMessage(chat, "<color=#AAAAAA>-- BLACKJACK --</color>"); SendLocalMessage(chat, "<color=#FFFFFF>/blackjackbet <amount></color> - Set blackjack bet"); SendLocalMessage(chat, "<color=#FFFFFF>/ready</color> - Toggle ready"); SendLocalMessage(chat, "<color=#FFFFFF>/start</color> - Begin round (host only)"); SendLocalMessage(chat, "<color=#FFFFFF>/hit</color> - Take a card"); SendLocalMessage(chat, "<color=#FFFFFF>/stand</color> - End your turn"); SendLocalMessage(chat, "<color=#FFFFFF>/leave</color> - Leave your seat"); SendLocalMessage(chat, "<color=#AAAAAA>-- ROULETTE --</color>"); SendLocalMessage(chat, "<color=#FFFFFF>/tbet <amount></color> - Set roulette stake per bet"); SendLocalMessage(chat, "<color=#FFFFFF>/rbet <type> [num]</color> - Place a bet"); SendLocalMessage(chat, " Types: number 0-36, red, black, even, odd, low, high, dozen 1-3, column 1-3"); SendLocalMessage(chat, "<color=#FFFFFF>/rclearbets</color> - Clear and refund all your bets"); SendLocalMessage(chat, "<color=#FFFFFF>/rstandby</color> - Toggle ready at roulette"); SendLocalMessage(chat, "<color=#FFFFFF>/rspin</color> - Spin the wheel (host only)"); SendLocalMessage(chat, "<color=#FFFFFF>/rleave</color> - Leave the roulette table"); SendLocalMessage(chat, "<color=#FFFFFF>/casinohelp</color> - This help"); } private static bool IsAllowedBet(int amount) { int[] allowedBets = Plugin.AllowedBets; foreach (int num in allowedBets) { if (num == amount) { return true; } } return false; } private static (BlackjackTable?, int) FindLocalSeat() { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return (null, -1); } BlackjackTable[] array = Object.FindObjectsOfType<BlackjackTable>(); BlackjackTable[] array2 = array; foreach (BlackjackTable blackjackTable in array2) { int seatForPlayer = blackjackTable.GetSeatForPlayer(mainPlayer); if (seatForPlayer >= 0) { return (blackjackTable, seatForPlayer); } } return (null, -1); } private static bool IsLocalPlayerSeatedAtAnyBlackjackTable() { var (blackjackTable, num) = FindLocalSeat(); return (Object)(object)blackjackTable != (Object)null && num >= 0; } private static RouletteTable? FindLocalRouletteTable() { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return null; } RouletteTable[] array = Object.FindObjectsOfType<RouletteTable>(); RouletteTable[] array2 = array; foreach (RouletteTable rouletteTable in array2) { if (rouletteTable.IsPlayerAtTable(mainPlayer)) { return rouletteTable; } } return null; } private static int GetLocalCrownBalance() { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return 0; } PlayerInventory component = ((Component)mainPlayer).GetComponent<PlayerInventory>(); if ((Object)(object)component == (Object)null) { return 0; } return component._heldCurrency; } private static string ReadyCountSummary(BlackjackTable table) { int num = 0; int num2 = 0; for (int i = 0; i < 5; i++) { if (!((Object)(object)table.GetSeatedPlayer(i) == (Object)null)) { num2++; if (table.IsPlayerReady(i)) { num++; } } } return $"({num}/{num2} ready)"; } private static void ShowLocalHandPrompt(BlackjackTable table, bool finalView) { try { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } int seatForPlayer = table.GetSeatForPlayer(mainPlayer); if (seatForPlayer >= 0) { string text = (finalView ? table.DescribePlayerHandFinal(seatForPlayer) : table.DescribePlayerHandStatus(seatForPlayer)); if (!string.IsNullOrEmpty(text)) { ErrorPromptTextManager.current.Init_ErrorPrompt(text); } } } catch (Exception ex) { Plugin.Log.LogError((object)("[Casino] ShowLocalHandPrompt failed: " + ex.Message)); } } private static void SendLocalMessage(ChatBehaviour chat, string message) { try { if (MaxOnscreenField != null) { try { MaxOnscreenField.SetValue(chat, 50); } catch { } } chat.Init_GameLogicMessage(message); } catch (Exception ex) { Plugin.Log.LogError((object)("[Casino] Failed to send local chat message: " + ex.Message)); } } private static void SetChatFocusFalse(ChatBehaviour chat) { try { typeof(ChatBehaviour).GetField("_focusedInChat", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(chat, false); } catch { } } } public class CasinoExitTrigger : MonoBehaviour { [CompilerGenerated] private sealed class <ForceReturnToSanctum>d__9 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; public string caller; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ForceReturnToSanctum>d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; ErrorPromptTextManager.current.Init_ErrorPrompt("Returning to Sanctum..."); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; ConfigurePortal(caller); <>2__current = null; <>1__state = 2; return true; case 2: <>1__state = -1; Plugin.Log.LogInfo((object)(caller + " Strategy 1: InteractQueue_RecallPortal...")); if (TryInteractQueue(caller)) { Plugin.Log.LogInfo((object)(caller + " InteractQueue_RecallPortal fired.")); return false; } <>2__current = null; <>1__state = 3; return true; case 3: <>1__state = -1; Plugin.Log.LogInfo((object)(caller + " Strategy 2: Cmd_SceneTransport (full path)...")); if (TrySceneTransport(player, "Assets/Scenes/00_zone_forest/_zone00_sanctum.unity", "startPoint")) { Plugin.Log.LogInfo((object)(caller + " Cmd_SceneTransport fired.")); return false; } Plugin.Log.LogInfo((object)(caller + " Strategy 3: Cmd_SceneTransport (short name)...")); if (TrySceneTransport(player, "Sanctum", "startPoint")) { Plugin.Log.LogInfo((object)(caller + " Cmd_SceneTransport (short) fired.")); return false; } Plugin.Log.LogInfo((object)(caller + " Strategy 4: _requestedRecall...")); if (TrySetRecallFlag(player)) { Plugin.Log.LogInfo((object)(caller + " _requestedRecall set.")); return false; } Plugin.Log.LogWarning((object)(caller + " Strategy 5: SceneManager.LoadScene...")); SceneManager.LoadScene("Assets/Scenes/00_zone_forest/_zone00_sanctum.unity"); 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 const string SANCTUM_PATH = "Assets/Scenes/00_zone_forest/_zone00_sanctum.unity"; private const float INPUT_COOLDOWN = 0.5f; private BoxCollider? _collider; private bool _playerNearby = false; private bool _isTransitioning = false; private float _nextInputTime = 0f; private void Awake() { _collider = ((Component)this).GetComponent<BoxCollider>(); Plugin.Log.LogInfo((object)"[ExitTrigger] Casino exit trigger active."); } private void Update() { if (_isTransitioning) { return; } Player mainPlayer = Player._mainPlayer; if (!((Object)(object)mainPlayer == (Object)null)) { bool flag = IsPlayerInRange(mainPlayer); if (flag && !_playerNearby) { _playerNearby = true; ErrorPromptTextManager.current.Init_ErrorPrompt("Press F to return to Sanctum."); } else if (!flag && _playerNearby) { _playerNearby = false; } if (_playerNearby && Input.GetKeyDown((KeyCode)102) && !(Time.time < _nextInputTime)) { _nextInputTime = Time.time + 0.5f; _isTransitioning = true; ((MonoBehaviour)this).StartCoroutine(ForceReturnToSanctum(mainPlayer)); } } } private bool IsPlayerInRange(Player player) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_collider != (Object)null) { Bounds bounds = ((Collider)_collider).bounds; return ((Bounds)(ref bounds)).Contains(((Component)player).transform.position); } return Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position) < 3f; } [IteratorStateMachine(typeof(<ForceReturnToSanctum>d__9))] public static IEnumerator ForceReturnToSanctum(Player player, string caller = "[ExitTrigger]") { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ForceReturnToSanctum>d__9(0) { player = player, caller = caller }; } private static void ConfigurePortal(string caller) { GameObject val = GameObject.Find("_entity_recallPortal"); if ((Object)(object)val == (Object)null) { return; } MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); MonoBehaviour[] array = componentsInChildren; foreach (MonoBehaviour val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } Type type = ((object)val2).GetType(); FieldInfo field = type.GetField("_scenePortal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value = field.GetValue(val2); if (value != null) { Type type2 = value.GetType(); type2.GetField("_subScene", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(value, "Assets/Scenes/00_zone_forest/_zone00_sanctum.unity"); type2.GetField("_spawnPointTag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(value, "startPoint"); type.GetField("_isPortalOpen", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(val2, true); field.SetValue(val2, value); Plugin.Log.LogInfo((object)(caller + " RecallPortal configured → 'Assets/Scenes/00_zone_forest/_zone00_sanctum.unity'")); break; } } } } private static bool TryInteractQueue(string caller) { GameObject val = GameObject.Find("_entity_recallPortal"); if ((Object)(object)val == (Object)null) { return false; } MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); string[] array = new string[5] { "InteractQueue_RecallPortal", "Init_RecallPortal", "Interact_RecallPortal", "Activate_RecallPortal", "Open_RecallPortal" }; MonoBehaviour[] array2 = componentsInChildren; foreach (MonoBehaviour val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } Type type = ((object)val2).GetType(); string[] array3 = array; foreach (string text in array3) { MethodInfo method = type.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(method == null)) { Plugin.Log.LogInfo((object)(caller + " Calling " + type.Name + "." + text + "()")); try { method.Invoke(val2, null); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)(caller + " " + text + " threw: " + ex.Message)); } } } } MonoBehaviour[] array4 = componentsInChildren; foreach (MonoBehaviour val3 in array4) { if (!((Object)(object)val3 == (Object)null) && !(((object)val3).GetType().Name != "RecallPortal")) { MethodInfo[] methods = ((object)val3).GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); StringBuilder stringBuilder = new StringBuilder(); MethodInfo[] array5 = methods; foreach (MethodInfo methodInfo in array5) { stringBuilder.Append(methodInfo.Name).Append(", "); } Plugin.Log.LogInfo((object)$"{caller} RecallPortal methods: {stringBuilder}"); } } return false; } private static bool TrySceneTransport(Player player, string sceneName, string spawnTag) { MethodInfo method = ((object)player).GetType().GetMethod("Cmd_SceneTransport", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log.LogWarning((object)"[ExitTrigger] Cmd_SceneTransport not found."); return false; } try { ParameterInfo[] parameters = method.GetParameters(); Plugin.Log.LogInfo((object)($"[ExitTrigger] Cmd_SceneTransport params: {parameters.Length} " + "(" + ((parameters.Length != 0) ? parameters[0].ParameterType.Name : "") + ")")); object[] parameters2; if (parameters.Length < 3) { parameters2 = ((parameters.Length != 2) ? new object[1] { sceneName } : new object[2] { sceneName, spawnTag }); } else { object obj = Enum.ToObject(parameters[2].ParameterType, 0); parameters2 = new object[3] { sceneName, spawnTag, obj }; } method.Invoke(player, parameters2); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[ExitTrigger] Cmd_SceneTransport threw: " + ex.Message)); return false; } } private static bool TrySetRecallFlag(Player player) { string[] array = new string[4] { "_requestedRecall", "_recallRequested", "_isRecalling", "_recall" }; foreach (string text in array) { FieldInfo field = ((object)player).GetType().GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && !(field.FieldType != typeof(bool))) { field.SetValue(player, true); Plugin.Log.LogInfo((object)("[ExitTrigger] Set " + text + "=true on Player.")); return true; } } return false; } } [BepInPlugin("dev.seth.atlysscasino", "Atlyss Casino", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <ShowHUDCoroutine>d__15 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public string message; public float duration; public float refreshInterval; private float <elapsed>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowHUDCoroutine>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <elapsed>5__1 = 0f; break; case 1: <>1__state = -1; <elapsed>5__1 += refreshInterval; break; } if (<elapsed>5__1 < duration) { try { ErrorPromptTextManager.current.Init_ErrorPrompt(message); } catch { return false; } <>2__current = (object)new WaitForSeconds(refreshInterval); <>1__state = 1; return true; } 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(); } } public static ManualLogSource Log = null; public static AssetBundle? AssetsBundle = null; public static int CurrentBet = 100; public static bool HasSetBet = false; public static int BlackjackBet = 100; public static bool HasSetBlackjackBet = false; public static int RouletteBet = 100; public static bool HasSetRouletteBet = false; public static readonly int[] AllowedBets = new int[4] { 10, 50, 100, 500 }; public static Plugin Instance { get; private set; } = null; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; LoadAssetBundle(); CasinoPatch.Init(); BlackjackSceneWatcher.Init(); BJNetcode.Initialize(); RNNetcode.Initialize(); Harmony val = new Harmony("dev.seth.atlysscasino"); val.PatchAll(); Log.LogInfo((object)"Atlyss Casino loaded!"); Log.LogInfo((object)"[Casino] Slots: /slotbet | Blackjack: /blackjackbet /ready /start /hit /stand /leave | Roulette: /tbet /rbet /rclearbets /rstandby /rspin /rleave | Help: /casinohelp"); } public static void ShowHUD(string message, float duration = 8f, float refreshInterval = 2.8f) { ((MonoBehaviour)Instance).StartCoroutine(ShowHUDCoroutine(message, duration, refreshInterval)); } [IteratorStateMachine(typeof(<ShowHUDCoroutine>d__15))] private static IEnumerator ShowHUDCoroutine(string message, float duration, float refreshInterval) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowHUDCoroutine>d__15(0) { message = message, duration = duration, refreshInterval = refreshInterval }; } private void LoadAssetBundle() { try { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, "atlysscasino_assets"); AssetsBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)AssetsBundle == (Object)null) { Log.LogError((object)("[Casino] Failed to load asset bundle at '" + text + "'")); } else { Log.LogInfo((object)"[Casino] Assets bundle loaded."); } } catch (Exception ex) { Log.LogError((object)("[Casino] Bundle load exception: " + ex.Message)); } } } public class SlotBetConfirm : MonoBehaviour { private SlotMachine? _machine; private bool _playerNearby = false; public void Setup(SlotMachine machine) { _machine = machine; } private void Update() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)mainPlayer).transform.position); bool flag = num < 2.5f; if (flag && !_playerNearby) { _playerNearby = true; if (Plugin.HasSetBet) { ErrorPromptTextManager.current.Init_ErrorPrompt($"Bet: {Plugin.CurrentBet} Crowns. " + "Press F to spin. Change bet with /slotbet <amount>."); } else { ErrorPromptTextManager.current.Init_ErrorPrompt("No bet set. Use /slotbet <amount> to set your bet."); } Plugin.Log.LogInfo((object)"[Casino] Player near slot trigger."); } else if (!flag && _playerNearby) { _playerNearby = false; } if (_playerNearby && Input.GetKeyDown((KeyCode)102)) { if (!Plugin.HasSetBet) { ErrorPromptTextManager.current.Init_ErrorPrompt("Set a bet first with /slotbet <amount>!"); } else { _machine?.TryPlay(); } } } } public class SlotMachine : MonoBehaviour { [CompilerGenerated] private sealed class <AnimateLever>d__45 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SlotMachine <>4__this; private float <elapsed>5__1; private float <duration>5__2; private Quaternion <start>5__3; private Quaternion <pulled>5__4; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AnimateLever>d__45(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)<>4__this._lever == (Object)null) { return false; } <elapsed>5__1 = 0f; <duration>5__2 = 0.3f; <start>5__3 = <>4__this._lever.localRotation; <pulled>5__4 = <start>5__3 * Quaternion.Euler(-30f, 0f, 0f); goto IL_00fe; case 1: <>1__state = -1; goto IL_00fe; case 2: <>1__state = -1; <elapsed>5__1 = 0f; break; case 3: { <>1__state = -1; break; } IL_00fe: if (<elapsed>5__1 < <duration>5__2) { <elapsed>5__1 += Time.deltaTime; <>4__this._lever.localRotation = Quaternion.Lerp(<start>5__3, <pulled>5__4, <elapsed>5__1 / <duration>5__2); <>2__current = null; <>1__state = 1; return true; } <>2__current = (object)new WaitForSeconds(0.3f); <>1__state = 2; return true; } if (<elapsed>5__1 < <duration>5__2) { <elapsed>5__1 += Time.deltaTime; <>4__this._lever.localRotation = Quaternion.Lerp(<pulled>5__4, <start>5__3, <elapsed>5__1 / <duration>5__2); <>2__current = null; <>1__state = 3; return true; } <>4__this._lever.localRotation = <start>5__3; 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(); } } [CompilerGenerated] private sealed class <FlashAllReels>d__41 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Material flashMat; public int times; public float interval; public int[] results; public SlotMachine <>4__this; private int <t>5__1; private int <i>5__2; private int <i>5__3; private int <i>5__4; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FlashAllReels>d__41(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this._symbolMaterials == null) { return false; } <t>5__1 = 0; break; case 1: <>1__state = -1; <i>5__3 = 0; while (<i>5__3 < 3) { <>4__this.SetReel(<i>5__3, <>4__this._symbolMaterials[results[<i>5__3]]); <i>5__3++; } <>2__current = (object)new WaitForSeconds(interval); <>1__state = 2; return true; case 2: <>1__state = -1; <t>5__1++; break; } if (<t>5__1 < times) { <i>5__2 = 0; while (<i>5__2 < 3) { <>4__this.SetReel(<i>5__2, flashMat); <i>5__2++; } <>2__current = (object)new WaitForSeconds(interval); <>1__state = 1; return true; } <i>5__4 = 0; while (<i>5__4 < 3) { <>4__this.SetReel(<i>5__4, flashMat); <i>5__4++; } 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(); } } [CompilerGenerated] private sealed class <PlaySlotsLocal>d__37 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int wager; public PlayerInventory inventory; public int r1; public int r2; public int r3; public SlotMachine <>4__this; private float <multiplier>5__1; private string <tier>5__2; private bool <bigWin>5__3; private bool <isJackpot>5__4; private string <resultLine>5__5; private int <payout>5__6; private int <i>5__7; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlaySlotsLocal>d__37(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <tier>5__2 = null; <resultLine>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; (float, string, bool) tuple = <>4__this.CalculatePayout(r1, r2, r3); <multiplier>5__1 = tuple.Item1; <tier>5__2 = tuple.Item2; <bigWin>5__3 = tuple.Item3; <isJackpot>5__4 = r1 == 4 && r2 == 4 && r3 == 4; <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.RunSpinVisuals(r1, r2, r3, <isJackpot>5__4, <bigWin>5__3, <multiplier>5__1 > 0f)); <>1__state = 1; return true; } case 1: <>1__state = -1; <resultLine>5__5 = "[ " + <>4__this._symbols[r1] + " | " + <>4__this._symbols[r2] + " | " + <>4__this._symbols[r3] + " ]"; if (<multiplier>5__1 > 0f) { <payout>5__6 = Mathf.FloorToInt((float)wager * <multiplier>5__1); if (<payout>5__6 < 1) { <payout>5__6 = 1; } PlayerInventory obj = inventory; obj.Network_heldCurrency += <payout>5__6; ErrorPromptTextManager.current.Init_ErrorPrompt($"{<resultLine>5__5}\n{<tier>5__2} Won {<payout>5__6} Crowns!"); Plugin.Log.LogInfo((object)($"[Slots] {<tier>5__2} — bet {wager}, payout {<payout>5__6} " + $"({<multiplier>5__1:F2}x).")); } else { ErrorPromptTextManager.current.Init_ErrorPrompt($"{<resultLine>5__5}\nNo match. Lost {wager} Crowns."); Plugin.Log.LogInfo((object)$"[Slots] Loss — bet {wager}."); } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; case 2: <>1__state = -1; <i>5__7 = 0; while (<i>5__7 < 3) { <>4__this.SetReel(<i>5__7, <>4__this.MatIdleBlank); <i>5__7++; } <>4__this.SetTopScreen(<>4__this.MatIdle); <>4__this.InUse = false; 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(); } } [CompilerGenerated] private sealed class <PlaySlotsRemote>d__38 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int r1; public int r2; public int r3; public SlotMachine <>4__this; private float <multiplier>5__1; private string <tier>5__2; private bool <bigWin>5__3; private bool <isJackpot>5__4; private int <i>5__5; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlaySlotsRemote>d__38(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <tier>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; (float, string, bool) tuple = <>4__this.CalculatePayout(r1, r2, r3); <multiplier>5__1 = tuple.Item1; <tier>5__2 = tuple.Item2; <bigWin>5__3 = tuple.Item3; <isJackpot>5__4 = r1 == 4 && r2 == 4 && r3 == 4; <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.RunSpinVisuals(r1, r2, r3, <isJackpot>5__4, <bigWin>5__3, <multiplier>5__1 > 0f)); <>1__state = 1; return true; } case 1: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; case 2: <>1__state = -1; <i>5__5 = 0; while (<i>5__5 < 3) { <>4__this.SetReel(<i>5__5, <>4__this.MatIdleBlank); <i>5__5++; } <>4__this.SetTopScreen(<>4__this.MatIdle); <>4__this.InUse = false; 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(); } } [CompilerGenerated] private sealed class <RunSpinVisuals>d__39 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int r1; public int r2; public int r3; public bool isJackpot; public bool bigWin; public bool isWin; public SlotMachine <>4__this; private int[] <results>5__1; private float[] <reelDurations>5__2; private int <i>5__3; private Material <flashMat>5__4; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RunSpinVisuals>d__39(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <results>5__1 = null; <reelDurations>5__2 = null; <flashMat>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)<>4__this._lever != (Object)null) { ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.AnimateLever()); } <>4__this.SetTopScreen(<>4__this.MatIdleBlank); <results>5__1 = new int[3] { r1, r2, r3 }; <reelDurations>5__2 = new float[3] { 1.5f, 2f, 2.5f }; <i>5__3 = 0; while (<i>5__3 < 3) { ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.SpinReel(<i>5__3, <reelDurations>5__2[<i>5__3], <results>5__1[<i>5__3])); <i>5__3++; } <>2__current = (object)new WaitForSeconds(<reelDurations>5__2[2] + 0.3f); <>1__state = 1; return true; case 1: <>1__state = -1; if (isWin) { <flashMat>5__4 = (isJackpot ? <>4__this.MatJackpot : <>4__this.MatWin); <>4__this.SetTopScreen(<flashMat>5__4); if (isJackpot) { <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FlashAllReels(<>4__this.MatJackpot, 6, 0.15f, <results>5__1)); <>1__state = 2; return true; } if (bigWin) { <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FlashAllReels(<>4__this.MatWin, 4, 0.2f, <results>5__1)); <>1__state = 3; return true; } <>2__current = (object)new WaitForSeconds(1.5f); <>1__state = 4; return true; } <>2__current = (object)new WaitForSeconds(1.5f); <>1__state = 5; return true; case 2: <>1__state = -1; goto IL_0263; case 3: <>1__state = -1; goto IL_0263; case 4: <>1__state = -1; goto IL_0263; case 5: { <>1__state = -1; break; } IL_0263: <flashMat>5__4 = null; break; } 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(); } } [CompilerGenerated] private sealed class <SpinReel>d__40 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int reelIndex; public float duration; public int finalResult; public SlotMachine <>4__this; private float <elapsed>5__1; private float <nextFlicker>5__2; private float <flickerSpeed>5__3; private float <progress>5__4; object? IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SpinReel>d__40(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this._symbolMaterials == null) { return false; } <elapsed>5__1 = 0f; <nextFlicker>5__2 = 0f; <flickerSpeed>5__3 = 0.08f; break; case 1: <>1__state = -1; break; } if (<elapsed>5__1 < duration) { if (<elapsed>5__1 >= <nextFlicker>5__2) { <>4__this.SetReel(reelIndex, <>4__this._symbolMaterials[Random.Range(0, <>4__this._symbolMaterials.Length)]); <progress>5__4 = <elapsed>5__1 / duration; <flickerSpeed>5__3 = Mathf.Lerp(0.05f, 0.35f, <progress>5__4); <nextFlicker>5__2 = <elapsed>5__1 + <flickerSpeed>5__3; } <elapsed>5__1 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } <>4__this.SetReel(reelIndex, <>4__this._symbolMaterials[finalResult]); 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(); } } public bool InUse = false; public float NextInputTime = 0f; private Transform? _lever; private GameObject? _backdrop; private MeshRenderer? _backdropRenderer; private GameObject[] _reels = (GameObject[])(object)new GameObject[3]; private MeshRenderer?[] _reelRenderers = (MeshRenderer?[])(object)new MeshRenderer[3]; private GameObject? _topScreen; private MeshRenderer? _topScreenRenderer; public Material? MatIdle; public Material? MatIdleBlank; public Material? MatWin; public Material? MatJackpot; public Material? MatCherry; public Material? MatLemon; public Material? MatOrange; public Material? MatStar; public Material? MatDiamond; public Material? MatSeven; private Material?[]? _symbolMaterials; private const int CherryIdx = 0; private const int LemonIdx = 1; private const int OrangeIdx = 2; private const int StarIdx = 3; private const int DiamondIdx = 4; private const int SevenIdx = 5; private readonly string[] _symbols = new string[6] { "Cherry", "Lemon", "Orange", "Star", "Diamond", "Seven" }; public void Init() { _lever = ((Component)this).transform.Find("Lever"); Transform val = ((Component)this).transform.Find("ScreenAnchor"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"[Slots] ScreenAnchor child not found!"); } else { BuildBackdrop(val); BuildThreeReels(val); } Transform val2 = ((Component)this).transform.Find("TopScreenAnchor"); if ((Object)(object)val2 != (Object)null) { BuildTopScreen(val2); } _symbolMaterials = (Material?[]?)(object)new Material[6] { MatCherry, MatLemon, MatOrange, MatStar, MatDiamond, MatSeven }; SetBackdrop(MatIdleBlank); for (int i = 0; i < 3; i++) { SetReel(i, MatIdleBlank); } SetTopScreen(MatIdle); } private void BuildBackdrop(Transform anchor) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "SlotScreenBackdrop"; Collider component = val.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(anchor, false); val.transform.localPosition = new Vector3(0f, 0f, 0.001f); val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; _backdrop = val; _backdropRenderer = val.GetComponent<MeshRenderer>(); } private void BuildThreeReels(Transform anchor) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) float num = 1f / 3f; float[] array = new float[3] { -1f / 3f, 0f, 1f / 3f }; for (int i = 0; i < 3; i++) { GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = $"SlotReel_{i}"; Collider component = val.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(anchor, false); val.transform.localPosition = new Vector3(array[i], 0f, -0.001f); val.transform.localRotation = Quaternion.identity; val.transform.localScale = new Vector3(num, 1f, 1f); _reels[i] = val; _reelRenderers[i] = val.GetComponent<MeshRenderer>(); } } private void BuildTopScreen(Transform anchor) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "SlotTopScreen"; Collider component = val.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(anchor, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; _topScreen = val; _topScreenRenderer = val.GetComponent<MeshRenderer>(); } public void TryPlay() { if (Time.time < NextInputTime) { return; } NextInputTime = Time.time + 0.5f; if (InUse) { ErrorPromptTextManager.current.Init_ErrorPrompt("Machine is in use!"); return; } Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null) { return; } PlayerInventory component = ((Component)mainPlayer).GetComponent<PlayerInventory>(); if (!((Object)(object)component == (Object)null)) { int currentBet = Plugin.CurrentBet; if (component._heldCurrency < currentBet) { ErrorPromptTextManager.current.Init_ErrorPrompt($"Not enough Crowns! Need {currentBet}, " + $"you have {component._heldCurrency}."); return; } int num = Random.Range(0, _symbols.Length); int num2 = Random.Range(0, _symbols.Length); int num3 = Random.Range(0, _symbols.Length); InUse = true; component.Network_heldCurrency -= currentBet; Plugin.Log.LogInfo((object)$"[Slots] Playing '{((Object)this).name}' with bet {currentBet} -> [{num}, {num2}, {num3}]."); BJNetcode.BroadcastSlotSpinResult(((Object)this).name, num, num2, num3); ((MonoBehaviour)this).StartCoroutine(PlaySlotsLocal(currentBet, component, num, num2, num3)); } } public void ApplyRemoteSpin(int r1, int r2, int r3) { if (InUse) { Plugin.Log.LogWarning((object)("[Slots] ApplyRemoteSpin on '" + ((Object)this).name + "' but machine is already in use — dropping remote spin to avoid visual clash.")); return; } if (r1 < 0 || r1 >= _symbols.Length || r2 < 0 || r2 >= _symbols.Length || r3 < 0 || r3 >= _symbols.Length) { Plugin.Log.LogError((object)("[Slots] ApplyRemoteSpin on '" + ((Object)this).name + "': invalid symbol indices " + $"[{r1}, {r2}, {r3}]. Spin not played.")); return; } InUse = true; Plugin.Log.LogInfo((object)$"[Slots] Mirroring remote spin on '{((Object)this).name}' -> [{r1}, {r2}, {r3}]."); ((MonoBehaviour)this).StartCoroutine(PlaySlotsRemote(r1, r2, r3)); } private static bool IsFruit(int idx) { return idx == 0 || idx == 1 || idx == 2; } private static bool IsStarOrSeven(int idx) { return idx == 3 || idx == 5; } private (float multiplier, string tier, bool bigWin) CalculatePayout(int r1, int r2, int r3) { if (r1 == r2 && r2 == r3) { if (r1 == 4) { return (100f, "JACKPOT!", true); } if (IsStarOrSeven(r1)) { return (2f, "Triple Match!", false); } return (1f, "Triple Fruit!", false); } int num = 0; int[] array = new int[3] { r1, r2, r3 }; foreach (int num2 in array) { if (num2 == 4) { num++; } } if (num == 2) { return (2f, "Two Diamonds!", false); } if (HasExactlyTwoOfSame(r1, r2, r3, out var matchedIdx)) { if (IsStarOrSeven(matchedIdx)) { return (0.5f, "Near Miss!", false); } if (IsFruit(matchedIdx)) { return (0.25f, "Fruit Pair", false); } } return (0f, "No match", false); } private static bool HasExactlyTwoOfSame(int r1, int r2, int r3, out int matchedIdx) { if (r1 == r2 && r2 == r3) { matchedIdx = -1; return false; } if (r1 == r2) { matchedIdx = r1; return true; } if (r2 == r3) { matchedIdx = r2; return true; } if (r1 == r3) { matchedIdx = r1; return true; } matchedIdx = -1; return false; } [IteratorStateMachine(typeof(<PlaySlotsLocal>d__37))] private IEnumerator PlaySlotsLocal(int wager, PlayerInventory inventory, int r1, int r2, int r3) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlaySlotsLocal>d__37(0) { <>4__this = this, wager = wager, inventory = inventory, r1 = r1, r2 = r2, r3 = r3 }; } [IteratorStateMachine(typeof(<PlaySlotsRemote>d__38))] private IEnumerator PlaySlotsRemote(int r1, int r2, int r3) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlaySlotsRemote>d__38(0) { <>4__this = this, r1 = r1, r2 = r2, r3 = r3 }; } [IteratorStateMachine(typeof(<RunSpinVisuals>d__39))] private IEnumerator RunSpinVisuals(int r1, int r2, int r3, bool isJackpot, bool bigWin, bool isWin) { /