Decompiled source of WheelOfWuck v1.0.0

WheelOfWuck.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Febucci.UI;
using Febucci.UI.Core;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WheelOfWuck")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WheelOfWuck")]
[assembly: AssemblyTitle("WheelOfWuck")]
[assembly: AssemblyVersion("1.0.0.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 WheelOfWuck
{
	public class RunRecord
	{
		public DateTime ended;

		public string gamemode;

		public bool won;

		public float seconds;

		public float height;

		public float score;

		public List<WheelResult> results;

		public List<string> route;

		public List<string> visited;

		public List<string> offRoute;
	}
	public static class History
	{
		public static readonly string FilePath = Path.Combine(Paths.ConfigPath, "senkodev.whiteknuckle.wheelofwuck.history.json");

		public static void Record(Roll roll, bool won, float seconds, float height, float score)
		{
			List<RunRecord> list = ((!File.Exists(FilePath)) ? new List<RunRecord>() : JsonConvert.DeserializeObject<List<RunRecord>>(File.ReadAllText(FilePath)));
			RunRecord runRecord = null;
			runRecord = new RunRecord();
			runRecord.ended = DateTime.Now;
			runRecord.gamemode = CL_GameManager.GetBaseGamemode()?.gamemodeName.Trim() ?? roll.gamemode;
			runRecord.won = won;
			runRecord.seconds = seconds;
			runRecord.height = height;
			runRecord.score = score;
			runRecord.results = roll.results;
			runRecord.route = roll.route;
			runRecord.visited = roll.visited;
			runRecord.offRoute = roll.offRoute;
			list.Add(runRecord);
			string text = "";
			text = JsonConvert.SerializeObject((object)list, (Formatting)1);
			File.WriteAllText(FilePath, text);
			Plugin.Logger.LogInfo((object)string.Format("run {0} written to the history: {1} after {2:0}s at {3:0}m", list.Count, won ? "won" : "died", seconds, height));
		}
	}
	public static class MenuHook
	{
		public const string ButtonName = "WheelOfWuck_Button";

		public static void AddButton(UI_TrinketPicker picker)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			Transform parent = ((Component)picker.playButton).transform.parent;
			if (!((Object)(object)parent.Find("WheelOfWuck_Button") != (Object)null))
			{
				GameObject val = Object.Instantiate<GameObject>(((Component)picker.playButton).gameObject, parent);
				string name = "WheelOfWuck_Button";
				((Object)val).name = name;
				val.transform.SetSiblingIndex(((Component)picker.playButton).transform.GetSiblingIndex() + 1);
				UI_FirstSelect[] components = val.GetComponents<UI_FirstSelect>();
				for (int i = 0; i < components.Length; i++)
				{
					Object.Destroy((Object)(object)components[i]);
				}
				Button component = val.GetComponent<Button>();
				_ = (Object)(object)component == (Object)null;
				component.onClick = new ButtonClickedEvent();
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					Open(picker);
				});
				((Selectable)component).interactable = true;
				val.GetComponentInChildren<TMP_Text>(true).text = "The Wheel";
				val.SetActive(true);
				Plugin.Logger.LogInfo((object)("Wheel button added next to Play in " + ((Object)parent).name + "."));
			}
		}

		private static void Open(UI_TrinketPicker picker)
		{
			M_Gamemode mode = Traverse.Create((object)picker).Field("currentGamemode").GetValue<M_Gamemode>();
			if ((Object)(object)mode == (Object)null)
			{
				mode = CL_GameManager.GetBaseGamemode();
			}
			WheelSet.Load();
			WheelUI.Open(WheelSet.Current, mode, (Roll roll) => RunSetup.Apply(roll, mode));
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "Initialize")]
	internal class Patch_TrinketPicker_Initialize
	{
		private static void Postfix(UI_TrinketPicker __instance)
		{
			RunSetup.RevertOnce();
			MenuHook.AddButton(__instance);
		}
	}
	[HarmonyPatch(typeof(UI_GamemodeScreen), "LoadGamemode")]
	internal class Patch_GamemodeScreen_LoadGamemode
	{
		private static bool Prefix(UI_GamemodeScreen __instance)
		{
			if (CL_SaveManager.loadSessionSaveOnLoad)
			{
				return true;
			}
			M_Gamemode value = Traverse.Create((object)__instance).Field("baseGamemode").GetValue<M_Gamemode>();
			M_Gamemode val = RunSetup.ChimneyInstead(Roll.Current, value);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			Plugin.Logger.LogInfo((object)("the roll says Chimney first, loading the Chimney instead of " + value.gamemodeName.Trim()));
			CL_GameManager.gamemode = val;
			SceneManager.LoadScene(val.gamemodeScene);
			if ((Object)(object)__instance.loadingText != (Object)null)
			{
				__instance.loadingText.SetActive(true);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(CL_GameManager), "RestartScene")]
	internal class Patch_GameManager_RestartScene
	{
		private static void Prefix(CL_GameManager __instance)
		{
			Roll current = Roll.Current;
			if (current != null && current.inPlay && current.leg != 0 && current.route.Contains("chimney") && Utils.Same(CL_GameManager.GetBaseGamemode()?.gamemodeName, "Chimney"))
			{
				M_Gamemode val = RunSetup.FindGamemode(current.gamemode);
				if (!((Object)(object)val == (Object)null))
				{
					Plugin.Logger.LogInfo((object)"the Chimney is done, this restart goes to the campaign run");
					Traverse.Create((object)__instance).Field("baseGamemode").SetValue((object)val);
					CL_GameManager.gamemode = val;
				}
			}
		}
	}
	[HarmonyPatch(typeof(UI_CloseButtonOnBack), "Update")]
	internal class Patch_CloseButtonOnBack_Update
	{
		private static bool Prefix()
		{
			return !WheelUI.IsOpen;
		}
	}
	[HarmonyPatch(typeof(UT_BranchGenerator), "Generate")]
	internal class Patch_BranchGenerator_Generate
	{
		private static void Postfix(UT_BranchGenerator __instance)
		{
			if ((Object)(object)RunHud.Instance == (Object)null || __instance.branch == null)
			{
				return;
			}
			foreach (M_GenerationBranch item in __instance.branch)
			{
				if ((Object)(object)item != (Object)null)
				{
					RunHud.Instance.BranchTaken(((Object)item).name);
				}
			}
		}
	}
	[HarmonyPatch(typeof(UT_ZoneTitler), "Play")]
	internal class Patch_ZoneTitler_Play
	{
		private static void Postfix(UT_ZoneTitler __instance)
		{
			if (!((Object)(object)RunHud.Instance == (Object)null))
			{
				RunHud.Instance.Titled(__instance.region, __instance.subRegion);
			}
		}
	}
	[HarmonyPatch(typeof(StatManager), "LoadStats")]
	internal class Patch_StatManager_LoadStats
	{
		private static void Postfix()
		{
			RunSetup.RevertOnce();
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "ReloadTrinkets")]
	internal class Patch_TrinketPicker_ReloadTrinkets
	{
		private static void Postfix(UI_TrinketPicker __instance)
		{
			MenuHook.AddButton(__instance);
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "OnEnable")]
	internal class Patch_TrinketPicker_OnEnable
	{
		private static void Postfix(UI_TrinketPicker __instance)
		{
			MenuHook.AddButton(__instance);
		}
	}
	[HarmonyPatch(typeof(CL_GameManager))]
	[HarmonyPatch("Awake")]
	internal class Patch_GameManager_Awake
	{
		public static void Postfix()
		{
			Roll current = Roll.Current;
			if (current != null && !CL_SaveManager.loadSessionSaveOnLoad)
			{
				M_Gamemode baseGamemode = CL_GameManager.GetBaseGamemode();
				if (!((Object)(object)baseGamemode == (Object)null))
				{
					current.inPlay = current.AppliesTo(baseGamemode) && current.MatchesSave(baseGamemode);
					current.ResetProgress();
					Plugin.Logger.LogInfo((object)(current.inPlay ? "the run uses the roll" : "the run doesn't match the roll, the wheel stays quiet"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(M_Gamemode))]
	[HarmonyPatch("Finish")]
	internal class Patch_Gamemode_Finish
	{
		private static void Postfix(M_Gamemode __instance, float time, bool hasFinished)
		{
			Roll current = Roll.Current;
			if (current != null && current.inPlay && current.AppliesTo(CL_GameManager.GetBaseGamemode()))
			{
				History.Record(current, hasFinished, time, CL_GameManager.gMan.GetPlayerBestTravelDistance(), __instance.GetPlayerScore(hasFinished));
				bool flag = false;
				if (hasFinished)
				{
					flag = true;
				}
				else if (current.ladderLooped && current.Route.Contains("ladder"))
				{
					flag = true;
					Plugin.Logger.LogInfo((object)"the Ladder was looped once, so this death still counts as beating it");
				}
				if (flag && current.LegDone() && current.NextLeg())
				{
					Plugin.Logger.LogInfo((object)string.Format("run {0} of the roll is done, the next run goes {1}", current.leg, string.Join(" > ", current.Route.ConvertAll<string>(Roll.Label))));
				}
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "senkodev.whiteknuckle.wheelofwuck";

		public const string PLUGIN_NAME = "WheelOfWuck";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	public enum HudCorner
	{
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}
	[BepInPlugin("senkodev.whiteknuckle.wheelofwuck", "WheelOfWuck", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		public static Plugin Instance;

		private readonly Harmony harmony = new Harmony("senkodev.whiteknuckle.wheelofwuck");

		public static ConfigEntry<KeyCode> HudKey;

		public static ConfigEntry<bool> ShowHud;

		public static ConfigEntry<HudCorner> HudPosition;

		public static ConfigEntry<float> HudScale;

		public static ConfigEntry<float> TickVolume;

		public static ConfigEntry<bool> RestartOnSkip;

		public static ConfigEntry<KeyCode> ChimneyStayKey;

		public static ConfigEntry<KeyCode> ChimneyGoKey;

		private void Awake()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			HudKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "HudKey", (KeyCode)289, "Shows or hides the panel during a wheel run.");
			ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHud", true, "Show the wheel results during the run.");
			HudPosition = ((BaseUnityPlugin)this).Config.Bind<HudCorner>("General", "HudPosition", HudCorner.TopRight, "Corner of the screen for the results.");
			HudScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HudScale", 0.75f, new ConfigDescription("Size of the results panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1f), Array.Empty<object>()));
			TickVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickVolume", 0.6f, new ConfigDescription("Volume of the ticking when the wheel spins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ChimneyStayKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ChimneyStayKey", (KeyCode)284, "After a loop of the Chimney: keep climbing.");
			ChimneyGoKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ChimneyGoKey", (KeyCode)287, "After a loop of the Chimney: end the run so the score counts, then Restart goes to the campaign run.");
			RestartOnSkip = ((BaseUnityPlugin)this).Config.Bind<bool>("General.Toggles", "RestartOnSkip", true, "Restart the run as soon as a shortcut the wheel picked can't be reached any more.");
			WheelSet.Load();
			WheelPicks.Load();
			Roll.Load();
			harmony.PatchAll();
			GameObject val = null;
			val = new GameObject("WheelOfWuck");
			if ((Object)(object)val != (Object)null)
			{
				((Object)val).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<RunHud>();
			}
			Logger.LogInfo((object)"Plugin senkodev.whiteknuckle.wheelofwuck is loaded!");
		}
	}
	public class WheelResult
	{
		public string id;

		public string title;

		public List<string> winners = new List<string>();
	}
	public class Roll
	{
		public static readonly string FilePath = Path.Combine(Paths.ConfigPath, "senkodev.whiteknuckle.wheelofwuck.roll.json");

		public static Roll Current;

		public DateTime rolledAt;

		public string gamemode;

		public List<WheelResult> results = new List<WheelResult>();

		public Dictionary<string, bool> settings = new Dictionary<string, bool>();

		public List<string> trinkets = new List<string>();

		public List<string> route = new List<string>();

		public List<string> notes = new List<string>();

		public List<string> visited = new List<string>();

		public List<string> offRoute = new List<string>();

		public List<string> skipped = new List<string>();

		public List<List<string>> legs = new List<List<string>>();

		public int leg;

		public List<string> activeSettings = new List<string>();

		public List<string> activeTrinkets = new List<string>();

		public List<string> beforeSettings;

		public List<string> beforeTrinkets;

		public List<string> chimneySettings = new List<string>();

		public List<string> beforeChimneySettings;

		public List<string> beforeChimneyTrinkets;

		public bool chimneyLooped;

		public bool ladderLooped;

		public bool inPlay;

		private static readonly List<string> climbOrder = new List<string> { "chimney", "sink", "chute", "duct", "ladder", "diver", "hotzone", "infested" };

		private static Dictionary<string, string[]> skipPoints = new Dictionary<string, string[]>
		{
			{
				"sink",
				new string[1] { "Deep Storage" }
			},
			{
				"chute",
				new string[3] { "Drainage System", "Waste Heap", "Pipe Organ" }
			},
			{
				"duct",
				new string[3] { "title:Service Shaft", "M3_Habitation_Shaft_0*", "M3_Habitation_Shaft_To_Pier" }
			},
			{
				"ladder",
				new string[2] { "M3_Habitation_Lab_Ending", "abyss" }
			},
			{
				"diver",
				new string[1] { "transit-scaffolds" }
			},
			{
				"hotzone",
				new string[1] { "infested" }
			}
		};

		private static Dictionary<string, string> routeKeys = new Dictionary<string, string>
		{
			{ "sink", "sink" },
			{ "chute", "chute" },
			{ "ladder", "ladder" },
			{ "rotten-duct", "duct" },
			{ "hadal-diver", "diver" },
			{ "hotzone", "hotzone" },
			{ "infestedlabs", "infested" },
			{ "chimney", "chimney" }
		};

		private static Dictionary<string, string> routeLabels = new Dictionary<string, string>
		{
			{ "sink", "Sink" },
			{ "chute", "Chute" },
			{ "ladder", "Ladder" },
			{ "duct", "Duct" },
			{ "diver", "Diver" },
			{ "hotzone", "Hot Zone" },
			{ "infested", "Infested Labs" },
			{ "chimney", "Chimney" }
		};

		private static Dictionary<string, string> routeUnlocks = new Dictionary<string, string>
		{
			{ "sink", "unlockedsink" },
			{ "chute", "chutedoorunlocked" },
			{ "duct", "hasvisited-deadmans-handle" },
			{ "diver", "hadaldiverunlocked" }
		};

		[JsonIgnore]
		public List<string> Route
		{
			get
			{
				if (legs.Count == 0)
				{
					return route;
				}
				return legs[Math.Min(leg, legs.Count - 1)];
			}
		}

		public static void Load()
		{
			if (!File.Exists(FilePath))
			{
				return;
			}
			Current = JsonConvert.DeserializeObject<Roll>(File.ReadAllText(FilePath));
			if (Current != null)
			{
				Current.route = InClimbOrder(Current.route);
				for (int i = 0; i < Current.legs.Count; i++)
				{
					Current.legs[i] = InClimbOrder(Current.legs[i]);
				}
			}
		}

		private static int Rank(string key)
		{
			int num = climbOrder.IndexOf(key);
			if (num == -1)
			{
				num = 99;
			}
			return num;
		}

		public static List<string> InClimbOrder(List<string> keys)
		{
			List<string> list = new List<string>();
			list.AddRange(keys);
			list.Sort((string a, string b) => Rank(a) - Rank(b));
			return list;
		}

		public void Save()
		{
			File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)this, (Formatting)1));
		}

		public void PlanLegs()
		{
			legs.Clear();
			leg = 0;
			List<string> list = new List<string>(route);
			list.Remove("chimney");
			if (route.Contains("chimney"))
			{
				legs.Add(new List<string> { "chimney" });
			}
			if (list.Contains("hotzone") && list.Contains("ladder"))
			{
				List<string> list2 = new List<string>(list);
				list2.Remove("hotzone");
				legs.Add(list2);
				legs.Add(new List<string> { "hotzone" });
			}
			else if (legs.Count > 0)
			{
				legs.Add(list);
			}
		}

		public bool LegDone()
		{
			bool flag = true;
			foreach (string item in Route)
			{
				if (!(item == "chimney") && !visited.Contains(item))
				{
					flag = false;
				}
			}
			if (flag)
			{
				return true;
			}
			return false;
		}

		public bool NextLeg()
		{
			if (leg >= legs.Count - 1)
			{
				return false;
			}
			leg++;
			ResetProgress();
			return true;
		}

		public bool HasRoute(string key)
		{
			return route.Contains(key);
		}

		public bool AppliesTo(M_Gamemode mode)
		{
			if (Utils.Same(mode.gamemodeName, gamemode))
			{
				return true;
			}
			if (route.Contains("chimney") && Utils.Same(mode.gamemodeName, "Chimney"))
			{
				return true;
			}
			return false;
		}

		public bool MatchesSave(M_Gamemode mode)
		{
			SaveData saveData = StatManager.saveData;
			List<string> collection = saveData.GetGameMode(mode.gamemodeName)?.activeSettings ?? new List<string>();
			List<string> list = (Utils.Same(mode.gamemodeName, "Chimney") ? chimneySettings : activeSettings);
			if (!new HashSet<string>(collection).SetEquals(list))
			{
				return false;
			}
			return new HashSet<string>(saveData.GetGamemodeTrinkets(mode.GetGamemodeName(true))).SetEquals(activeTrinkets);
		}

		public void ResetProgress()
		{
			visited.Clear();
			offRoute.Clear();
			skipped.Clear();
			chimneyLooped = false;
			ladderLooped = false;
			Save();
		}

		public bool Visit(string key)
		{
			if (key == null)
			{
				return false;
			}
			if (visited.Contains(key))
			{
				return false;
			}
			visited.Add(key);
			if ((!(key == "infested")) ? (!Route.Contains(key)) : Route.Contains("hotzone"))
			{
				offRoute.Add(key);
			}
			Save();
			return true;
		}

		public List<string> Arrive(string place)
		{
			List<string> list = new List<string>();
			if (place == null)
			{
				return list;
			}
			foreach (string item in Route)
			{
				if (!skipPoints.TryGetValue(item, out var value))
				{
					continue;
				}
				bool flag = false;
				string[] array = value;
				foreach (string text in array)
				{
					flag = ((!text.EndsWith("*")) ? Utils.Same(text, place) : place.StartsWith(text.TrimEnd('*'), StringComparison.OrdinalIgnoreCase));
					if (flag)
					{
						break;
					}
				}
				if (flag && !visited.Contains(item) && !skipped.Contains(item))
				{
					skipped.Add(item);
					list.Add(item);
				}
			}
			if (list.Count > 0)
			{
				Save();
			}
			return list;
		}

		public static string Label(string key)
		{
			if (routeLabels.TryGetValue(key, out var value))
			{
				return value;
			}
			return key;
		}

		public static bool RouteUnlocked(string key)
		{
			if (key == "chimney")
			{
				return RunSetup.GamemodeUnlocked(RunSetup.FindGamemode("Chimney"));
			}
			if (!routeUnlocks.TryGetValue(key, out var value))
			{
				return true;
			}
			return StatManager.saveData.GetFlag(value)?.value ?? false;
		}

		public static string RouteKey(string regionName, string subregionName, string gamemodeName)
		{
			if (gamemodeName == "Ladder")
			{
				return "ladder";
			}
			if (regionName != null && routeKeys.TryGetValue(regionName, out var value))
			{
				return value;
			}
			if (subregionName != null && routeKeys.TryGetValue(subregionName, out value))
			{
				return value;
			}
			return null;
		}
	}
	public class RunHud : MonoBehaviour
	{
		public static RunHud Instance;

		private GameObject canvas;

		private GameObject notice;

		private CanvasGroup noticeGroup;

		private bool restarting;

		private int asked;

		private bool inLoopRoom;

		private bool asking;

		private TextMeshProUGUI text;

		private HudCorner builtCorner;

		private float builtScale;

		private CL_GameManager seenManager;

		private static string Compose(Roll roll)
		{
			List<string> list = new List<string>();
			list.Add("<b><color=#EEB211>WHEEL OF WUCK</color></b>");
			foreach (WheelResult result in roll.results)
			{
				if (result.winners.Count <= 0)
				{
					continue;
				}
				string text = "";
				foreach (string winner in result.winners)
				{
					if (text != "")
					{
						text += ", ";
					}
					text += winner;
				}
				list.Add("<color=#AAAAAA>" + result.title + ":</color> " + text);
			}
			if (roll.legs.Count > 1)
			{
				for (int i = 0; i < roll.legs.Count; i++)
				{
					List<string> list2 = new List<string>();
					foreach (string item in roll.legs[i])
					{
						string text2 = ((i < roll.leg) ? "#55DD55" : ((i > roll.leg) ? "#777777" : (roll.visited.Contains(item) ? "#55DD55" : (roll.skipped.Contains(item) ? "#FF5555" : "#FFFFFF"))));
						list2.Add("<color=" + text2 + ">" + Roll.Label(item) + "</color>");
					}
					string text3 = ((i == roll.leg) ? ("<color=#EEB211>Run " + (i + 1) + ":</color>") : ("<color=#AAAAAA>Run " + (i + 1) + ":</color>"));
					if (list2.Count == 0)
					{
						list2.Add((i < roll.leg) ? "<color=#55DD55>Campaign</color>" : ((i > roll.leg) ? "<color=#777777>Campaign</color>" : "<color=#FFFFFF>Campaign</color>"));
					}
					list.Add(text3 + " " + string.Join(" > ", list2));
				}
			}
			else if (roll.Route.Count > 0)
			{
				List<string> list3 = new List<string>();
				foreach (string item2 in roll.Route)
				{
					string text4 = (roll.visited.Contains(item2) ? "#55DD55" : (roll.skipped.Contains(item2) ? "#FF5555" : "#FFFFFF"));
					list3.Add("<color=" + text4 + ">" + Roll.Label(item2) + "</color>");
				}
				list.Add("<color=#AAAAAA>Path:</color> " + string.Join(" > ", list3));
			}
			if (roll.offRoute.Count > 0)
			{
				list.Add("<color=#FF5555>Off route: " + string.Join(", ", roll.offRoute.ConvertAll<string>(Roll.Label)) + "</color>");
			}
			return string.Join("\n", list);
		}

		private void Awake()
		{
			Instance = this;
		}

		private void Update()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			Roll current = Roll.Current;
			if (asking && ((Object)(object)CL_GameManager.gMan != (Object)(object)seenManager || !CL_GameManager.IsInGame()))
			{
				asked = 1;
			}
			seenManager = CL_GameManager.gMan;
			int num;
			if (current != null && current.inPlay && CL_GameManager.IsInGame())
			{
				num = (current.AppliesTo(CL_GameManager.GetBaseGamemode()) ? 1 : 0);
				if (num != 0 && Input.GetKeyDown(Plugin.HudKey.Value))
				{
					Plugin.ShowHud.Value = !Plugin.ShowHud.Value;
				}
			}
			else
			{
				num = 0;
			}
			if (num != 0)
			{
				Track(current);
			}
			if ((Object)(object)notice != (Object)null && asked == 0 && (Object)(object)noticeGroup != (Object)null && noticeGroup.alpha > 0.9f && !restarting)
			{
				if (Input.GetKeyDown(Plugin.ChimneyStayKey.Value))
				{
					asked = 1;
				}
				if (Input.GetKeyDown(Plugin.ChimneyGoKey.Value))
				{
					asked = 2;
				}
			}
			if (num == 0 || !Plugin.ShowHud.Value)
			{
				if ((Object)(object)canvas != (Object)null)
				{
					canvas.SetActive(false);
				}
				return;
			}
			if ((Object)(object)canvas == (Object)null || builtCorner != Plugin.HudPosition.Value || builtScale != Plugin.HudScale.Value)
			{
				Build();
			}
			canvas.SetActive(!CL_GameManager.gMan.isPaused && !OS_Manager.inUse);
			string text = Compose(current);
			if (((TMP_Text)this.text).text != text)
			{
				((TMP_Text)this.text).text = text;
				Transform parent = ((Transform)((TMP_Text)this.text).rectTransform).parent;
				LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((parent is RectTransform) ? parent : null));
			}
		}

		private void Build()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)canvas);
			}
			builtCorner = Plugin.HudPosition.Value;
			builtScale = Plugin.HudScale.Value;
			canvas = new GameObject("WheelOfWuck_Hud");
			Canvas obj = canvas.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 100;
			CanvasScaler obj2 = canvas.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			bool flag = builtCorner == HudCorner.TopRight || builtCorner == HudCorner.BottomRight;
			bool flag2 = builtCorner == HudCorner.TopLeft || builtCorner == HudCorner.TopRight;
			GameObject val = new GameObject("Panel", new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(canvas.transform, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor((float)(flag ? 1 : 0), (float)(flag2 ? 1 : 0));
			component.pivot = val2;
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.sizeDelta = new Vector2(320f, 100f);
			component.anchoredPosition = new Vector2((float)(flag ? (-24) : 24), (float)(flag2 ? (-24) : 24));
			((Transform)component).localScale = Vector3.one * builtScale;
			val.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			VerticalLayoutGroup obj3 = val.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true;
			text = new GameObject("Text", new Type[1] { typeof(RectTransform) }).AddComponent<TextMeshProUGUI>();
			((Transform)((TMP_Text)text).rectTransform).SetParent((Transform)(object)component, false);
			((TMP_Text)text).rectTransform.sizeDelta = new Vector2(320f, 80f);
			((TMP_Text)text).font = Utils.GetFont();
			((TMP_Text)text).fontSize = 14f;
			((TMP_Text)text).alignment = (TextAlignmentOptions)(flag ? 260 : 257);
			((Graphic)text).raycastTarget = false;
		}

		private void Track(Roll roll)
		{
			if ((Object)(object)WorldLoader.instance == (Object)null)
			{
				return;
			}
			Traverse obj = Traverse.Create((object)WorldLoader.instance);
			string text = obj.Field("currentRegion").GetValue<M_Region>()?.regionName;
			string text2 = obj.Field("currentSubregion").GetValue<M_Subregion>()?.subregionName;
			LevelInfo currentLevel = WorldLoader.instance.GetCurrentLevel();
			string text3 = ((currentLevel == null) ? null : currentLevel.GetLevel()?.levelName);
			string text4 = Roll.RouteKey(text, text2, CL_GameManager.GetCurrentGamemode()?.gamemodeName);
			if (roll.Visit(text4))
			{
				Plugin.Logger.LogInfo((object)("entered " + Roll.Label(text4) + (roll.offRoute.Contains(text4) ? " (off route)" : "")));
			}
			Skipped(roll, roll.Arrive(text));
			Skipped(roll, roll.Arrive(text2));
			Skipped(roll, roll.Arrive(text3));
			if (text4 != null)
			{
				Skipped(roll, roll.Arrive(text4));
			}
			bool flag = text3 != null && text3.StartsWith("MX_Chimney_LoopRoom") && roll.route.Contains("chimney");
			if (flag && !inLoopRoom)
			{
				if (!roll.chimneyLooped)
				{
					roll.chimneyLooped = true;
					roll.Save();
					Plugin.Logger.LogInfo((object)"one loop of the Chimney is done");
					roll.NextLeg();
				}
				else
				{
					Plugin.Logger.LogInfo((object)"another loop of the Chimney is done");
				}
				if (!asking)
				{
					((MonoBehaviour)this).StartCoroutine(AskAfterLoop(roll));
				}
			}
			inLoopRoom = flag;
			if (text3 != null && text3.StartsWith("M3_Habitation_LadderWarp_Loop") && roll.Route.Contains("ladder") && !roll.ladderLooped)
			{
				roll.ladderLooped = true;
				roll.Save();
				Plugin.Logger.LogInfo((object)"one loop of the Ladder is done, dying from here still counts as beating it");
				((MonoBehaviour)this).StartCoroutine(Flash("ONE LOOP OF THE LADDER DONE.\n<size=60%>Walk out to end the run or keep climbing - this run counts as complete either way.</size>"));
			}
		}

		private IEnumerator AskAfterLoop(Roll roll)
		{
			asking = true;
			asked = 0;
			Notice("ONE LOOP OF THE CHIMNEY DONE.\n<size=60%>" + ((object)Plugin.ChimneyStayKey.Value/*cast due to .constrained prefix*/).ToString() + ": keep climbing      " + ((object)Plugin.ChimneyGoKey.Value/*cast due to .constrained prefix*/).ToString() + ": end the run here and proceed to the campaign</size>");
			yield return Fade(0f, 1f, 0.5f);
			while (asked == 0)
			{
				yield return null;
			}
			yield return Fade(1f, 0f, 0.5f);
			if ((Object)(object)notice != (Object)null)
			{
				Object.Destroy((Object)(object)notice);
			}
			if (asked == 2 && (Object)(object)CL_GameManager.gMan != (Object)null && CL_GameManager.IsInGame() && (Object)(object)ENT_Player.playerObject != (Object)null)
			{
				Plugin.Logger.LogInfo((object)"ending the Chimney run so the score counts, Restart goes to the campaign");
				((GameEntity)ENT_Player.playerObject).Kill("", (DamageInfo)null);
			}
			asked = 0;
			asking = false;
		}

		private IEnumerator Flash(string message)
		{
			Notice(message);
			yield return Fade(0f, 1f, 0.5f);
			yield return (object)new WaitForSecondsRealtime(5f);
			yield return Fade(1f, 0f, 0.8f);
			if ((Object)(object)notice != (Object)null)
			{
				Object.Destroy((Object)(object)notice);
			}
		}

		public void BranchTaken(string branchName)
		{
			Roll current = Roll.Current;
			if (current == null || !current.inPlay)
			{
				return;
			}
			string text = null;
			branchName = branchName ?? "";
			if (branchName.Contains("TangledSink"))
			{
				text = "sink";
			}
			else if (branchName.Contains("ExpulsionChute"))
			{
				text = "chute";
			}
			else if (branchName.Contains("RottenDuct"))
			{
				text = "duct";
			}
			else if (branchName.Contains("HadalDiver"))
			{
				text = "diver";
			}
			else if (branchName.Contains("Ladder"))
			{
				text = "ladder";
			}
			else if (branchName.Contains("Nest_HotZone"))
			{
				text = "hotzone";
			}
			else if (branchName.Contains("InfestedLabs"))
			{
				text = "infested";
			}
			if (text != null)
			{
				Plugin.Logger.LogInfo((object)("the game is building the " + Roll.Label(text) + " (" + branchName + ")"));
				if (current.Visit(text))
				{
					Plugin.Logger.LogInfo((object)("entered " + Roll.Label(text) + (current.offRoute.Contains(text) ? " (off route)" : "")));
				}
				if (text == "infested")
				{
					Skipped(current, current.Arrive("infested"));
				}
			}
		}

		public void Titled(string region, string subregion)
		{
			Roll current = Roll.Current;
			if (current != null && current.inPlay)
			{
				Plugin.Logger.LogInfo((object)("area title: " + region + " / " + subregion));
				Skipped(current, current.Arrive("title:" + subregion));
				Skipped(current, current.Arrive("title:" + region));
			}
		}

		public void Skipped(Roll roll, List<string> keys)
		{
			if (keys.Count == 0)
			{
				return;
			}
			string text = "";
			for (int i = 0; i < keys.Count; i++)
			{
				if (i > 0)
				{
					text += " and the ";
				}
				text += Roll.Label(keys[i]);
			}
			Plugin.Logger.LogInfo((object)("skipped the " + text));
			if (Plugin.RestartOnSkip.Value && !restarting)
			{
				((MonoBehaviour)this).StartCoroutine(Restart(text));
			}
		}

		private IEnumerator Restart(string names)
		{
			restarting = true;
			Notice("YOU SKIPPED THE " + names.ToUpperInvariant() + ".\n<size=60%>The wheel restarts the run.</size>");
			yield return Fade(0f, 1f, 0.5f);
			yield return (object)new WaitForSecondsRealtime(3.7f);
			yield return Fade(1f, 0f, 0.8f);
			if ((Object)(object)CL_GameManager.gMan != (Object)null && CL_GameManager.IsInGame())
			{
				Plugin.Logger.LogInfo((object)"restarting the run");
				AccessTools.Method(typeof(CL_SaveManager), "DeleteSessionSave", (Type[])null, (Type[])null).Invoke(null, new object[2]
				{
					CL_GameManager.GetGamemodeName(false, true),
					CL_GameManager.IsHardmode()
				});
				CL_SaveManager.isSavedRun = false;
				CL_GameManager.ChangeState("restart");
			}
			yield return (object)new WaitForSecondsRealtime(1.5f);
			if ((Object)(object)notice != (Object)null)
			{
				Object.Destroy((Object)(object)notice);
			}
			restarting = false;
		}

		private IEnumerator Fade(float from, float to, float seconds)
		{
			for (float t = 0f; t < seconds; t += Time.unscaledDeltaTime)
			{
				if (!((Object)(object)noticeGroup != (Object)null))
				{
					break;
				}
				noticeGroup.alpha = Mathf.SmoothStep(from, to, t / seconds);
				yield return null;
			}
			if ((Object)(object)noticeGroup != (Object)null)
			{
				noticeGroup.alpha = to;
			}
		}

		private void Notice(string message)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)notice != (Object)null && Object.op_Implicit((Object)(object)notice))
			{
				Object.Destroy((Object)(object)notice);
			}
			notice = new GameObject("WheelOfWuck_Notice");
			Object.DontDestroyOnLoad((Object)(object)notice);
			Canvas obj = notice.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 101;
			noticeGroup = notice.AddComponent<CanvasGroup>();
			noticeGroup.alpha = 0f;
			CanvasScaler obj2 = notice.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			TextMeshProUGUI obj3 = new GameObject("Text", new Type[1] { typeof(RectTransform) }).AddComponent<TextMeshProUGUI>();
			((Transform)((TMP_Text)obj3).rectTransform).SetParent(notice.transform, false);
			((TMP_Text)obj3).rectTransform.sizeDelta = new Vector2(1400f, 200f);
			((TMP_Text)obj3).rectTransform.anchoredPosition = new Vector2(0f, 280f);
			((TMP_Text)obj3).font = Utils.GetFont("Ticketing SDF GreyGlow");
			((TMP_Text)obj3).fontSize = 48f;
			((Graphic)obj3).color = Utils.Hex("#FF2F39");
			((TMP_Text)obj3).alignment = (TextAlignmentOptions)514;
			((Graphic)obj3).raycastTarget = false;
			((TMP_Text)obj3).text = message;
		}
	}
	public static class RunSetup
	{
		public static bool didRevert;

		public static List<string> Apply(Roll roll, M_Gamemode mode)
		{
			List<string> list = new List<string>();
			string gamemodeName = mode.gamemodeName;
			SaveData saveData = StatManager.saveData;
			saveData.SetupGamemode(gamemodeName);
			Roll current = Roll.Current;
			if (current != null && current.beforeSettings != null && Utils.Same(current.gamemode, gamemodeName) && current.MatchesSave(mode))
			{
				roll.beforeSettings = current.beforeSettings;
				roll.beforeTrinkets = current.beforeTrinkets;
			}
			else
			{
				roll.beforeSettings = new List<string>(saveData.GetGameMode(gamemodeName).activeSettings);
				roll.beforeTrinkets = new List<string>(saveData.GetGamemodeTrinkets(mode.GetGamemodeName(true)));
			}
			foreach (string clearSetting in WheelSet.Current.clearSettings)
			{
				saveData.SetSetting(gamemodeName, clearSetting, false);
			}
			foreach (KeyValuePair<string, bool> setting in roll.settings)
			{
				GamemodeSetting val = FindSetting(mode, setting.Key);
				if ((Object)(object)val == (Object)null)
				{
					list.Add(gamemodeName.Trim() + " has no setting called " + setting.Key + ".");
					continue;
				}
				if (setting.Value && !SettingUnlocked(val))
				{
					list.Add(val.title + " is still locked");
					saveData.SetSetting(gamemodeName, val.id, false);
					continue;
				}
				saveData.SetSetting(gamemodeName, val.id, setting.Value);
				if (!setting.Value)
				{
					continue;
				}
				foreach (string exclusiveSetting in val.exclusiveSettings)
				{
					saveData.SetSetting(gamemodeName, exclusiveSetting, false);
				}
			}
			List<string> list2 = new List<string>();
			int num = 1;
			foreach (string trinket in roll.trinkets)
			{
				Trinket val2 = FindTrinket(mode, trinket);
				if ((Object)(object)val2 == (Object)null)
				{
					list.Add(trinket + " is not offered in " + gamemodeName.Trim() + ".");
				}
				else if (val2.comingSoon || !val2.IsUnlocked())
				{
					list.Add(val2.title + " is still locked.");
				}
				else if (val2.settingBlacklist.Exists((Predicate<string>)mode.HasActiveSetting))
				{
					list.Add(val2.title + " can't be used with the chosen settings.");
				}
				else if (!list2.Contains(((Object)val2).name))
				{
					list2.Add(((Object)val2).name);
					num += (val2.isBinding ? val2.cost : (-val2.cost));
				}
			}
			if (num < 0)
			{
				list?.Add("Too expensive! Take off some trinkets before playing the run.");
			}
			saveData.SetGamemodeTrinkets(mode.GetGamemodeName(true), list2);
			roll.gamemode = gamemodeName;
			roll.activeSettings = new List<string>(saveData.GetGameMode(gamemodeName).activeSettings);
			roll.activeTrinkets = list2;
			roll.chimneySettings = new List<string>();
			if (roll.route.Contains("chimney"))
			{
				M_Gamemode val3 = FindGamemode("Chimney");
				if ((Object)(object)val3 == (Object)null)
				{
					list.Add("The Chimney gamemode was not found, so the run stays in the campaign.");
				}
				else if (!GamemodeUnlocked(val3))
				{
					list.Add("The Chimney is not unlocked yet, so the run stays in the campaign.");
				}
				else
				{
					string gamemodeName2 = val3.gamemodeName;
					saveData.SetupGamemode(gamemodeName2);
					if (current == null || current.beforeChimneyTrinkets == null || !current.route.Contains("chimney") || !current.MatchesSave(val3))
					{
						roll.beforeChimneySettings = new List<string>(saveData.GetGameMode(gamemodeName2).activeSettings);
						roll.beforeChimneyTrinkets = new List<string>(saveData.GetGamemodeTrinkets(val3.GetGamemodeName(true)));
					}
					else
					{
						roll.beforeChimneySettings = current.beforeChimneySettings;
						roll.beforeChimneyTrinkets = current.beforeChimneyTrinkets;
					}
					foreach (string clearSetting2 in WheelSet.Current.clearSettings)
					{
						saveData.SetSetting(gamemodeName2, clearSetting2, false);
					}
					foreach (KeyValuePair<string, bool> setting2 in roll.settings)
					{
						GamemodeSetting val4 = FindSetting(val3, setting2.Key);
						if (!((Object)(object)val4 == (Object)null) && (!setting2.Value || SettingUnlocked(val4)))
						{
							saveData.SetSetting(gamemodeName2, val4.id, setting2.Value);
						}
					}
					saveData.SetGamemodeTrinkets(val3.GetGamemodeName(true), new List<string>(list2));
					roll.chimneySettings = new List<string>(saveData.GetGameMode(gamemodeName2).activeSettings);
				}
			}
			roll.ResetProgress();
			Roll.Current = roll;
			roll.Save();
			RefreshMenus(mode);
			StatManager.instance.SaveStats(true);
			Plugin.Logger.LogInfo((object)("rolled " + gamemodeName.Trim() + ": route [" + string.Join(" > ", roll.route) + "], trinkets [" + string.Join(", ", list2) + "], settings [" + string.Join(", ", roll.activeSettings) + "]"));
			return list;
		}

		public static void RevertOnce()
		{
			if (didRevert)
			{
				return;
			}
			Roll roll = Roll.Current;
			if (roll == null || roll.beforeSettings == null || StatManager.saveData == null || CL_GameManager.IsInGame())
			{
				return;
			}
			M_Gamemode val = Array.Find(Resources.FindObjectsOfTypeAll<M_Gamemode>(), (M_Gamemode m) => Utils.Same(m.gamemodeName, roll.gamemode));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			didRevert = true;
			if (!roll.MatchesSave(val))
			{
				Plugin.Logger.LogInfo((object)"the menu was changed since the roll, leaving it alone");
				return;
			}
			SaveData saveData = StatManager.saveData;
			foreach (GamemodeSetting gamemodeSetting in val.gamemodeSettings)
			{
				saveData.SetSetting(val.gamemodeName, gamemodeSetting.id, roll.beforeSettings.Contains(gamemodeSetting.id));
			}
			saveData.SetGamemodeTrinkets(val.GetGamemodeName(true), new List<string>(roll.beforeTrinkets));
			M_Gamemode val2 = ((roll.route.Contains("chimney") && roll.beforeChimneyTrinkets != null) ? FindGamemode("Chimney") : null);
			if ((Object)(object)val2 != (Object)null && roll.MatchesSave(val2))
			{
				foreach (GamemodeSetting gamemodeSetting2 in val2.gamemodeSettings)
				{
					saveData.SetSetting(val2.gamemodeName, gamemodeSetting2.id, roll.beforeChimneySettings.Contains(gamemodeSetting2.id));
				}
				saveData.SetGamemodeTrinkets(val2.GetGamemodeName(true), new List<string>(roll.beforeChimneyTrinkets));
			}
			RefreshMenus(val);
			StatManager.instance.SaveStats(true);
			Plugin.Logger.LogInfo((object)"put the menu back the way it was before the wheel, the last roll is still on the wheel");
		}

		private static void RefreshMenus(M_Gamemode mode)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			UI_GamemodeSetting[] array = Resources.FindObjectsOfTypeAll<UI_GamemodeSetting>();
			foreach (UI_GamemodeSetting val in array)
			{
				Scene scene = ((Component)val).gameObject.scene;
				if (((Scene)(ref scene)).name != null)
				{
					val.toggle.SetIsOnWithoutNotify(StatManager.saveData.IsSettingActive(mode.gamemodeName, val.gamemodeSetting.id));
					Traverse.Create((object)val).Method("UpdateColor", Array.Empty<object>()).GetValue();
				}
			}
			UI_GamemodeScreen instance = UI_GamemodeScreen.instance;
			if ((Object)(object)instance != (Object)null && ((Component)instance).gameObject.activeInHierarchy && (Object)(object)instance.GetGamemode() == (Object)(object)mode)
			{
				instance.RefreshCurrentGamemode();
			}
			UI_TrinketPicker[] array2 = Object.FindObjectsOfType<UI_TrinketPicker>();
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i].ReloadTrinkets();
			}
			SettingsManager.RefreshSettings("");
		}

		public static M_Gamemode FindGamemode(string name)
		{
			M_Gamemode[] array = Resources.FindObjectsOfTypeAll<M_Gamemode>();
			foreach (M_Gamemode val in array)
			{
				if (Utils.Same(val.gamemodeName, name))
				{
					return val;
				}
			}
			return null;
		}

		public static bool GamemodeUnlocked(M_Gamemode mode)
		{
			if ((Object)(object)mode == (Object)null)
			{
				return false;
			}
			if (mode.unlockAchievement == null || mode.unlockAchievement == "")
			{
				return true;
			}
			return CL_AchievementManager.GetAchievementValue(mode.unlockAchievement);
		}

		public static M_Gamemode ChimneyInstead(Roll roll, M_Gamemode mode)
		{
			if (roll == null || (Object)(object)mode == (Object)null)
			{
				return null;
			}
			if (!Utils.Same(mode.gamemodeName, roll.gamemode))
			{
				return null;
			}
			if (!roll.Route.Contains("chimney"))
			{
				return null;
			}
			M_Gamemode val = FindGamemode("Chimney");
			if ((Object)(object)val == (Object)null || !GamemodeUnlocked(val) || !roll.MatchesSave(val))
			{
				return null;
			}
			return val;
		}

		public static Trinket FindTrinket(M_Gamemode mode, string name)
		{
			List<Trinket> list = new List<Trinket>(mode.availableTrinkets.trinkets);
			list.AddRange(mode.availableTrinkets.bindings);
			return list.Find((Trinket t) => Utils.Same(((Object)t).name, name) || Utils.Same(t.title, name));
		}

		public static GamemodeSetting FindSetting(M_Gamemode mode, string id)
		{
			return mode.gamemodeSettings.Find((GamemodeSetting s) => Utils.Same(s.id, id));
		}

		public static bool SettingUnlocked(GamemodeSetting setting)
		{
			if ((Object)(object)setting.unlock == (Object)null)
			{
				return true;
			}
			return setting.unlock.CheckUnlock();
		}
	}
	public static class Utils
	{
		private static TMP_FontAsset _font;

		private static Dictionary<string, TMP_FontAsset> fonts = new Dictionary<string, TMP_FontAsset>();

		private static Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();

		public static bool Same(string a, string b)
		{
			if (a == null || b == null)
			{
				if (a == null && b == null)
				{
					return true;
				}
				return false;
			}
			string a2 = a.Trim();
			string b2 = b.Trim();
			if (string.Equals(a2, b2, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		public static TMP_FontAsset GetFont()
		{
			if ((Object)(object)_font != (Object)null)
			{
				return _font;
			}
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val in array)
			{
				if (((Object)val).name == "Ticketing SDF Smooth")
				{
					_font = val;
					break;
				}
			}
			if ((Object)(object)_font == (Object)null)
			{
				_font = TMP_Settings.defaultFontAsset;
			}
			return _font;
		}

		public static TMP_FontAsset GetFont(string name)
		{
			if (fonts.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val in array)
			{
				if (((Object)val).name == name)
				{
					value = val;
					break;
				}
			}
			if ((Object)(object)value == (Object)null)
			{
				value = GetFont();
			}
			fonts[name] = value;
			return value;
		}

		public static Sprite GetSprite(string name)
		{
			if (sprites.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			foreach (Sprite val in array)
			{
				if (((Object)val).name == name)
				{
					value = val;
					break;
				}
			}
			if ((Object)(object)value == (Object)null)
			{
				Plugin.Logger.LogWarning((object)("no sprite called " + name));
			}
			sprites[name] = value;
			return value;
		}

		public static string OneLine(string s)
		{
			return s.Replace("\n", " ").Trim();
		}

		public static Color Hex(string hex)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_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)
			Color magenta = Color.magenta;
			if (!ColorUtility.TryParseHtmlString(hex, ref magenta))
			{
				magenta = Color.magenta;
			}
			return magenta;
		}
	}
	public static class WheelLogic
	{
		public static List<(WheelDef wheel, EntryDef entry)> wins = new List<(WheelDef, EntryDef)>();

		private static Random rng = new Random();

		public static int SpinsFor(WheelDef wheel)
		{
			if (int.TryParse(wheel.spins, out var result))
			{
				return result;
			}
			int num = 0;
			for (int i = 0; i < wins.Count; i++)
			{
				if (wins[i].wheel.id == wheel.spins)
				{
					num += wins[i].entry.count;
				}
			}
			return num;
		}

		public static int Slack(M_Gamemode mode)
		{
			int num = 1;
			for (int i = 0; i < wins.Count; i++)
			{
				(WheelDef, EntryDef) tuple = wins[i];
				if (!string.IsNullOrEmpty(tuple.Item2.trinket))
				{
					Trinket val = RunSetup.FindTrinket(mode, tuple.Item2.trinket);
					if (!((Object)(object)val == (Object)null))
					{
						int cost = val.cost;
						num = ((!val.isBinding) ? (num - cost) : (num + cost));
					}
				}
			}
			return num;
		}

		public static List<EntryDef> Live(WheelDef wheel, M_Gamemode mode)
		{
			List<EntryDef> list = new List<EntryDef>();
			int num = Slack(mode);
			foreach (EntryDef entry in wheel.entries)
			{
				if (!WheelPicks.IsEnabled(wheel, entry) || entry.weight <= 0f || (wheel.unique && wins.Any(((WheelDef wheel, EntryDef entry) w) => w.wheel == wheel && w.entry == entry)))
				{
					continue;
				}
				if (!string.IsNullOrEmpty(entry.trinket))
				{
					Trinket val = RunSetup.FindTrinket(mode, entry.trinket);
					if ((Object)(object)val != (Object)null && !val.isBinding && num - val.cost < 0)
					{
						Plugin.Logger.LogInfo((object)(entry.text + " stays off the " + wheel.title + " wheel: not enough bindings to afford it"));
						continue;
					}
				}
				string text = Locked(entry, mode);
				if (text != null)
				{
					Plugin.Logger.LogInfo((object)$"{entry.text} stays off the {wheel.title} wheel: {text}");
				}
				else
				{
					list.Add(entry);
				}
			}
			return list;
		}

		public static string Locked(EntryDef entry, M_Gamemode mode)
		{
			if (!string.IsNullOrEmpty(entry.trinket))
			{
				Trinket val = RunSetup.FindTrinket(mode, entry.trinket);
				if ((Object)(object)val == (Object)null)
				{
					return mode.gamemodeName + " offers no trinket or binding called " + entry.trinket;
				}
				if (val.comingSoon || !val.IsUnlocked())
				{
					return val.title + " is not unlocked yet";
				}
			}
			if (entry.settings != null)
			{
				foreach (KeyValuePair<string, bool> setting in entry.settings)
				{
					GamemodeSetting val2 = RunSetup.FindSetting(mode, setting.Key);
					if ((Object)(object)val2 == (Object)null)
					{
						return mode.gamemodeName + " has no setting called " + setting.Key;
					}
					if (setting.Value && !RunSetup.SettingUnlocked(val2))
					{
						return val2.title + " is not unlocked yet";
					}
				}
			}
			if (entry.route != null)
			{
				foreach (string item in entry.route)
				{
					if (!Roll.RouteUnlocked(item))
					{
						return "the " + Roll.Label(item) + " is not unlocked yet";
					}
				}
			}
			return null;
		}

		public static EntryDef Pick(List<EntryDef> live)
		{
			double num = 0.0;
			int count = live.Count;
			for (int i = 0; i < count; i++)
			{
				num += (double)live[i].weight;
			}
			double num2 = rng.NextDouble() * num;
			foreach (EntryDef item in live)
			{
				num2 -= (double)item.weight;
				if (num2 < 0.0)
				{
					return item;
				}
			}
			return live[live.Count - 1];
		}

		public static Roll BuildRoll(List<WheelResult> results)
		{
			Roll roll = new Roll();
			roll.rolledAt = DateTime.Now;
			roll.results = results;
			foreach (var win in wins)
			{
				EntryDef item = win.entry;
				if (item.settings != null)
				{
					foreach (KeyValuePair<string, bool> setting in item.settings)
					{
						roll.settings[setting.Key] = setting.Value;
					}
				}
				if (item.route != null)
				{
					foreach (string item2 in item.route)
					{
						if (!roll.route.Contains(item2))
						{
							roll.route.Add(item2);
						}
					}
				}
				if (!string.IsNullOrEmpty(item.trinket) && !roll.trinkets.Contains(item.trinket))
				{
					roll.trinkets.Add(item.trinket);
				}
				if (!string.IsNullOrEmpty(item.note))
				{
					roll.notes.Add(item.note);
				}
			}
			roll.route = Roll.InClimbOrder(roll.route);
			roll.PlanLegs();
			if (roll.legs.Count > 1)
			{
				List<string> list = new List<string>();
				foreach (List<string> leg in roll.legs)
				{
					list.Add((leg.Count == 0) ? "the campaign" : string.Join(" > ", leg.ConvertAll<string>(Roll.Label)));
				}
				roll.notes.Add(list.Count + " runs: " + string.Join(", then ", list) + ".");
			}
			return roll;
		}
	}
	public class WheelPicks
	{
		public static readonly string FilePath = Path.Combine(Paths.ConfigPath, "senkodev.whiteknuckle.wheelofwuck.picks.json");

		public static WheelPicks Current = new WheelPicks();

		public Dictionary<string, Dictionary<string, bool>> enabled = new Dictionary<string, Dictionary<string, bool>>();

		public static void Load()
		{
			if (!File.Exists(FilePath))
			{
				return;
			}
			try
			{
				Current = JsonConvert.DeserializeObject<WheelPicks>(File.ReadAllText(FilePath)) ?? new WheelPicks();
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("could not read " + FilePath + ", using the wheel defaults: " + ex.Message));
				Current = new WheelPicks();
			}
		}

		public void Save()
		{
			File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)this, (Formatting)1));
		}

		public static bool IsEnabled(WheelDef wheel, EntryDef entry)
		{
			if (Current.enabled.TryGetValue(wheel.id, out var value) && value.TryGetValue(entry.text, out var value2))
			{
				return value2;
			}
			return entry.enabled;
		}

		public static void Set(WheelDef wheel, EntryDef entry, bool on)
		{
			if (!Current.enabled.TryGetValue(wheel.id, out var value))
			{
				value = new Dictionary<string, bool>();
				Current.enabled[wheel.id] = value;
			}
			if (on == entry.enabled)
			{
				value.Remove(entry.text);
			}
			else
			{
				value[entry.text] = on;
			}
			if (value.Count == 0)
			{
				Current.enabled.Remove(wheel.id);
			}
			Current.Save();
		}

		public static void Clear()
		{
			Current.enabled.Clear();
			Current.Save();
		}
	}
	public class WheelSet
	{
		public static readonly string FilePath = Path.Combine(Paths.ConfigPath, "senkodev.whiteknuckle.wheelofwuck.wheels.json");

		public static WheelSet Current;

		private static DateTime loadedAt;

		public string title = "Wheel of Wuck";

		public List<string> colors = new List<string> { "#3369E8", "#D50F25", "#EEB211", "#009925" };

		public List<string> clearSettings = new List<string> { "ironknuckle", "competitive" };

		public List<WheelDef> wheels = new List<WheelDef>();

		public static void Load()
		{
			if (!File.Exists(FilePath))
			{
				try
				{
					File.WriteAllText(FilePath, Default());
				}
				catch
				{
				}
			}
			DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(FilePath);
			if (Current != null && lastWriteTimeUtc == loadedAt)
			{
				return;
			}
			loadedAt = lastWriteTimeUtc;
			try
			{
				Current = JsonConvert.DeserializeObject<WheelSet>(File.ReadAllText(FilePath));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("could not read " + FilePath + ", using the shipped wheels: " + ex.Message));
				Current = JsonConvert.DeserializeObject<WheelSet>(Default());
			}
		}

		private static string Default()
		{
			using StreamReader streamReader = new StreamReader(typeof(WheelSet).Assembly.GetManifestResourceStream("wheels.json"));
			return streamReader.ReadToEnd();
		}
	}
	public class WheelDef
	{
		public string id;

		public string title;

		public string spins = "1";

		public bool unique = true;

		public List<EntryDef> entries = new List<EntryDef>();
	}
	[JsonObject(/*Could not decode attribute arguments.*/)]
	public class EntryDef
	{
		public string text;

		public float weight = 1f;

		public bool enabled = true;

		public Dictionary<string, bool> settings;

		public List<string> route;

		public string trinket;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int count;

		public string note;
	}
	public class WheelSettings : MonoBehaviour
	{
		private static readonly Color Box = Utils.Hex("#FF7800");

		private static readonly Color Faded = Utils.Hex("#A66922");

		private static readonly Color Grey = Utils.Hex("#575757");

		private WheelSet set;

		private M_Gamemode mode;

		private Action onClose;

		public List<Toggle> toggles = new List<Toggle>();

		public List<(WheelDef wheel, EntryDef entry)> rows = new List<(WheelDef, EntryDef)>();

		private bool _built;

		private AudioClip tickOn;

		private AudioClip tickOff;

		private TextMeshProUGUI hint;

		private const string HintText = "Tick what can land on each wheel.";

		public static WheelSettings Current { get; private set; }

		public static bool IsOpen => (Object)(object)Current != (Object)null;

		public static void Open(Transform parent, WheelSet set, M_Gamemode mode, Action onClose)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Current != (Object)null))
			{
				RectTransform obj = WheelUI.Rect("Settings", parent, Vector2.zero, Vector2.zero);
				obj.anchorMin = Vector2.zero;
				obj.anchorMax = Vector2.one;
				obj.offsetMin = Vector2.zero;
				obj.offsetMax = Vector2.zero;
				Current = ((Component)obj).gameObject.AddComponent<WheelSettings>();
				Current.set = set;
				Current.mode = mode;
				Current.onClose = onClose;
				Current.Build();
				Current._built = true;
			}
		}

		public void Close()
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			onClose?.Invoke();
		}

		public void Defaults()
		{
			if ((Object)(object)tickOff != (Object)null)
			{
				AudioManager.PlayUISound(tickOff, 0.8f, 1f);
			}
			WheelPicks.Clear();
			int count = toggles.Count;
			for (int i = 0; i < count; i++)
			{
				bool enabled = rows[i].entry.enabled;
				Toggle obj = toggles[i];
				obj.SetIsOnWithoutNotify(enabled);
				Tint(obj, enabled);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Current == (Object)(object)this)
			{
				Current = null;
			}
		}

		private void Build()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Expected O, but got Unknown
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Expected O, but got Unknown
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 1f);
			AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
			foreach (AudioClip val2 in array)
			{
				if (((Object)val2).name == "mbutton4")
				{
					tickOn = val2;
				}
				if (((Object)val2).name == "mbutton5")
				{
					tickOff = val2;
				}
			}
			((Graphic)WheelUI.Fill("Dim", ((Component)this).transform, new Color(0f, 0f, 0f, 0.6f))).raycastTarget = true;
			Transform parent = WheelUI.Panel("Panel", ((Component)this).transform, new Vector2(1100f, 920f), Vector2.zero, "WHEEL SETTINGS", Utils.Hex("#606060"), Utils.Hex("#959595"));
			hint = WheelUI.Text("Hint", parent, new Vector2(1000f, 30f), new Vector2(0f, -54f), "Tick what can land on each wheel.", 18f, (TextAlignmentOptions)514, WheelUI.Dim, val);
			((TMP_Text)hint).font = Utils.GetFont("Ticketing SDF");
			RectTransform val3 = WheelUI.Rect("View", parent, new Vector2(1040f, 740f), new Vector2(0f, -90f), val);
			((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f);
			((Component)val3).gameObject.AddComponent<RectMask2D>();
			RectTransform val4 = WheelUI.Rect("Content", (Transform)(object)val3, Vector2.zero, Vector2.zero, val);
			val4.anchorMin = new Vector2(0f, 1f);
			val4.anchorMax = new Vector2(1f, 1f);
			val4.pivot = val;
			val4.sizeDelta = Vector2.zero;
			VerticalLayoutGroup obj = ((Component)val4).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).padding = new RectOffset(16, 16, 6, 10);
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 4f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((Component)val4).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			ScrollRect obj2 = ((Component)val3).gameObject.AddComponent<ScrollRect>();
			obj2.content = val4;
			obj2.horizontal = false;
			obj2.vertical = true;
			obj2.movementType = (MovementType)2;
			obj2.scrollSensitivity = 30f;
			foreach (WheelDef wheel in set.wheels)
			{
				TextMeshProUGUI obj3 = WheelUI.Text("Header", (Transform)(object)val4, new Vector2(0f, 34f), Vector2.zero, wheel.title.ToUpperInvariant(), 24f, (TextAlignmentOptions)1025, WheelUI.Orange);
				((TMP_Text)obj3).font = Utils.GetFont("Ticketing SDF GreyGlow");
				((Component)obj3).gameObject.AddComponent<LayoutElement>().preferredHeight = 34f;
				((Component)WheelUI.Image("Rule", (Transform)(object)val4, Vector2.zero, Vector2.zero, new Color(0.58f, 0.58f, 0.58f, 0.6f))).gameObject.AddComponent<LayoutElement>().preferredHeight = 2f;
				RectTransform val5 = WheelUI.Rect("Grid", (Transform)(object)val4, Vector2.zero, Vector2.zero);
				GridLayoutGroup obj4 = ((Component)val5).gameObject.AddComponent<GridLayoutGroup>();
				obj4.cellSize = new Vector2(246f, 34f);
				obj4.spacing = new Vector2(8f, 2f);
				((LayoutGroup)obj4).padding = new RectOffset(0, 0, 4, 2);
				obj4.constraint = (Constraint)1;
				obj4.constraintCount = 4;
				((LayoutGroup)obj4).childAlignment = (TextAnchor)0;
				foreach (EntryDef entry in wheel.entries)
				{
					AddRow((Transform)(object)val5, wheel, entry);
				}
			}
			Vector2 val6 = default(Vector2);
			((Vector2)(ref val6))..ctor(0f, -416f);
			WheelUI.Button("Defaults", parent, new Vector2(170f, 48f), val6 + new Vector2(-100f, 0f), "DEFAULTS", Defaults, primary: false);
			WheelUI.Button("Done", parent, new Vector2(170f, 48f), val6 + new Vector2(100f, 0f), "DONE", Close);
		}

		private void AddRow(Transform parent, WheelDef wheel, EntryDef entry)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_008f: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = WheelUI.Rect("Entry", parent, Vector2.zero, Vector2.zero);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = Color.clear;
			Vector2 value = default(Vector2);
			((Vector2)(ref value))..ctor(0f, 0.5f);
			Image val2 = WheelUI.Image("Box", (Transform)(object)val, new Vector2(26f, 26f), new Vector2(6f, 0f), Box, Utils.GetSprite("window_outline_02"), value, value);
			val2.type = (Type)1;
			val2.pixelsPerUnitMultiplier = 0.5f;
			Image val3 = WheelUI.Image("Check", ((Component)val2).transform, new Vector2(30f, 30f), Vector2.zero, WheelUI.Orange, Utils.GetSprite("window_X_02"));
			TextMeshProUGUI val4 = WheelUI.Text("Label", (Transform)(object)val, Vector2.zero, Vector2.zero, entry.text, 20f, (TextAlignmentOptions)4097, WheelUI.Ink);
			((TMP_Text)val4).font = Utils.GetFont("Ticketing SDF");
			((TMP_Text)val4).rectTransform.anchorMin = Vector2.zero;
			((TMP_Text)val4).rectTransform.anchorMax = Vector2.one;
			((TMP_Text)val4).rectTransform.offsetMin = new Vector2(42f, 0f);
			((TMP_Text)val4).rectTransform.offsetMax = new Vector2(-4f, 0f);
			((TMP_Text)val4).enableAutoSizing = true;
			((TMP_Text)val4).fontSizeMin = 12f;
			((TMP_Text)val4).fontSizeMax = 20f;
			((TMP_Text)val4).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val4).overflowMode = (TextOverflowModes)1;
			Toggle toggle = ((Component)val).gameObject.AddComponent<Toggle>();
			((Selectable)toggle).targetGraphic = (Graphic)(object)val2;
			toggle.graphic = (Graphic)(object)val3;
			toggle.toggleTransition = (ToggleTransition)0;
			Toggle obj = toggle;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			ColorBlock colors = ((Selectable)toggle).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = Utils.Hex("#FF0000");
			((ColorBlock)(ref colors)).pressedColor = Utils.Hex("#C8C8C8");
			((ColorBlock)(ref colors)).selectedColor = Color.white;
			((ColorBlock)(ref colors)).disabledColor = Utils.Hex("#7D7D7D80");
			((Selectable)toggle).colors = colors;
			bool flag = WheelPicks.IsEnabled(wheel, entry);
			toggle.SetIsOnWithoutNotify(flag);
			if (WheelLogic.Locked(entry, mode) != null)
			{
				((Selectable)toggle).interactable = false;
				((Component)val3).gameObject.SetActive(false);
				WheelUI.Image("Lock", ((Component)val2).transform, new Vector2(28f, 28f), Vector2.zero, Grey, Utils.GetSprite("Icon_Lock"));
				((Graphic)val2).color = Grey;
				((Graphic)val4).color = Grey;
				((TMP_Text)val4).text = entry.text + "  <size=65%>locked</size>";
			}
			else
			{
				Tint(toggle, flag);
				((UnityEvent<bool>)(object)toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool flag2)
				{
					if (!flag2 && !AnotherOn(wheel, toggle))
					{
						toggle.SetIsOnWithoutNotify(true);
						Tint(toggle, on: true);
						if ((Object)(object)tickOff != (Object)null)
						{
							AudioManager.PlayUISound(tickOff, 0.8f, 1f);
						}
						Warn("At least one entry has to stay on for " + wheel.title + ".");
					}
					else
					{
						WheelPicks.Set(wheel, entry, flag2);
						Tint(toggle, flag2);
						AudioClip val5 = (flag2 ? tickOn : tickOff);
						if ((Object)(object)val5 != (Object)null)
						{
							AudioManager.PlayUISound(val5, 0.8f, 1f);
						}
					}
				});
			}
			toggles.Add(toggle);
			rows.Add((wheel, entry));
		}

		public bool AnotherOn(WheelDef wheel, Toggle except)
		{
			int num = 0;
			for (int i = 0; i < toggles.Count; i++)
			{
				if (rows[i].wheel == wheel)
				{
					Toggle val = toggles[i];
					if (!((Object)(object)val == (Object)(object)except) && ((Selectable)val).interactable && val.isOn)
					{
						num++;
					}
				}
			}
			return num > 0;
		}

		private void Warn(string message)
		{
			if (!((Object)(object)hint == (Object)null))
			{
				((MonoBehaviour)this).StopAllCoroutines();
				((MonoBehaviour)this).StartCoroutine(WarnFor(message, 2.5f));
			}
		}

		private IEnumerator WarnFor(string message, float seconds)
		{
			((TMP_Text)hint).text = message;
			((Graphic)hint).color = WheelUI.Red;
			yield return (object)new WaitForSecondsRealtime(seconds);
			if ((Object)(object)hint != (Object)null)
			{
				((TMP_Text)hint).text = "Tick what can land on each wheel.";
				((Graphic)hint).color = WheelUI.Dim;
			}
		}

		private static void Tint(Toggle toggle, bool on)
		{
			//IL_0019: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (((Selectable)toggle).interactable)
			{
				((Graphic)((Component)toggle).GetComponentInChildren<TMP_Text>()).color = (on ? WheelUI.Ink : Faded);
				Color box = Box;
				box.a = (on ? 1f : 0.55f);
				((Selectable)toggle).targetGraphic.color = box;
			}
		}
	}
	public class WheelUI : MonoBehaviour
	{
		private const float Radius = 290f;

		private static readonly Vector2 WheelCentre = new Vector2(-290f, -50f);

		private static readonly Vector2 PanelCentre = new Vector2(335f, -50f);

		private static readonly Vector2 PanelSize = new Vector2(440f, 560f);

		private static readonly Vector2 Middle = new Vector2(0.5f, 0.5f);

		public static readonly Color Ink = Color.white;

		public static readonly Color Frame = Utils.Hex("#A1A1A1");

		public static readonly Color Orange = Utils.Hex("#FF9D00");

		public static readonly Color Red = Utils.Hex("#FF2F39");

		public static readonly Color Magenta = Utils.Hex("#B43EA8");

		public static readonly Color Dim = Utils.Hex("#9F9F9F");

		public static float SpinSeconds = 6f;

		public static int SpinTurns = 5;

		private WheelSet set;

		private M_Gamemode mode;

		private Func<Roll, List<string>> apply;

		private RectTransform wheelGroup;

		private RectTransform wheel;

		private RectTransform pointer;

		private Image wheelImage;

		private TextMeshProUGUI resultsText;

		private TextMeshProUGUI hint;

		private GameObject winnerPanel;

		private TextAnimator_TMP winnerText;

		private Button actionButton;

		private Button resetButton;

		private Button settingsButton;

		private Button cancelButton;

		private Button lastButton;

		private GameObject selectedBefore;

		private AudioClip tickClip;

		private AudioClip winClip;

		private float[] starts;

		private float[] spans;

		private Color[] sliceColors;

		private Sprite highlight;

		private int lastSlice;

		private float pointerKick;

		private float pointerReturn = 160f;

		private float lastDegrees;

		private float lastDegreesTime;

		private float wheelSpeed;

		private int spinCount;

		private bool actionPressed;

		private bool resetPressed;

		private bool useLast;

		private bool previewLast;

		private bool wasReset;

		private List<WheelResult> results = new List<WheelResult>();

		private const float launchPart = 0.06f;

		private const float friction = 1.45f;

		public static WheelUI Current { get; private set; }

		public static bool IsOpen => (Object)(object)Current != (Object)null;

		public static void Open(WheelSet set, M_Gamemode mode, Func<Roll, List<string>> apply)
		{
			//IL_0013: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Current != (Object)null))
			{
				GameObject val = new GameObject("WheelOfWuck_Overlay");
				Canvas obj = val.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 32000;
				CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
				obj2.uiScaleMode = (ScaleMode)1;
				obj2.referenceResolution = new Vector2(1920f, 1080f);
				obj2.matchWidthOrHeight = 0.5f;
				val.AddComponent<GraphicRaycaster>();
				Current = val.AddComponent<WheelUI>();
				Current.set = set;
				Current.mode = mode;
				Current.apply = apply;
			}
		}

		public void Press()
		{
			if (((Selectable)actionButton).interactable)
			{
				actionPressed = true;
			}
		}

		public void Reset()
		{
			if (((Selectable)resetButton).interactable)
			{
				resetPressed = true;
				actionPressed = true;
			}
		}

		private void Start()
		{
			Build();
			selectedBefore = EventSystem.current.currentSelectedGameObject;
			AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
			foreach (AudioClip val in array)
			{
				if (((Object)val).name == "click_01")
				{
					tickClip = val;
				}
				if (((Object)val).name == "mbutton1")
				{
					winClip = val;
				}
			}
			((MonoBehaviour)this).StartCoroutine(Run());
		}

		private void OnDestroy()
		{
			ClearWheel();
			EventSystem current = EventSystem.current;
			if (current != null)
			{
				current.SetSelectedGameObject(selectedBefore);
			}
			if ((Object)(object)Current == (Object)(object)this)
			{
				Current = null;
			}
		}

		public void Back()
		{
			if (WheelSettings.IsOpen)
			{
				WheelSettings.Current.Close();
			}
			else
			{
				Cancel();
			}
		}

		private void Update()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)27))
			{
				Back();
			}
			if ((Object)(object)EventSystem.current.currentSelectedGameObject != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
			pointerKick = Mathf.MoveTowards(pointerKick, 0f, Time.unscaledDeltaTime * pointerReturn);
			((Transform)pointer).localRotation = Quaternion.Euler(0f, 0f, pointerKick);
		}

		private void Build()
		{
			//IL_0041: 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_007a: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0507: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_051b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0545: Unknown result type (might be due to invalid IL or missing references)
			//IL_0554: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Unknown result type (might be due to invalid IL or missing references)
			Vector2 value = default(Vector2);
			((Vector2)(ref value))..ctor(0.5f, 1f);
			Vector2 value2 = default(Vector2);
			((Vector2)(ref value2))..ctor(0.5f, 0f);
			((Graphic)Fill("Dim", ((Component)this).transform, new Color(0.02f, 0.02f, 0.03f, 0.92f))).raycastTarget = true;
			((TAnimCore)Shaky(Text("Title", ((Component)this).transform, new Vector2(1200f, 80f), new Vector2(0f, -10f), "", 56f, (TextAlignmentOptions)514, Ink, value))).SetText(set.title.ToUpperInvariant());
			wheelGroup = Rect("WheelGroup", ((Component)this).transform, Vector2.zero, Vector2.zero);
			wheel = Rect("Wheel", (Transform)(object)wheelGroup, new Vector2(580f, 580f), WheelCentre);
			wheelImage = ((Component)wheel).gameObject.AddComponent<Image>();
			((Graphic)wheelImage).raycastTarget = false;
			pointer = ((Graphic)Image("Pointer", (Transform)(object)wheelGroup, new Vector2(60f, 42f), WheelCentre + new Vector2(342f, 0f), Color.white, PointerSprite(120, 84, Color.white, Color.black, 5f), (Vector2?)null, (Vector2?)new Vector2(1f, 0.5f))).rectTransform;
			lastButton = Button("Last", (Transform)(object)wheelGroup, new Vector2(240f, 48f), WheelCentre + new Vector2(0f, -334f), "LAST ROLL", delegate
			{
				useLast = true;
				actionPressed = true;
			}, primary: false);
			Transform parent = Panel("Results", ((Component)this).transform, PanelSize, PanelCentre, "THE RUN", Magenta, Magenta);
			resultsText = Text("ResultsText", parent, new Vector2(PanelSize.x - 44f, PanelSize.y - 150f), new Vector2(0f, -62f), "", 22f, (TextAlignmentOptions)257, Ink, value);
			((TMP_Text)resultsText).font = Utils.GetFont("Ticketing SDF");
			hint = Text("Hint", parent, new Vector2(PanelSize.x - 44f, 60f), new Vector2(0f, 16f), "", 18f, (TextAlignmentOptions)1026, Dim, value2);
			((TMP_Text)hint).font = Utils.GetFont("Ticketing SDF");
			RectTransform val = Rect("Buttons", ((Component)this).transform, new Vector2(PanelSize.x, 50f), new Vector2(PanelCentre.x, PanelCentre.y - PanelSize.y / 2f - 40f));
			HorizontalLayoutGroup obj = ((Component)val).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 16f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)4;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			actionButton = Button("Action", (Transform)(object)val, new Vector2(136f, 50f), Vector2.zero, "SPIN", Press);
			resetButton = Button("Reset", (Transform)(object)val, new Vector2(136f, 50f), Vector2.zero, "RESET", Reset, primary: false);
			settingsButton = Button("Settings", (Transform)(object)val, new Vector2(136f, 50f), Vector2.zero, "SETTINGS", OpenSettings, primary: false);
			cancelButton = Button("Cancel", (Transform)(object)val, new Vector2(136f, 50f), Vector2.zero, "CANCEL", Cancel, primary: false);
			RectTransform val2 = Rect("Winner", ((Component)this).transform, new Vector2(520f, 160f), WheelCentre);
			Panel("Frame", (Transform)(object)val2, new Vector2(520f, 160f), Vector2.zero, "THE WHEEL SAYS", Red, Red);
			winnerPanel = ((Component)val2).gameObject;
			winnerText = Shaky(Text("WinnerText", (Transform)(object)val2, new Vector2(500f, 90f), new Vector2(0f, 12f), "", 40f, (TextAlignmentOptions)514, Ink, value2));
			winnerPanel.SetActive(false);
		}

		private static TextAnimator_TMP Shaky(TextMeshProUGUI text)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			TextAnimator_TMP val = ((Component)text).gameObject.AddComponent<TextAnimator_TMP>();
			((TAnimCore)val).DefaultBehaviorsTags = new string[1] { "shake" };
			((TAnimCore)val).DefaultAppearancesTags = new string[0];
			((TAnimCore)val).defaultTagsMode = (DefaultTagsMode)1;
			((TAnimCore)val).useDynamicScaling = true;
			((TAnimCore)val).referenceFontSize = 250f;
			return val;
		}

		private void OpenSettings()
		{
			if (!WheelSettings.IsOpen)
			{
				WheelSettings.Open(((Component)this).transform, set, mode, delegate
				{
					resetPressed = true;
					actionPressed = true;
				});
			}
		}

		private IEnumerator Run()
		{
			while (true)
			{
				resetPressed = false;
				useLast = false;
				WheelLogic.wins.Clear();
				results = new List<WheelResult>();
				previewLast = Roll.Current != null && !wasReset;
				((Component)lastButton).gameObject.SetActive(Roll.Current != null);
				((Component)resetButton).gameObject.SetActive(false);
				((Component)settingsButton).gameObject.SetActive(true);
				((Component)wheelGroup).gameObject.SetActive(true);
				((Component)cancelButton).gameObject.SetActive(true);
				((TMP_Text)hint).text = "";
				foreach (WheelDef wheelDef in set.wheels)
				{
					int spins = WheelLogic.SpinsFor(wheelDef);
					WheelResult result = new WheelResult
					{
						id = wheelDef.id,
						title = wheelDef.title
					};
					for (int spin = 0; spin < spins; spin++)
					{
						List<EntryDef> live = WheelLogic.Live(wheelDef, mode);
						if (live.Count == 0)
						{
							Plugin.Logger.LogWarning((object)("nothing left to spin on the " + wheelDef.title + " wheel"));
							break;
						}
						if (live.Count == 1)
						{
							EntryDef entryDef = live[0];
							Plugin.Logger.LogInfo((object)("only " + entryDef.text + " can land on the " + wheelDef.title + " wheel, no spin needed"));
							WheelLogic.wins.Add((wheelDef, entryDef));
							result.winners.Add(entryDef.text);
							if (!results.Contains(result))
							{
								results.Add(result);
							}
							RefreshResults(wheelDef);
							continue;
						}
						EntryDef winner = WheelLogic.Pick(live);
						ShowWheel(live);
						RefreshResults(wheelDef);
						yield return WaitForAction("SPIN");
						if (useLast || resetPressed)
						{
							break;
						}
						previewLast = false;
						((Component)lastButton).gameObject.SetActive(false);
						((Component)settingsButton).gameObject.SetActive(false);
						RefreshResults(wheelDef);
						((Selectable)resetButton).interactable = false;
						yield return Spin(live.IndexOf(winner));
						WheelLogic.wins.Add((wheelDef, winner));
						result.winners.Add(winner.text);
						if (!results.Contains(result))
						{
							results.Add(result);
						}
						RefreshResults(wheelDef);
						((Component)resetButton).gameObject.SetActive(true);
						winnerPanel.SetActive(true);
						((TAnimCore)winnerText).SetText(winner.text);
						yield return PopIn(winnerPanel.transform);
						AudioManager.PlayUISound(winClip, 0.8f, 1f);
						yield return WaitForAction("NEXT");
						winnerPanel.SetActive(false);
						if (resetPressed)
						{
							break;
						}
					}
					if (useLast || resetPressed)
					{
						break;
					}
				}
				if (resetPressed)
				{
					wasReset = true;
					continue;
				}
				ClearWheel();
				((Component)wheelGroup).gameObject.SetActive(false);
				((Component)cancelButton).gameObject.SetActive(false);
				((Component)settingsButton).gameObject.SetActive(false);
				Roll roll = (useLast ? Roll.Current : WheelLogic.BuildRoll(results));
				results = roll.results;
				previewLast = false;
				List<string> list = apply(roll);
				list.InsertRange(0, roll.notes);
				RefreshResults(null, list);
				((TMP_Text)hint).text = "Everything is picked. Press Play when you're ready, or Reset to spin again.";
				((Component)resetButton).gameObject.SetActive(true);
				yield return WaitForAction("DONE");
				if (!resetPressed)
				{
					break;
				}
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private void Cancel()
		{
			Plugin.Logger.LogInfo((object)"wheel cancelled, nothing changed");
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private IEnumerator WaitForAction(string label)
		{
			actionPressed = false;
			((Selectable)actionButton).interactable = true;
			((Selectable)resetButton).interactable = true;
			SetLabel(actionButton, label);
			while (!actionPressed)
			{
				yield return null;
			}
			actionPressed = false;
		}

		private void RefreshResults(WheelDef current, List<string> notes = null)
		{
			List<string> list = new List<string>();
			foreach (WheelDef wheelDef in set.wheels)
			{
				WheelResult wheelResult = results.Find((WheelResult r) => r.id == wheelDef.id);
				WheelResult wheelResult2 = null;
				if (previewLast)
				{
					wheelResult2 = Roll.Current.results.Find((WheelResult r) => r.id == wheelDef.id);
				}
				if (wheelDef == current)
				{
					list.Add("<color=#FF9D00>" + wheelDef.title + ":</color> " + Winners(wheelResult));
				}
				else if (wheelResult != null)
				{
					list.Add("<color=#AAAAAA>" + wheelDef.title + ":</color> " + Winners(wheelResult));
				}
				else if (wheelResult2 != null)
				{
					list.Add("<color=#555555>" + wheelDef.title + ": " + Winners(wheelResult2) + "</color>");
				}
				else
				{
					list.Add("<color=#555555>" + wheelDef.title + "</color>");
				}
			}
			if (notes != null)
			{
				foreach (string note in notes)
				{
					list.Add("<color=#FF9D00>" + note + "</color>");
				}
			}
			((TMP_Text)resultsText).text = string.Join("\n", list);
		}

		private static string Winners(WheelResult result)
		{
			if (result == null)
			{
				return "";
			}
			string text = "";
			for (int i = 0; i < result.winners.Count; i++)
			{
				if (i != 0)
				{
					text += ", ";
				}
				text += result.winners[i];
			}
			return text;
		}

		private void ShowWheel(List<EntryDef> live)
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: 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)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			ClearWheel();
			float num = 0f;
			for (int i = 0; i < live.Count; i++)
			{
				num += live[i].weight;
			}
			starts = new float[live.Count];
			spans = new float[live.Count];
			for (int j = 0; j < live.Count; j++)
			{
				starts[j] = ((j == 0) ? 0f : (starts[j - 1] + spans[j - 1]));
				spans[j] = 360f * live[j].weight / num;
			}
			spans[live.Count - 1] = 360f - starts[live.Count - 1];
			List<Color> list = set.colors.ConvertAll<Color>(Utils.Hex);
			sliceColors = (Color[])(object)new Color[live.Count];
			for (int k = 0; k < live.Count; k++)
			{
				sliceColors[k] = list[k % list.Count];
			}
			int num2 = live.Count - 1;
			if (num2 > 1 && list.Count > 2 && sliceColors[num2] == sliceColors[0])
			{
				sliceColors[num2] = list[1];
			}
			wheelImage.sprite = WheelSprite(1024, starts, spans, sliceColors);
			((Graphic)wheelImage).color = Color.white;
			((Transform)wheel).localRotation = Quaternion.identity;
			lastSlice = -1;
			Vector2 val = default(Vector2);
			for (int l = 0; l < live.Count; l++)
			{
				float num3 = starts[l] + spans[l] / 2f;
				float num4 = Mathf.Clamp(348f * Mathf.Sin(spans[l] * (MathF.PI / 180f) / 2f), 16f, 64f);
				((Vector2)(ref val))..ctor(Mathf.Cos(num3 * (MathF.PI / 180f)), Mathf.Sin(num3 * (MathF.PI / 180f)));
				TextMeshProUGUI obj = Text("Label", (Transform)(object)wheel, new Vector2(214.6f, num4), val * 272.6f, live[l].text, 24f, (TextAlignmentOptions)4100, Color.white, (Vector2?)null, (Vector2?)new Vector2(1f, 0.5f));
				((Transform)((TMP_Text)obj).rectTransform).localRotation = Quaternion.Euler(0f, 0f, num3);
				((TMP_Text)obj).enableAutoSizing = true;
				((TMP_Text)obj).fontSizeMin = 11f;
				((TMP_Text)obj).fontSizeMax = Mathf.Min(26f, num4 * 0.8f);
				((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
				((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
				((TMP_Text)obj).fontStyle = (FontStyles)1;
				((TMP_Text)obj).outlineColor = Color32.op_Implicit(Color.black);
				((TMP_Text)obj).outlineWidth = 0.25f;
			}
		}

		private void ClearWheel()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			foreach (Transform item in (Transform)wheel)
			{
				Object.Destroy((Object)(object)((Component)item).GetComponent<TMP_Text>().fontMaterial);
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			if ((Object)(object)highlight != (Object)null)
			{
				DestroySprite(highlight);
			}
			highlight = null;
			if ((Object)(object)wheelImage.sprite != (Object)null)
			{
				DestroySprite(wheelImage.sprite);
			}
			wheelImage.sprite = null;
			((Graphic)wheelImage).color = Color.clear;
		}

		private IEnumerator Spin(int winner)
		{
			((Selectable)actionButton).interactable = false;
			spinCount++;
			Color[] array = (Color[])sliceColors.Clone();
			for (int i = 0; i < array.Length; i++)
			{
				if (i != winner)
				{
					array[i] = Color.Lerp(array[i], Color.black, 0.6f);
				}
			}
			highlight = WheelSprite(1024, starts, spans, array);
			float num = starts[winner] + spans[winner] * Random.Range(0.15f, 0.85f);
			float start = ((Transform)wheel).localEulerAngles.z;
			int num2 = Mathf.Max(2, SpinTurns + Random.Range(-1, 2));
			float delta = (float)num2 * 360f + Mathf.Repeat(start + num, 360f);
			float duration = SpinSeconds;
			float pullBack = Mathf.Min(14f, spans[winner] * 0.4f);
			float pullTime = Mathf.Min(0.3f, duration * 0.05f);
			float[] travel = SpinProfile(512);
			lastDegrees = start;
			lastDegreesTime = Time.unscaledTime;
			for (float elapsed = 0f; elapsed < pullTime; elapsed += Time.unscaledDeltaTime)
			{
				float num3 = elapsed / pullTime;
				float num4 = 1f - num3;
				SetRotation(start + pullBack * (1f - num4 * num4));
				yield return null;
			}
			float spinFrom = start + pullBack;
			float spinDelta = delta + pullBack;
			for (float elapsed = 0f; elapsed < duration; elapsed += Time.unscaledDeltaTime)
			{
				SetRotation(spinFrom - spinDelta * Sample(travel, elapsed / duration));
				yield return null;
			}
			float settle = Mathf.Min(1.5f, spans[winner] * 0.08f);
			for (float elapsed = 0f; elapsed < 0.35f; elapsed += Time.unscaledDeltaTime)
			{
				float num5 = elapsed / 0.35f;
				SetRotation(start - delta - settle * Mathf.Sin(num5 * MathF.PI));
				yield return null;
			}
			SetRotation(start - delta);
			wheelSpeed = 0f;
			DestroySprite(wheelImage.sprite);
			wheelImage.sprite = highlight;
			highlight = null;
			for (int j = 0; j < ((Transform)wheel).childCount; j++)
			{
				if (j != winner)
				{
					((Graphic)((Component)((Transform)wheel).GetChild(j)).GetComponent<TMP_Text>()).color = new Color(0.55f, 0.55f, 0.55f);
				}
			}
			yield return (object)new WaitForSecondsRealtime(0.6f);
		}

		private static float[] SpinProfile(int samples)
		{
			float[] array = new float[samples + 1];
			float num = 0f;
			array[0] = 0f;
			for (int i = 1; i <= samples; i++)
			{
				float num2 = (float)i / (float)samples;
				float num3 = 0f;
				if (num2 < 0.06f)
				{
					num3 = Mathf.Sin(num2 / 0.06f * MathF.PI * 0.5f);
				}
				else
				{
					float num4 = (num2 - 0.06f) / 0.94f;
					num3 = Mathf.Pow(1f - num4, 1.45f);
				}
				num = (array[i] = num + num3);
			}
			for (int j = 0; j <= samples; j++)
			{
				array[j] /= num;
			}
			array[samples] = 1f;
			return array;
		}

		private static float Sample(float[] table, float t)
		{
			if (t <= 0f)
			{
				return 0f;
			}
			if (t >= 1f)
			{
				return 1f;
			}
			float num = t * (float)(table.Length - 1);
			int num2 = Mathf.FloorToInt(num);
			float num3 = num - (float)num2;
			if (num2 >= table.Length - 1)
			{
				return 1f;
			}
			float num4 = table[num2];
			float num5 = table[num2 + 1];
			return num4 + (num5 - num4) * num3;
		}

		private static float Ease(float t)
		{
			float num = 0.1f;
			float num2 = 0.05f;
			if (t < num)
			{
				return num2 * (t / num) * (t / num);
			}
			return num2 + (1f - num2) * (1f - Mathf.Pow(1f - (t - num) / (1f - num), 4f));
		}

		private void SetRotation(float degrees)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			((Transform)wheel).localRotation = Quaternion.Euler(0f, 0f, degrees);
			float unscaledTime = Time.uns