Decompiled source of PEAK ROULETTE v1.0.1

plugins/PeakRoulette.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using PeakRoulette.Localization;
using PeakRoulette.Net;
using PeakRoulette.Placement;
using PeakRoulette.Table;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;

[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("ThomasAusHH")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A roulette table for PEAK. Place your bets, watch the ball drop - the house always wins.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+b8b7730b2037d040a03239a068ff901da839fc5c")]
[assembly: AssemblyProduct("PeakRoulette")]
[assembly: AssemblyTitle("PeakRoulette")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://discord.gg/nKUHvzdmVp")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 PeakRoulette
{
	public static class BundleAssets
	{
		private const string ResourceName = "PeakRoulette.Assets.peakroulette.bundle";

		private static AssetBundle _bundle;

		private static bool _tried;

		private static readonly Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();

		public static GameObject Table => Prefab("RouletteTable");

		public static GameObject Chip => Prefab("Chip");

		public static GameObject Prefab(string name)
		{
			if (Prefabs.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (!_tried)
			{
				_tried = true;
				try
				{
					Load();
				}
				catch (Exception arg)
				{
					RouletteLog.Error($"[Bundle] Laden fehlgeschlagen: {arg}");
				}
			}
			if ((Object)(object)_bundle == (Object)null)
			{
				return null;
			}
			GameObject val = _bundle.LoadAsset<GameObject>(name);
			if ((Object)(object)val == (Object)null)
			{
				RouletteLog.Warning("[Bundle] Prefab '" + name + "' nicht im Bundle. Inhalt: " + string.Join(", ", _bundle.GetAllAssetNames()));
				return null;
			}
			RebindShaders(val);
			Prefabs[name] = val;
			return val;
		}

		private static void Load()
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PeakRoulette.Assets.peakroulette.bundle");
			if (stream == null)
			{
				RouletteLog.Warning("[Bundle] Kein eingebettetes Bundle in der DLL.");
				return;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			byte[] array = memoryStream.ToArray();
			_bundle = AssetBundle.LoadFromMemory(array);
			if ((Object)(object)_bundle == (Object)null)
			{
				RouletteLog.Warning($"[Bundle] AssetBundle.LoadFromMemory lieferte null ({array.Length} Bytes).");
			}
			else
			{
				RouletteLog.Info(string.Format("[Bundle] Geladen: {0} KB, Inhalt: {1}", array.Length / 1024, string.Join(", ", _bundle.GetAllAssetNames())));
			}
		}

		private static void RebindShaders(GameObject prefab)
		{
			HashSet<Material> hashSet = new HashSet<Material>();
			int num = 0;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
				foreach (Material val in sharedMaterials)
				{
					if (!((Object)(object)val == (Object)null) && hashSet.Add(val) && !((Object)(object)val.shader == (Object)null))
					{
						Shader val2 = Shader.Find(((Object)val.shader).name);
						if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)val.shader)
						{
							val.shader = val2;
							num++;
						}
					}
				}
			}
			RouletteLog.Debug($"[Bundle] {((Object)prefab).name}: {hashSet.Count} Materialien, {num} Shader neu gebunden.");
		}
	}
	[BepInPlugin("com.thomasaushh.peakroulette", "PEAK ROULETTE", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.thomasaushh.peakroulette";

		public const string PluginName = "PEAK ROULETTE";

		public const string PluginVersion = "1.0.1";

		public const string VersionLabel = "";

		public static string DisplayVersion
		{
			get
			{
				if (!string.IsNullOrEmpty(""))
				{
					return "1.0.1 ";
				}
				return "1.0.1";
			}
		}

		internal static ManualLogSource Log { get; private set; }

		internal static Plugin Instance { get; private set; }

		internal static ConfigEntry<bool> EnableAtCampfires { get; private set; }

		internal static ConfigEntry<bool> EnableAtAirport { get; private set; }

		internal static ConfigEntry<int> ChipPercent { get; private set; }

		internal static ConfigEntry<int> MaxChipsPerRound { get; private set; }

		internal static ConfigEntry<float> BettingSeconds { get; private set; }

		internal static ConfigEntry<bool> BankCurse { get; private set; }

		internal static ConfigEntry<bool> PeakShader { get; private set; }

		internal static ConfigEntry<float> SoundVolume { get; private set; }

		internal static ConfigEntry<float> AttractVolume { get; private set; }

		internal static ConfigEntry<RouletteLogLevel> LogLevel { get; private set; }

		private void Awake()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)("PEAK ROULETTE " + DisplayVersion + " geladen."));
			EnableAtCampfires = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableAtCampfires", true, "Ein Roulette-Tisch neben jedem Lagerfeuer auf der Insel.");
			EnableAtAirport = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableAtAirport", true, "Ein Tisch im Flughafen (Freispiel: Chips kosten nichts, Gewinne wirken nicht - das Spiel blockt dort Statuswerte).");
			ChipPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Balance", "ChipPercent", 1, new ConfigDescription("Wert eines Chips in Prozent der Lebensleiste (wird beim Setzen als Verletzung abgezogen).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			MaxChipsPerRound = ((BaseUnityPlugin)this).Config.Bind<int>("Balance", "MaxChipsPerRound", 20, new ConfigDescription("Hoechstzahl Chips je Spieler und Runde.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60), Array.Empty<object>()));
			BettingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "BettingSeconds", 20f, new ConfigDescription("Sekunden vom ersten Chip bis zum Dreh (jeder weitere Chip haelt mindestens 5 s offen).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), Array.Empty<object>()));
			BankCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance", "BankCurse", true, "Faellt die Zero und niemand liegt auf ihr, verflucht die Bank alle, die gesetzt hatten.");
			PeakShader = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "PeakShader", true, "Korpus im Spiel-Look (Shader W/Peak_Standard mit gemalten Schichten). Aus = glattes URP-Material.");
			SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 1f, new ConfigDescription("Lautstaerke des Mods, zusaetzlich zu Master- und SFX-Regler des Spiels. 0 = stumm.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			AttractVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "AttractVolume", 1f, new ConfigDescription("Lautstaerke der Lockmelodie im Leerlauf, zusaetzlich zu Audio.Volume. 0 = aus.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			LogLevel = ((BaseUnityPlugin)this).Config.Bind<RouletteLogLevel>("Logging", "LogLevel", RouletteLogLevel.Info, "Wie gespraechig der Mod im BepInEx-Log ist.");
			Loc.Initialize();
			RouletteNet.Register();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Loc.Refresh();
			try
			{
				if ((int)mode == 0)
				{
					RouletteLog.Info("[Plugin] Szene '" + ((Scene)(ref scene)).name + "' geladen.");
					((MonoBehaviour)this).StartCoroutine(TablePlacer.PlaceForScene(((Scene)(ref scene)).name));
				}
			}
			catch (Exception arg)
			{
				RouletteLog.Error($"[Plugin] Fehler in OnSceneLoaded: {arg}");
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}
	}
	public enum RouletteLogLevel
	{
		Error,
		Warning,
		Info,
		Debug
	}
	internal static class RouletteLog
	{
		private const string Prefix = "[PeakRoulette] ";

		public static void Error(string message)
		{
			if (Enabled(RouletteLogLevel.Error))
			{
				Plugin.Log.LogError((object)("[PeakRoulette] " + message));
			}
		}

		public static void Warning(string message)
		{
			if (Enabled(RouletteLogLevel.Warning))
			{
				Plugin.Log.LogWarning((object)("[PeakRoulette] " + message));
			}
		}

		public static void Info(string message)
		{
			if (Enabled(RouletteLogLevel.Info))
			{
				Plugin.Log.LogInfo((object)("[PeakRoulette] " + message));
			}
		}

		public static void Debug(string message)
		{
			if (Enabled(RouletteLogLevel.Debug))
			{
				Plugin.Log.LogInfo((object)("[PeakRoulette] " + message));
			}
		}

		private static bool Enabled(RouletteLogLevel level)
		{
			if (Plugin.Log == null)
			{
				return false;
			}
			RouletteLogLevel rouletteLogLevel = ((Plugin.LogLevel != null) ? Plugin.LogLevel.Value : RouletteLogLevel.Info);
			return level <= rouletteLogLevel;
		}
	}
	internal static class BuildInfo
	{
		public const string Version = "1.0.1";

		public const string Label = "";

		public const string ProductName = "PEAK ROULETTE";
	}
}
namespace PeakRoulette.Table
{
	public class BetSpot : MonoBehaviour, IInteractibleConstant, IInteractible
	{
		private const float CastSeconds = 0.25f;

		public RouletteTable Table;

		public byte Key;

		public GameObject Highlight;

		public bool holdOnFinish => false;

		public bool IsInteractible(Character interactor)
		{
			if ((Object)(object)interactor == (Object)null || !interactor.IsLocal || (Object)(object)Table == (Object)null)
			{
				return false;
			}
			if ((Object)(object)interactor.data == (Object)null || interactor.data.dead || interactor.data.fullyPassedOut)
			{
				return false;
			}
			return Table.BetsOpen;
		}

		public void Interact(Character interactor)
		{
		}

		public void HoverEnter()
		{
			if ((Object)(object)Highlight != (Object)null)
			{
				Highlight.SetActive(true);
			}
		}

		public void HoverExit()
		{
			if ((Object)(object)Highlight != (Object)null)
			{
				Highlight.SetActive(false);
			}
		}

		public Vector3 Center()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)this).transform.position;
		}

		public Transform GetTransform()
		{
			return ((Component)this).transform;
		}

		public string GetInteractionText()
		{
			if ((Object)(object)Table == (Object)null)
			{
				return string.Empty;
			}
			if (!Table.CanLocalBet(out var reasonKey))
			{
				return Loc.T(reasonKey);
			}
			int chipPercent = RewardService.ChipPercent;
			int num = Table.ChipsOf(RouletteNet.LocalActor, Key);
			int num2 = RouletteRules.Payout(Key);
			if (Table.IsAirport)
			{
				return Loc.T("interact.bet.free", num2);
			}
			if (num <= 0)
			{
				return Loc.T("interact.bet", chipPercent, num2);
			}
			return Loc.T("interact.bet.more", chipPercent, num * chipPercent, num2);
		}

		public string GetName()
		{
			return RouletteRules.Name(Key);
		}

		public bool IsConstantlyInteractable(Character interactor)
		{
			return IsInteractible(interactor);
		}

		public float GetInteractTime(Character interactor)
		{
			return 0.25f;
		}

		public void Interact_CastFinished(Character interactor)
		{
			if (!((Object)(object)interactor == (Object)null) && interactor.IsLocal && !((Object)(object)Table == (Object)null))
			{
				Table.LocalBet(Key);
			}
		}

		public void CancelCast(Character interactor)
		{
		}

		public void ReleaseInteract(Character interactor)
		{
		}
	}
	internal static class InteractionRange
	{
		private const float Extended = 3.4f;

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

		private static float _original = -1f;

		private static bool _extended;

		public static void Report(int tableId, bool near)
		{
			if (near)
			{
				NearTables.Add(tableId);
			}
			else
			{
				NearTables.Remove(tableId);
			}
			Apply();
		}

		public static void Forget(int tableId)
		{
			if (NearTables.Remove(tableId))
			{
				Apply();
			}
		}

		private static void Apply()
		{
			try
			{
				Interaction instance = Interaction.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				bool flag = NearTables.Count > 0;
				if (flag != _extended)
				{
					if (flag)
					{
						_original = instance.distance;
						instance.distance = Mathf.Max(instance.distance, 3.4f);
					}
					else if (_original > 0f)
					{
						instance.distance = _original;
					}
					_extended = flag;
				}
			}
			catch (Exception ex)
			{
				RouletteLog.Debug("[Range] " + ex.Message);
			}
		}
	}
	public static class PeakStyle
	{
		private const string ShaderName = "W/Peak_Standard";

		private static Material _template;

		private static bool _searched;

		private static readonly Dictionary<string, Material> Cache = new Dictionary<string, Material>();

		private static readonly string[] PreferredNames = new string[9] { "Kiosk", "Counter", "Desk", "Table", "Chair", "Bench", "Crate", "Box", "Wood" };

		public static bool Enabled
		{
			get
			{
				if (Plugin.PeakShader != null)
				{
					return Plugin.PeakShader.Value;
				}
				return true;
			}
		}

		public static Material Template
		{
			get
			{
				if ((Object)(object)_template != (Object)null || _searched)
				{
					return _template;
				}
				_searched = true;
				try
				{
					Material val = null;
					Material[] array = Resources.FindObjectsOfTypeAll<Material>();
					foreach (Material val2 in array)
					{
						if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null || ((Object)val2.shader).name != "W/Peak_Standard" || ((Object)val2).name.Contains("(Instance)") || val2.GetFloat("_UseAlpha") > 0.5f)
						{
							continue;
						}
						if ((Object)(object)val == (Object)null)
						{
							val = val2;
						}
						string[] preferredNames = PreferredNames;
						foreach (string value in preferredNames)
						{
							if (((Object)val2).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
							{
								_template = val2;
								break;
							}
						}
						if ((Object)(object)_template != (Object)null)
						{
							break;
						}
					}
					if (_template == null)
					{
						_template = val;
					}
					RouletteLog.Info(((Object)(object)_template != (Object)null) ? ("[Style] PEAK-Vorlage: '" + ((Object)_template).name + "'") : "[Style] Kein Material mit W/Peak_Standard geladen - URP-Fallback.");
				}
				catch (Exception ex)
				{
					RouletteLog.Warning("[Style] Vorlagensuche fehlgeschlagen: " + ex.Message);
				}
				return _template;
			}
		}

		public static Material Styled(string key, Material urpFallback, Color color, float smoothness, float metallic)
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//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_0050: Expected O, but got Unknown
			//IL_008d: 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)
			if (Cache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Material val = null;
			Material val2 = (Enabled ? Template : null);
			if ((Object)(object)val2 != (Object)null)
			{
				try
				{
					val = new Material(val2)
					{
						name = "PeakRoulette_" + key
					};
					val.SetTexture("_BaseTexture", (Texture)null);
					val.SetFloat("_BaseTexAmount", 0f);
					val.SetFloat("_UseUV2", 0f);
					val.DisableKeyword("_USEUV2_ON");
					val.SetColor("_BaseColor", color);
					val.SetColor("_Tint", Color.white);
					val.SetFloat("_BaseSmooth", smoothness);
					val.SetFloat("_BaseMetallic", metallic);
					val.SetFloat("_Triplanar1On", 1f);
					val.SetFloat("_Triplanar2On", 1f);
					val.SetFloat("_Triplanar3On", 1f);
					val.SetFloat("_VertexColorAmount", 0f);
					val.SetFloat("_Interactable", 0f);
					val.EnableKeyword("_INTERACTABLE_ON");
				}
				catch (Exception ex)
				{
					RouletteLog.Warning("[Style] Klonen fehlgeschlagen: " + ex.Message);
					val = null;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = new Material(urpFallback)
				{
					name = "PeakRoulette_" + key + "_URP"
				};
				val.SetColor("_BaseColor", color);
				val.SetFloat("_Smoothness", smoothness);
				val.SetFloat("_Metallic", metallic);
				val.EnableKeyword("_EMISSION");
				val.SetColor("_EmissionColor", Color.black);
			}
			Cache[key] = val;
			return val;
		}
	}
	public enum RoundOutcome
	{
		NotPlaying,
		Lose,
		Win,
		BigWin,
		Jackpot,
		Cursed
	}
	public static class RewardService
	{
		private const float Step = 0.025f;

		private const float Epsilon = 0.0001f;

		private static float _pending;

		private static Character _ledgerOwner;

		public static float ChipFraction => (float)Mathf.Clamp((Plugin.ChipPercent == null) ? 1 : Plugin.ChipPercent.Value, 1, 10) / 100f;

		public static int ChipPercent => Mathf.RoundToInt(ChipFraction * 100f);

		public static float Pending
		{
			get
			{
				if (!(_pending > 0f))
				{
					return 0f;
				}
				return _pending;
			}
		}

		public static bool CanAfford()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || localCharacter.refs == null || (Object)(object)localCharacter.refs.afflictions == (Object)null)
			{
				return false;
			}
			try
			{
				return localCharacter.refs.afflictions.statusSum + Pending + ChipFraction < 0.93f;
			}
			catch
			{
				return true;
			}
		}

		public static bool PayChip()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				return false;
			}
			if (!CanAfford())
			{
				return false;
			}
			return ChargeInjury(localCharacter, ChipFraction);
		}

		private static void SyncLedger(Character character)
		{
			if (!((Object)(object)_ledgerOwner == (Object)(object)character))
			{
				_ledgerOwner = character;
				_pending = 0f;
			}
		}

		private static bool ChargeInjury(Character character, float amount)
		{
			SyncLedger(character);
			_pending += amount;
			int num = Mathf.FloorToInt(_pending / 0.025f + 0.0001f);
			if (num <= 0)
			{
				RouletteLog.Info($"[Reward] Chip gesetzt: {_pending * 100f:F1} % angeschrieben (Leiste kennt nur 2,5-%-Stufen).");
				return true;
			}
			float num2 = (float)num * 0.025f;
			bool flag = character.refs.afflictions.AddStatus((STATUSTYPE)0, num2, false, true, true, false);
			_pending = (flag ? (_pending - num2) : 0f);
			RouletteLog.Info(string.Format("[Reward] Chip gesetzt: Injury +{0:F3} ({1}), Rest {2:F1} %.", num2, flag ? "angewendet" : "vom Spiel abgelehnt", _pending * 100f));
			return flag;
		}

		private static void HealInjury(Character character, float amount)
		{
			SyncLedger(character);
			_pending -= amount;
			if (_pending >= 0f)
			{
				return;
			}
			float currentStatus = character.refs.afflictions.GetCurrentStatus((STATUSTYPE)0);
			if (currentStatus <= 0f)
			{
				_pending = 0f;
				return;
			}
			int num = Mathf.FloorToInt((0f - _pending) / 0.025f + 0.0001f);
			if (num > 0)
			{
				float num2 = Mathf.Min((float)num * 0.025f, currentStatus);
				character.refs.afflictions.SubtractStatus((STATUSTYPE)0, num2, false, false);
				_pending += (float)num * 0.025f;
			}
		}

		private static void ClearLedger()
		{
			_pending = 0f;
		}

		public static RoundOutcome Settle(IReadOnlyList<RouletteTable.BetEntry> bets, int number, bool airport, out int netPercent)
		{
			netPercent = 0;
			int localActor = RouletteNet.LocalActor;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			bool flag = false;
			bool flag2 = false;
			foreach (RouletteTable.BetEntry bet in bets)
			{
				flag2 = true;
				if (bet.Key == 0)
				{
					flag = true;
				}
				if (bet.Actor != localActor)
				{
					continue;
				}
				num += bet.Chips;
				if (RouletteRules.Wins(bet.Key, number))
				{
					int num5 = RouletteRules.Payout(bet.Key);
					num2 += bet.Chips * (num5 + 1);
					if (num5 > num3 || (num5 == num3 && bet.Chips > num4))
					{
						num3 = num5;
						num4 = bet.Chips;
					}
				}
			}
			if (num == 0)
			{
				return RoundOutcome.NotPlaying;
			}
			netPercent = Mathf.RoundToInt((float)(num2 - num) * ChipFraction * 100f);
			if (airport)
			{
				if (number == 0 && !flag)
				{
					return RoundOutcome.Cursed;
				}
				if (num2 != 0)
				{
					if (num3 < 35)
					{
						if (num3 < 2)
						{
							return RoundOutcome.Win;
						}
						return RoundOutcome.BigWin;
					}
					return RoundOutcome.Jackpot;
				}
				return RoundOutcome.Lose;
			}
			Character character = Character.localCharacter;
			if ((Object)(object)character == (Object)null)
			{
				return RoundOutcome.Lose;
			}
			if (number == 0 && !flag && flag2 && (Plugin.BankCurse == null || Plugin.BankCurse.Value))
			{
				float curse = Mathf.Clamp(0.1f + 0.01f * (float)num, 0.1f, 0.3f);
				Apply(delegate
				{
					character.refs.afflictions.AddStatus((STATUSTYPE)5, curse, false, true, true, false);
				}, $"Bank verflucht: Curse +{curse:F2}");
				return RoundOutcome.Cursed;
			}
			if (num2 == 0)
			{
				return RoundOutcome.Lose;
			}
			float heal = (float)num2 * ChipFraction;
			Apply(delegate
			{
				HealInjury(character, heal);
			}, $"Heilung {heal:F2}");
			int n = Mathf.Max(1, num4);
			switch (num3)
			{
			case 35:
				Apply(delegate
				{
					character.refs.afflictions.ClearAllStatus(true, true);
					ClearLedger();
				}, "volle Heilung");
				Apply(delegate
				{
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_InfiniteStamina(Mathf.Min(240f, 90f + 30f * (float)n)), false);
				}, "unendliche Ausdauer");
				Apply(delegate
				{
					//IL_0010: 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_0020: 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_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_FasterBoi
					{
						totalTime = 60f,
						moveSpeedMod = 0.35f,
						climbSpeedMod = 0.35f,
						drowsyOnEnd = 0.05f
					}, false);
				}, "Tempo");
				Apply(delegate
				{
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_LowGravity(1, 45f), false);
				}, "leichte Schwerkraft");
				return RoundOutcome.Jackpot;
			case 2:
				Apply(delegate
				{
					//IL_0010: 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_0038: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_HealAll
					{
						maxHealing = heal * 0.5f,
						totalTime = 0.1f
					}, false);
				}, "Heilung aller Werte");
				Apply(delegate
				{
					//IL_0010: 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_0038: Unknown result type (might be due to invalid IL or missing references)
					//IL_0043: Unknown result type (might be due to invalid IL or missing references)
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_005f: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_FasterBoi
					{
						totalTime = Mathf.Min(90f, 30f + 10f * (float)n),
						moveSpeedMod = 0.3f,
						climbSpeedMod = 0.3f,
						drowsyOnEnd = 0.05f
					}, false);
				}, "Tempo");
				return RoundOutcome.BigWin;
			default:
				Apply(delegate
				{
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_003d: Expected O, but got Unknown
					character.refs.afflictions.AddAffliction((Affliction)new Affliction_AddBonusStamina(Mathf.Min(0.5f, 0.2f + 0.05f * (float)n), 0.1f), false);
				}, "Bonus-Ausdauer");
				return RoundOutcome.Win;
			}
		}

		private static void Apply(Action action, string what)
		{
			try
			{
				action();
				RouletteLog.Info("[Reward] " + what + ".");
			}
			catch (Exception ex)
			{
				RouletteLog.Warning("[Reward] " + what + " fehlgeschlagen: " + ex.Message);
			}
		}
	}
	public static class RouletteAudio
	{
		private const int Rate = 44100;

		private static AudioMixerGroup _sfxGroup;

		private static float _nextSearch;

		private static AudioClip _chip;

		private static AudioClip _roll;

		private static AudioClip _drop;

		private static AudioClip _win;

		private static AudioClip _jackpot;

		private static AudioClip _lose;

		private static AudioClip _curse;

		private static AudioClip _coin;

		private static AudioClip _attract;

		private static AudioClip _tick;

		private static uint _noiseState = 2654435769u;

		public static float Volume
		{
			get
			{
				if (Plugin.SoundVolume == null)
				{
					return 1f;
				}
				return Mathf.Clamp(Plugin.SoundVolume.Value, 0f, 2f);
			}
		}

		public static float AttractVolume => Volume * ((Plugin.AttractVolume != null) ? Mathf.Clamp(Plugin.AttractVolume.Value, 0f, 2f) : 1f);

		public static AudioMixerGroup SfxGroup
		{
			get
			{
				if ((Object)(object)_sfxGroup != (Object)null)
				{
					return _sfxGroup;
				}
				if (Time.unscaledTime < _nextSearch)
				{
					return null;
				}
				_nextSearch = Time.unscaledTime + 5f;
				try
				{
					SFX_Player val = Object.FindFirstObjectByType<SFX_Player>();
					if ((Object)(object)val != (Object)null && (Object)(object)val.defaultMixerGroup != (Object)null)
					{
						_sfxGroup = val.defaultMixerGroup;
					}
					AudioMixer val2 = (((Object)(object)_sfxGroup != (Object)null) ? _sfxGroup.audioMixer : MasterMixer);
					if ((Object)(object)_sfxGroup == (Object)null && (Object)(object)val2 != (Object)null)
					{
						_sfxGroup = FindSfx(val2);
					}
					if ((Object)(object)_sfxGroup == (Object)null)
					{
						AudioMixerGroup val3 = null;
						AudioMixerGroup[] array = Resources.FindObjectsOfTypeAll<AudioMixerGroup>();
						float num = default(float);
						foreach (AudioMixerGroup val4 in array)
						{
							if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.audioMixer == (Object)null) && val4.audioMixer.GetFloat("SFXVolume", ref num))
							{
								if (string.Equals(((Object)val4).name, "SFX", StringComparison.OrdinalIgnoreCase))
								{
									_sfxGroup = val4;
									break;
								}
								if ((Object)(object)val3 == (Object)null && ((Object)val4).name.IndexOf("sfx", StringComparison.OrdinalIgnoreCase) >= 0)
								{
									val3 = val4;
								}
								if (val2 == null)
								{
									val2 = val4.audioMixer;
								}
							}
						}
						if (_sfxGroup == null)
						{
							_sfxGroup = val3;
						}
					}
					if ((Object)(object)_sfxGroup == (Object)null && (Object)(object)val2 != (Object)null)
					{
						AudioMixerGroup[] array2 = val2.FindMatchingGroups("Master");
						if (array2 != null && array2.Length != 0)
						{
							_sfxGroup = array2[0];
						}
					}
					if ((Object)(object)_sfxGroup != (Object)null)
					{
						RouletteLog.Info("[Audio] Ausgabe ueber Mixer-Gruppe '" + ((Object)_sfxGroup).name + "' (" + ((Object)_sfxGroup.audioMixer).name + ") - folgt Master- und SFX-Regler.");
					}
					else
					{
						RouletteLog.Warning("[Audio] Keine Mixergruppe gefunden - Lautstaerke folgt den Spielreglern nicht (Config: Audio.Volume).");
					}
				}
				catch (Exception ex)
				{
					RouletteLog.Warning("[Audio] Mixer-Suche fehlgeschlagen: " + ex.Message);
				}
				return _sfxGroup;
			}
		}

		private static AudioMixer MasterMixer
		{
			get
			{
				try
				{
					AudioMixerGroup val = (((Object)(object)SingletonAsset<StaticReferences>.Instance != (Object)null) ? SingletonAsset<StaticReferences>.Instance.masterMixerGroup : null);
					return ((Object)(object)val != (Object)null) ? val.audioMixer : null;
				}
				catch (Exception ex)
				{
					RouletteLog.Debug("[Audio] StaticReferences nicht lesbar: " + ex.Message);
					return null;
				}
			}
		}

		public static AudioClip Chip => _chip ?? (_chip = Build("PeakRoulette_Chip", 0.16f, (float t, float d) => Mathf.Sin(MathF.PI * 5800f * t) * Env(t, 0f, 0.01f, 60f) * 0.7f + Noise(t) * Env(t, 0f, 0.004f, 120f) * 0.5f));

		public static AudioClip Roll => _roll ?? (_roll = Build("PeakRoulette_Roll", 1.2f, delegate(float t, float d)
		{
			float num = Mathf.Sin(MathF.PI * 480f * t) * 0.1f + Mathf.Sin(MathF.PI * 722f * t) * 0.06f;
			float num2 = Noise(t) * 0.22f;
			float num3 = 0.8f + 0.2f * Mathf.Sin(20.734512f * t);
			return (num + num2) * num3;
		}));

		public static AudioClip Tick => _tick ?? (_tick = Build("PeakRoulette_Tick", 0.08f, (float t, float d) => Mathf.Sin(MathF.PI * 3600f * t) * Env(t, 0f, 0.005f, 140f) * 0.8f));

		public static AudioClip Drop => _drop ?? (_drop = Build("PeakRoulette_Drop", 0.55f, delegate(float t, float d)
		{
			float num = 0f;
			for (int i = 0; i < 6; i++)
			{
				float num2 = (float)(i * i) * 0.012f;
				float num3 = t - num2;
				if (num3 >= 0f)
				{
					num += Mathf.Sin(MathF.PI * 2f * (1500f - (float)i * 120f) * num3) * Env(num3, 0f, 0.004f, 150f) * (0.5f - (float)i * 0.05f);
				}
			}
			float num4 = t - 0.3f;
			if (num4 >= 0f)
			{
				num += Mathf.Sin(MathF.PI * 840f * num4) * Env(num4, 0f, 0.03f, 40f) * 0.9f + Noise(t) * Env(num4, 0f, 0.01f, 90f) * 0.3f;
			}
			return num;
		}));

		public static AudioClip Win => _win ?? (_win = Build("PeakRoulette_Win", 0.95f, (float t, float d) => Arpeggio(t, new float[4] { 523.25f, 659.25f, 783.99f, 1046.5f }, 0.17f, 0.9f)));

		public static AudioClip Jackpot => _jackpot ?? (_jackpot = Build("PeakRoulette_Jackpot", 2.4f, delegate(float t, float d)
		{
			if (t < 1.1f)
			{
				return Arpeggio(t, new float[7] { 523.25f, 659.25f, 783.99f, 1046.5f, 1318.5f, 1568f, 2093f }, 0.11f, 0.9f);
			}
			float num = t - 1.1f;
			float num2 = Mathf.Sin(MathF.PI * 2093f * num) + Mathf.Sin(MathF.PI * 2637f * num) + Mathf.Sin(MathF.PI * 3136f * num);
			float num3 = 1f + 0.02f * Mathf.Sin(MathF.PI * 12f * num);
			return num2 / 3f * num3 * Env(num, 0.02f, 1.2f, 2.2f) * 0.8f;
		}));

		public static AudioClip Lose => _lose ?? (_lose = Build("PeakRoulette_Lose", 0.7f, (float t, float d) => Saw(Mathf.Lerp(170f, 85f, t / d), t) * Env(t, 0.01f, 0.6f, 3f) * 0.45f));

		public static AudioClip Curse => _curse ?? (_curse = Build("PeakRoulette_Curse", 1.4f, delegate(float t, float d)
		{
			float num = Mathf.Lerp(240f, 95f, t / d);
			float num2 = Mathf.Sin(MathF.PI * 2f * num * t);
			float num3 = Mathf.Sin(MathF.PI * 2f * (num * 1.06f) * t);
			float num4 = 0.6f + 0.4f * Mathf.Sin(MathF.PI * 18f * t);
			return (num2 + num3) * 0.5f * num4 * Env(t, 0.05f, 1.2f, 1.8f) * 0.7f;
		}));

		public static AudioClip Coin => _coin ?? (_coin = Build("PeakRoulette_Coin", 0.5f, delegate(float t, float d)
		{
			float num = ((t < 0.22f) ? t : (t - 0.22f));
			return (Mathf.Sin(MathF.PI * 4700f * num) + 0.6f * Mathf.Sin(MathF.PI * 7040f * num)) * Env(num, 0f, 0.2f, 22f) * 0.5f;
		}));

		public static AudioClip Attract => _attract ?? (_attract = Build("PeakRoulette_Attract", 6f, delegate(float t, float d)
		{
			float[] array = new float[16]
			{
				659.25f, 783.99f, 987.77f, 1318.5f, 987.77f, 783.99f, 659.25f, 587.33f, 698.46f, 880f,
				1046.5f, 1396.9f, 1046.5f, 880f, 698.46f, 523.25f
			};
			float num = 0f;
			int num2 = (int)(t / 0.17f);
			if (num2 < array.Length)
			{
				float num3 = t - (float)num2 * 0.17f;
				float num4 = array[num2];
				float num5 = Mathf.Sin(MathF.PI * 2f * num4 * num3) + 0.4f * Mathf.Sin(MathF.PI * 2f * num4 * 2f * num3) + 0.12f * Mathf.Sin(MathF.PI * 2f * num4 * 4f * num3);
				num += num5 / 1.5f * Env(num3, 0.004f, 0.03f, 9f) * 0.5f;
			}
			float num6 = t - 3.2f;
			if (num6 >= 0f)
			{
				int num7 = (int)(num6 / 0.17f);
				if (num7 < array.Length)
				{
					float num8 = num6 - (float)num7 * 0.17f;
					float num9 = array[num7] * 0.5f;
					num += Mathf.Sin(MathF.PI * 2f * num9 * num8) * Env(num8, 0.005f, 0.05f, 10f) * 0.28f;
				}
			}
			float[] array2 = new float[2] { 2.9f, 5.8f };
			foreach (float num10 in array2)
			{
				float num11 = t - num10;
				if (num11 >= 0f && num11 < 0.25f)
				{
					num += (Mathf.Sin(MathF.PI * 4700f * num11) + 0.5f * Mathf.Sin(MathF.PI * 7040f * num11)) * Env(num11, 0f, 0.05f, 24f) * 0.22f;
				}
			}
			return num;
		}));

		private static AudioMixerGroup FindSfx(AudioMixer mixer)
		{
			float num = default(float);
			if ((Object)(object)mixer == (Object)null || !mixer.GetFloat("SFXVolume", ref num))
			{
				return null;
			}
			string[] array = new string[3] { "SFX", "Sfx", "sfx" };
			foreach (string text in array)
			{
				AudioMixerGroup[] array2 = mixer.FindMatchingGroups(text);
				if (array2 != null && array2.Length != 0)
				{
					return array2[0];
				}
			}
			return null;
		}

		public static bool Route(AudioSource source)
		{
			if ((Object)(object)source == (Object)null)
			{
				return false;
			}
			AudioMixerGroup sfxGroup = SfxGroup;
			if ((Object)(object)sfxGroup == (Object)null)
			{
				return false;
			}
			source.outputAudioMixerGroup = sfxGroup;
			return true;
		}

		private static float Env(float t, float attack, float hold, float decayRate)
		{
			if (t < 0f)
			{
				return 0f;
			}
			if (t < attack)
			{
				return t / attack;
			}
			float num = t - attack - hold;
			if (!(num <= 0f))
			{
				return Mathf.Exp((0f - num) * decayRate);
			}
			return 1f;
		}

		private static float Saw(float freq, float t)
		{
			float num = freq * t % 1f;
			return 2f * num - 1f;
		}

		private static float Noise(float t)
		{
			_noiseState ^= _noiseState << 13;
			_noiseState ^= _noiseState >> 17;
			_noiseState ^= _noiseState << 5;
			return (float)_noiseState / 4.2949673E+09f * 2f - 1f;
		}

		private static float Arpeggio(float t, float[] notes, float noteLength, float gain)
		{
			int num = Mathf.Min(notes.Length - 1, (int)(t / noteLength));
			float num2 = t - (float)num * noteLength;
			float num3 = notes[num];
			float num4 = Mathf.Sin(MathF.PI * 2f * num3 * num2) + 0.35f * Mathf.Sin(MathF.PI * 2f * num3 * 2f * num2) + 0.15f * Mathf.Sin(MathF.PI * 2f * num3 * 3f * num2);
			float hold = ((num == notes.Length - 1) ? 0.5f : 0.02f);
			return num4 / 1.5f * Env(num2, 0.005f, hold, 12f) * gain;
		}

		private static AudioClip Build(string name, float seconds, Func<float, float, float> generator)
		{
			int num = (int)(seconds * 44100f);
			float[] array = new float[num];
			float num2 = 0.001f;
			for (int i = 0; i < num; i++)
			{
				float arg = (float)i / 44100f;
				num2 = Mathf.Max(num2, Mathf.Abs(array[i] = generator(arg, seconds)));
			}
			float num3 = Mathf.Min(1f, 0.85f / num2);
			for (int j = 0; j < num; j++)
			{
				array[j] = Mathf.Clamp(array[j] * num3, -1f, 1f);
			}
			AudioClip obj = AudioClip.Create(name, num, 1, 44100, false);
			obj.SetData(array, 0);
			return obj;
		}
	}
	public static class RouletteRules
	{
		public const byte Red = 37;

		public const byte Black = 38;

		public const byte Even = 39;

		public const byte Odd = 40;

		public const byte Low = 41;

		public const byte High = 42;

		public const byte Dozen1 = 43;

		public const byte Dozen2 = 44;

		public const byte Dozen3 = 45;

		public const byte Column1 = 46;

		public const byte Column2 = 47;

		public const byte Column3 = 48;

		public const byte KeyCount = 49;

		private static readonly HashSet<int> Reds = new HashSet<int>
		{
			1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
			21, 23, 25, 27, 30, 32, 34, 36
		};

		public static bool IsRed(int n)
		{
			return Reds.Contains(n);
		}

		public static bool IsNumber(byte key)
		{
			return key <= 36;
		}

		public static string AnchorName(byte key)
		{
			if (key <= 36)
			{
				return $"Bet_{key}";
			}
			return key switch
			{
				37 => "Bet_Red", 
				38 => "Bet_Black", 
				39 => "Bet_Even", 
				40 => "Bet_Odd", 
				41 => "Bet_Low", 
				42 => "Bet_High", 
				43 => "Bet_Dozen1", 
				44 => "Bet_Dozen2", 
				45 => "Bet_Dozen3", 
				46 => "Bet_Column1", 
				47 => "Bet_Column2", 
				_ => "Bet_Column3", 
			};
		}

		public static string Name(byte key)
		{
			if (key == 0)
			{
				return Loc.T("bet.zero");
			}
			if (key <= 36)
			{
				return key.ToString();
			}
			return key switch
			{
				37 => Loc.T("bet.red"), 
				38 => Loc.T("bet.black"), 
				39 => Loc.T("bet.even"), 
				40 => Loc.T("bet.odd"), 
				41 => Loc.T("bet.low"), 
				42 => Loc.T("bet.high"), 
				43 => Loc.T("bet.dozen1"), 
				44 => Loc.T("bet.dozen2"), 
				45 => Loc.T("bet.dozen3"), 
				46 => Loc.T("bet.column1"), 
				47 => Loc.T("bet.column2"), 
				_ => Loc.T("bet.column3"), 
			};
		}

		public static int Payout(byte key)
		{
			if (key <= 36)
			{
				return 35;
			}
			if (key >= 43)
			{
				return 2;
			}
			return 1;
		}

		public static bool Wins(byte key, int number)
		{
			if (key <= 36)
			{
				return key == number;
			}
			if (number == 0)
			{
				return false;
			}
			return key switch
			{
				37 => IsRed(number), 
				38 => !IsRed(number), 
				39 => number % 2 == 0, 
				40 => number % 2 == 1, 
				41 => number <= 18, 
				42 => number >= 19, 
				43 => number <= 12, 
				44 => number >= 13 && number <= 24, 
				45 => number >= 25, 
				46 => number % 3 == 1, 
				47 => number % 3 == 2, 
				48 => number % 3 == 0, 
				_ => false, 
			};
		}

		public static string ColorName(int number)
		{
			if (number == 0)
			{
				return Loc.T("color.green");
			}
			if (!IsRed(number))
			{
				return Loc.T("color.black");
			}
			return Loc.T("color.red");
		}

		public static Color NumberColor(int number)
		{
			//IL_0012: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			if (number == 0)
			{
				return new Color(0.2f, 0.9f, 0.35f);
			}
			if (!IsRed(number))
			{
				return new Color(0.75f, 0.75f, 0.8f);
			}
			return new Color(1f, 0.25f, 0.2f);
		}

		public static Color ChipColor(int actorNumber)
		{
			//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_0032: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00a3: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			Color[] array = (Color[])(object)new Color[8]
			{
				new Color(0.85f, 0.12f, 0.12f),
				new Color(0.15f, 0.35f, 0.85f),
				new Color(0.15f, 0.6f, 0.22f),
				new Color(0.1f, 0.1f, 0.12f),
				new Color(0.95f, 0.75f, 0.2f),
				new Color(0.6f, 0.2f, 0.75f),
				new Color(0.95f, 0.5f, 0.15f),
				new Color(0.2f, 0.75f, 0.8f)
			};
			int num = ((actorNumber >= 0) ? (actorNumber % array.Length) : 0);
			return array[num];
		}
	}
	public class RouletteTable : MonoBehaviour
	{
		public enum TableState
		{
			Idle,
			Betting,
			Spinning,
			Result
		}

		public sealed class BetEntry
		{
			public int Actor;

			public string Name;

			public byte Key;

			public int Chips;

			public readonly List<GameObject> ChipObjects = new List<GameObject>();
		}

		public static readonly Dictionary<int, RouletteTable> Registry = new Dictionary<int, RouletteTable>();

		private const float BallTrackRadius = 0.385f;

		private const float BallTrackHeight = 0.1655f;

		private const float SpinSeconds = 7f;

		private const float ResultSeconds = 7f;

		private const float MinSecondsAfterBet = 5f;

		private const float AmbientVolume = 0.1f;

		private const float OneShotVolume = 0.5f;

		private const float LoopVolume = 0.35f;

		private bool _audioRouted;

		public int Id;

		public bool IsAirport;

		public Transform WheelPivot;

		public Transform BallPivot;

		public Transform Ball;

		public Transform Dolly;

		public Dictionary<byte, Transform> Anchors = new Dictionary<byte, Transform>();

		public GameObject ChipPrefab;

		public Material ChipMaterial;

		public Renderer[] Lights;

		public Material LightOff;

		public Material LightOn;

		public Material LightBright;

		public TMP_Text TitleText;

		public TMP_Text MessageText;

		public AudioSource Audio;

		public AudioSource LoopAudio;

		public AudioSource AmbientAudio;

		public Light MarqueeLight;

		public Renderer[] HoverRenderers;

		public Color HoverGlow;

		public ParticleSystem FxCoins;

		public ParticleSystem FxLose;

		public ParticleSystem FxBallDrop;

		public ParticleSystem FxConfetti;

		public ParticleSystem FxRays;

		public ParticleSystem FxSparkle;

		private readonly List<BetEntry> _bets = new List<BetEntry>();

		private readonly Dictionary<int, Material> _chipMaterials = new Dictionary<int, Material>();

		private float _betsCloseAt;

		private float _lightClock;

		private int _lightMode;

		private float _marqueeLightBase = 1.2f;

		private Color _marqueeLightColor = Color.white;

		private static readonly Color CurseLight = new Color(0.6f, 0.15f, 0.9f);

		private float _wheelSpeed;

		private int _lastShownSeconds = -1;

		private Coroutine _spin;

		public TableState State { get; private set; }

		public int LastNumber { get; private set; } = -1;

		public IReadOnlyList<BetEntry> Bets => _bets;

		public bool HasBets => _bets.Count > 0;

		public bool BetsOpen
		{
			get
			{
				if (State != TableState.Idle)
				{
					return State == TableState.Betting;
				}
				return true;
			}
		}

		public void Initialize()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Registry[Id] = this;
			RefreshTexts();
			Loc.LanguageChanged += RefreshTexts;
			if ((Object)(object)MarqueeLight != (Object)null)
			{
				_marqueeLightBase = MarqueeLight.intensity;
				_marqueeLightColor = MarqueeLight.color;
			}
			if ((Object)(object)AmbientAudio != (Object)null)
			{
				try
				{
					AmbientAudio.clip = RouletteAudio.Attract;
					AmbientAudio.time = Random.Range(0f, 5.9f);
					AmbientAudio.Play();
				}
				catch (Exception ex)
				{
					RouletteLog.Debug("[Audio] Lockmelodie: " + ex.Message);
				}
			}
			_wheelSpeed = 12f;
		}

		private void OnDestroy()
		{
			InteractionRange.Forget(Id);
			Loc.LanguageChanged -= RefreshTexts;
			if (Registry.TryGetValue(Id, out var value) && (Object)(object)value == (Object)(object)this)
			{
				Registry.Remove(Id);
			}
		}

		public void RefreshTexts()
		{
			if ((Object)(object)TitleText != (Object)null)
			{
				TitleText.text = Loc.T("table.name");
			}
			if (State == TableState.Idle && (Object)(object)MessageText != (Object)null)
			{
				MessageText.text = IdleText();
			}
		}

		private string IdleText()
		{
			return Loc.T(IsAirport ? "screen.idle.airport" : "screen.idle");
		}

		public int ChipsOf(int actor)
		{
			int num = 0;
			foreach (BetEntry bet in _bets)
			{
				if (bet.Actor == actor)
				{
					num += bet.Chips;
				}
			}
			return num;
		}

		public int ChipsOf(int actor, byte key)
		{
			foreach (BetEntry bet in _bets)
			{
				if (bet.Actor == actor && bet.Key == key)
				{
					return bet.Chips;
				}
			}
			return 0;
		}

		public bool CanLocalBet(out string reasonKey)
		{
			reasonKey = null;
			if (!BetsOpen)
			{
				reasonKey = "interact.bet.closed";
				return false;
			}
			int num = ((Plugin.MaxChipsPerRound != null) ? Plugin.MaxChipsPerRound.Value : 20);
			if (ChipsOf(RouletteNet.LocalActor) >= num)
			{
				reasonKey = "interact.bet.limit";
				return false;
			}
			if (!IsAirport && !RewardService.CanAfford())
			{
				reasonKey = "interact.bet.life";
				return false;
			}
			return true;
		}

		public void LocalBet(byte key)
		{
			if (CanLocalBet(out var _))
			{
				if (!IsAirport && !RewardService.PayChip())
				{
					RouletteLog.Info("[Bet] Chip nicht bezahlt - kein Einsatz.");
					return;
				}
				string localName = RouletteNet.LocalName;
				RouletteNet.SendBet(Id, key, 1, localName);
				ApplyBet(RouletteNet.LocalActor, localName, key, 1);
			}
		}

		public void ApplyBet(int actor, string name, byte key, int count)
		{
			if (!BetsOpen)
			{
				RouletteLog.Debug($"[Bet] Einsatz von {name} auf {key} waehrend {State} ignoriert.");
			}
			else
			{
				if (key >= 49 || count <= 0)
				{
					return;
				}
				BetEntry betEntry = null;
				foreach (BetEntry bet in _bets)
				{
					if (bet.Actor == actor && bet.Key == key)
					{
						betEntry = bet;
						break;
					}
				}
				if (betEntry == null)
				{
					betEntry = new BetEntry
					{
						Actor = actor,
						Name = name,
						Key = key
					};
					_bets.Add(betEntry);
				}
				for (int i = 0; i < count; i++)
				{
					betEntry.Chips++;
					SpawnChip(betEntry);
				}
				Play(RouletteAudio.Chip, 0.8f);
				if (State == TableState.Idle)
				{
					State = TableState.Betting;
					float num = ((Plugin.BettingSeconds != null) ? Plugin.BettingSeconds.Value : 20f);
					_betsCloseAt = Time.time + Mathf.Max(5f, num);
					_lastShownSeconds = -1;
				}
				else if (_betsCloseAt - Time.time < 5f)
				{
					_betsCloseAt = Time.time + 5f;
				}
				RouletteLog.Debug($"[Bet] {name} (Actor {actor}) hat {betEntry.Chips} Chip(s) auf {RouletteRules.AnchorName(key)}.");
			}
		}

		private void SpawnChip(BetEntry entry)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ChipPrefab == (Object)null || !Anchors.TryGetValue(entry.Key, out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			int num = 0;
			foreach (BetEntry bet in _bets)
			{
				if (bet.Key == entry.Key)
				{
					num += bet.ChipObjects.Count;
				}
			}
			try
			{
				GameObject val = Object.Instantiate<GameObject>(ChipPrefab, value);
				((Object)val).name = $"Chip_{entry.Actor}";
				val.transform.localPosition = new Vector3(0f, (float)num * 0.0046f, 0f);
				val.transform.localRotation = Quaternion.Euler(0f, (float)num * 23f + (float)entry.Actor * 41f, 0f);
				SetLayerRecursive(val.transform, ((Component)this).gameObject.layer);
				Material sharedMaterial = ChipMaterialFor(entry.Actor);
				Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>();
				foreach (Renderer val2 in componentsInChildren)
				{
					if ((Object)(object)val2.sharedMaterial != (Object)null && ((Object)val2.sharedMaterial).name.StartsWith("M_Chip", StringComparison.Ordinal))
					{
						val2.sharedMaterial = sharedMaterial;
					}
					Collider component = ((Component)val2).GetComponent<Collider>();
					if ((Object)(object)component != (Object)null)
					{
						Object.Destroy((Object)(object)component);
					}
				}
				entry.ChipObjects.Add(val);
			}
			catch (Exception ex)
			{
				RouletteLog.Warning("[Bet] Chip konnte nicht gesetzt werden: " + ex.Message);
			}
		}

		private Material ChipMaterialFor(int actor)
		{
			//IL_0040: 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_0046: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (_chipMaterials.TryGetValue(actor, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = (((Object)(object)ChipMaterial != (Object)null) ? new Material(ChipMaterial) : new Material(Shader.Find("Universal Render Pipeline/Lit")));
			value.SetColor("_BaseColor", RouletteRules.ChipColor(actor));
			_chipMaterials[actor] = value;
			return value;
		}

		private void ClearBets()
		{
			foreach (BetEntry bet in _bets)
			{
				foreach (GameObject chipObject in bet.ChipObjects)
				{
					if ((Object)(object)chipObject != (Object)null)
					{
						Object.Destroy((Object)(object)chipObject);
					}
				}
			}
			_bets.Clear();
		}

		private static void SetLayerRecursive(Transform t, int layer)
		{
			((Component)t).gameObject.layer = layer;
			for (int i = 0; i < t.childCount; i++)
			{
				SetLayerRecursive(t.GetChild(i), layer);
			}
		}

		public void RequestSpin()
		{
			if (State == TableState.Betting)
			{
				if (RouletteNet.IsAuthority)
				{
					MasterSpin();
				}
				else
				{
					RouletteNet.SendSpinRequest(Id);
				}
			}
		}

		public void MasterSpin()
		{
			if (State == TableState.Betting)
			{
				int num = new Random((Environment.TickCount * 397) ^ Id ^ (int)(Time.realtimeSinceStartup * 1000f)).Next(0, 37);
				RouletteLog.Info($"[Spin] Tisch {Id}: {num} ({RouletteRules.ColorName(num)}), {_bets.Count} Einsaetze.");
				RouletteNet.SendSpin(Id, num);
				PlaySpin(num);
			}
		}

		public void PlaySpin(int number)
		{
			if (number < 0 || number > 36)
			{
				return;
			}
			if (State == TableState.Spinning)
			{
				RouletteLog.Debug($"[Spin] Tisch {Id}: Dreh laeuft schon, {number} ignoriert.");
				return;
			}
			if (_spin != null)
			{
				((MonoBehaviour)this).StopCoroutine(_spin);
			}
			_spin = ((MonoBehaviour)this).StartCoroutine(SpinRoutine(number));
		}

		private IEnumerator SpinRoutine(int number)
		{
			State = TableState.Spinning;
			_lightMode = 0;
			if ((Object)(object)MessageText != (Object)null)
			{
				MessageText.text = Loc.T("screen.spinning");
			}
			if ((Object)(object)Ball != (Object)null && (Object)(object)BallPivot != (Object)null)
			{
				Ball.SetParent(BallPivot, false);
				Ball.localPosition = new Vector3(0.385f, 0.1655f, 0f);
				Ball.localRotation = Quaternion.identity;
			}
			if ((Object)(object)LoopAudio != (Object)null)
			{
				LoopAudio.clip = RouletteAudio.Roll;
				LoopAudio.pitch = 1.3f;
				LoopAudio.volume = 0.35f * RouletteAudio.Volume;
				LoopAudio.Play();
			}
			Transform pocket = (((Object)(object)WheelPivot != (Object)null) ? WheelPivot.Find($"Pocket_{number}") : null);
			float t = 0f;
			float trackPhase = 5.46f;
			float dropPhase = 7f - trackPhase;
			float nextTick = trackPhase * 0.55f;
			float ballAngle = 0f;
			while (t < trackPhase)
			{
				t += Time.deltaTime;
				float num = Mathf.Clamp01(t / trackPhase);
				_wheelSpeed = Mathf.Lerp(200f, 60f, num);
				float num2 = Mathf.Lerp(-620f, -90f, num * num);
				ballAngle += num2 * Time.deltaTime;
				if ((Object)(object)BallPivot != (Object)null)
				{
					BallPivot.localRotation = Quaternion.Euler(0f, ballAngle, 0f);
				}
				if ((Object)(object)LoopAudio != (Object)null)
				{
					LoopAudio.pitch = Mathf.Lerp(1.3f, 0.7f, num);
					LoopAudio.volume = Mathf.Lerp(0.35f, 0.21000001f, num) * RouletteAudio.Volume;
				}
				if (t >= nextTick)
				{
					Play(RouletteAudio.Tick, Mathf.Lerp(0.3f, 0.8f, num));
					nextTick = t + Mathf.Lerp(0.18f, 0.06f, num);
				}
				yield return null;
			}
			if ((Object)(object)LoopAudio != (Object)null)
			{
				LoopAudio.Stop();
			}
			Vector3 startWorld = (((Object)(object)Ball != (Object)null) ? Ball.position : Vector3.zero);
			t = 0f;
			while (t < dropPhase && (Object)(object)Ball != (Object)null && (Object)(object)pocket != (Object)null)
			{
				t += Time.deltaTime;
				float num3 = Mathf.Clamp01(t / dropPhase);
				_wheelSpeed = Mathf.Lerp(60f, 40f, num3);
				float num4 = 1f - (1f - num3) * (1f - num3);
				Vector3 val = Vector3.Lerp(startWorld, pocket.position, num4);
				val += Vector3.up * Mathf.Sin(num3 * MathF.PI) * 0.03f * (1f - num3) + Vector3.up * Mathf.Abs(Mathf.Sin(num3 * 14f)) * 0.006f * (1f - num3);
				Ball.position = val;
				yield return null;
			}
			if ((Object)(object)Ball != (Object)null && (Object)(object)pocket != (Object)null)
			{
				Ball.SetParent(pocket, false);
				Ball.localPosition = Vector3.zero;
			}
			LastNumber = number;
			Play(RouletteAudio.Drop);
			if ((Object)(object)FxBallDrop != (Object)null && (Object)(object)pocket != (Object)null)
			{
				((Component)FxBallDrop).transform.position = pocket.position;
				PlayFx(FxBallDrop);
			}
			if ((Object)(object)Dolly != (Object)null && Anchors.TryGetValue((byte)number, out var value) && (Object)(object)value != (Object)null)
			{
				Dolly.position = value.position + Vector3.up * 0.0046f * (float)CountChipsOn((byte)number);
			}
			yield return (object)new WaitForSeconds(0.4f);
			bool flag = false;
			foreach (BetEntry bet in _bets)
			{
				if (bet.Key == 0)
				{
					flag = true;
				}
			}
			bool bankWins = number == 0 && !flag && _bets.Count > 0;
			if ((Object)(object)MessageText != (Object)null)
			{
				MessageText.text = ((number == 0) ? Loc.T(flag ? "screen.result.zero.hit" : "screen.result.zero") : Loc.T("screen.result", number, RouletteRules.ColorName(number)));
			}
			int netPercent = 0;
			RoundOutcome roundOutcome;
			try
			{
				roundOutcome = RewardService.Settle(_bets, number, IsAirport, out netPercent);
			}
			catch (Exception arg)
			{
				RouletteLog.Error($"[Spin] Abrechnung fehlgeschlagen: {arg}");
				roundOutcome = RoundOutcome.NotPlaying;
			}
			RouletteLog.Info($"[Spin] Tisch {Id}: lokal {roundOutcome} ({netPercent:+0;-0;0}%).");
			PlayOutcome(roundOutcome, bankWins, netPercent);
			State = TableState.Result;
			yield return (object)new WaitForSeconds(2.5f);
			if ((Object)(object)MessageText != (Object)null)
			{
				MessageText.text = (bankWins ? Loc.T("screen.cursed") : WinnersLine(number));
			}
			yield return (object)new WaitForSeconds(4.5f);
			ClearBets();
			_lightMode = 0;
			State = TableState.Idle;
			if ((Object)(object)MessageText != (Object)null)
			{
				MessageText.text = IdleText();
			}
			_spin = null;
		}

		private int CountChipsOn(byte key)
		{
			int num = 0;
			foreach (BetEntry bet in _bets)
			{
				if (bet.Key == key)
				{
					num += bet.ChipObjects.Count;
				}
			}
			return num;
		}

		private string WinnersLine(int number)
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			Dictionary<int, string> dictionary2 = new Dictionary<int, string>();
			foreach (BetEntry bet in _bets)
			{
				dictionary2[bet.Actor] = bet.Name;
				dictionary.TryGetValue(bet.Actor, out var value);
				value -= bet.Chips;
				if (RouletteRules.Wins(bet.Key, number))
				{
					value += bet.Chips * (RouletteRules.Payout(bet.Key) + 1);
				}
				dictionary[bet.Actor] = value;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<int, int> item in dictionary)
			{
				if (item.Value > 0)
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append("   ");
					}
					stringBuilder.Append(dictionary2[item.Key].ToUpperInvariant()).Append(" +").Append(item.Value * RewardService.ChipPercent)
						.Append('%');
				}
			}
			if (stringBuilder.Length != 0)
			{
				return Loc.T("screen.winners", stringBuilder.ToString());
			}
			return Loc.T("screen.nowinners");
		}

		private void PlayOutcome(RoundOutcome outcome, bool bankWins, int net)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			switch (outcome)
			{
			case RoundOutcome.Jackpot:
				Play(RouletteAudio.Jackpot);
				PlayFx(FxCoins);
				PlayFx(FxConfetti);
				PlayFx(FxRays);
				PlaySparkle(new Color(1f, 0.95f, 0.6f), new Color(1f, 0.7f, 0.2f));
				_lightMode = 1;
				break;
			case RoundOutcome.BigWin:
				Play(RouletteAudio.Win);
				Play(RouletteAudio.Coin, 0.8f);
				PlayFx(FxCoins);
				PlayFx(FxConfetti);
				_lightMode = 1;
				break;
			case RoundOutcome.Win:
				Play(RouletteAudio.Win, 0.9f);
				PlayFx(FxCoins);
				_lightMode = 1;
				break;
			case RoundOutcome.Cursed:
				Play(RouletteAudio.Curse);
				_lightMode = 2;
				break;
			case RoundOutcome.Lose:
				Play(RouletteAudio.Lose, 0.8f);
				PlayFx(FxLose);
				break;
			default:
				if (bankWins)
				{
					Play(RouletteAudio.Curse, 0.6f);
					_lightMode = 2;
				}
				else
				{
					Play(RouletteAudio.Coin, 0.5f);
				}
				break;
			}
		}

		private void Update()
		{
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			if (State != TableState.Spinning)
			{
				_wheelSpeed = Mathf.MoveTowards(_wheelSpeed, 12f, Time.deltaTime * 12f);
			}
			if ((Object)(object)WheelPivot != (Object)null)
			{
				WheelPivot.Rotate(0f, _wheelSpeed * Time.deltaTime, 0f, (Space)1);
			}
			if (State == TableState.Betting)
			{
				float num = Mathf.Max(0f, _betsCloseAt - Time.time);
				int num2 = Mathf.CeilToInt(num);
				if (num2 != _lastShownSeconds && (Object)(object)MessageText != (Object)null)
				{
					_lastShownSeconds = num2;
					MessageText.text = Loc.T("screen.betting", num2);
				}
				if (num <= 0f && RouletteNet.IsAuthority)
				{
					MasterSpin();
				}
			}
			UpdateLights();
			if (!_audioRouted && (Object)(object)RouletteAudio.SfxGroup != (Object)null)
			{
				RouletteAudio.Route(Audio);
				RouletteAudio.Route(LoopAudio);
				RouletteAudio.Route(AmbientAudio);
				_audioRouted = true;
			}
			Transform val = (((Object)(object)MainCamera.instance != (Object)null) ? ((Component)MainCamera.instance).transform : null);
			if ((Object)(object)val != (Object)null)
			{
				Vector3 val2 = ((Component)this).transform.TransformPoint(new Vector3(0f, 0.8f, 0f));
				int id = Id;
				Vector3 val3 = val.position - val2;
				InteractionRange.Report(id, ((Vector3)(ref val3)).sqrMagnitude < 20.25f);
			}
			if ((Object)(object)AmbientAudio != (Object)null)
			{
				float num3 = ((State == TableState.Idle) ? (0.1f * RouletteAudio.AttractVolume) : 0f);
				AmbientAudio.volume = Mathf.MoveTowards(AmbientAudio.volume, num3, Time.deltaTime * 0.5f);
			}
		}

		private void UpdateLights()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			if (Lights == null || Lights.Length == 0)
			{
				return;
			}
			_lightClock += Time.deltaTime;
			if ((Object)(object)MarqueeLight != (Object)null)
			{
				float num = _lightMode switch
				{
					1 => 1.6f + 0.8f * Mathf.Abs(Mathf.Sin(_lightClock * 12f)), 
					2 => 0.6f + 0.5f * Mathf.PerlinNoise(_lightClock * 9f, 0.3f), 
					3 => 0.2f, 
					_ => 1f + 0.08f * Mathf.Sin(_lightClock * 3f), 
				};
				MarqueeLight.intensity = _marqueeLightBase * num;
				Light marqueeLight = MarqueeLight;
				marqueeLight.color = (Color)(_lightMode switch
				{
					1 => Color.Lerp(_marqueeLightColor, Color.white, 0.5f + 0.5f * Mathf.Sin(_lightClock * 12f)), 
					2 => Color.Lerp(_marqueeLightColor, CurseLight, 0.6f + 0.4f * Mathf.PerlinNoise(_lightClock * 7f, 0.7f)), 
					_ => _marqueeLightColor, 
				});
			}
			switch (_lightMode)
			{
			case 1:
			{
				bool flag2 = Mathf.FloorToInt(_lightClock * 8f) % 2 == 0;
				Renderer[] lights = Lights;
				for (int k = 0; k < lights.Length; k++)
				{
					lights[k].sharedMaterial = (flag2 ? LightBright : LightOff);
				}
				break;
			}
			case 2:
			{
				int num4 = Mathf.FloorToInt(_lightClock * 14f);
				for (int j = 0; j < Lights.Length; j++)
				{
					bool flag = (num4 * 31 + j * 17) % 7 < 3;
					Lights[j].sharedMaterial = (flag ? LightOn : LightOff);
				}
				break;
			}
			case 3:
			{
				Renderer[] lights = Lights;
				for (int k = 0; k < lights.Length; k++)
				{
					lights[k].sharedMaterial = LightOff;
				}
				break;
			}
			default:
			{
				float num2 = ((State == TableState.Spinning) ? 18f : ((State == TableState.Betting) ? 9f : 5f));
				int num3 = Mathf.FloorToInt(_lightClock * num2);
				for (int i = 0; i < Lights.Length; i++)
				{
					Lights[i].sharedMaterial = (((i + num3) % 3 == 0) ? LightOn : LightOff);
				}
				break;
			}
			}
		}

		private void Play(AudioClip clip, float volume = 1f)
		{
			if (!((Object)(object)Audio == (Object)null) && !((Object)(object)clip == (Object)null))
			{
				Audio.PlayOneShot(clip, volume * 0.5f * RouletteAudio.Volume);
			}
		}

		private void PlayFx(ParticleSystem fx)
		{
			if ((Object)(object)fx == (Object)null)
			{
				return;
			}
			try
			{
				fx.Play(true);
			}
			catch (Exception ex)
			{
				RouletteLog.Debug("[Fx] " + ((Object)fx).name + ": " + ex.Message);
			}
		}

		private void PlaySparkle(Color a, Color b)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)FxSparkle == (Object)null))
			{
				try
				{
					MainModule main = FxSparkle.main;
					((MainModule)(ref main)).startColor = new MinMaxGradient(a, b);
				}
				catch (Exception ex)
				{
					RouletteLog.Debug("[Fx] Sparkle-Farbe: " + ex.Message);
				}
				PlayFx(FxSparkle);
			}
		}
	}
	public static class TableBuilder
	{
		private static readonly Color BodyColor = new Color(0.85f, 0.65f, 0.15f);

		private static readonly Color TrimColor = new Color(0.45f, 0.1f, 0.1f);

		private static readonly Color Glow = new Color(1f, 0.85f, 0.25f);

		private const float PxToM = 0.001015625f;

		private const float TableTop = 0.8f;

		private static TMP_FontAsset _font;

		private static bool _fontSearched;

		private static Material _highlightMaterial;

		public static RouletteTable Build(int id, Vector3 position, Quaternion rotation, bool airport = false)
		{
			//IL_0019: 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_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: 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_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_04df: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0511: Unknown result type (might be due to invalid IL or missing references)
			//IL_0539: Unknown result type (might be due to invalid IL or missing references)
			//IL_055e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0577: Unknown result type (might be due to invalid IL or missing references)
			//IL_0586: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_069e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_073d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0742: Unknown result type (might be due to invalid IL or missing references)
			//IL_0754: Unknown result type (might be due to invalid IL or missing references)
			//IL_0769: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0802: Unknown result type (might be due to invalid IL or missing references)
			//IL_0813: Unknown result type (might be due to invalid IL or missing references)
			//IL_0818: Unknown result type (might be due to invalid IL or missing references)
			//IL_081d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0827: Expected O, but got Unknown
			GameObject table = BundleAssets.Table;
			if ((Object)(object)table == (Object)null)
			{
				throw new Exception("Tisch-Prefab fehlt (Bundle nicht geladen).");
			}
			GameObject val = Object.Instantiate<GameObject>(table, position, rotation);
			((Object)val).name = $"PeakRoulette_Table_{id}";
			SetLayerRecursive(val.transform, LayerMask.NameToLayer("Default"));
			Material val2 = null;
			Material val3 = null;
			Material val4 = null;
			Material val5 = null;
			Material chipMaterial = null;
			List<Renderer> list = new List<Renderer>();
			List<Renderer> list2 = new List<Renderer>();
			List<Renderer> list3 = new List<Renderer>();
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val6 in componentsInChildren)
			{
				if (val6 is ParticleSystemRenderer)
				{
					continue;
				}
				Material[] sharedMaterials = val6.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val7 = sharedMaterials[j];
					if ((Object)(object)val7 == (Object)null)
					{
						continue;
					}
					switch (((Object)val7).name)
					{
					case "M_Body":
						if (val2 == null)
						{
							val2 = PeakStyle.Styled("Body", val7, BodyColor, 0.55f, 0.4f);
						}
						sharedMaterials[j] = val2;
						flag = true;
						list.Add(val6);
						break;
					case "M_Trim":
						if (val3 == null)
						{
							val3 = PeakStyle.Styled("Trim", val7, TrimColor, 0.6f, 0.5f);
						}
						sharedMaterials[j] = val3;
						flag = true;
						list.Add(val6);
						break;
					case "M_Lamp":
						val4 = val7;
						if (((Object)val6).name.StartsWith("Lamp_", StringComparison.Ordinal))
						{
							list3.Add(val6);
						}
						break;
					case "M_Marquee":
						if (val5 == null)
						{
							val5 = Emissive(val7, Glow, Glow);
						}
						sharedMaterials[j] = val5;
						flag = true;
						break;
					}
				}
				if (flag)
				{
					val6.sharedMaterials = sharedMaterials;
				}
				if (((Object)val6).name == "Bowl" || ((Object)val6).name == "BowlSlope" || ((Object)val6).name == "WheelHead")
				{
					list2.Add(val6);
				}
			}
			GameObject chip = BundleAssets.Chip;
			if ((Object)(object)chip != (Object)null)
			{
				componentsInChildren = chip.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val8 in componentsInChildren)
				{
					if ((Object)(object)val8.sharedMaterial != (Object)null && ((Object)val8.sharedMaterial).name == "M_Chip")
					{
						chipMaterial = val8.sharedMaterial;
						break;
					}
				}
			}
			object proto = (((Object)(object)val4 != (Object)null) ? ((object)val4) : ((object)new Material(Shader.Find("Universal Render Pipeline/Lit"))));
			Material val9 = Emissive((Material)proto, Glow * 0.35f, Glow * 0.15f);
			Material lightOn = Emissive((Material)proto, Glow, Glow * 1.6f);
			Material lightBright = Emissive((Material)proto, Color.white, Glow * 4f);
			foreach (Renderer item in list3)
			{
				item.sharedMaterial = val9;
			}
			Light componentInChildren = val.GetComponentInChildren<Light>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.color = Glow;
			}
			RouletteTable rouletteTable = val.AddComponent<RouletteTable>();
			rouletteTable.Id = id;
			rouletteTable.IsAirport = airport;
			rouletteTable.WheelPivot = Require(val, "WheelPivot");
			rouletteTable.BallPivot = Require(val, "BallPivot");
			rouletteTable.Ball = Require(val, "BallPivot/Ball");
			rouletteTable.Dolly = val.transform.Find("Dolly");
			rouletteTable.ChipPrefab = chip;
			rouletteTable.ChipMaterial = chipMaterial;
			rouletteTable.Lights = list3.ToArray();
			rouletteTable.LightOff = val9;
			rouletteTable.LightOn = lightOn;
			rouletteTable.LightBright = lightBright;
			rouletteTable.MarqueeLight = componentInChildren;
			rouletteTable.HoverRenderers = list.ToArray();
			rouletteTable.HoverGlow = Glow;
			rouletteTable.FxCoins = FindFx(val, "FX_Coins");
			rouletteTable.FxLose = FindFx(val, "FX_Lose");
			rouletteTable.FxBallDrop = FindFx(val, "FX_BallDrop");
			rouletteTable.FxConfetti = FindFx(val, "FX_Confetti");
			rouletteTable.FxRays = FindFx(val, "FX_Rays");
			rouletteTable.FxSparkle = FindFx(val, "FX_Sparkle");
			for (byte b = 0; b < 49; b++)
			{
				Transform val10 = val.transform.Find(RouletteRules.AnchorName(b));
				if ((Object)(object)val10 != (Object)null)
				{
					rouletteTable.Anchors[b] = val10;
				}
			}
			Transform val11 = Require(val, "TitleAnchor");
			Transform val12 = Require(val, "MessageAnchor");
			rouletteTable.TitleText = Text(val, "TitleText", val11.localPosition, 70f, 20f, 40f, 120f, Glow);
			rouletteTable.MessageText = Text(val, "MessageText", val12.localPosition, 56f, 8f, 20f, 60f, new Color(1f, 0.85f, 0.4f));
			BoxCollider obj = val.AddComponent<BoxCollider>();
			obj.center = new Vector3(0f, 0.4f, 0f);
			obj.size = new Vector3(2.46f, 0.8f, 1.1f);
			GameObject val13 = new GameObject("WheelInteract");
			val13.transform.SetParent(val.transform, false);
			val13.transform.localPosition = new Vector3(0.68f, 0.98f, 0f);
			val13.layer = val.layer;
			val13.AddComponent<BoxCollider>().size = new Vector3(0.92f, 0.36f, 0.92f);
			WheelInteract wheelInteract = val13.AddComponent<WheelInteract>();
			wheelInteract.Table = rouletteTable;
			wheelInteract.HoverRenderers = list2.ToArray();
			foreach (KeyValuePair<byte, Transform> anchor in rouletteTable.Anchors)
			{
				BuildSpot(val, rouletteTable, anchor.Key, anchor.Value);
			}
			AudioSource val14 = val.AddComponent<AudioSource>();
			val14.spatialBlend = 1f;
			val14.rolloffMode = (AudioRolloffMode)1;
			val14.minDistance = 2f;
			val14.maxDistance = 28f;
			val14.playOnAwake = false;
			val14.dopplerLevel = 0f;
			rouletteTable.Audio = val14;
			GameObject val15 = new GameObject("LoopAudio");
			val15.transform.SetParent(val.transform, false);
			val15.transform.localPosition = new Vector3(0.68f, 0.95f, 0f);
			AudioSource val16 = val15.AddComponent<AudioSource>();
			val16.spatialBlend = 1f;
			val16.rolloffMode = (AudioRolloffMode)1;
			val16.minDistance = 1.5f;
			val16.maxDistance = 18f;
			val16.playOnAwake = false;
			val16.loop = true;
			val16.volume = 0.6f;
			val16.dopplerLevel = 0f;
			rouletteTable.LoopAudio = val16;
			GameObject val17 = new GameObject("AmbientAudio");
			val17.transform.SetParent(val.transform, false);
			val17.transform.localPosition = new Vector3(0f, 1.9f, -0.4f);
			AudioSource val18 = val17.AddComponent<AudioSource>();
			val18.spatialBlend = 1f;
			val18.rolloffMode = (AudioRolloffMode)2;
			val18.minDistance = 1f;
			val18.maxDistance = 18f;
			val18.SetCustomCurve((AudioSourceCurveType)0, new AnimationCurve((Keyframe[])(object)new Keyframe[5]
			{
				new Keyframe(0f, 1f),
				new Keyframe(0.12f, 0.6f),
				new Keyframe(0.4f, 0.22f),
				new Keyframe(0.75f, 0.06f),
				new Keyframe(1f, 0f)
			}));
			val18.playOnAwake = false;
			val18.loop = true;
			val18.volume = 0f;
			val18.dopplerLevel = 0f;
			val18.spread = 20f;
			rouletteTable.AmbientAudio = val18;
			RouletteAudio.Route(val14);
			RouletteAudio.Route(val16);
			RouletteAudio.Route(val18);
			rouletteTable.Initialize();
			return rouletteTable;
		}

		private static Vector2 SpotSize(byte key)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_004b: 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_0084: 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_006a: 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)
			if (key == 0)
			{
				return new Vector2(90f, 300f) * 0.001015625f;
			}
			if (key <= 36)
			{
				return new Vector2(80f, 100f) * 0.001015625f;
			}
			if (key >= 46)
			{
				return new Vector2(90f, 100f) * 0.001015625f;
			}
			if (key >= 43)
			{
				return new Vector2(320f, 70f) * 0.001015625f;
			}
			return new Vector2(160f, 70f) * 0.001015625f;
		}

		private static void BuildSpot(GameObject root, RouletteTable table, byte key, Transform anchor)
		{
			//IL_0001: 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_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_002e: 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_0045: 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_0059: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00f4: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = SpotSize(key);
			GameObject val2 = new GameObject("Spot_" + RouletteRules.AnchorName(key));
			val2.transform.SetParent(root.transform, false);
			val2.transform.localPosition = new Vector3(anchor.localPosition.x, 0.815f, anchor.localPosition.z);
			val2.layer = root.layer;
			val2.AddComponent<BoxCollider>().size = new Vector3(val.x, 0.03f, val.y);
			BetSpot betSpot = val2.AddComponent<BetSpot>();
			betSpot.Table = table;
			betSpot.Key = key;
			GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)val3).name = "Highlight";
			Collider component = val3.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			val3.transform.SetParent(root.transform, false);
			val3.transform.localPosition = new Vector3(anchor.localPosition.x, 0.809f, anchor.localPosition.z);
			val3.transform.localScale = new Vector3(val.x, 0.003f, val.y);
			val3.layer = root.layer;
			Renderer component2 = val3.GetComponent<Renderer>();
			component2.sharedMaterial = HighlightMaterial();
			component2.shadowCastingMode = (ShadowCastingMode)0;
			val3.SetActive(false);
			betSpot.Highlight = val3;
		}

		private static Material HighlightMaterial()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00e4: Expected O, but got Unknown
			if ((Object)(object)_highlightMaterial != (Object)null)
			{
				return _highlightMaterial;
			}
			Material val = new Material(Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Universal Render Pipeline/Lit"))
			{
				name = "PeakRoulette_Highlight"
			};
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.9f, 0.3f, 0.45f);
			val.SetColor("_BaseColor", val2);
			val.SetColor("_Color", val2);
			val.SetFloat("_Surface", 1f);
			val.SetFloat("_Blend", 0f);
			val.SetFloat("_ZWrite", 0f);
			val.SetInt("_SrcBlend", 5);
			val.SetInt("_DstBlend", 10);
			val.SetOverrideTag("RenderType", "Transparent");
			val.renderQueue = 3000;
			val.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			_highlightMaterial = val;
			return val;
		}

		private static Transform Require(GameObject root, string path)
		{
			Transform obj = root.transform.Find(path);
			if ((Object)(object)obj == (Object)null)
			{
				throw new Exception("'" + path + "' fehlt im Prefab");
			}
			return obj;
		}

		private static ParticleSystem FindFx(GameObject root, string name)
		{
			Transform val = root.transform.Find(name);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).GetComponent<ParticleSystem>();
		}

		private static Material Emissive(Material proto, Color color, Color emission)
		{
			//IL_0001: 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_000c: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Material val = new Material(proto);
			val.SetColor("_BaseColor", color);
			val.SetColor("_Color", color);
			val.EnableKeyword("_EMISSION");
			val.SetColor("_EmissionColor", emission);
			return val;
		}

		private static void SetLayerRecursive(Transform t, int layer)
		{
			((Component)t).gameObject.layer = layer;
			for (int i = 0; i < t.childCount; i++)
			{
				SetLayerRecursive(t.GetChild(i), layer);
			}
		}

		private static TMP_Text Text(GameObject parent, string name, Vector3 localPos, float widthCm, float heightCm, float minSize, float maxSize, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent.transform, false);
			val.transform.localPosition = localPos;
			val.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
			val.transform.localScale = Vector3.one * 0.01f;
			try
			{
				TextMeshPro val2 = val.AddComponent<TextMeshPro>();
				TMP_FontAsset font = GetFont();
				if ((Object)(object)font != (Object)null)
				{
					((TMP_Text)val2).font = font;
				}
				((TMP_Text)val2).rectTransform.sizeDelta = new Vector2(widthCm, heightCm);
				((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
				((TMP_Text)val2).enableAutoSizing = true;
				((TMP_Text)val2).fontSizeMin = minSize;
				((TMP_Text)val2).fontSizeMax = maxSize;
				((TMP_Text)val2).fontSize = maxSize;
				((Graphic)val2).color = color;
				((TMP_Text)val2).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)val2).overflowMode = (TextOverflowModes)3;
				((TMP_Text)val2).characterSpacing = 2f;
				((TMP_Text)val2).text = "";
				return (TMP_Text)(object)val2;
			}
			catch (Exception ex)
			{
				RouletteLog.Warning("[Builder] Text '" + name + "' konnte nicht angelegt werden: " + ex.Message);
				Object.Destroy((Object)(object)val);
				return null;
			}
		}

		public static TMP_FontAsset GetFont()
		{
			if ((Object)(object)_font != (Object)null || _fontSearched)
			{
				return _font;
			}
			try
			{
				TMP_FontAsset val = null;
				TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				foreach (TMP_FontAsset val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						string text = ((Object)val2).name.ToLowerInvariant();
						if (text.Contains("daruma"))
						{
							_font = val2;
							break;
						}
						if ((Object)(object)val == (Object)null && !text.Contains("icon") && !text.Contains("emoji") && !text.Contains("sprite"))
						{
							val = val2;
						}
					}
				}
				if ((Object)(object)_font == (Object)null)
				{
					_font = val;
				}
				if ((Object)(object)_font != (Object)null)
				{
					_fontSearched = true;
					RouletteLog.Debug("[Builder] Font: " + ((Object)_font).name);
				}
			}
			catch (Exception ex)
			{
				RouletteLog.Warning("[Builder] Font-Suche fehlgeschlagen: " + ex.Message);
			}
			return _font;
		}
	}
	public class WheelInteract : MonoBehaviour, IInteractibleConstant, IInteractible
	{
		private const float CastSeconds = 0.6f;

		public RouletteTable Table;

		public Renderer[] HoverRenderers;

		private MaterialPropertyBlock _block;

		private bool _hovered;

		public bool holdOnFinish => false;

		public bool IsInteractible(Character interactor)
		{
			if ((Object)(object)interactor == (Object)null || !interactor.IsLocal || (Object)(object)Table == (Object)null)
			{
				return false;
			}
			if ((Object)(object)interactor.data == (Object)null || interactor.data.dead || interactor.data.fullyPassedOut)
			{
				return false;
			}
			return Table.BetsOpen;
		}

		public void Interact(Character interactor)
		{
		}

		public void HoverEnter()
		{
			SetHover(on: true);
		}

		public void HoverExit()
		{
			SetHover(on: false);
		}

		private void SetHover(bool on)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_006f: 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)
			if (_hovered == on || HoverRenderers == null)
			{
				return;
			}
			_hovered = on;
			if (_block == null)
			{
				_block = new MaterialPropertyBlock();
			}
			_block.SetFloat("_Interactable", on ? 1f : 0f);
			_block.SetColor("_EmissionColor", (Color)(on ? new Color(0.4f, 0.3f, 0.1f) : Color.black));
			Renderer[] hoverRenderers = HoverRenderers;
			foreach (Renderer val in hoverRenderers)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.SetPropertyBlock(_block);
				}
			}
		}

		public Vector3 Center()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)this).transform.position;
		}

		public Transform GetTransform()
		{
			return ((Component)this).transform;
		}

		public string GetInteractionText()
		{
			if ((Object)(object)Table == (Object)null)
			{
				return string.Empty;
			}
			if (Table.State == RouletteTable.TableState.Spinning || Table.State == RouletteTable.TableState.Result)
			{
				return Loc.T("interact.spin.busy");
			}
			if (!Table.HasBets)
			{
				return Loc.T("interact.spin.nobets");
			}
			return Loc.T("interact.spin");
		}

		public string GetName()
		{
			return Loc.T("wheel.name");
		}

		public bool IsConstantlyInteractable(Character interactor)
		{
			return IsInteractible(interactor);
		}

		public float GetInteractTime(Character interactor)
		{
			return 0.6f;
		}

		public void Interact_CastFinished(Character interactor)
		{
			if (!((Object)(object)interactor == (Object)null) && interactor.IsLocal && !((Object)(object)Table == (Object)null))
			{
				Table.RequestSpin();
			}
		}

		public void CancelCast(Character interactor)
		{
		}

		public void ReleaseInteract(Character interactor)
		{
		}
	}
}
namespace PeakRoulette.Placement
{
	public static class TablePlacer
	{
		public readonly struct Placement
		{
			public readonly int Id;

			public readonly Vector3 Point;

			public readonly Quaternion Rotation;

			public Placement(int id, Vector3 point, Quaternion rotation)
			{
				//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)
				Id = id;
				Point = point;
				Rotation = rotation;
			}
		}

