Decompiled source of SafehouseBlackjack v0.5.1

WhiteKnuckleBlackjack.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using WhiteKnuckleBlackjack.Assets;
using WhiteKnuckleBlackjack.Rules;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Battery_Boy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Battery_Boy")]
[assembly: AssemblyDescription("A White Knuckle blackjack machine built entirely around in-game assets.")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1")]
[assembly: AssemblyProduct("Safehouse Blackjack")]
[assembly: AssemblyTitle("WhiteKnuckleBlackjack")]
[assembly: AssemblyVersion("0.5.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 WhiteKnuckleBlackjack
{
	internal sealed class BlackjackAnnouncementPlayer : MonoBehaviour
	{
		private readonly List<AudioClip> _clips = new List<AudioClip>();

		private readonly List<AudioClip> _winClips = new List<AudioClip>();

		private readonly List<int> _shuffleBag = new List<int>();

		private readonly List<int> _winShuffleBag = new List<int>();

		private AudioSource? _source;

		private ManualLogSource? _log;

		private float _chance;

		private int _lastClip = -1;

		private int _lastWinClip = -1;

		private bool _announcementPending;

		internal void Configure(int chancePercent, ManualLogSource log)
		{
			_chance = (float)Mathf.Clamp(chancePercent, 0, 100) / 100f;
			_log = log;
			_source = ((Component)this).gameObject.AddComponent<AudioSource>();
			_source.playOnAwake = false;
			_source.loop = false;
			_source.spatialBlend = 0f;
			_source.volume = 1f;
			string directory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "PA");
			((MonoBehaviour)this).StartCoroutine(LoadAudio(directory));
		}

		internal void QueueAfterRound(RoundOutcome outcome)
		{
			bool flag = outcome == RoundOutcome.PlayerWin || outcome == RoundOutcome.PlayerBlackjack;
			List<AudioClip> list = ((flag && _winClips.Count > 0) ? _winClips : _clips);
			if (!_announcementPending && !((Object)(object)_source == (Object)null) && list.Count != 0 && !(Random.value > _chance))
			{
				int index = ((flag && list == _winClips) ? TakeShuffledIndex(list, _winShuffleBag, ref _lastWinClip) : TakeShuffledIndex(list, _shuffleBag, ref _lastClip));
				_announcementPending = true;
				((MonoBehaviour)this).StartCoroutine(PlayAfterDelay(Random.Range(0.65f, 2.25f), list[index]));
			}
		}

		private IEnumerator LoadAudio(string directory)
		{
			if (!Directory.Exists(directory))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Blackjack PA directory was not found: " + directory));
				}
				yield break;
			}
			string[] array = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly).OrderBy<string, string>((string result) => result, StringComparer.OrdinalIgnoreCase).ToArray();
			string[] array2 = array;
			foreach (string path in array2)
			{
				string absoluteUri = new Uri(path).AbsoluteUri;
				UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)13);
				try
				{
					yield return request.SendWebRequest();
					if ((int)request.result != 1)
					{
						ManualLogSource? log2 = _log;
						if (log2 != null)
						{
							log2.LogWarning((object)("Could not load blackjack PA clip " + Path.GetFileName(path) + ": " + request.error));
						}
						continue;
					}
					AudioClip content = DownloadHandlerAudioClip.GetContent(request);
					if (!((Object)(object)content == (Object)null))
					{
						((Object)content).name = Path.GetFileNameWithoutExtension(path);
						if (((Object)content).name.StartsWith("Blackjack_Win_", StringComparison.OrdinalIgnoreCase))
						{
							_winClips.Add(content);
						}
						else
						{
							_clips.Add(content);
						}
					}
				}
				finally
				{
					((IDisposable)request)?.Dispose();
				}
			}
			ManualLogSource? log3 = _log;
			if (log3 != null)
			{
				log3.LogInfo((object)("Blackjack PA clips loaded: general=" + _clips.Count + ", win-only=" + _winClips.Count));
			}
		}

		private IEnumerator PlayAfterDelay(float delay, AudioClip clip)
		{
			yield return (object)new WaitForSecondsRealtime(delay);
			_announcementPending = false;
			if (!((Object)(object)_source == (Object)null) && !_source.isPlaying && !((Object)(object)clip == (Object)null))
			{
				_source.PlayOneShot(clip);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)("Blackjack PA announcement=" + ((Object)clip).name));
				}
			}
		}

		private static int TakeShuffledIndex(List<AudioClip> clips, List<int> shuffleBag, ref int lastClip)
		{
			if (shuffleBag.Count == 0)
			{
				for (int i = 0; i < clips.Count; i++)
				{
					shuffleBag.Add(i);
				}
				for (int num = shuffleBag.Count - 1; num > 0; num--)
				{
					int num2 = Random.Range(0, num + 1);
					List<int> list = shuffleBag;
					int index = num;
					int index2 = num2;
					int value = shuffleBag[num2];
					int value2 = shuffleBag[num];
					list[index] = value;
					shuffleBag[index2] = value2;
				}
				if (shuffleBag.Count > 1 && shuffleBag[shuffleBag.Count - 1] == lastClip)
				{
					int num3 = Random.Range(0, shuffleBag.Count - 1);
					List<int> list = shuffleBag;
					int index2 = num3;
					int index = shuffleBag.Count - 1;
					int value2 = shuffleBag[shuffleBag.Count - 1];
					int value = shuffleBag[num3];
					list[index2] = value2;
					shuffleBag[index] = value;
				}
			}
			int index3 = shuffleBag.Count - 1;
			int num4 = shuffleBag[index3];
			shuffleBag.RemoveAt(index3);
			lastClip = num4;
			return num4;
		}
	}
	internal sealed class BlackjackController : IDisposable
	{
		private readonly ModConfig _config;

		private readonly ManualLogSource _log;

		private readonly BlackjackGame _game;

		private readonly Wallet _wallet;

		private bool _payoutApplied;

		private int _observedWalletBalance;

		internal int SelectedBet { get; private set; }

		internal int WalletBalance => _wallet.Balance;

		internal bool CanDouble
		{
			get
			{
				if (_game.Phase == RoundPhase.PlayerTurn && _game.Player.Cards.Count == 2)
				{
					return WalletBalance >= _game.Bet;
				}
				return false;
			}
		}

		internal string StatusLine => _game.Message;

		internal string PlayerDisplay
		{
			get
			{
				if (_game.Player.Cards.Count != 0)
				{
					return _game.Player.ToString();
				}
				return "--";
			}
		}

		internal string PlayerHandReadout => HandReadout.Cards(_game.Player);

		internal string PlayerTotalReadout => HandReadout.Total(_game.Player);

		internal string DealerHandReadout => HandReadout.Cards(_game.Dealer, _game.HoleCardHidden ? 1 : (-1));

		internal string DealerTotalReadout => HandReadout.Total(_game.Dealer, _game.HoleCardHidden ? 1 : (-1));

		internal string DealerDisplay
		{
			get
			{
				if (_game.Dealer.Cards.Count == 0)
				{
					return "--";
				}
				if (!_game.HoleCardHidden)
				{
					return _game.Dealer.ToString();
				}
				Card card = _game.Dealer.Cards[0];
				return card.ShortName + "  ??  [" + card.HardValue + "+]";
			}
		}

		internal Hand PlayerHand => _game.Player;

		internal Hand DealerHand => _game.Dealer;

		internal bool HideDealerHoleCard => _game.HoleCardHidden;

		internal RoundPhase Phase => _game.Phase;

		internal event Action? Changed;

		internal event Action<RoundOutcome>? RoundSettled;

		internal BlackjackController(ModConfig config, ManualLogSource log)
		{
			_config = config;
			_log = log;
			_wallet = new Wallet(config);
			_game = new BlackjackGame(config.DealerHitsSoft17.Value, Environment.TickCount);
			SelectedBet = ClampBet(config.MinimumBet.Value);
			_observedWalletBalance = _wallet.Balance;
		}

		internal void Tick()
		{
			bool flag = false;
			int balance = _wallet.Balance;
			if (balance != _observedWalletBalance)
			{
				_observedWalletBalance = balance;
				flag = true;
			}
			if (_game.Phase == RoundPhase.Betting)
			{
				int num = ClampBet(SelectedBet);
				if (num != SelectedBet)
				{
					SelectedBet = num;
					flag = true;
				}
			}
			if (flag)
			{
				RaiseChanged();
			}
		}

		internal void IncreaseBet()
		{
			if (_game.Phase != RoundPhase.PlayerTurn && _game.Phase != RoundPhase.DealerTurn)
			{
				SelectedBet = ClampBet(SelectedBet + Math.Max(1, _config.BetStep.Value));
				RaiseChanged();
			}
		}

		internal void DecreaseBet()
		{
			if (_game.Phase != RoundPhase.PlayerTurn && _game.Phase != RoundPhase.DealerTurn)
			{
				SelectedBet = ClampBet(SelectedBet - Math.Max(1, _config.BetStep.Value));
				RaiseChanged();
			}
		}

		internal void DealOrNewRound()
		{
			if (_game.Phase == RoundPhase.PlayerTurn || _game.Phase == RoundPhase.DealerTurn)
			{
				return;
			}
			if (_game.Phase == RoundPhase.Settled)
			{
				_game.ReturnToBetting();
			}
			SelectedBet = ClampBet(SelectedBet);
			if (SelectedBet <= 0 || !_wallet.TrySpend(SelectedBet))
			{
				_log.LogMessage((object)"Blackjack: not enough roaches/chips for that wager.");
				RaiseChanged();
				return;
			}
			_payoutApplied = false;
			if (!_game.StartRound(SelectedBet))
			{
				_wallet.Add(SelectedBet);
				return;
			}
			ApplyPayoutIfSettled();
			RaiseChanged();
		}

		internal void Hit()
		{
			if (_game.Hit())
			{
				ApplyPayoutIfSettled();
				RaiseChanged();
			}
		}

		internal void Stand()
		{
			if (_game.Stand())
			{
				ApplyPayoutIfSettled();
				RaiseChanged();
			}
		}

		internal void DoubleDown()
		{
			if (!CanDouble)
			{
				return;
			}
			int bet = _game.Bet;
			if (_wallet.TrySpend(bet))
			{
				if (!_game.DoubleDown())
				{
					_wallet.Add(bet);
					return;
				}
				ApplyPayoutIfSettled();
				RaiseChanged();
			}
		}

		private void ApplyPayoutIfSettled()
		{
			if (_game.Phase == RoundPhase.Settled && !_payoutApplied)
			{
				_payoutApplied = true;
				int num = _game.Payout();
				if (num > 0)
				{
					_wallet.Add(num);
				}
				this.RoundSettled?.Invoke(_game.Outcome);
			}
		}

		private int ClampBet(int value)
		{
			int val = Math.Max(Math.Max(1, _config.MinimumBet.Value), _config.MaximumBet.Value);
			int val2 = Math.Max(0, WalletBalance);
			return Math.Max(0, Math.Min(Math.Min(value, val), val2));
		}

		private void RaiseChanged()
		{
			_observedWalletBalance = _wallet.Balance;
			this.Changed?.Invoke();
		}

		public void Dispose()
		{
		}
	}
	internal sealed class Wallet
	{
		private readonly ModConfig _config;

		private int _practiceBalance;

		internal int Balance
		{
			get
			{
				try
				{
					return _config.Economy.Value switch
					{
						EconomyMode.RunRoaches => CL_GameManager.GetRoaches(false), 
						EconomyMode.FacilityCredits => CL_GameManager.GetRoaches(true), 
						_ => _practiceBalance, 
					};
				}
				catch
				{
					return _practiceBalance;
				}
			}
		}

		internal Wallet(ModConfig config)
		{
			_config = config;
			_practiceBalance = Math.Max(0, config.PracticeStartingChips.Value);
		}

		internal bool TrySpend(int amount)
		{
			if (amount <= 0 || Balance < amount)
			{
				return false;
			}
			Set(Balance - amount);
			return true;
		}

		internal void Add(int amount)
		{
			if (amount > 0)
			{
				Set(Balance + amount);
			}
		}

		private void Set(int value)
		{
			value = Math.Max(0, value);
			try
			{
				switch (_config.Economy.Value)
				{
				case EconomyMode.RunRoaches:
					CL_GameManager.SetRoaches(Math.Min(999, value), false);
					break;
				case EconomyMode.FacilityCredits:
					CL_GameManager.SetRoaches(Math.Min(9999, value), true);
					break;
				default:
					_practiceBalance = value;
					break;
				}
			}
			catch
			{
				_practiceBalance = value;
			}
		}
	}
	internal sealed class PhysicalTable : IDisposable
	{
		private sealed class CardVisual
		{
			internal const string HiddenDealerCardText = "Dealer card (hidden)";

			internal readonly Card Card;

			internal readonly GameObject GameObject;

			private readonly TextMesh? _text;

			private readonly Item? _heldItemData;

			private bool _heldTextIsHidden;

			internal CardVisual(Card card, GameObject gameObject, TextMesh? text, Item? heldItemData, bool hidden)
			{
				Card = card;
				GameObject = gameObject;
				_text = text;
				_heldItemData = heldItemData;
				_heldTextIsHidden = hidden;
			}

			internal void UpdateLabel(bool hidden)
			{
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_text != (Object)null)
				{
					_text.text = (hidden ? "▥" : Card.ShortName);
					_text.color = (Color)((!hidden && (Card.Suit == 1 || Card.Suit == 2)) ? new Color(0.8f, 0.12f, 0.08f) : Color.black);
				}
				if (_heldItemData == null || _heldTextIsHidden == hidden)
				{
					return;
				}
				_heldTextIsHidden = hidden;
				string text = (hidden ? "Dealer card (hidden)" : CardHeldName(Card));
				try
				{
					_heldItemData.SetFirstDataStringsofType("text", text);
					HandItem_Note[] array = Resources.FindObjectsOfTypeAll<HandItem_Note>();
					foreach (HandItem_Note val in array)
					{
						if (!((Object)(object)val == (Object)null) && ((HandItem)val).item == _heldItemData && !((Object)(object)val.text == (Object)null))
						{
							val.text.text = DarkMachineFunctions.ProcessText(text, true).TrimStart();
						}
					}
				}
				catch
				{
				}
			}
		}

		private sealed class CounterDisplay
		{
			private readonly UT_RoachCounter? _native;

			private readonly NativeCounterTicker? _ticker;

			private readonly TextMesh? _fallbackText;

			private int _lastValue = int.MinValue;

			internal CounterDisplay(UT_RoachCounter? native, NativeCounterTicker? ticker, TextMesh? fallbackText)
			{
				_native = native;
				_ticker = ticker;
				_fallbackText = fallbackText;
			}

			internal void SetValue(int value)
			{
				int num = Math.Min(999, Math.Max(0, value));
				if (num != _lastValue)
				{
					_lastValue = num;
					UT_RoachCounter? native = _native;
					if (native != null)
					{
						((NumberCounter)native).SetDigits(num);
					}
					_ticker?.SetValue(num);
					if ((Object)(object)_fallbackText != (Object)null)
					{
						_fallbackText.text = num.ToString("000");
					}
				}
			}
		}

		private readonly GameObject _root;

		private readonly BlackjackController _controller;

		private readonly AssetCatalog _assets;

		private readonly ManualLogSource _log;

		private readonly List<CardVisual> _dealerCardVisuals = new List<CardVisual>();

		private readonly List<CardVisual> _playerCardVisuals = new List<CardVisual>();

		private readonly List<Mesh> _generatedMeshes = new List<Mesh>();

		private readonly List<ParticleSystem> _winConfetti = new List<ParticleSystem>();

		private readonly List<AudioSource> _winSounds = new List<AudioSource>();

		private readonly List<ParticleSystem> _lossParticles = new List<ParticleSystem>();

		private AudioSource? _lossSound;

		private readonly CounterDisplay _walletCounter;

		private readonly CounterDisplay _betCounter;

		private readonly CL_Button? _hitButton;

		private readonly CL_Button? _standButton;

		private readonly CL_Button? _betDownButton;

		private readonly CL_Button? _betUpButton;

		private TextMesh? _playerHandReadout;

		private TextMesh? _playerTotalReadout;

		private TextMesh? _dealerHandReadout;

		private TextMesh? _dealerTotalReadout;

		private readonly bool _usesAuthoredRoomLocalTransform;

		internal bool IsAlive => (Object)(object)_root != (Object)null;

		internal bool IsEditing => false;

		internal bool IsAuthoredRoomLocalFor(Transform levelRoot)
		{
			if ((Object)(object)_root != (Object)null && _usesAuthoredRoomLocalTransform)
			{
				return (Object)(object)_root.transform.parent == (Object)(object)levelRoot;
			}
			return false;
		}

		private PhysicalTable(Transform levelRoot, BlackjackController controller, ModConfig config, ManualLogSource log, Vector3? fixedPosition = null, Quaternion? fixedRotation = null, bool fixedTransformIsLocal = false)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			_log = log;
			_controller = controller;
			_assets = AssetCatalog.Discover(levelRoot);
			_usesAuthoredRoomLocalTransform = fixedTransformIsLocal;
			_root = new GameObject("WK_Blackjack_Table");
			try
			{
				_root.transform.SetParent(levelRoot, !fixedTransformIsLocal);
				if (fixedPosition.HasValue && fixedRotation.HasValue)
				{
					if (fixedTransformIsLocal)
					{
						_root.transform.localPosition = fixedPosition.Value;
						_root.transform.localRotation = fixedRotation.Value;
						_root.transform.localScale = Vector3.one;
						_log.LogInfo((object)"Applied exact Blender prefab-local transform without player or floor-ray adjustment.");
					}
					else
					{
						Vector3 value = fixedPosition.Value;
						float num = FindGroundY(value, value.y - 1.74f);
						_root.transform.position = new Vector3(value.x, num, value.z);
						_root.transform.rotation = fixedRotation.Value;
						_log.LogInfo((object)("Blender GROUND aligned to world floor Y=" + num.ToString("0.###")));
					}
				}
				else
				{
					PlaceInFrontOfPlayer(_root.transform, config.TableOffset.Value);
				}
				BuildFurniture();
				BuildDecorations();
				BuildCelebrationShooters();
				BuildLossEffect();
				BuildHandDisplay();
				BuildInstructionNote();
				_walletCounter = CreateCounterDisplay("WK_Blackjack_WalletCounter", new string[3] { "WhiteKnuckleBlackjack.Assets.WagerOnesWheel.obj", "WhiteKnuckleBlackjack.Assets.WagerTensWheel.obj", "WhiteKnuckleBlackjack.Assets.WagerHundredsWheel.obj" }, (Vector3[])(object)new Vector3[3]
				{
					new Vector3(0.51472276f, 1.8156396f, -0.018863142f),
					new Vector3(0.7305726f, 1.8156396f, -0.018863142f),
					new Vector3(0.94642234f, 1.8156396f, -0.018863142f)
				}, new Vector3(0.64f, 1.8156396f, 0.40528f));
				_betCounter = CreateCounterDisplay("WK_Blackjack_BetCounter", new string[3] { "WhiteKnuckleBlackjack.Assets.WalletOnesWheel.obj", "WhiteKnuckleBlackjack.Assets.WalletTensWheel.obj", "WhiteKnuckleBlackjack.Assets.WalletHundredsWheel.obj" }, (Vector3[])(object)new Vector3[3]
				{
					new Vector3(-0.92850775f, 1.8156396f, -0.015233129f),
					new Vector3(-0.7126579f, 1.8156396f, -0.015233129f),
					new Vector3(-0.49680817f, 1.8156396f, -0.015233129f)
				}, new Vector3(-0.64f, 1.8156396f, 0.40891f));
				_hitButton = CreateButton("WK_Blackjack_Hit", "WhiteKnuckleBlackjack.Assets.HitButton.obj", new Vector3(-0.3999626f, 1.7712188f, 1.0282702f), new Vector3(0.2005618f, 0.1139842f, 0.22f), _assets.ActionButtonTemplate, delegate
				{
					HitOrDeal(controller);
				});
				_standButton = CreateButton("WK_Blackjack_Stand", "WhiteKnuckleBlackjack.Assets.StandButton.obj", new Vector3(0.3981274f, 1.7712188f, 1.0191802f), new Vector3(0.2005618f, 0.1139842f, 0.22f), _assets.ActionButtonTemplate, controller.Stand);
				_betDownButton = CreateButton("WK_Blackjack_BetDown", "WhiteKnuckleBlackjack.Assets.BetDownButton.obj", new Vector3(-0.1470144f, 1.7686613f, 0.8662343f), new Vector3(0.22f, 0.1241184f, 0.22f), _assets.BetDownButtonTemplate, controller.DecreaseBet);
				_betUpButton = CreateButton("WK_Blackjack_BetUp", "WhiteKnuckleBlackjack.Assets.BetUpButton.obj", new Vector3(0.1429856f, 1.7686613f, 0.8662343f), new Vector3(0.22f, 0.1241184f, 0.22f), _assets.BetUpButtonTemplate, controller.IncreaseBet);
				_controller.RoundSettled += PlayRoundEffects;
			}
			catch
			{
				CleanupFailedConstruction();
				throw;
			}
		}

		private void CleanupFailedConstruction()
		{
			_controller.RoundSettled -= PlayRoundEffects;
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
				Object.Destroy((Object)(object)_root);
			}
			foreach (Mesh generatedMesh in _generatedMeshes)
			{
				if ((Object)(object)generatedMesh != (Object)null)
				{
					Object.Destroy((Object)(object)generatedMesh);
				}
			}
			_generatedMeshes.Clear();
		}

		internal static PhysicalTable Create(Transform levelRoot, BlackjackController controller, ModConfig config, ManualLogSource log)
		{
			return new PhysicalTable(levelRoot, controller, config, log);
		}

		internal static PhysicalTable CreateAt(Transform levelRoot, Vector3 position, Quaternion rotation, BlackjackController controller, ModConfig config, ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new PhysicalTable(levelRoot, controller, config, log, position, rotation);
		}

		internal static PhysicalTable CreateAtLocal(Transform levelRoot, Vector3 localPosition, Quaternion localRotation, BlackjackController controller, ModConfig config, ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new PhysicalTable(levelRoot, controller, config, log, localPosition, localRotation, fixedTransformIsLocal: true);
		}

		internal void Render(BlackjackController controller)
		{
			if (!((Object)(object)_root == (Object)null))
			{
				_walletCounter.SetValue(controller.WalletBalance);
				_betCounter.SetValue(controller.SelectedBet);
				SetButtonState(_hitButton, controller.Phase == RoundPhase.Betting || controller.Phase == RoundPhase.Settled || controller.Phase == RoundPhase.PlayerTurn);
				SetButtonState(_standButton, controller.Phase == RoundPhase.PlayerTurn);
				bool active = controller.Phase == RoundPhase.Betting || controller.Phase == RoundPhase.Settled;
				SetButtonState(_betDownButton, active);
				SetButtonState(_betUpButton, active);
				RenderHandDisplay(controller);
				RebuildCards(controller);
			}
		}

		private static void HitOrDeal(BlackjackController controller)
		{
			if (controller.Phase == RoundPhase.Betting || controller.Phase == RoundPhase.Settled)
			{
				controller.DealOrNewRound();
			}
			else
			{
				controller.Hit();
			}
		}

		internal void EditorTick()
		{
		}

		private static void PlaceInFrontOfPlayer(Transform root, Vector3 offset)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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)
			//IL_00c9: 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_00cd: 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_00ea: 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_00f8: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			Vector3 val = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : root.parent.position);
			Vector3 val2 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.forward : root.parent.forward);
			Vector3 val3 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.right : root.parent.right);
			val2.y = 0f;
			val3.y = 0f;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = Vector3.forward;
			}
			((Vector3)(ref val2)).Normalize();
			((Vector3)(ref val3)).Normalize();
			Vector3 val4 = val + val3 * offset.x + val2 * offset.z;
			float num = FindGroundY(val4, val.y - 1.74f);
			root.position = new Vector3(val4.x, num + offset.y, val4.z);
			root.rotation = Quaternion.LookRotation(-val2, Vector3.up);
			Plugin.Log.LogInfo((object)("Blender GROUND aligned to world floor Y=" + num.ToString("0.###")));
		}

		private static float FindGroundY(Vector3 requested, float fallback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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)
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(new Vector3(requested.x, requested.y + 0.25f, requested.z), Vector3.down, ref val, 6f, -5, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val)).normal.y > 0.45f)
			{
				return ((RaycastHit)(ref val)).point.y;
			}
			return fallback;
		}

		private void BuildFurniture()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CreateEmbeddedStaticMesh("WK_Blackjack_UpsideDownUpgradeConsole", "WhiteKnuckleBlackjack.Assets.BlackjackTableBase.obj", _assets.UpgradeConsoleMaterial, addCollision: true);
				CreateEmbeddedStaticMesh("WK_Blackjack_WalletDialHousing", "WhiteKnuckleBlackjack.Assets.WalletDialHousing.obj", _assets.DesktopComputerMaterial, addCollision: false);
				CreateEmbeddedStaticMesh("WK_Blackjack_WagerDialHousing", "WhiteKnuckleBlackjack.Assets.WagerDialHousing.obj", _assets.DesktopComputerMaterial, addCollision: false);
				CreateEmbeddedStaticMesh("WK_Blackjack_CardDispenser", "WhiteKnuckleBlackjack.Assets.CardDispenser.obj", _assets.RecyclerMaterial, addCollision: false);
				return;
			}
			catch (Exception ex)
			{
				_log.LogError((object)("Could not build the edited Blender furniture: " + ex));
			}
			_log.LogWarning((object)"Using the emergency 2 m table fallback.");
			CreateBox("WK_Blackjack_EmergencyTable", _root.transform, new Vector3(0f, 1f, 0f), new Vector3(2f, 2f, 2f), _assets.FurnitureMaterial);
		}

		private void BuildDecorations()
		{
			CreateOptionalDecoration("WK_Blackjack_Radio", "WhiteKnuckleBlackjack.Assets.Radio.obj");
			CreateOptionalDecoration("WK_Blackjack_Mug", "WhiteKnuckleBlackjack.Assets.Mug.obj");
			CreateOptionalDecoration("WK_Blackjack_Skull", "WhiteKnuckleBlackjack.Assets.Skull.obj");
			CreateOptionalDecoration("WK_Blackjack_HandWheel", "WhiteKnuckleBlackjack.Assets.HandWheel.obj");
			CreateOptionalDecoration("WK_Blackjack_FrontGrate", "WhiteKnuckleBlackjack.Assets.FrontGrate.obj");
			CreateOptionalDecoration("WK_Blackjack_PowerLeverHousing", "WhiteKnuckleBlackjack.Assets.PowerLeverHousing.obj");
			CreateOptionalDecoration("WK_Blackjack_PowerLeverHandle", "WhiteKnuckleBlackjack.Assets.PowerLeverHandle.obj");
			CreateOptionalDecoration("WK_Blackjack_Book", "WhiteKnuckleBlackjack.Assets.Book.obj");
		}

		private void BuildInstructionNote()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(0.7f, 1.785f, 0.63f);
			Collider component = CreateBox("WK_Blackjack_InstructionNote", _root.transform, val, new Vector3(0.6f, 0.004f, 0.34f), _assets.CardMaterial).GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			GameObject val2 = new GameObject("WK_Blackjack_InstructionNoteText");
			val2.transform.SetParent(_root.transform, false);
			val2.transform.localPosition = val + Vector3.up * 0.003f;
			val2.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			TextMesh obj = val2.AddComponent<TextMesh>();
			obj.text = "THIS IS BLACKJACK.\nTHE LEFT BUTTON IS \"STAND.\"\nTHE RIGHT BUTTON IS \"HIT/DEAL.\"\n\nAT THE TOP, YELLOW IS THE\nDEALER'S HAND, AND RED IS YOURS.\n\nTHE MACHINE FOLLOWS BASIC\nBLACKJACK RULES. ONCE LOST,\nYOU CANNOT GET YOUR ROACHES BACK.";
			obj.color = Color.black;
			obj.fontSize = 64;
			obj.characterSize = 0.00265f;
			obj.lineSpacing = 0.82f;
			obj.fontStyle = (FontStyle)1;
			obj.anchor = (TextAnchor)4;
			obj.alignment = (TextAlignment)1;
			obj.richText = false;
		}

		private void BuildCelebrationShooters()
		{
			//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_0043: 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)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			CreateOptionalDecoration("WK_Blackjack_CelebrationShooter_Left", "WhiteKnuckleBlackjack.Assets.CelebrationShooterLeft.obj");
			CreateOptionalDecoration("WK_Blackjack_CelebrationShooter_Right", "WhiteKnuckleBlackjack.Assets.CelebrationShooterRight.obj");
			Quaternion localRotation = Quaternion.LookRotation(new Vector3(0f, Mathf.Sin(0.61086524f), Mathf.Cos(0.61086524f)), Vector3.up);
			Vector3[] array = (Vector3[])(object)new Vector3[2]
			{
				new Vector3(-1.0000001f, 1.9230404f, -0.8586025f),
				new Vector3(0.9999999f, 1.9230404f, -0.8586025f)
			};
			foreach (Vector3 localPosition in array)
			{
				CreateCelebrationEffect(localPosition, localRotation);
			}
		}

		private void CreateCelebrationEffect(Vector3 localPosition, Quaternion localRotation)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("WK_Blackjack_CelebrationEmitter");
			val.transform.SetParent(_root.transform, false);
			val.transform.localPosition = localPosition;
			val.transform.localRotation = localRotation;
			if ((Object)(object)_assets.CelebrationParticleTemplate != (Object)null)
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)_assets.CelebrationParticleTemplate).gameObject, val.transform, false);
				((Object)val2).name = "WK_Blackjack_NativeTrainingConfetti";
				val2.transform.localPosition = Vector3.zero;
				val2.transform.localRotation = Quaternion.identity;
				val2.transform.localScale = Vector3.one;
				val2.SetActive(true);
				ParticleSystem[] componentsInChildren = val2.GetComponentsInChildren<ParticleSystem>(true);
				foreach (ParticleSystem val3 in componentsInChildren)
				{
					MainModule main = val3.main;
					((MainModule)(ref main)).playOnAwake = false;
					((MainModule)(ref main)).loop = false;
					((MainModule)(ref main)).stopAction = (ParticleSystemStopAction)0;
					val3.Stop(true, (ParticleSystemStopBehavior)0);
					_winConfetti.Add(val3);
				}
				AudioSource[] componentsInChildren2 = val2.GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource val4 in componentsInChildren2)
				{
					val4.playOnAwake = false;
					val4.Stop();
					_winSounds.Add(val4);
				}
			}
			else
			{
				_log.LogWarning((object)"Native training-finish confetti was not available for a blackjack shooter.");
			}
			if ((Object)(object)_assets.CelebrationWhistleTemplate != (Object)null)
			{
				AudioSource val5 = val.AddComponent<AudioSource>();
				CopyAudioSource(_assets.CelebrationWhistleTemplate, val5);
				val5.playOnAwake = false;
				_winSounds.Add(val5);
			}
			else
			{
				_log.LogWarning((object)"Native tutorial-finish whistle was not available for a blackjack shooter.");
			}
		}

		private static void CopyAudioSource(AudioSource source, AudioSource destination)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			destination.clip = source.clip;
			destination.outputAudioMixerGroup = source.outputAudioMixerGroup;
			destination.mute = source.mute;
			destination.bypassEffects = source.bypassEffects;
			destination.bypassListenerEffects = source.bypassListenerEffects;
			destination.bypassReverbZones = source.bypassReverbZones;
			destination.priority = source.priority;
			destination.volume = source.volume;
			destination.pitch = source.pitch;
			destination.panStereo = source.panStereo;
			destination.spatialBlend = source.spatialBlend;
			destination.reverbZoneMix = source.reverbZoneMix;
			destination.dopplerLevel = source.dopplerLevel;
			destination.spread = source.spread;
			destination.rolloffMode = source.rolloffMode;
			destination.minDistance = source.minDistance;
			destination.maxDistance = source.maxDistance;
			destination.loop = false;
		}

		private void BuildLossEffect()
		{
			//IL_0020: 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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			CreateLossParticleEffect(_assets.LossSmokeTemplate, "WK_Blackjack_LossSmoke", new Vector3(0f, 2.48f, -0.57f), Quaternion.identity);
			if ((Object)(object)_assets.LossFailureClip != (Object)null)
			{
				GameObject val = new GameObject("WK_Blackjack_LossAudio");
				val.transform.SetParent(_root.transform, false);
				val.transform.localPosition = new Vector3(0f, 2.24f, -0.53f);
				_lossSound = val.AddComponent<AudioSource>();
				_lossSound.clip = _assets.LossFailureClip;
				AudioSource? lossSound = _lossSound;
				AudioSource? celebrationWhistleTemplate = _assets.CelebrationWhistleTemplate;
				lossSound.outputAudioMixerGroup = ((celebrationWhistleTemplate != null) ? celebrationWhistleTemplate.outputAudioMixerGroup : null);
				_lossSound.playOnAwake = false;
				_lossSound.loop = false;
				_lossSound.volume = 0.9f;
				_lossSound.spatialBlend = 1f;
				_lossSound.rolloffMode = (AudioRolloffMode)0;
				_lossSound.minDistance = 1.5f;
				_lossSound.maxDistance = 18f;
			}
			else
			{
				_log.LogWarning((object)"Native electrical power-down sound was not available for the loss cue.");
			}
		}

		private void CreateLossParticleEffect(ParticleSystem? template, string name, Vector3 localPosition, Quaternion localRotation)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null)
			{
				_log.LogWarning((object)(name + " could not find its native White Knuckle particle template."));
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, _root.transform, false);
			((Object)val).name = name;
			val.transform.localPosition = localPosition;
			val.transform.localRotation = localRotation;
			val.transform.localScale = Vector3.one;
			val.SetActive(true);
			ParticleSystem[] componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val2 in componentsInChildren)
			{
				MainModule main = val2.main;
				((MainModule)(ref main)).playOnAwake = false;
				((MainModule)(ref main)).loop = false;
				((MainModule)(ref main)).stopAction = (ParticleSystemStopAction)0;
				val2.Stop(true, (ParticleSystemStopBehavior)0);
				_lossParticles.Add(val2);
			}
			AudioSource[] componentsInChildren2 = val.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource obj in componentsInChildren2)
			{
				obj.playOnAwake = false;
				obj.Stop();
				((Behaviour)obj).enabled = false;
			}
		}

		private void PlayRoundEffects(RoundOutcome outcome)
		{
			if (outcome == RoundOutcome.DealerWin)
			{
				PlayLossEffect();
			}
			else
			{
				PlayWinCelebration(outcome);
			}
		}

		private void PlayLossEffect()
		{
			foreach (ParticleSystem lossParticle in _lossParticles)
			{
				if (!((Object)(object)lossParticle == (Object)null))
				{
					lossParticle.Stop(true, (ParticleSystemStopBehavior)0);
					lossParticle.Play(true);
				}
			}
			if ((Object)(object)_lossSound != (Object)null && (Object)(object)_lossSound.clip != (Object)null)
			{
				_lossSound.Stop();
				_lossSound.Play();
			}
			_log.LogInfo((object)"Blackjack loss: fired native machine smoke and power-down audio.");
		}

		private void PlayWinCelebration(RoundOutcome outcome)
		{
			if (outcome != RoundOutcome.PlayerWin && outcome != RoundOutcome.PlayerBlackjack)
			{
				return;
			}
			foreach (ParticleSystem item in _winConfetti)
			{
				if (!((Object)(object)item == (Object)null))
				{
					item.Stop(true, (ParticleSystemStopBehavior)0);
					item.Play(true);
				}
			}
			foreach (AudioSource winSound in _winSounds)
			{
				if (!((Object)(object)winSound == (Object)null) && !((Object)(object)winSound.clip == (Object)null))
				{
					winSound.Stop();
					winSound.Play();
				}
			}
			_log.LogInfo((object)"Blackjack win: fired both 35-degree training confetti shooters.");
		}

		private void BuildHandDisplay()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CreateEmbeddedStaticMesh("WK_Blackjack_HandDisplay", "WhiteKnuckleBlackjack.Assets.HandDisplay.obj", _assets.DesktopComputerMaterial, addCollision: false);
				_playerHandReadout = CreateScreenText("WK_Blackjack_PlayerHandReadout", new Vector3(-0.33862492f, 2.3457873f, -0.6752408f));
				_playerTotalReadout = CreateScreenText("WK_Blackjack_PlayerTotalReadout", new Vector3(-0.07037853f, 2.3457875f, -0.6752409f));
				_dealerHandReadout = CreateScreenText("WK_Blackjack_DealerHandReadout", new Vector3(0.15956767f, 2.3457873f, -0.6752408f));
				_dealerTotalReadout = CreateScreenText("WK_Blackjack_DealerTotalReadout", new Vector3(0.4137063f, 2.3457873f, -0.6752409f));
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Could not add the Blender-authored hand display: " + ex.Message));
			}
		}

		private TextMesh CreateScreenText(string name, Vector3 panelCenter)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(0f, 0.25881907f, 0.96592575f);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, 0.9659258f, -0.25881904f);
			GameObject val3 = new GameObject(name);
			val3.transform.SetParent(_root.transform, false);
			val3.transform.localPosition = panelCenter + val * 0.0025f;
			val3.transform.localRotation = Quaternion.LookRotation(-val, val2);
			TextMesh obj = val3.AddComponent<TextMesh>();
			obj.text = "--";
			obj.color = new Color(1f, 0.92f, 0.72f, 1f);
			obj.fontSize = 64;
			obj.characterSize = 0.0075f;
			obj.fontStyle = (FontStyle)1;
			obj.anchor = (TextAnchor)4;
			obj.alignment = (TextAlignment)1;
			obj.richText = false;
			return obj;
		}

		private void RenderHandDisplay(BlackjackController controller)
		{
			SetScreenText(_playerHandReadout, controller.PlayerHandReadout, 0.29452705f, 0.0075f);
			SetScreenText(_playerTotalReadout, controller.PlayerTotalReadout, 0.14453761f, 0.012f);
			SetScreenText(_dealerHandReadout, controller.DealerHandReadout, 0.26623788f, 0.0075f);
			SetScreenText(_dealerTotalReadout, controller.DealerTotalReadout, 0.14453758f, 0.012f);
		}

		private static void SetScreenText(TextMesh? text, string value, float panelWidth, float preferredSize)
		{
			if (!((Object)(object)text == (Object)null))
			{
				text.text = value;
				float num = Math.Max(1f, (float)value.Length * 0.55f * (float)text.fontSize * 0.1f);
				text.characterSize = Math.Min(preferredSize, panelWidth * 0.9f / num);
			}
		}

		private void CreateOptionalDecoration(string name, string resourceName)
		{
			try
			{
				CreateEmbeddedStaticMesh(name, resourceName, _assets.FurnitureMaterial, addCollision: false);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Could not add optional Blender decoration " + name + ": " + ex.Message));
			}
		}

		private GameObject CreateEmbeddedStaticMesh(string name, string resourceName, Material? material, bool addCollision)
		{
			return CreateEmbeddedMesh(name, _root.transform, resourceName, material, addCollision);
		}

		private GameObject CreateEmbeddedMesh(string name, Transform parent, string resourceName, Material? material, bool addCollision)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			EmbeddedObjLoader.LoadedObj loadedObj = EmbeddedObjLoader.Load(resourceName);
			Mesh mesh = loadedObj.Mesh;
			_generatedMeshes.Add(mesh);
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer val2 = val.AddComponent<MeshRenderer>();
			if (loadedObj.MaterialNames.Length != 0)
			{
				Material[] array = (Material[])(object)new Material[loadedObj.MaterialNames.Length];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = (resourceName.EndsWith("LayoutLabels.obj", StringComparison.Ordinal) ? (material ?? ((Renderer)val2).sharedMaterial) : (_assets.MaterialNamed(loadedObj.MaterialNames[i], material) ?? material ?? ((Renderer)val2).sharedMaterial));
				}
				((Renderer)val2).sharedMaterials = array;
			}
			else if ((Object)(object)material != (Object)null)
			{
				((Renderer)val2).sharedMaterial = material;
			}
			if (addCollision)
			{
				MeshCollider obj = val.AddComponent<MeshCollider>();
				obj.sharedMesh = mesh;
				obj.convex = false;
			}
			return val;
		}

		private CL_Button? CreateButton(string name, string visualResourceName, Vector3 colliderCenter, Vector3 colliderSize, GameObject? template, Action action)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			CreateEmbeddedStaticMesh(name + "_ExactBlenderVisual", visualResourceName, _assets.FurnitureMaterial, addCollision: false);
			GameObject val = new GameObject(name + "_InvisibleInteraction");
			val.SetActive(false);
			val.transform.SetParent(_root.transform, false);
			val.transform.localPosition = colliderCenter;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			if ((Object)(object)template != (Object)null)
			{
				val.layer = template.layer;
			}
			BoxCollider obj = val.AddComponent<BoxCollider>();
			obj.size = colliderSize;
			((Collider)obj).isTrigger = false;
			CL_Button val2 = val.AddComponent<CL_Button>();
			val.AddComponent<ObjectTagger>().tags = new List<string> { "Button" };
			val2.active = true;
			val2.maxPresses = 0;
			val2.pressCooldown = 0.12f;
			val2.projectilesCanPress = false;
			val2.hammerCanPress = false;
			val2.activeEvent = new UnityEvent();
			val2.activeEvent.AddListener((UnityAction)delegate
			{
				action();
			});
			CopyNativeButtonSounds(val2, template, _assets.ActionButtonTemplate, _assets.BetUpButtonTemplate, _assets.BetDownButtonTemplate);
			_log.LogInfo((object)(name + " native press sound=" + (((Object)(object)val2.pressSound == (Object)null) ? "unavailable" : ((Object)val2.pressSound).name)));
			val.SetActive(true);
			return val2;
		}

		private static void CopyNativeButtonSounds(CL_Button target, params GameObject?[] templates)
		{
			foreach (GameObject val in templates)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				CL_Button component = val.GetComponent<CL_Button>();
				CL_HoldButton component2 = val.GetComponent<CL_HoldButton>();
				if ((Object)(object)component != (Object)null)
				{
					if ((Object)(object)target.pressSound == (Object)null)
					{
						target.pressSound = component.pressSound;
					}
					if ((Object)(object)target.cooldownEndSound == (Object)null)
					{
						target.cooldownEndSound = component.cooldownEndSound;
					}
				}
				else if ((Object)(object)component2 != (Object)null)
				{
					if ((Object)(object)target.pressSound == (Object)null)
					{
						target.pressSound = component2.pressSound;
					}
					if ((Object)(object)target.cooldownEndSound == (Object)null)
					{
						target.cooldownEndSound = component2.letgoSound;
					}
				}
				if ((Object)(object)target.pressSound != (Object)null && (Object)(object)target.cooldownEndSound != (Object)null)
				{
					break;
				}
			}
		}

		private CounterDisplay CreateCounterDisplay(string name, string[] resources, Vector3[] pivots, Vector3 fallbackPosition)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> list = new List<GameObject>();
			GameObject val = null;
			try
			{
				if (resources.Length != 3 || pivots.Length != 3)
				{
					throw new InvalidOperationException("A blackjack counter requires exactly three saved wheels.");
				}
				Transform[] array = (Transform[])(object)new Transform[3];
				for (int i = 0; i < array.Length; i++)
				{
					GameObject val2 = CreateEmbeddedStaticMesh(name + "_Wheel_" + i, resources[i], _assets.CounterWheelMaterial, addCollision: false);
					list.Add(val2);
					UnmirrorCounterDigitFaces(val2);
					val2.transform.localPosition = pivots[i];
					val2.transform.localRotation = Quaternion.identity;
					val2.transform.localScale = Vector3.one;
					array[i] = val2.transform;
				}
				Transform[] array2 = array;
				val = new GameObject(name + "_NativeLogic");
				val.SetActive(false);
				val.transform.SetParent(_root.transform, false);
				val.transform.localPosition = fallbackPosition;
				val.transform.localRotation = Quaternion.identity;
				val.transform.localScale = Vector3.one;
				UT_RoachCounter obj = val.AddComponent<UT_RoachCounter>();
				obj.counters = array2;
				obj.customInput = true;
				obj.negative = false;
				NativeCounterTicker nativeCounterTicker = val.AddComponent<NativeCounterTicker>();
				nativeCounterTicker.Configure(array2, _assets.CounterTickerAudio);
				val.SetActive(true);
				CounterDisplay counterDisplay = new CounterDisplay(obj, nativeCounterTicker, null);
				counterDisplay.SetValue(0);
				return counterDisplay;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.SetActive(false);
				}
				foreach (GameObject item in list)
				{
					if ((Object)(object)item != (Object)null)
					{
						item.SetActive(false);
					}
				}
				_log.LogError((object)("Could not load exact Blender counter wheels: " + ex));
				GameObject val3 = new GameObject(name + "_FallbackDigits");
				val3.transform.SetParent(_root.transform, false);
				val3.transform.localPosition = fallbackPosition;
				val3.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
				TextMesh val4 = val3.AddComponent<TextMesh>();
				val4.color = Color.white;
				val4.fontSize = 48;
				val4.characterSize = 0.0036f;
				val4.anchor = (TextAnchor)4;
				val4.alignment = (TextAlignment)1;
				val4.text = "000";
				return new CounterDisplay(null, null, val4);
			}
		}

		private static void UnmirrorCounterDigitFaces(GameObject wheel)
		{
			MeshFilter component = wheel.GetComponent<MeshFilter>();
			Mesh val = ((component != null) ? component.sharedMesh : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Vector2[] uv = val.uv;
			if (uv.Length == 0)
			{
				return;
			}
			float num = float.PositiveInfinity;
			float num2 = float.NegativeInfinity;
			for (int i = 0; i < uv.Length; i++)
			{
				if (!(uv[i].x >= 0.5f))
				{
					num = Mathf.Min(num, uv[i].x);
					num2 = Mathf.Max(num2, uv[i].x);
				}
			}
			if (float.IsInfinity(num) || num2 - num < 0.0001f)
			{
				return;
			}
			float num3 = num + num2;
			for (int j = 0; j < uv.Length; j++)
			{
				if (uv[j].x < 0.5f)
				{
					uv[j].x = num3 - uv[j].x;
				}
			}
			val.uv = uv;
		}

		private static void SetButtonState(CL_Button? button, bool active)
		{
			if ((Object)(object)button == (Object)null)
			{
				return;
			}
			try
			{
				button.SetInteractable(active);
			}
			catch
			{
				button.active = active;
			}
		}

		private void RebuildCards(BlackjackController controller)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!HandPrefixMatches(controller.DealerHand, _dealerCardVisuals) || !HandPrefixMatches(controller.PlayerHand, _playerCardVisuals))
			{
				ClearCards();
			}
			int num = 0;
			while (_playerCardVisuals.Count < controller.PlayerHand.Cards.Count || _dealerCardVisuals.Count < controller.DealerHand.Cards.Count)
			{
				if (_playerCardVisuals.Count < controller.PlayerHand.Cards.Count)
				{
					int count = _playerCardVisuals.Count;
					_playerCardVisuals.Add(CreateCardVisual(controller.PlayerHand.Cards[count], CardPosition(dealer: false, count), CardTextPosition(dealer: false, count), hidden: false, (float)num++ * 0.11f));
				}
				if (_dealerCardVisuals.Count < controller.DealerHand.Cards.Count)
				{
					int count2 = _dealerCardVisuals.Count;
					bool hidden = controller.HideDealerHoleCard && count2 == 1;
					_dealerCardVisuals.Add(CreateCardVisual(controller.DealerHand.Cards[count2], CardPosition(dealer: true, count2), CardTextPosition(dealer: true, count2), hidden, (float)num++ * 0.11f));
				}
			}
			for (int i = 0; i < _playerCardVisuals.Count; i++)
			{
				_playerCardVisuals[i].UpdateLabel(hidden: false);
			}
			for (int j = 0; j < _dealerCardVisuals.Count; j++)
			{
				_dealerCardVisuals[j].UpdateLabel(controller.HideDealerHoleCard && j == 1);
			}
		}

		private static bool HandPrefixMatches(Hand hand, List<CardVisual> visuals)
		{
			if (hand.Cards.Count < visuals.Count)
			{
				return false;
			}
			for (int i = 0; i < visuals.Count; i++)
			{
				Card card = hand.Cards[i];
				if (visuals[i].Card.Rank != card.Rank || visuals[i].Card.Suit != card.Suit)
				{
					return false;
				}
			}
			return true;
		}

		private static Vector3 CardPosition(bool dealer, int index)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (index < 2)
			{
				if (dealer)
				{
					if (index != 0)
					{
						return new Vector3(0.14964f, 1.7546397f, -0.011034936f);
					}
					return new Vector3(-0.13036f, 1.7506398f, -0.011034936f);
				}
				if (index != 0)
				{
					return new Vector3(0.13721f, 1.7546397f, 0.57987f);
				}
				return new Vector3(-0.14279f, 1.7506398f, 0.57987f);
			}
			int num = index - 2;
			int num2 = num % 5;
			int num3 = num / 5;
			float num4 = num2 switch
			{
				1 => -0.04f, 
				2 => 0.04f, 
				3 => -0.02f, 
				4 => 0.02f, 
				_ => 0f, 
			};
			float num5;
			switch (num2)
			{
			case 1:
			case 2:
				num5 = -0.02f;
				break;
			case 3:
			case 4:
				num5 = -0.04f;
				break;
			default:
				num5 = 0f;
				break;
			}
			float num6 = num5 - (float)num3 * 0.06f;
			Vector3 val = (dealer ? new Vector3(0.009639994f, 1.7586396f, -0.24103494f) : new Vector3(-0.002790004f, 1.7586396f, 0.34987f));
			return new Vector3(val.x + num4, val.y + (float)num * 0.004f, val.z + num6);
		}

		private static Vector3 CardTextPosition(bool dealer, int index)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = CardPosition(dealer, index);
			if (dealer && index == 0)
			{
				return new Vector3(val.x, 1.7459306f, val.z);
			}
			return new Vector3(val.x, val.y - 0.004709192f, val.z);
		}

		private CardVisual CreateCardVisual(Card value, Vector3 localPosition, Vector3 textPosition, bool hidden, float delay)
		{
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			Item val = null;
			float num = 1f;
			Renderer[] array = Array.Empty<Renderer>();
			GameObject val2;
			Renderer[] array2;
			if ((Object)(object)_assets.CardTemplate != (Object)null)
			{
				val2 = Object.Instantiate<GameObject>(_assets.CardTemplate, _root.transform, false);
				((Object)val2).name = "WK_Blackjack_Card";
				val2.SetActive(false);
				Item_Object component = val2.GetComponent<Item_Object>();
				if (component?.itemData != null)
				{
					val = component.itemData.GetClone((Item)null, false);
					val.dataModules?.RemoveAll((Item_Data module) => module is Item_Data_Text);
					val.SetFirstDataStringsofType("text", hidden ? "Dealer card (hidden)" : CardHeldName(value));
					component.itemData = val;
					val.InitializeItemData(component);
				}
				array = val2.GetComponentsInChildren<Renderer>(true);
				array2 = array;
				foreach (Renderer obj in array2)
				{
					obj.enabled = false;
					obj.forceRenderingOff = true;
				}
				val2.transform.localScale = Vector3.one * 0.56294465f;
				num = 1.7763736f;
			}
			else
			{
				val2 = new GameObject("WK_Blackjack_Card");
				val2.transform.SetParent(_root.transform, false);
			}
			val2.transform.localPosition = localPosition;
			val2.transform.localRotation = Quaternion.identity;
			GameObject val3 = CreateEmbeddedMesh("WK_Blackjack_Card_ExactBlenderVisual", val2.transform, "WhiteKnuckleBlackjack.Assets.CardMesh.obj", _assets.CardMaterial, addCollision: false);
			val3.transform.localPosition = Vector3.zero;
			val3.transform.localRotation = Quaternion.identity;
			val3.transform.localScale = Vector3.one * num;
			if ((Object)(object)val2.GetComponentInChildren<Collider>(true) == (Object)null)
			{
				Mesh sharedMesh = val3.GetComponent<MeshFilter>().sharedMesh;
				BoxCollider obj2 = val2.AddComponent<BoxCollider>();
				Bounds bounds = sharedMesh.bounds;
				obj2.center = ((Bounds)(ref bounds)).center * num;
				bounds = sharedMesh.bounds;
				obj2.size = ((Bounds)(ref bounds)).size * num;
				val2.AddComponent<Rigidbody>();
			}
			val2.SetActive(true);
			array2 = array;
			foreach (Renderer val4 in array2)
			{
				if ((Object)(object)val4 != (Object)null)
				{
					val4.enabled = false;
					val4.forceRenderingOff = true;
				}
			}
			TextMesh val5 = AddCardText("", textPosition, 0.1f, Color.black);
			if ((Object)(object)val5 != (Object)null)
			{
				((Component)val5).transform.SetParent(val2.transform, true);
			}
			CardVisual cardVisual = new CardVisual(value, val2, val5, val, hidden);
			cardVisual.UpdateLabel(hidden);
			val2.AddComponent<DealtCardMotion>().Configure(_root.transform, new Vector3(0.01461f, 1.9006397f, -0.5f), localPosition, delay);
			return cardVisual;
		}

		private static string CardHeldName(Card card)
		{
			return card.Rank switch
			{
				1 => "Ace", 
				11 => "Jack", 
				12 => "Queen", 
				13 => "King", 
				_ => card.Rank.ToString(), 
			} + " of " + card.Suit switch
			{
				0 => "Spades", 
				1 => "Hearts", 
				2 => "Diamonds", 
				_ => "Clubs", 
			};
		}

		private TextMesh? AddCardText(string value, Vector3 localPosition, float characterSize, Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("WK_Blackjack_Text_" + value);
				val.transform.SetParent(_root.transform, false);
				val.transform.localPosition = localPosition;
				val.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
				TextMesh obj = val.AddComponent<TextMesh>();
				obj.text = value;
				obj.color = color;
				obj.fontSize = 48;
				obj.characterSize = characterSize * 0.08f;
				obj.anchor = (TextAnchor)4;
				obj.alignment = (TextAlignment)1;
				return obj;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Could not create blackjack label: " + ex.Message));
				return null;
			}
		}

		private static GameObject CreateBox(string name, Transform parent, Vector3 localPosition, Vector3 localScale, Material? material)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)val).name = name;
			val.transform.SetParent(parent, false);
			val.transform.localPosition = localPosition;
			val.transform.localScale = localScale;
			if ((Object)(object)material != (Object)null)
			{
				((Renderer)val.GetComponent<MeshRenderer>()).sharedMaterial = material;
			}
			return val;
		}

		public void Dispose()
		{
			_controller.RoundSettled -= PlayRoundEffects;
			ClearCards();
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
				Object.Destroy((Object)(object)_root);
			}
			foreach (Mesh generatedMesh in _generatedMeshes)
			{
				if ((Object)(object)generatedMesh != (Object)null)
				{
					Object.Destroy((Object)(object)generatedMesh);
				}
			}
			_generatedMeshes.Clear();
		}

		private void ClearCards()
		{
			foreach (CardVisual dealerCardVisual in _dealerCardVisuals)
			{
				if ((Object)(object)dealerCardVisual.GameObject != (Object)null)
				{
					Object.Destroy((Object)(object)dealerCardVisual.GameObject);
				}
			}
			foreach (CardVisual playerCardVisual in _playerCardVisuals)
			{
				if ((Object)(object)playerCardVisual.GameObject != (Object)null)
				{
					Object.Destroy((Object)(object)playerCardVisual.GameObject);
				}
			}
			_dealerCardVisuals.Clear();
			_playerCardVisuals.Clear();
		}
	}
	internal sealed class NativeCounterTicker : MonoBehaviour
	{
		private Transform[] _wheels = Array.Empty<Transform>();

		private readonly int[] _digits = new int[3];

		private UT_AudioClipHandler? _audio;

		private int _pendingWheelMask;

		private float _nextTickAt;

		private bool _initialized;

		internal void Configure(Transform[] wheels, UT_AudioClipHandler? audio)
		{
			_wheels = wheels;
			_audio = audio;
		}

		internal void SetValue(int value)
		{
			int num = Math.Min(999, Math.Max(0, value));
			for (int i = 0; i < _digits.Length; i++)
			{
				int num2 = num % 10;
				if (_initialized && num2 != _digits[i])
				{
					_pendingWheelMask |= 1 << i;
				}
				_digits[i] = num2;
				num /= 10;
			}
			_initialized = true;
		}

		private void Update()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			UT_AudioClipHandler audio = _audio;
			if ((Object)(object)audio == (Object)null || _pendingWheelMask == 0 || Time.timeScale < 0.8f || Time.unscaledTime < _nextTickAt)
			{
				return;
			}
			int num = Math.Min(_wheels.Length, _digits.Length);
			for (int i = 0; i < num; i++)
			{
				int num2 = 1 << i;
				if ((_pendingWheelMask & num2) != 0)
				{
					Transform val = _wheels[i];
					_pendingWheelMask &= ~num2;
					_nextTickAt = Time.unscaledTime + 0.075f;
					if ((Object)(object)val == (Object)null)
					{
						return;
					}
					try
					{
						audio.PlaySound("vending:ticker", val.position);
						return;
					}
					catch
					{
						_audio = null;
						return;
					}
				}
			}
			_pendingWheelMask = 0;
		}
	}
	internal sealed class DealtCardMotion : MonoBehaviour
	{
		private Transform? _table;

		private Vector3 _start;

		private Vector3 _target;

		private Quaternion _startRotation;

		private Quaternion _targetRotation;

		private Rigidbody[] _bodies = Array.Empty<Rigidbody>();

		private Collider[] _colliders = Array.Empty<Collider>();

		private bool[] _bodyWasKinematic = Array.Empty<bool>();

		private bool[] _bodyUsedGravity = Array.Empty<bool>();

		private bool[] _colliderWasEnabled = Array.Empty<bool>();

		private float _delay;

		private float _elapsed;

		private bool _finished;

		internal void Configure(Transform table, Vector3 start, Vector3 target, float delay)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			_table = table;
			_start = start;
			_target = target;
			_delay = delay;
			_startRotation = Quaternion.Euler(-28f, 0f, 0f);
			_targetRotation = Quaternion.identity;
			_bodies = ((Component)this).GetComponentsInChildren<Rigidbody>(true);
			_colliders = ((Component)this).GetComponentsInChildren<Collider>(true);
			_bodyWasKinematic = new bool[_bodies.Length];
			_bodyUsedGravity = new bool[_bodies.Length];
			_colliderWasEnabled = new bool[_colliders.Length];
			((Component)this).transform.SetParent(table, false);
			((Component)this).transform.localPosition = start;
			((Component)this).transform.localRotation = _startRotation;
			for (int i = 0; i < _bodies.Length; i++)
			{
				Rigidbody val = _bodies[i];
				_bodyWasKinematic[i] = val.isKinematic;
				_bodyUsedGravity[i] = val.useGravity;
				val.useGravity = false;
				val.isKinematic = true;
			}
			for (int j = 0; j < _colliders.Length; j++)
			{
				_colliderWasEnabled[j] = _colliders[j].enabled;
				_colliders[j].enabled = false;
			}
		}

		private void Update()
		{
			//IL_006a: 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_0076: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00b4: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			if (_finished || (Object)(object)_table == (Object)null)
			{
				return;
			}
			_elapsed += Time.unscaledDeltaTime;
			if (_elapsed < _delay)
			{
				return;
			}
			float num = Mathf.Clamp01((_elapsed - _delay) / 0.52f);
			float num2 = num * num * (3f - 2f * num);
			((Component)this).transform.localPosition = Vector3.Lerp(_start, _target, num2) + Vector3.up * (Mathf.Sin(num * MathF.PI) * 0.28f);
			((Component)this).transform.localRotation = Quaternion.Slerp(_startRotation, _targetRotation, num2);
			if (num < 1f)
			{
				return;
			}
			_finished = true;
			((Component)this).transform.localPosition = _target;
			((Component)this).transform.localRotation = _targetRotation;
			for (int i = 0; i < _colliders.Length; i++)
			{
				if ((Object)(object)_colliders[i] != (Object)null)
				{
					_colliders[i].enabled = _colliderWasEnabled[i];
				}
			}
			for (int j = 0; j < _bodies.Length; j++)
			{
				Rigidbody val = _bodies[j];
				if (!((Object)(object)val == (Object)null))
				{
					val.isKinematic = _bodyWasKinematic[j];
					val.useGravity = _bodyUsedGravity[j];
					if (!val.isKinematic)
					{
						val.velocity = _table.TransformDirection(new Vector3(0f, -0.03f, 0.04f));
					}
				}
			}
			Object.Destroy((Object)(object)this);
		}
	}
	[BepInPlugin("com.battery_boy.whiteknuckle.blackjack", "Safehouse Blackjack", "0.5.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private readonly struct InterludePlacement
		{
			internal readonly string LevelToken;

			internal readonly bool HasAuthoredLocalTransform;

			internal readonly Vector3 LocalPosition;

			internal readonly Quaternion LocalRotation;

			internal InterludePlacement(string levelToken)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				LevelToken = levelToken;
				HasAuthoredLocalTransform = false;
				LocalPosition = Vector3.zero;
				LocalRotation = Quaternion.identity;
			}

			internal InterludePlacement(string levelToken, Vector3 localPosition, Quaternion localRotation)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: 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)
				LevelToken = levelToken;
				HasAuthoredLocalTransform = true;
				LocalPosition = localPosition;
				LocalRotation = localRotation;
			}
		}

		public const string PluginGuid = "com.battery_boy.whiteknuckle.blackjack";

		public const string PluginName = "Safehouse Blackjack";

		public const string PluginVersion = "0.5.1";

		internal static ManualLogSource Log = null;

		internal static ModConfig Settings = null;

		internal static Plugin Instance = null;

		private BlackjackController? _controller;

		private PhysicalTable? _table;

		private BlackjackRuntimeDriver? _driver;

		private BlackjackAnnouncementPlayer? _announcements;

		private Harmony? _harmony;

		private M_Level? _firstRoom;

		private Transform? _activeInterludeRoot;

		private InterludePlacement? _activeInterludePlacement;

		private float _interludePlacementReadyAt;

		private GameObject? _runtimeAnchor;

		private float _nextSafeCheck;

		private float _showHintUntil;

		private bool _wasSafe;

		private bool _updateObserved;

		private int _lastRuntimeFrame = -1;

		private static readonly InterludePlacement[] FirstInterludePlacements = new InterludePlacement[3]
		{
			new InterludePlacement("Campaign_Interlude_Silo_To_Pipeworks_01", new Vector3(-0.10492229f, 48.652714f, 11.552661f), new Quaternion(0f, -1f, 0f, 0f)),
			new InterludePlacement("M5_Habitation_Shaft_Inter01"),
			new InterludePlacement("Campaign_Interlude_Habitation_To_Abyss_01")
		};

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new ModConfig(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.battery_boy.whiteknuckle.blackjack");
			InstallRuntimePatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
			GameObject val = new GameObject("WK_Blackjack_RuntimeDriver");
			Object.DontDestroyOnLoad((Object)(object)val);
			_driver = val.AddComponent<BlackjackRuntimeDriver>();
			_announcements = val.AddComponent<BlackjackAnnouncementPlayer>();
			_announcements.Configure(Settings.PAAnnouncementChancePercent.Value, Log);
			CreateController();
			Log.LogInfo((object)"Safehouse Blackjack 0.5.1 loaded");
		}

		private void InstallRuntimePatches()
		{
			InstallPostfix(typeof(M_Level), "Awake", "LevelAwakePostfix");
			InstallPostfix(typeof(M_Level), "OnEnter", "LevelEnterPostfix");
			InstallPostfix(typeof(ENT_Player), "Start", "PlayerStartPostfix");
			InstallPostfix(typeof(ENT_Player), "Update", "PlayerUpdatePostfix");
		}

		private void InstallPostfix(Type targetType, string targetName, string patchName)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(targetType, targetName, (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(BlackjackRuntimePatches), patchName, (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null)
				{
					Log.LogError((object)("Blackjack hook missing: " + targetType.Name + "." + targetName));
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
				bool flag = patchInfo != null && patchInfo.Owners.Contains("com.battery_boy.whiteknuckle.blackjack");
				Log.LogInfo((object)("Blackjack hook " + targetType.Name + "." + targetName + " installed=" + flag));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Blackjack hook failed for " + targetType.Name + "." + targetName + ": " + ex));
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Log.LogWarning((object)"Blackjack Unity plugin host was destroyed; persistent static runtime remains available.");
		}

		private void CreateController()
		{
			_controller?.Dispose();
			_controller = new BlackjackController(Settings, Log);
			_controller.Changed += RefreshTable;
			if ((Object)(object)_announcements != (Object)null)
			{
				_controller.RoundSettled += _announcements.QueueAfterRound;
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			_wasSafe = false;
			_nextSafeCheck = 0f;
			_showHintUntil = Time.unscaledTime + 15f;
			if (TryGetActiveExactPlacement(out Transform root, out InterludePlacement _))
			{
				if (_table != null && _table.IsAlive && !_table.IsAuthoredRoomLocalFor(root))
				{
					DestroyTable();
				}
				DestroyRuntimeAnchor();
				_interludePlacementReadyAt = 0f;
				Log.LogInfo((object)"Scene loaded while exact authored interlude remains active; preserving its room-local placement state.");
			}
			else
			{
				_activeInterludeRoot = null;
				_activeInterludePlacement = null;
				DestroyTable();
				DestroyRuntimeAnchor();
			}
		}

		internal unsafe void RuntimeUpdate()
		{
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			if (_lastRuntimeFrame == Time.frameCount)
			{
				return;
			}
			_lastRuntimeFrame = Time.frameCount;
			if (!_updateObserved)
			{
				_updateObserved = true;
				Log.LogInfo((object)"Blackjack runtime update loop started.");
			}
			_controller?.Tick();
			_table?.EditorTick();
			HandleFallbackKeys();
			if (!Settings.Enabled.Value || Time.unscaledTime < _nextSafeCheck)
			{
				return;
			}
			_nextSafeCheck = Time.unscaledTime + 0.4f;
			Transform val = FindCurrentSafeAreaRoot();
			bool flag = IsSafeNow() || (Object)(object)val != (Object)null;
			bool flag2 = _table == null || !_table.IsAlive;
			InterludePlacement? activeInterludePlacement = _activeInterludePlacement;
			bool flag3 = (Object)(object)_activeInterludeRoot != (Object)null && activeInterludePlacement.HasValue;
			if (flag2 && flag3 && Time.unscaledTime >= _interludePlacementReadyAt)
			{
				InterludePlacement value = activeInterludePlacement.Value;
				Vector3 position;
				Quaternion rotation;
				string anchorName;
				if (value.HasAuthoredLocalTransform)
				{
					SpawnTableAtLocal(_activeInterludeRoot, value.LocalPosition, value.LocalRotation, value.LevelToken + " exact Blender room-local placement");
				}
				else if (TryCalculateRoomPlacement(_activeInterludeRoot, out position, out rotation, out anchorName))
				{
					SpawnTableAt(_activeInterludeRoot, position, rotation, value.LevelToken + " room-local automatic placement");
					ManualLogSource log = Log;
					string[] obj = new string[5] { "Automatically placed interlude machine from room anchor ", anchorName, " at ", null, null };
					Vector3 val2 = position;
					obj[3] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
					obj[4] = ".";
					log.LogInfo((object)string.Concat(obj));
				}
			}
			if (flag && flag2 && !flag3)
			{
				string reason = (((Object)(object)val != (Object)null) ? "safe-area bounds" : "game safe flag");
				SpawnTable(val, reason);
			}
			else if (!flag && _wasSafe && !flag3)
			{
				DestroyTable();
			}
			if (flag != _wasSafe)
			{
				Log.LogInfo((object)(flag ? "Safe area detected; placing blackjack table." : "Left safe area; removing blackjack table."));
			}
			_wasSafe = flag;
		}

		private static bool IsSafeNow()
		{
			try
			{
				return CL_GameManager.IsSafe();
			}
			catch
			{
				return false;
			}
		}

		private static Transform? FindCurrentSafeAreaRoot()
		{
			//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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null)
			{
				return null;
			}
			Vector3 position = ((Component)playerObject).transform.position;
			M_Level[] array = Object.FindObjectsOfType<M_Level>();
			foreach (M_Level val in array)
			{
				if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || !val.safeArea)
				{
					continue;
				}
				try
				{
					Bounds val2 = val.CalculateBounds();
					((Bounds)(ref val2)).Expand(2f);
					Vector3 val3 = ((Component)val).transform.InverseTransformPoint(position);
					if (((Bounds)(ref val2)).Contains(val3))
					{
						return ((Component)val).transform;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private void SpawnTable(Transform? preferredRoot = null, string reason = "manual placement")
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			DestroyTable();
			if (_controller == null)
			{
				return;
			}
			Transform val = preferredRoot;
			try
			{
				if (val == null)
				{
					val = WorldLoader.GetCurrentLevelParentRoot();
				}
			}
			catch
			{
			}
			if ((Object)(object)val == (Object)null)
			{
				if (_runtimeAnchor == null)
				{
					_runtimeAnchor = new GameObject("WK_Blackjack_RuntimeAnchor");
				}
				val = _runtimeAnchor.transform;
				Log.LogWarning((object)"No current level root was available; using a temporary scene anchor.");
			}
			try
			{
				_table = PhysicalTable.Create(val, _controller, Settings, Log);
				RefreshTable();
				Log.LogInfo((object)("Blackjack table placed (" + reason + ")."));
			}
			catch (Exception ex)
			{
				_table = null;
				Log.LogError((object)("Blackjack table placement failed: " + ex));
			}
		}

		private void DestroyTable()
		{
			_table?.Dispose();
			_table = null;
		}

		private void DestroyRuntimeAnchor()
		{
			if ((Object)(object)_runtimeAnchor != (Object)null)
			{
				Object.Destroy((Object)(object)_runtimeAnchor);
			}
			_runtimeAnchor = null;
		}

		private void RefreshTable()
		{
			_table?.Render(_controller);
		}

		private void HandleFallbackKeys()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if (_controller == null || !Settings.KeyboardFallback.Value)
			{
				return;
			}
			if (Input.GetKeyDown(Settings.RespawnTableKey.Value))
			{
				Log.LogInfo((object)"F6 manual table placement requested.");
				_showHintUntil = Time.unscaledTime + 15f;
				SpawnTable(null, "F6 manual placement");
				return;
			}
			PhysicalTable? table = _table;
			if ((table == null || !table.IsEditing) && (_table != null || _wasSafe))
			{
				if (Input.GetKeyDown(Settings.IncreaseBetKey.Value))
				{
					_controller.IncreaseBet();
				}
				if (Input.GetKeyDown(Settings.DecreaseBetKey.Value))
				{
					_controller.DecreaseBet();
				}
				if (Input.GetKeyDown(Settings.DealKey.Value))
				{
					_controller.DealOrNewRound();
				}
				if (Input.GetKeyDown(Settings.HitKey.Value))
				{
					_controller.Hit();
				}
				if (Input.GetKeyDown(Settings.StandKey.Value))
				{
					_controller.Stand();
				}
				if (Input.GetKeyDown(Settings.DoubleKey.Value))
				{
					_controller.DoubleDown();
				}
			}
		}

		internal void DrawGui()
		{
		}

		internal void LevelEntered(M_Level level)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)level == (Object)null || !Settings.Enabled.Value)
			{
				return;
			}
			string text = AssetCatalog.HierarchyPath(((Component)level).transform);
			bool flag = text.IndexOf("Interlude", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)level).name.IndexOf("Interlude", StringComparison.OrdinalIgnoreCase) >= 0;
			Log.LogInfo((object)("Entered level: " + text + " (interlude=" + flag + ")"));
			if (!flag)
			{
				return;
			}
			if (TryGetInterludePlacement(((Component)level).transform, out var result))
			{
				bool flag2 = (Object)(object)_activeInterludeRoot == (Object)(object)((Component)level).transform && _activeInterludePlacement.HasValue;
				_activeInterludeRoot = ((Component)level).transform;
				_activeInterludePlacement = result;
				if (result.HasAuthoredLocalTransform)
				{
					_interludePlacementReadyAt = 0f;
					if (!flag2 || _table == null || !_table.IsAlive || !_table.IsAuthoredRoomLocalFor(((Component)level).transform))
					{
						SpawnTableAtLocal(((Component)level).transform, result.LocalPosition, result.LocalRotation, result.LevelToken + " exact Blender placement on interlude entry");
					}
					return;
				}
				if (!flag2)
				{
					DestroyTable();
				}
				_interludePlacementReadyAt = Time.unscaledTime + 3f;
				Log.LogInfo((object)"Configured interlude detected; waiting for its room-local anchor to settle.");
			}
			else
			{
				_activeInterludeRoot = ((Component)level).transform;
				_activeInterludePlacement = null;
				DestroyTable();
				SpawnTable(((Component)level).transform, "interlude entry");
			}
		}

		internal void LocalPlayerStarted(ENT_Player player)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)ENT_Player.playerObject || !Settings.Enabled.Value)
			{
				return;
			}
			if (TryGetActiveExactPlacement(out Transform root, out InterludePlacement placement))
			{
				if (_table == null || !_table.IsAlive || !_table.IsAuthoredRoomLocalFor(root))
				{
					SpawnTableAtLocal(root, placement.LocalPosition, placement.LocalRotation, placement.LevelToken + " exact placement protected from player Start");
				}
				Log.LogInfo((object)"Skipped first-room player-relative table because an exact authored interlude is active.");
				return;
			}
			ManualLogSource log = Log;
			Scene activeScene = SceneManager.GetActiveScene();
			log.LogInfo((object)("Local player started in " + ((Scene)(ref activeScene)).name + "; placing first-room blackjack table."));
			if ((Object)(object)_firstRoom != (Object)null && (Object)(object)_firstRoom.spawnPosition != (Object)null)
			{
				Transform spawnPosition = _firstRoom.spawnPosition;
				Vector3 forward = spawnPosition.forward;
				forward.y = 0f;
				if (((Vector3)(ref forward)).sqrMagnitude < 0.01f)
				{
					forward = Vector3.forward;
				}
				((Vector3)(ref forward)).Normalize();
				Vector3 position = spawnPosition.position + forward * 1.8f;
				SpawnTableAt(((Component)_firstRoom).transform, position, Quaternion.LookRotation(-forward, Vector3.up), "M1_Intro_01 spawn point");
			}
			else
			{
				SpawnTable(null, "initial player spawn");
			}
		}

		internal void LevelAwake(M_Level level)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)level == (Object)null)
			{
				return;
			}
			string text = ((Object)level).name + " / " + level.levelName;
			if (Settings.Enabled.Value && TryGetInterludePlacement(((Component)level).transform, out var result) && result.HasAuthoredLocalTransform)
			{
				bool num = _table != null && _table.IsAlive && _table.IsAuthoredRoomLocalFor(((Component)level).transform);
				_activeInterludeRoot = ((Component)level).transform;
				_activeInterludePlacement = result;
				_interludePlacementReadyAt = 0f;
				if (!num)
				{
					SpawnTableAtLocal(((Component)level).transform, result.LocalPosition, result.LocalRotation, result.LevelToken + " exact Blender placement during M_Level.Awake");
				}
			}
			if (text.IndexOf("M1_Intro_01", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				_firstRoom = level;
				Log.LogInfo((object)("Found first playable room: " + text + "; spawn marker=" + (((Object)(object)level.spawnPosition == (Object)null) ? "missing" : ((object)level.spawnPosition.position/*cast due to .constrained prefix*/).ToString())));
			}
		}

		private unsafe void SpawnTableAt(Transform levelRoot, Vector3 position, Quaternion rotation, string reason)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			DestroyTable();
			if (_controller == null)
			{
				return;
			}
			try
			{
				_table = PhysicalTable.CreateAt(levelRoot, position, rotation, _controller, Settings, Log);
				RefreshTable();
				ManualLogSource log = Log;
				string[] obj = new string[5] { "Blackjack table placed at ", null, null, null, null };
				Vector3 val = position;
				obj[1] = ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString();
				obj[2] = " (";
				obj[3] = reason;
				obj[4] = ").";
				log.LogInfo((object)string.Concat(obj));
			}
			catch (Exception ex)
			{
				_table = null;
				Log.LogError((object)("Blackjack fixed placement failed: " + ex));
			}
		}

		private unsafe void SpawnTableAtLocal(Transform levelRoot, Vector3 localPosition, Quaternion localRotation, string reason)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			DestroyTable();
			if (_controller == null)
			{
				return;
			}
			try
			{
				RemovePartialTableChildren(levelRoot);
				_table = PhysicalTable.CreateAtLocal(levelRoot, localPosition, localRotation, _controller, Settings, Log);
				RefreshTable();
				ManualLogSource log = Log;
				string[] obj = new string[5] { "Blackjack table attached at room-local position ", null, null, null, null };
				Vector3 val = localPosition;
				obj[1] = ((object)(*(Vector3*)(&val))/*cast due to .constrained