		public readonly struct AirportSpot
		{
			public readonly float X;

			public readonly float Y;

			public readonly float Z;

			public readonly float Yaw;

			public AirportSpot(float x, float y, float z, float yaw)
			{
				X = x;
				Y = y;
				Z = z;
				Yaw = yaw;
			}
		}

		private static readonly List<RouletteTable> Spawned = new List<RouletteTable>();

		private static readonly List<Placement> Layout = new List<Placement>();

		private static string _scene;

		private static bool _gotLayout;

		private static int _nextDevId = 10000;

		private static readonly AirportSpot[] AirportLayout = new AirportSpot[1]
		{
			new AirportSpot(-2.84f, 0.55f, 94.59f, 270f)
		};

		private static int GroundMask => LayerMask.GetMask(new string[3] { "Terrain", "Map", "Default" });

		private static int ClearanceMask => LayerMask.GetMask(new string[4] { "Terrain", "Map", "Default", "Character" });

		public static IReadOnlyList<RouletteTable> All => Spawned;

		public static void ClearAll()
		{
			foreach (RouletteTable item in Spawned)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)item).gameObject);
				}
			}
			Spawned.Clear();
			Layout.Clear();
			RouletteTable.Registry.Clear();
		}

		public static IEnumerator PlaceForScene(string sceneName)
		{
			ClearAll();
			_scene = sceneName;
			_gotLayout = false;
			if (sceneName == "Airport")
			{
				if (Plugin.EnableAtAirport.Value)
				{
					yield return PlaceAirport();
				}
			}
			else if (sceneName.StartsWith("Level_", StringComparison.Ordinal) && Plugin.EnableAtCampfires.Value)
			{
				yield return PlaceCampfires(sceneName);
			}
		}

		private static IEnumerator PlaceAirport()
		{
			yield return null;
			yield return null;
			int num = 0;
			AirportSpot[] airportLayout = AirportLayout;
			for (int i = 0; i < airportLayout.Length; i++)
			{
				AirportSpot airportSpot = airportLayout[i];
				Vector3 point = SnapToGround(new Vector3(airportSpot.X, airportSpot.Y, airportSpot.Z));
				Create(num, point, Quaternion.Euler(0f, airportSpot.Yaw, 0f), airport: true);
				num++;
			}
			RouletteLog.Info($"[Placer] {num} Tisch(e) im Flughafen (fester Aufbau).");
		}

		private static Vector3 SnapToGround(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//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_0015: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(pos + Vector3.up * 2f, Vector3.down, ref val, 8f, GroundMask, (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val)).point;
			}
			return pos;
		}

		public static string SpotLine(Vector3 p, float yaw)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			return string.Format(CultureInfo.InvariantCulture, "new AirportSpot({0:F2}f, {1:F2}f, {2:F2}f, {3:F0}f),", p.x, p.y, p.z, Mathf.Repeat(yaw, 360f));
		}

		private static int SeedFor(string sceneName)
		{
			string arg = "solo";
			try
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null)
				{
					arg = PhotonNetwork.CurrentRoom.Name ?? "solo";
				}
			}
			catch
			{
			}
			return Fnv($"{sceneName}|{arg}|{Ascents.currentAscent}");
		}

		private static int Fnv(string text)
		{
			int num = -2128831035;
			foreach (char c in text)
			{
				num = (num ^ c) * 16777619;
			}
			return num;
		}

		private static IEnumerator PlaceCampfires(string sceneName)
		{
			RouletteLog.Info("[Placer] Beobachte Lagerfeuer in '" + sceneName + "' ...");
			HashSet<Campfire> handled = new HashSet<Campfire>();
			int sceneSeed = SeedFor(sceneName);
			int placedTotal = 0;
			while (true)
			{
				Scene val = SceneManager.GetActiveScene();
				if (!(((Scene)(ref val)).name == sceneName))
				{
					break;
				}
				if ((Object)(object)Character.localCharacter != (Object)null)
				{
					bool authority = RouletteNet.IsAuthority;
					bool somethingNew = false;
					Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsSortMode)0);
					foreach (Campfire val2 in array)
					{
						if ((Object)(object)val2 == (Object)null || handled.Contains(val2) || !((Component)val2).gameObject.activeInHierarchy)
						{
							continue;
						}
						val = ((Component)val2).gameObject.scene;
						if (!(((Scene)(ref val)).name != sceneName))
						{
							handled.Add(val2);
							somethingNew = true;
							if (authority)
							{
								placedTotal += PlaceAtCampfire(val2, sceneSeed);
							}
							yield return null;
						}
					}
					if (authority)
					{
						if (somethingNew)
						{
							RouletteNet.SendLayout(sceneName, Layout, 0);
						}
					}
					else if (somethingNew || !_gotLayout)
					{
						RouletteNet.RequestLayout(sceneName);
					}
				}
				yield return (object)new WaitForSeconds(2f);
			}
			RouletteLog.Info($"[Placer] '{sceneName}' verlassen - {placedTotal} Tische an {handled.Count} Lagerfeuern.");
		}

		private static int PlaceAtCampfire(Campfire campfire, int sceneSeed)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0134: 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)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)campfire).transform.position;
			int num = Fnv($"roulette|{Mathf.RoundToInt(position.x * 2f)}|{Mathf.RoundToInt(position.y * 2f)}|{Mathf.RoundToInt(position.z * 2f)}");
			int num2 = (num & 0x3FFFFFFF) % 900000000 + 100000;
			if (RouletteTable.Registry.ContainsKey(num2))
			{
				return 0;
			}
			Random random = new Random(sceneSeed ^ num);
			if (!TryFindSpotNear(position, ((Component)campfire).transform.forward, 4.6f, random.Next(), out var point, out var rotation))
			{
				RouletteLog.Info("[Placer] Kein Platz fuer einen Tisch an Lagerfeuer '" + ((Object)campfire).name + "' bei " + Fmt(position) + ".");
				return 0;
			}
			RouletteTable rouletteTable = Create(num2, point, rotation);
			if ((Object)(object)rouletteTable != (Object)null)
			{
				Layout.Add(new Placement(num2, point, rotation));
			}
			RouletteLog.Info("[Placer] Lagerfeuer '" + ((Object)campfire).name + "' bei " + Fmt(position) + ": " + (((Object)(object)rouletteTable != (Object)null) ? ("Tisch bei " + Fmt(point)) : "kein Tisch") + ".");
			return ((Object)(object)rouletteTable != (Object)null) ? 1 : 0;
		}

		private static bool TryFindSpotNear(Vector3 center, Vector3 forward, float distance, int seed, out Vector3 point, out Quaternion rotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result typ