Decompiled source of PeglinRelicRerolls v1.0.1

PeglinRelicRerolls.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Audio;
using Battle;
using Battle.Attacks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cruciball;
using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using HarmonyLib;
using I2.Loc;
using Map;
using Microsoft.CodeAnalysis;
using Peglin.ClassSystem;
using PeglinRelicRerolls.Core;
using PeglinUI;
using PeglinUI.MainMenu.Cruciball;
using PeglinUI.OrbDisplay;
using PeglinUI.PostBattle;
using Relics;
using Saving;
using Scenarios.Shop;
using TMPro;
using UI;
using UnityEngine;
using UnityEngine.Audio;
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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("PeglinRelicRerolls")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+d9fbc65b988e1d0cf8a484b791c1f254d6993d62")]
[assembly: AssemblyProduct("PeglinRelicRerolls")]
[assembly: AssemblyTitle("PeglinRelicRerolls")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PeglinRelicRerolls
{
	internal static class BombCelebration
	{
		private const int BombCount = 14;

		private const float SpreadSeconds = 1.2f;

		private const float BangSeconds = 0.3f;

		private const float ExplosionSeconds = 0.65f;

		private const float BangVolume = 0.6f;

		private static GameObject _bombPrefab;

		private static AudioClip _bangSound;

		private static AudioMixerGroup _sfxMixer;

		private static AudioSource _audio;

		private static readonly Random Random = new Random();

		public static void Remember(GameObject prefab, PegAudioManager audioManager)
		{
			if ((Object)(object)prefab != (Object)null)
			{
				_bombPrefab = prefab;
			}
			if ((Object)(object)audioManager != (Object)null)
			{
				Traverse obj = Traverse.Create((object)audioManager);
				AudioClip value = obj.Field("_bombExplosionSfx").GetValue<AudioClip>();
				if ((Object)(object)value != (Object)null)
				{
					_bangSound = value;
				}
				AudioSource value2 = obj.Field("_sfxAudioSource").GetValue<AudioSource>();
				if ((Object)(object)value2 != (Object)null && (Object)(object)value2.outputAudioMixerGroup != (Object)null)
				{
					_sfxMixer = value2.outputAudioMixerGroup;
				}
			}
		}

		public static void Play()
		{
			GameObject val = FindPrefab();
			Camera main = Camera.main;
			if ((Object)(object)val == (Object)null || (Object)(object)main == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Bomb celebration skipped: bomb prefab not loaded yet (fight a battle first).");
				return;
			}
			RerollHud.Ensure();
			RerollHud.RunCoroutine(Celebrate(val, main));
		}

		private static GameObject FindPrefab()
		{
			if ((Object)(object)_bombPrefab != (Object)null)
			{
				return _bombPrefab;
			}
			BombLob val = ((IEnumerable<BombLob>)Resources.FindObjectsOfTypeAll<BombLob>()).FirstOrDefault((Func<BombLob, bool>)delegate(BombLob bomb)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (!bomb.isRigged)
				{
					Scene scene = ((Component)bomb).gameObject.scene;
					return !((Scene)(ref scene)).IsValid();
				}
				return false;
			});
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).gameObject;
		}

		private static IEnumerator Celebrate(GameObject prefab, Camera camera)
		{
			int topLayer = ((SortingLayer.layers.Length != 0) ? ((SortingLayer)(ref SortingLayer.layers[SortingLayer.layers.Length - 1])).id : 0);
			float[] array = (from _ in Enumerable.Range(0, 14)
				select (float)Random.NextDouble() * 1.2f into result
				orderby result
				select result).ToArray();
			float num = 0f;
			float[] array2 = array;
			foreach (float delay in array2)
			{
				if (delay > num)
				{
					yield return (object)new WaitForSecondsRealtime(delay - num);
					num = delay;
				}
				if ((Object)(object)camera == (Object)null)
				{
					break;
				}
				Vector3 position = camera.ViewportToWorldPoint(new Vector3(0.05f + (float)Random.NextDouble() * 0.9f, 0.08f + (float)Random.NextDouble() * 0.84f, 0f));
				position.z = 0f;
				SpawnExplosion(prefab, position, topLayer);
			}
		}

		private static void SpawnExplosion(GameObject prefab, Vector3 position, int sortingLayer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(prefab, position, Quaternion.Euler(0f, 0f, (float)Random.NextDouble() * 360f));
			BombLob component = val.GetComponent<BombLob>();
			if ((Object)(object)component != (Object)null)
			{
				component.OnBombTossComplete = null;
				((Behaviour)component).enabled = false;
			}
			Rigidbody2D component2 = val.GetComponent<Rigidbody2D>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.isKinematic = true;
				component2.velocity = Vector2.zero;
				component2.simulated = false;
			}
			Collider2D[] componentsInChildren = val.GetComponentsInChildren<Collider2D>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Behaviour)componentsInChildren[i]).enabled = false;
			}
			Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>();
			foreach (Renderer obj in componentsInChildren2)
			{
				obj.sortingLayerID = sortingLayer;
				obj.sortingOrder = 1000;
			}
			Animator component3 = val.GetComponent<Animator>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.updateMode = (AnimatorUpdateMode)2;
				component3.SetTrigger("explode");
			}
			RerollHud.RunCoroutine(BangAfter(0.3f));
			RerollHud.RunCoroutine(DestroyAfter(val, 0.65f));
		}

		private static IEnumerator BangAfter(float seconds)
		{
			yield return (object)new WaitForSecondsRealtime(seconds);
			AudioClip val = FindBangSound();
			AudioSource val2 = AudioPlayer();
			if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
			{
				val2.PlayOneShot(val, 0.6f);
			}
		}

		private static AudioClip FindBangSound()
		{
			if ((Object)(object)_bangSound != (Object)null)
			{
				return _bangSound;
			}
			PegSfx val = ((IEnumerable<PegSfx>)Resources.FindObjectsOfTypeAll<PegSfx>()).FirstOrDefault((Func<PegSfx, bool>)((PegSfx sfx) => (Object)(object)sfx.BombExplosionSfx != (Object)null));
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.BombExplosionSfx;
		}

		private static AudioSource AudioPlayer()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if ((Object)(object)_audio == (Object)null)
			{
				GameObject val = new GameObject("PeglinRelicRerollsAudio");
				Object.DontDestroyOnLoad((Object)val);
				_audio = val.AddComponent<AudioSource>();
				_audio.playOnAwake = false;
				_audio.spatialBlend = 0f;
				_audio.ignoreListenerPause = true;
			}
			if ((Object)(object)_sfxMixer != (Object)null && (Object)(object)_audio.outputAudioMixerGroup != (Object)(object)_sfxMixer)
			{
				_audio.outputAudioMixerGroup = _sfxMixer;
			}
			return _audio;
		}

		private static IEnumerator DestroyAfter(GameObject target, float seconds)
		{
			yield return (object)new WaitForSecondsRealtime(seconds);
			if ((Object)(object)target != (Object)null)
			{
				Object.Destroy((Object)(object)target);
			}
		}
	}
	[HarmonyPatch(typeof(BattleController), "Start")]
	internal static class RememberBombPrefabPatch
	{
		private static void Postfix(BattleController __instance, GameObject ____tossableBombPrefab)
		{
			BombCelebration.Remember(____tossableBombPrefab, ((Component)__instance).GetComponent<PegAudioManager>());
		}
	}
	[HarmonyPatch(typeof(CruciballLevelSelector), "UpdateCruciballSelection")]
	internal static class CruciballDescriptionPatch
	{
		private static void Postfix(CruciballLevelSelector __instance, Class ____selectedClass)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			int selectedCruciballLevel = PersistentPlayerData.Instance.GetSelectedCruciballLevel(____selectedClass);
			int value = Plugin.CruciballPenaltyPerLevel.Value;
			int[] penaltyLevels = RerollRules.ParsePenaltyLevels(Plugin.CruciballPenaltyLevels.Value);
			if (RerollRules.IsPenaltyLevel(value, penaltyLevels, selectedCruciballLevel) && !((Object)(object)__instance.currentLevelDescText == (Object)null))
			{
				string arg = ((value == 1) ? "relic reroll" : "relic rerolls");
				TMP_Text currentLevelDescText = __instance.currentLevelDescText;
				currentLevelDescText.text += $" Start with {value} fewer {arg}.";
			}
		}
	}
	internal static class DieSprite
	{
		private struct Face
		{
			public Vector2 Origin;

			public Vector2 EdgeU;

			public Vector2 EdgeV;

			public Color Color;

			public Vector2[] Pips;

			public float PipRadius;

			public Vector2 ToFace(Vector2 point)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = point - Origin;
				float num = EdgeU.x * EdgeV.y - EdgeV.x * EdgeU.y;
				return new Vector2((val.x * EdgeV.y - EdgeV.x * val.y) / num, (EdgeU.x * val.y - val.x * EdgeU.y) / num);
			}
		}

		private const int Size = 32;

		private const float CentreX = 16f;

		private const float TopY = 1.5f;

		private const float HalfWidth = 14f;

		private const float SideHeight = 15f;

		private static readonly Color TopColor = Color32.op_Implicit(new Color32((byte)234, (byte)92, (byte)112, byte.MaxValue));

		private static readonly Color LeftColor = Color32.op_Implicit(new Color32((byte)170, (byte)30, (byte)52, byte.MaxValue));

		private static readonly Color RightColor = Color32.op_Implicit(new Color32((byte)214, (byte)50, (byte)72, byte.MaxValue));

		private static readonly Color OutlineColor = Color32.op_Implicit(new Color32((byte)64, (byte)14, (byte)24, byte.MaxValue));

		private static readonly Color PipColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)250, (byte)244, byte.MaxValue));

		private static Sprite _sprite;

		public static Sprite Get()
		{
			//IL_007a: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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)
			//IL_0183: 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_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: 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_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: 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_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: 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)
			if ((Object)(object)_sprite != (Object)null)
			{
				return _sprite;
			}
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(16f, 1.5f);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(2f, 8.5f);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(30f, 8.5f);
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(16f, 15.5f);
			Vector2 edgeV = default(Vector2);
			((Vector2)(ref edgeV))..ctor(0f, 15f);
			Face[] array = new Face[3]
			{
				new Face
				{
					Origin = val,
					EdgeU = val3 - val,
					EdgeV = val2 - val,
					Color = TopColor,
					Pips = (Vector2[])(object)new Vector2[1]
					{
						new Vector2(0.5f, 0.5f)
					},
					PipRadius = 0.17f
				},
				new Face
				{
					Origin = val2,
					EdgeU = val4 - val2,
					EdgeV = edgeV,
					Color = LeftColor,
					Pips = (Vector2[])(object)new Vector2[2]
					{
						new Vector2(0.28f, 0.28f),
						new Vector2(0.72f, 0.72f)
					},
					PipRadius = 0.13f
				},
				new Face
				{
					Origin = val4,
					EdgeU = val3 - val4,
					EdgeV = edgeV,
					Color = RightColor,
					Pips = (Vector2[])(object)new Vector2[3]
					{
						new Vector2(0.75f, 0.22f),
						new Vector2(0.5f, 0.5f),
						new Vector2(0.25f, 0.78f)
					},
					PipRadius = 0.12f
				}
			};
			Color val5 = default(Color);
			((Color)(ref val5))..ctor(0f, 0f, 0f, 0f);
			Color[,] array2 = new Color[32, 32];
			bool[,] array3 = new bool[32, 32];
			Vector2 point = default(Vector2);
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					array2[j, i] = val5;
					((Vector2)(ref point))..ctor((float)j + 0.5f, (float)i + 0.5f);
					Face[] array4 = array;
					for (int k = 0; k < array4.Length; k++)
					{
						Face face = array4[k];
						Vector2 val6 = face.ToFace(point);
						if (val6.x < 0f || val6.x > 1f || val6.y < 0f || val6.y > 1f)
						{
							continue;
						}
						Color val7 = face.Color;
						Vector2[] pips = face.Pips;
						foreach (Vector2 val8 in pips)
						{
							Vector2 val9 = val6 - val8;
							if (((Vector2)(ref val9)).sqrMagnitude <= face.PipRadius * face.PipRadius)
							{
								val7 = PipColor;
							}
						}
						array2[j, i] = val7;
						array3[j, i] = true;
						break;
					}
				}
			}
			Texture2D val10 = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1
			};
			for (int m = 0; m < 32; m++)
			{
				for (int n = 0; n < 32; n++)
				{
					Color val11 = array2[n, m];
					if (array3[n, m] && IsEdge(array3, n, m))
					{
						val11 = OutlineColor;
					}
					val10.SetPixel(n, 31 - m, val11);
				}
			}
			val10.Apply();
			_sprite = Sprite.Create(val10, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
			((Object)_sprite).name = "PeglinRelicRerollsDie";
			return _sprite;
		}

		private static bool IsEdge(bool[,] filled, int x, int y)
		{
			if (x != 0 && y != 0 && x != 31 && y != 31 && filled[x - 1, y] && filled[x + 1, y] && filled[x, y - 1])
			{
				return !filled[x, y + 1];
			}
			return true;
		}
	}
	internal static class ModLog
	{
		public static void Info(string message)
		{
			if (Plugin.EnableLogging == null || Plugin.EnableLogging.Value)
			{
				Plugin.Log.LogInfo((object)message);
			}
		}
	}
	[BepInPlugin("PeglinRelicRerolls", "PeglinRelicRerolls", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "PeglinRelicRerolls";

		public const string Name = "PeglinRelicRerolls";

		public const string Version = "1.0.1";

		public const string SupportedGameVersion = "2.0.12";

		private const string LegacyConfigFile = "com.pierremarais.peglin.rerolls.cfg";

		internal const string LegacyStateFile = "PeglinRerolls.state";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> StartingRerolls;

		internal static ConfigEntry<bool> EnableBattleReroll;

		internal static ConfigEntry<bool> EnableChestReroll;

		internal static ConfigEntry<bool> EnableShopReroll;

		internal static ConfigEntry<bool> EnableShopRelicReroll;

		internal static ConfigEntry<int> ShopRerollLimit;

		internal static ConfigEntry<int> ShopRerollCost;

		internal static ConfigEntry<double> ChestRareUpgradeChance;

		internal static ConfigEntry<double> ChestBossUpgradeChance;

		internal static ConfigEntry<KeyboardShortcut> RerollHotkey;

		internal static ConfigEntry<KeyboardShortcut> ControllerRerollButton;

		internal static ConfigEntry<bool> ShowRerollBadge;

		internal static ConfigEntry<bool> EnableLogging;

		internal static ConfigEntry<int> BossRerollLimit;

		internal static ConfigEntry<string> CruciballPenaltyLevels;

		internal static ConfigEntry<int> CruciballPenaltyPerLevel;

		private const string KeyHelp = " Key names: https://docs.unity3d.com/ScriptReference/KeyCode.html";

		internal static bool DevModeActive => false;

		private void CheckGameVersion()
		{
			string version = Application.version;
			if (!(version == "2.0.12"))
			{
				Log.LogWarning((object)("PeglinRelicRerolls 1.0.1 was built for Peglin v2.0.12, but this is Peglin v" + version + ". Rerolls may not work correctly until the mod is updated for this game version."));
			}
		}

		private void MigrateLegacyConfig()
		{
			string text = Path.Combine(Paths.ConfigPath, "com.pierremarais.peglin.rerolls.cfg");
			if (!File.Exists(text) || File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			try
			{
				File.Move(text, ((BaseUnityPlugin)this).Config.ConfigFilePath);
				((BaseUnityPlugin)this).Config.Reload();
				Log.LogInfo((object)("Moved settings from com.pierremarais.peglin.rerolls.cfg to " + Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath) + "."));
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Couldn't move com.pierremarais.peglin.rerolls.cfg to the new config name: " + ex.Message));
			}
		}

		private void Awake()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			MigrateLegacyConfig();
			CheckGameVersion();
			StartingRerolls = ((BaseUnityPlugin)this).Config.Bind<int>("General", "StartingRerolls", 5, "Rerolls granted at the start of every new run.");
			RerollHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "RerollHotkey", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "Keyboard shortcut for the reroll button on relic screens and in the shop. Key names: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			ControllerRerollButton = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ControllerRerollButton", new KeyboardShortcut((KeyCode)339, Array.Empty<KeyCode>()), "Controller button for rerolling. Default JoystickButton9 is clicking the right stick (R3) on Xbox-layout controllers, including PlayStation and other pads when Steam Input is on. Set to None to disable. Key names: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			ShowRerollBadge = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowRerollBadge", true, "Show a die with your reroll count above the relic bar, whenever the relic bar is on screen.");
			EnableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLogging", true, "Write reroll details (offers, do-not-offer lists, saves) to BepInEx/LogOutput.log. Warnings and errors are always logged.");
			EnableBattleReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Relic Screens", "EnableBattleReroll", true, "Show the reroll button on the relic reward screen after miniboss/boss battles. Rerolls keep the same rarity.");
			EnableChestReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Relic Screens", "EnableChestReroll", true, "Show the reroll button when opening a treasure chest.");
			ChestRareUpgradeChance = ((BaseUnityPlugin)this).Config.Bind<double>("Relic Screens", "ChestRareUpgradeChance", 0.15, new ConfigDescription("Chance that rerolling a common chest offers a rare relic instead.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 1.0), Array.Empty<object>()));
			ChestBossUpgradeChance = ((BaseUnityPlugin)this).Config.Bind<double>("Relic Screens", "ChestBossUpgradeChance", 0.001, new ConfigDescription("Chance of something special when rerolling a rare chest.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 1.0), Array.Empty<object>()));
			BossRerollLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Relic Screens", "BossRerollLimit", 1, "Rerolls allowed on the floor boss relic reward. Set to -1 for no limit.");
			EnableShopReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Shop", "EnableShopReroll", true, "Replace one common relic in each shop with a purchasable reroll (one per shop).");
			EnableShopRelicReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Shop", "EnableShopRelicReroll", true, "Allow spending a reroll in the shop to reroll its unbought relics.");
			ShopRerollLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "ShopRerollLimit", 3, "How many times each shop's relics can be rerolled. Set to -1 for no limit.");
			ShopRerollCost = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "ShopRerollCost", 20, "Gold cost of a reroll in the shop. Doubled by Wand of Greed and in act 4, like relic prices.");
			CruciballPenaltyLevels = ((BaseUnityPlugin)this).Config.Bind<string>("Cruciball", "PenaltyLevels", "5,10,15", "Comma-separated cruciball levels that each reduce your starting rerolls.");
			CruciballPenaltyPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Cruciball", "PenaltyPerLevel", 1, "Rerolls removed for each penalty level reached. Set to 0 to disable.");
			new Harmony("PeglinRelicRerolls").PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"PeglinRelicRerolls 1.0.1 loaded.");
		}
	}
	internal static class RelicPool
	{
		private static readonly MethodInfo PossibleRelicsOfRarity = AccessTools.Method(typeof(RelicManager), "GetAllPosibleRelicsOfRarityList", (Type[])null, (Type[])null);

		private static readonly MethodInfo IsRelicValid = AccessTools.Method(typeof(RelicManager), "CheckIfRelicValid", (Type[])null, (Type[])null);

		public static int CountAvailable(RelicManager relicManager, RelicRarity rarity, IEnumerable<Relic> exclude)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)relicManager == (Object)null || PossibleRelicsOfRarity == null || IsRelicValid == null)
			{
				return int.MaxValue;
			}
			try
			{
				IEnumerable obj = (IEnumerable)PossibleRelicsOfRarity.Invoke(relicManager, new object[2] { rarity, false });
				List<Relic> list = Exclusions(relicManager, exclude);
				int num = 0;
				foreach (object item in obj)
				{
					if ((bool)IsRelicValid.Invoke(relicManager, new object[4] { item, rarity, list, false }))
					{
						num++;
					}
				}
				return num;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"Couldn't count {rarity} relics: {ex.Message}");
				return int.MaxValue;
			}
		}

		public static Relic[] Draw(RelicManager relicManager, RelicRarity rarity, int count, IEnumerable<Relic> exclude)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Relic[] multipleRelicsOffOfQueue = relicManager.GetMultipleRelicsOffOfQueue(count, rarity, false);
			RelicRarity[] array = Enumerable.Repeat<RelicRarity>(rarity, count).ToArray();
			return (from relic in relicManager.CheckAndUpdateSeededRelicOffers(multipleRelicsOffOfQueue, array, Exclusions(relicManager, exclude).ToArray(), false, false)
				where (Object)(object)relic != (Object)null && (Object)(object)relic != (Object)(object)relicManager.consolationPrize
				select relic).Distinct().ToArray();
		}

		public static List<Relic> AvailableShopOnly(RelicManager relicManager, IEnumerable<Relic> exclude)
		{
			HashSet<Relic> excluded = new HashSet<Relic>(exclude.Where((Relic relic) => (Object)(object)relic != (Object)null));
			return (relicManager.ShopRelicPool ?? new List<Relic>()).Where((Relic relic) => (Object)(object)relic != (Object)null && !excluded.Contains(relic) && !Owns(relicManager, relic)).Distinct().ToList();
		}

		public static Relic DrawShopOnly(RelicManager relicManager, IEnumerable<Relic> exclude)
		{
			HashSet<Relic> hashSet = new HashSet<Relic>(exclude.Where((Relic relic) => (Object)(object)relic != (Object)null));
			int num = relicManager.ShopRelicPool?.Count ?? 0;
			for (int num2 = 0; num2 < num; num2++)
			{
				Relic shopOnlyRelicOffOfQueue = relicManager.GetShopOnlyRelicOffOfQueue();
				if ((Object)(object)shopOnlyRelicOffOfQueue != (Object)null && !hashSet.Contains(shopOnlyRelicOffOfQueue))
				{
					return shopOnlyRelicOffOfQueue;
				}
			}
			return null;
		}

		public static RelicRarity RarityOf(RelicManager relicManager, Relic relic)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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)
			object value = Traverse.Create((object)relicManager).Field("_selectedClass").GetValue();
			RelicRarity[] array = new RelicRarity[3];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			RelicRarity[] array2 = (RelicRarity[])(object)array;
			foreach (RelicRarity val in array2)
			{
				if (PossibleRelicsOfRarity == null || !(PossibleRelicsOfRarity.Invoke(relicManager, new object[2] { val, false }) is IEnumerable enumerable))
				{
					continue;
				}
				foreach (object item in enumerable)
				{
					Traverse val2 = Traverse.Create(item);
					if (!((Object)(object)val2.Field("relic").GetValue<Relic>() != (Object)(object)relic))
					{
						if (val2.Field("classRarities").GetValue() is IDictionary dictionary && value != null && dictionary.Contains(value))
						{
							return (RelicRarity)dictionary[value];
						}
						return val;
					}
				}
			}
			if (!((Object)(object)relic != (Object)null))
			{
				return (RelicRarity)1;
			}
			return relic.globalRarity;
		}

		public static List<Relic> Exclusions(RelicManager relicManager, IEnumerable<Relic> relics)
		{
			List<Relic> excluded = relics.Where((Relic relic) => (Object)(object)relic != (Object)null).ToList();
			excluded.AddRange(from relic in ShopRelics(relicManager)
				where !excluded.Contains(relic)
				select relic);
			return excluded;
		}

		public static IEnumerable<Relic> ShopRelics(RelicManager relicManager)
		{
			HashSet<Relic> hashSet = new HashSet<Relic>();
			if (relicManager.ShopRelicPool != null)
			{
				hashSet.UnionWith(relicManager.ShopRelicPool.Where((Relic relic) => (Object)(object)relic != (Object)null));
			}
			if (Traverse.Create((object)relicManager).Field("_classLoadouts").GetValue() is IEnumerable enumerable)
			{
				foreach (object item in enumerable)
				{
					List<Relic> value = Traverse.Create(item).Field("Loadout").Field("ShopRelicOverrides")
						.Field("relics")
						.GetValue<List<Relic>>();
					if (value != null)
					{
						hashSet.UnionWith(value.Where((Relic relic) => (Object)(object)relic != (Object)null));
					}
				}
			}
			return hashSet;
		}

		public static string DisplayName(Relic relic)
		{
			if (!((Object)(object)relic == (Object)null))
			{
				if (!string.IsNullOrEmpty(relic.englishDisplayName))
				{
					return relic.englishDisplayName;
				}
				return ((Object)relic).name;
			}
			return "(none)";
		}

		private static bool Owns(RelicManager relicManager, Relic relic)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (Traverse.Create((object)relicManager).Field("_ownedRelics").GetValue() is IDictionary dictionary)
			{
				return dictionary.Contains(relic.effect);
			}
			return false;
		}
	}
	internal static class RelicRerollSession
	{
		private static readonly RelicScreenInstance<Relic> Instance = new RelicScreenInstance<Relic>();

		private static BattleUpgradeCanvas _canvas;

		private static RelicRarity _baseRarity;

		private static bool _isTreasure;

		private static RelicIcon[] _slots = (RelicIcon[])(object)new RelicIcon[0];

		private static int _unseenInScreenPool;

		private static int _notOnScreenInPool;

		private static bool IsBossReward
		{
			get
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Invalid comparison between Unknown and I4
				if (!_isTreasure)
				{
					return (int)_baseRarity == 3;
				}
				return false;
			}
		}

		private static int AvailableInScreenPool => RerollRules.AvailableToReroll(_unseenInScreenPool, _notOnScreenInPool);

		public static int RemainingOnScreen => RerollRules.RemainingOnScreen(IsBossReward, Instance.RerollsUsed, Plugin.BossRerollLimit.Value);

		public static bool CanRerollNow => RerollRules.CanReroll(RerollState.Count, RemainingOnScreen, AvailableInScreenPool);

		public static bool ScreenLimitReached => RemainingOnScreen <= 0;

		public static bool PoolExhausted => AvailableInScreenPool <= 0;

		public static string DisabledReason
		{
			get
			{
				if (ScreenLimitReached)
				{
					if (Plugin.BossRerollLimit.Value != 0)
					{
						return "disabled, the floor boss reroll has been used";
					}
					return "disabled for floor boss rewards";
				}
				if (PoolExhausted)
				{
					if (!IsBossReward)
					{
						return "disabled for this non floor boss encounter, no more relics to reroll into";
					}
					return "disabled, no more boss relics to reroll into";
				}
				return null;
			}
		}

		public static bool IsActive
		{
			get
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Invalid comparison between Unknown and I4
				if ((Object)(object)_canvas == (Object)null || !((Behaviour)_canvas).isActiveAndEnabled)
				{
					return false;
				}
				if (GameBlockingWindow.windowOpen)
				{
					return false;
				}
				Traverse val = Traverse.Create((object)_canvas);
				if ((int)val.Field("_state").GetValue<State>() != 1)
				{
					return false;
				}
				CanvasGroup value = val.Field("_mainCanvasGroup").GetValue<CanvasGroup>();
				if ((Object)(object)value != (Object)null && !value.interactable)
				{
					return false;
				}
				GameObject value2 = val.Field("_relicPanel").GetValue<GameObject>();
				if ((Object)(object)value2 == (Object)null || !value2.activeInHierarchy)
				{
					return false;
				}
				UpgradeConfirmationRelic value3 = val.Field("_upgradeConfirmationRelic").GetValue<UpgradeConfirmationRelic>();
				if (!((Object)(object)value3 == (Object)null))
				{
					return !((Component)value3).gameObject.activeInHierarchy;
				}
				return true;
			}
		}

		public static void Begin(BattleUpgradeCanvas canvas, RelicRarity rarity, bool isTreasure)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			_canvas = canvas;
			_baseRarity = rarity;
			_isTreasure = isTreasure;
			Instance.Enter(canvas);
			_slots = OfferedIcons();
			Instance.MarkSeen(OfferedRelics());
			RefreshPoolCounts(RelicManagerFor(canvas));
			RerollHud.Ensure();
			ModLog.Info($"Relic screen opened: rarity={rarity}, chest={isTreasure}");
			LogSeen();
		}

		private static void RefreshPoolCounts(RelicManager relicManager)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_unseenInScreenPool = RelicPool.CountAvailable(relicManager, _baseRarity, Instance.Seen);
			_notOnScreenInPool = RelicPool.CountAvailable(relicManager, _baseRarity, OfferedRelics());
		}

		private static RelicManager RelicManagerFor(BattleUpgradeCanvas canvas)
		{
			if (!((Object)(object)canvas != (Object)null))
			{
				return null;
			}
			return Traverse.Create((object)canvas).Field("_relicManager").GetValue<RelicManager>();
		}

		public static void EndInstance()
		{
			if (Instance.Seen.Count > 0)
			{
				ModLog.Info($"Moved on: cleared {Instance.Seen.Count} relic(s) from the do-not-offer list.");
			}
			Instance.Clear();
		}

		private static void LogSeen()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			string arg = string.Join(", ", Instance.Seen.Select(RelicPool.DisplayName));
			ModLog.Info($"Do-not-offer list for this screen ({Instance.Seen.Count}): {arg}");
			ModLog.Info($"{_baseRarity} relics left: {_unseenInScreenPool} unseen, {_notOnScreenInPool} not on screen (shop relics excluded)");
		}

		public static void TryReroll()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Invalid comparison between Unknown and I4
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Invalid comparison between Unknown and I4
			if (!IsActive || PauseMenu.Paused)
			{
				return;
			}
			RelicManager val = RelicManagerFor(_canvas);
			RelicIcon[] array = _slots.Where((RelicIcon icon) => (Object)(object)icon != (Object)null).ToArray();
			if ((Object)(object)val == (Object)null || array.Length == 0 || !CanRerollNow || !RerollState.TrySpend())
			{
				UIAudioManager.InvalidSelectionSfxRequested?.Invoke();
				return;
			}
			if (RerollRules.ShouldRecycleSeen(_unseenInScreenPool, _notOnScreenInPool))
			{
				Instance.RecycleSeen(OfferedRelics());
				_unseenInScreenPool = _notOnScreenInPool;
				ModLog.Info("Do-not-offer list was full: recycled it, keeping only the relics on screen.");
			}
			RelicRarity val2 = RollRarity(val);
			Relic[] array2 = RelicPool.Draw(val, val2, array.Length, Instance.Seen);
			if (!Instance.OffersSomethingNew(array2))
			{
				RerollState.Refund();
				UIAudioManager.InvalidSelectionSfxRequested?.Invoke();
				ModLog.Info("Reroll refunded: no unseen relics left to offer.");
				return;
			}
			HideRelicTooltip hideTooltip = RelicIcon.HideTooltip;
			if (hideTooltip != null)
			{
				hideTooltip.Invoke(false);
			}
			for (int num = 0; num < array.Length; num++)
			{
				bool flag = num < array2.Length;
				((Component)((Component)array[num]).transform.parent).gameObject.SetActive(flag);
				if (flag)
				{
					array[num].SetRelic(array2[num]);
					array[num].shouldShowTooltip = false;
					RerollAnimation.FlipIn(((Component)array[num]).transform.parent, num);
				}
			}
			RerollAnimation.PlaySound();
			KeepControllerSelectionVisible(array);
			Instance.MarkSeen(array2);
			Instance.RecordReroll();
			RefreshPoolCounts(val);
			ModLog.Info(string.Format("Rerolled at {0}: {1} of {2} slot(s) filled: {3}. ", val2, array2.Length, array.Length, string.Join(", ", array2.Select(RelicPool.DisplayName))) + $"Rerolls left: {RerollState.Count}");
			LogSeen();
			if ((int)val2 == 3 && (int)_baseRarity != 3)
			{
				ModLog.Info("Chest rerolled into a boss relic!");
				BombCelebration.Play();
			}
		}

		private static void KeepControllerSelectionVisible(RelicIcon[] icons)
		{
			EventSystem current = EventSystem.current;
			GameObject val = (((Object)(object)current != (Object)null) ? current.currentSelectedGameObject : null);
			if (!((Object)(object)val == (Object)null) && !val.activeInHierarchy && icons.Length != 0)
			{
				current.SetSelectedGameObject(((Component)((Component)icons[0]).transform.parent).gameObject);
			}
		}

		private static RelicIcon[] OfferedIcons()
		{
			GameObject val = (((Object)(object)_canvas != (Object)null) ? Traverse.Create((object)_canvas).Field("_relicPanel").GetValue<GameObject>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return (RelicIcon[])(object)new RelicIcon[0];
			}
			return val.GetComponentsInChildren<RelicIcon>();
		}

		private static Relic[] OfferedRelics()
		{
			return (from icon in OfferedIcons()
				select icon.relic into relic
				where (Object)(object)relic != (Object)null
				select relic).ToArray();
		}

		private static RelicRarity RollRarity(RelicManager relicManager)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (!_isTreasure || ((int)_baseRarity != 1 && (int)_baseRarity != 2))
			{
				return _baseRarity;
			}
			double roll = RerollRules.UpgradeRoll(StaticGameData.currentSeed, RerollState.Used);
			ChestTier chestTier = ToTier(_baseRarity);
			ChestTier chestTier2 = RerollRules.ChestRerollTier(chestTier, roll, Plugin.ChestRareUpgradeChance.Value, Plugin.ChestBossUpgradeChance.Value);
			int unseenInRolledPool = ((chestTier2 == chestTier) ? _unseenInScreenPool : RelicPool.CountAvailable(relicManager, ToRarity(chestTier2), Instance.Seen));
			return ToRarity(RerollRules.AvailableTier(chestTier, chestTier2, unseenInRolledPool));
		}

		private static ChestTier ToTier(RelicRarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)rarity != 2)
			{
				if ((int)rarity == 3)
				{
					return ChestTier.Boss;
				}
				return ChestTier.Common;
			}
			return ChestTier.Rare;
		}

		private static RelicRarity ToRarity(ChestTier tier)
		{
			return (RelicRarity)(tier switch
			{
				ChestTier.Boss => 3, 
				ChestTier.Rare => 2, 
				_ => 1, 
			});
		}
	}
	[HarmonyPatch(typeof(BattleUpgradeCanvas), "SetupRelicGrant")]
	internal static class SetupRelicGrantPatch
	{
		private static void Postfix(BattleUpgradeCanvas __instance, RelicRarity rarity, bool isTreasure)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (isTreasure ? Plugin.EnableChestReroll.Value : Plugin.EnableBattleReroll.Value)
			{
				RelicRerollSession.Begin(__instance, rarity, isTreasure);
			}
		}
	}
	internal static class RerollAnimation
	{
		private const float FlipSeconds = 0.22f;

		private const float StaggerSeconds = 0.06f;

		public static void FlipIn(Transform target, int order)
		{
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null))
			{
				ShortcutExtensions.DOKill((Component)(object)target, true);
				Vector3 localScale = target.localScale;
				target.localScale = new Vector3(0f, localScale.y, localScale.z);
				TweenSettingsExtensions.SetUpdate<TweenerCore<Vector3, Vector3, VectorOptions>>(TweenSettingsExtensions.SetEase<TweenerCore<Vector3, Vector3, VectorOptions>>(TweenSettingsExtensions.SetDelay<TweenerCore<Vector3, Vector3, VectorOptions>>(ShortcutExtensions.DOScaleX(target, localScale.x, 0.22f), (float)order * 0.06f), (Ease)27), true);
			}
		}

		public static void PlaySound()
		{
			UIButtonClicked onUIButtonClicked = UIButtonClickEventDispatcher.OnUIButtonClicked;
			if (onUIButtonClicked != null)
			{
				onUIButtonClicked.Invoke((ButtonSfx)3);
			}
		}
	}
	internal class RerollHud : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Reroll;

			public static Func<KeyCode, bool> <1>__GetKeyDown;

			public static Func<KeyCode, bool> <2>__GetKey;
		}

		private const float ButtonHeight = 72f;

		private const float ButtonPadding = 48f;

		private const float MinButtonWidth = 380f;

		private const float MaxButtonWidth = 1200f;

		private const float IconSize = 48f;

		private const float IconGap = 14f;

		private const float CountHeightRatio = 0.44f;

		private static RerollHud _instance;

		private static double _lastRerollTime = double.NegativeInfinity;

		private GameObject _panel;

		private RectTransform _panelRect;

		private Image _panelImage;

		private Button _button;

		private TextMeshProUGUI _label;

		private Image _icon;

		private GameObject _badge;

		private RectTransform _badgeRect;

		private TextMeshProUGUI _badgeCount;

		private TextMeshProUGUI _badgeCountShadow;

		private float _countFontScale = 0.5f;

		private float _countMeasuredAt = -1f;

		private TMP_FontAsset _countMeasuredFont;

		private bool _countCalibrated;

		private bool _badgeStyled;

		private float _nextStyleAttempt;

		private RelicUI _relicUI;

		private float _nextRelicUISearch;

		private const string ShownState = "shown";

		private string _lastBadgeState;

		private Transform _lastBadgeParent;

		private int _countCalibrationTries;

		private float _nextControllerCheck;

		private bool _controllerConnected;

		private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];

		public static void Ensure()
		{
			//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_001e: Expected O, but got Unknown
			if (!((Object)(object)_instance != (Object)null))
			{
				GameObject val = new GameObject("PeglinRelicRerollsHud");
				Object.DontDestroyOnLoad((Object)val);
				_instance = val.AddComponent<RerollHud>();
			}
		}

		public static void RunCoroutine(IEnumerator routine)
		{
			Ensure();
			((MonoBehaviour)_instance).StartCoroutine(routine);
		}

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Canvas", new Type[3]
			{
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			val.transform.SetParent(((Component)this).transform, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 500;
			CanvasScaler component2 = val.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 0.5f;
			BuildButton(val.transform);
		}

		private void BuildButton(Transform parent)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00b4: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: 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_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: 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_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Expected O, but got Unknown
			_panel = new GameObject("RerollButton", new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button),
				typeof(Outline)
			});
			_panel.transform.SetParent(parent, false);
			_panelRect = _panel.GetComponent<RectTransform>();
			RectTransform panelRect = _panelRect;
			RectTransform panelRect2 = _panelRect;
			RectTransform panelRect3 = _panelRect;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0f);
			panelRect3.pivot = val;
			Vector2 val2 = (panelRect.anchorMin = (panelRect2.anchorMax = val));
			_panelRect.anchoredPosition = new Vector2(0f, 36f);
			_panelRect.sizeDelta = new Vector2(380f, 72f);
			_panelImage = _panel.GetComponent<Image>();
			((Graphic)_panelImage).color = Color32.op_Implicit(new Color32((byte)92, (byte)58, (byte)36, (byte)240));
			Outline component = _panel.GetComponent<Outline>();
			((Shadow)component).effectColor = Color32.op_Implicit(new Color32((byte)240, (byte)196, (byte)92, byte.MaxValue));
			((Shadow)component).effectDistance = new Vector2(4f, -4f);
			_button = _panel.GetComponent<Button>();
			ColorBlock colors = ((Selectable)_button).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(0.85f, 0.85f, 0.85f, 1f);
			((ColorBlock)(ref colors)).highlightedColor = Color.white;
			((ColorBlock)(ref colors)).pressedColor = new Color(0.6f, 0.6f, 0.6f, 1f);
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((ColorBlock)(ref colors)).disabledColor = new Color(0.45f, 0.45f, 0.45f, 0.75f);
			((Selectable)_button).colors = colors;
			Button button = _button;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)button).navigation = navigation;
			ButtonClickedEvent onClick = _button.onClick;
			object obj = <>O.<0>__Reroll;
			if (obj == null)
			{
				UnityAction val5 = Reroll;
				<>O.<0>__Reroll = val5;
				obj = (object)val5;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			_icon = new GameObject("Icon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			}).GetComponent<Image>();
			((Component)_icon).transform.SetParent(_panel.transform, false);
			_icon.sprite = DieSprite.Get();
			_icon.preserveAspect = true;
			((Graphic)_icon).raycastTarget = false;
			((Graphic)_icon).rectTransform.sizeDelta = new Vector2(48f, 48f);
			_label = CreateText("Label", _panel.transform, 34f, (TextAlignmentOptions)514);
			RectTransform rectTransform = ((TMP_Text)_label).rectTransform;
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			rectTransform.anchorMax = val2;
			rectTransform.anchorMin = val2;
			((TMP_Text)_label).enableAutoSizing = true;
			((TMP_Text)_label).fontSizeMin = 18f;
			((TMP_Text)_label).fontSizeMax = 34f;
			((Graphic)_label).color = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)236, (byte)184, byte.MaxValue));
			_panel.SetActive(false);
		}

		private void BuildBadge(Transform parent)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//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_014a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_badge != (Object)null)
			{
				_badge.SetActive(false);
				Object.Destroy((Object)(object)_badge);
			}
			_badge = new GameObject("PeglinRelicRerollsBadge", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(LayoutElement)
			});
			_badge.transform.SetParent(parent, false);
			_badge.transform.SetAsLastSibling();
			_badge.GetComponent<LayoutElement>().ignoreLayout = true;
			_badgeRect = _badge.GetComponent<RectTransform>();
			RectTransform badgeRect = _badgeRect;
			RectTransform badgeRect2 = _badgeRect;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			badgeRect2.anchorMax = val;
			badgeRect.anchorMin = val;
			_badgeRect.pivot = Vector2.zero;
			Image component = _badge.GetComponent<Image>();
			component.sprite = DieSprite.Get();
			component.preserveAspect = true;
			((Graphic)component).raycastTarget = false;
			_badgeCountShadow = CreateBadgeText("CountShadow");
			((Graphic)_badgeCountShadow).color = Color32.op_Implicit(new Color32((byte)20, (byte)12, (byte)18, byte.MaxValue));
			_badgeCount = CreateBadgeText("Count");
			((Graphic)_badgeCount).color = Color.white;
			_badgeStyled = false;
		}

		private TextMeshProUGUI CreateBadgeText(string name)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = CreateText(name, _badge.transform, 36f, (TextAlignmentOptions)1028);
			RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(1f, 0f);
			rectTransform.pivot = val;
			Vector2 anchorMin = (rectTransform.anchorMax = val);
			rectTransform.anchorMin = anchorMin;
			return obj;
		}

		private static TextMeshProUGUI CreateText(string name, Transform parent, float size, TextAlignmentOptions alignment)
		{
			//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_0033: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).alignment = alignment;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).enableWordWrapping = false;
			return obj;
		}

		private void Update()
		{
			UpdateButton(PauseMenu.Paused);
			UpdateBadge();
		}

		private void UpdateButton(bool paused)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			bool isActive = RelicRerollSession.IsActive;
			bool flag = !isActive && ShopRerollSession.IsActive;
			bool flag2 = (isActive || flag) && !paused;
			if (_panel.activeSelf != flag2)
			{
				_panel.SetActive(flag2);
			}
			if (flag2)
			{
				UseGameFont((TMP_Text)(object)_label);
				bool flag3 = (isActive ? RelicRerollSession.CanRerollNow : ShopRerollSession.CanRerollNow);
				((Selectable)_button).interactable = flag3;
				((Graphic)_panelImage).raycastTarget = flag3;
				((Graphic)_icon).color = (Color)(flag3 ? Color.white : new Color(0.55f, 0.55f, 0.55f, 0.75f));
				string text = (isActive ? RelicRerollSession.DisabledReason : ShopRerollSession.DisabledReason);
				string buttonText;
				if (text != null)
				{
					buttonText = $"Rerolls - {RerollState.Count} ({text})";
				}
				else if (isActive)
				{
					buttonText = $"Reroll ({RerollState.Count})  [{KeyHint()}]";
				}
				else
				{
					int remainingInShop = ShopRerollSession.RemainingInShop;
					string arg = ((remainingInShop == int.MaxValue) ? "" : $", {remainingInShop} left in this shop");
					buttonText = $"Reroll shop relics ({RerollState.Count}{arg})  [{KeyHint()}]";
				}
				SetButtonText(buttonText);
				KeyboardShortcut value = Plugin.RerollHotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() || IsButtonDown(Plugin.ControllerRerollButton.Value))
				{
					Reroll();
				}
			}
		}

		private static bool IsButtonDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return ShortcutRules.IsDown(((KeyboardShortcut)(ref shortcut)).MainKey, ((KeyboardShortcut)(ref shortcut)).Modifiers, (Func<KeyCode, bool>)Input.GetKeyDown, (Func<KeyCode, bool>)Input.GetKey);
		}

		private unsafe string KeyHint()
		{
			//IL_0052: 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)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime >= _nextControllerCheck)
			{
				_nextControllerCheck = Time.unscaledTime + 1f;
				_controllerConnected = Input.GetJoystickNames().Any((string name) => !string.IsNullOrEmpty(name));
			}
			KeyboardShortcut value = Plugin.RerollHotkey.Value;
			string text = ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString();
			value = Plugin.ControllerRerollButton.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if (!_controllerConnected || (int)mainKey == 0)
			{
				return text;
			}
			return text + " / " + ControllerButtonName(mainKey);
		}

		private unsafe static string ControllerButtonName(KeyCode button)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected I4, but got Unknown
			return (button - 330) switch
			{
				0 => "A", 
				1 => "B", 
				2 => "X", 
				3 => "Y", 
				4 => "LB", 
				5 => "RB", 
				6 => "View", 
				7 => "Menu", 
				8 => "L3", 
				9 => "R3", 
				_ => ((object)(*(KeyCode*)(&button))/*cast due to .constrained prefix*/).ToString(), 
			};
		}

		private static void Reroll()
		{
			if (RerollRules.DebouncePassed(Time.unscaledTimeAsDouble, _lastRerollTime))
			{
				_lastRerollTime = Time.unscaledTimeAsDouble;
				if (RelicRerollSession.IsActive)
				{
					RelicRerollSession.TryReroll();
				}
				else if (ShopRerollSession.IsActive)
				{
					ShopRerollSession.TryReroll();
				}
			}
		}

		private void SetButtonText(string text)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			if (!(((TMP_Text)_label).text == text))
			{
				((TMP_Text)_label).text = text;
				float x = ((TMP_Text)_label).GetPreferredValues(text, float.PositiveInfinity, 72f).x;
				float num = Mathf.Clamp(x + 62f + 48f, 380f, 1200f);
				_panelRect.sizeDelta = new Vector2(num, 72f);
				float num2 = Mathf.Min(x, num - 62f - 48f);
				float num3 = (0f - (62f + num2)) / 2f;
				((Graphic)_icon).rectTransform.anchoredPosition = new Vector2(num3 + 24f, 0f);
				((TMP_Text)_label).rectTransform.sizeDelta = new Vector2(num2, 72f);
				((TMP_Text)_label).rectTransform.anchoredPosition = new Vector2(num3 + 62f + num2 / 2f, 0f);
			}
		}

		private void UpdateBadge()
		{
			string text = ((!Plugin.ShowRerollBadge.Value) ? "turned off in config" : RelicBarHiddenReason());
			if (text == null && (Object)(object)((Component)_relicUI).transform.parent == (Object)null)
			{
				text = "relic bar has no parent to attach to";
			}
			if (text != null)
			{
				if (_lastBadgeState != text)
				{
					_lastBadgeState = text;
					ModLog.Info("Reroll badge: hidden (" + text + ")");
				}
				if ((Object)(object)_badge != (Object)null && _badge.activeSelf)
				{
					_badge.SetActive(false);
				}
				return;
			}
			Transform parent = ((Component)_relicUI).transform.parent;
			if ((Object)(object)_badge == (Object)null || (Object)(object)_badge.transform.parent != (Object)(object)parent)
			{
				BuildBadge(parent);
			}
			if (!_badge.activeSelf)
			{
				_badge.SetActive(true);
			}
			if (_badge.transform.GetSiblingIndex() != parent.childCount - 1)
			{
				_badge.transform.SetAsLastSibling();
			}
			if (_lastBadgeState != "shown" || (Object)(object)_lastBadgeParent != (Object)(object)parent)
			{
				_lastBadgeState = "shown";
				_lastBadgeParent = parent;
				ModLog.Info("Reroll badge: shown, attached to " + PathOf(parent));
			}
			PositionBadge();
			if (!_badgeStyled && Time.unscaledTime >= _nextStyleAttempt)
			{
				UseGameFont((TMP_Text)(object)_badgeCount);
				UseGameFont((TMP_Text)(object)_badgeCountShadow);
				_badgeStyled = CopyRelicCountdownStyle();
				_nextStyleAttempt = Time.unscaledTime + 0.5f;
			}
			string text2 = RerollState.Count.ToString();
			((TMP_Text)_badgeCount).text = text2;
			((TMP_Text)_badgeCountShadow).text = text2;
		}

		private string RelicBarHiddenReason()
		{
			if ((Object)(object)_relicUI == (Object)null || !((Behaviour)_relicUI).isActiveAndEnabled)
			{
				if (Time.unscaledTime < _nextRelicUISearch)
				{
					if (!((Object)(object)_relicUI == (Object)null))
					{
						return "relic bar inactive";
					}
					return "no relic bar in this scene";
				}
				_nextRelicUISearch = Time.unscaledTime + 0.5f;
				RelicUI val = ((IEnumerable<RelicUI>)Object.FindObjectsOfType<RelicUI>()).FirstOrDefault((Func<RelicUI, bool>)((RelicUI relicUI) => ((Behaviour)relicUI).isActiveAndEnabled));
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_relicUI)
				{
					_relicUI = val;
					ModLog.Info("Reroll badge: using relic bar " + PathOf(((Component)val).transform));
				}
				if ((Object)(object)_relicUI == (Object)null)
				{
					return "no relic bar in this scene";
				}
				if (!((Behaviour)_relicUI).isActiveAndEnabled)
				{
					return "relic bar inactive";
				}
			}
			Canvas componentInParent = ((Component)_relicUI).GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent != (Object)null && !((Behaviour)componentInParent).enabled)
			{
				return "relic bar canvas disabled";
			}
			float num = EffectiveAlpha(((Component)_relicUI).transform);
			if (!(num > 0.05f))
			{
				return $"relic bar faded out, alpha {num:0.00}";
			}
			return null;
		}

		private static string PathOf(Transform transform)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			string text2 = text;
			Scene scene = ((Component)transform).gameObject.scene;
			return text2 + " (scene " + ((Scene)(ref scene)).name + ")";
		}

		private static float EffectiveAlpha(Transform transform)
		{
			float num = 1f;
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				CanvasGroup component = ((Component)val).GetComponent<CanvasGroup>();
				if (!((Object)(object)component == (Object)null) && ((Behaviour)component).enabled)
				{
					num *= component.alpha;
					if (component.ignoreParentGroups)
					{
						break;
					}
				}
				val = val.parent;
			}
			return num;
		}

		private void PositionBadge()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_01d0: 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_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = _badge.transform.parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)_relicUI == (Object)null || (Object)(object)val == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)_relicUI).transform;
			RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			for (int i = 0; i < ((Component)_relicUI).transform.childCount; i++)
			{
				Transform child = ((Component)_relicUI).transform.GetChild(i);
				if (((Component)child).gameObject.activeInHierarchy && (Object)(object)((Component)child).GetComponent<RelicIcon>() != (Object)null)
				{
					val2 = (RectTransform)child;
					break;
				}
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				val2.GetWorldCorners(_corners);
				Vector2 val3 = Vector2.op_Implicit(((Transform)val).InverseTransformPoint(_corners[1]));
				Vector2 val4 = Vector2.op_Implicit(((Transform)val).InverseTransformPoint(_corners[2]));
				Vector2 val5 = Vector2.op_Implicit(((Transform)val).InverseTransformPoint(_corners[0]));
				float num = Mathf.Min(val4.x - val3.x, val3.y - val5.y);
				if (!(num <= 0f))
				{
					float num2 = num * 0.12f;
					((Transform)_badgeRect).localScale = Vector3.one;
					_badgeRect.sizeDelta = new Vector2(num, num);
					((Transform)_badgeRect).localPosition = new Vector3(val3.x, val3.y + num2, 0f);
					float fontSize = CountFontSize(num);
					((TMP_Text)_badgeCount).fontSize = fontSize;
					((TMP_Text)_badgeCountShadow).fontSize = fontSize;
					Vector2 sizeDelta = default(Vector2);
					((Vector2)(ref sizeDelta))..ctor(num * 0.95f, num * 0.7f);
					Vector2 val6 = default(Vector2);
					((Vector2)(ref val6))..ctor((0f - num) * 0.02f, num * 0.02f);
					((TMP_Text)_badgeCount).rectTransform.sizeDelta = sizeDelta;
					((TMP_Text)_badgeCountShadow).rectTransform.sizeDelta = sizeDelta;
					((TMP_Text)_badgeCount).rectTransform.anchoredPosition = val6;
					((TMP_Text)_badgeCountShadow).rectTransform.anchoredPosition = val6 + new Vector2(num * 0.03f, (0f - num) * 0.03f);
				}
			}
		}

		private float CountFontSize(float size)
		{
			int num;
			if (!(Mathf.Abs(size - _countMeasuredAt) > 0.5f))
			{
				num = (((Object)(object)_countMeasuredFont != (Object)(object)((TMP_Text)_badgeCount).font) ? 1 : 0);
				if (num == 0)
				{
					goto IL_0037;
				}
			}
			else
			{
				num = 1;
			}
			_countCalibrationTries = 0;
			goto IL_0037;
			IL_0037:
			if (num != 0 || !_countCalibrated)
			{
				CalibrateCountFont(size);
			}
			return Mathf.Max(1f, size * _countFontScale);
		}

		private void CalibrateCountFont(float size)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			_countMeasuredAt = size;
			_countMeasuredFont = ((TMP_Text)_badgeCount).font;
			_countCalibrated = false;
			_countFontScale = 0.5f;
			if (string.IsNullOrEmpty(((TMP_Text)_badgeCount).text))
			{
				return;
			}
			((TMP_Text)_badgeCount).fontSize = size;
			((TMP_Text)_badgeCount).ForceMeshUpdate(false, false);
			Bounds textBounds = ((TMP_Text)_badgeCount).textBounds;
			float y = ((Bounds)(ref textBounds)).size.y;
			if (y <= 0.01f)
			{
				if (++_countCalibrationTries >= 3)
				{
					_countCalibrated = true;
				}
				return;
			}
			_countCalibrationTries = 0;
			_countFontScale = Mathf.Clamp(0.44f * size / y, 0.1f, 1.5f);
			_countCalibrated = true;
			object[] obj = new object[4] { y, size, _countFontScale, null };
			TMP_FontAsset font = ((TMP_Text)_badgeCount).font;
			obj[3] = ((font != null) ? ((Object)font).name : null);
			ModLog.Info(string.Format("Reroll badge: count {0:0.#} tall at font size {1:0.#}, scale {2:0.00} ({3})", obj));
		}

		private bool CopyRelicCountdownStyle()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			RelicIcon[] array = Object.FindObjectsOfType<RelicIcon>();
			foreach (RelicIcon val in array)
			{
				if (!((Object)(object)val.countdownText == (Object)null))
				{
					((TMP_Text)_badgeCount).font = (((Object)(object)val.countdownText.font != (Object)null) ? val.countdownText.font : TMP_Settings.defaultFontAsset);
					Color color = ((Graphic)val.countdownText).color;
					color.a = 1f;
					((Graphic)_badgeCount).color = color;
					Material fontSharedMaterial = val.countdownText.fontSharedMaterial;
					if ((Object)(object)fontSharedMaterial != (Object)null)
					{
						((TMP_Text)_badgeCount).fontSharedMaterial = fontSharedMaterial;
					}
					((TMP_Text)_badgeCountShadow).font = ((TMP_Text)_badgeCount).font;
					if ((Object)(object)val.countdownTextDropShadow != (Object)null)
					{
						Color color2 = ((Graphic)val.countdownTextDropShadow).color;
						color2.a = 1f;
						((Graphic)_badgeCountShadow).color = color2;
					}
					return true;
				}
			}
			return false;
		}

		private static void UseGameFont(TMP_Text target)
		{
			if ((Object)(object)target.font != (Object)null && (Object)(object)target.font != (Object)(object)TMP_Settings.defaultFontAsset)
			{
				return;
			}
			TextMeshProUGUI[] array = Object.FindObjectsOfType<TextMeshProUGUI>();
			foreach (TextMeshProUGUI val in array)
			{
				if ((Object)(object)val != (Object)(object)target && (Object)(object)((TMP_Text)val).font != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)(object)TMP_Settings.defaultFontAsset)
				{
					target.font = ((TMP_Text)val).font;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(RelicUI), "OnEnable")]
	internal static class RelicBarEnablePatch
	{
		private static void Postfix()
		{
			RerollHud.Ensure();
		}
	}
	internal static class RerollState
	{
		private static readonly RerollCounter Counter = new RerollCounter();

		private static string FilePath => Path.Combine(Paths.ConfigPath, "PeglinRelicRerolls.state");

		public static int Count => Counter.Count;

		public static int Used => Counter.Used;

		public static void ResetForNewRun(CruciballManager cruciball)
		{
			int num = (((Object)(object)cruciball != (Object)null) ? cruciball.currentCruciballLevel : 0);
			Counter.Reset(StartingCountFor(num));
			ModLog.Info($"New run (cruciball {num}): rerolls set to {Count}");
		}

		public static void Add(int amount)
		{
			Counter.Add(amount);
		}

		public static bool TrySpend()
		{
			return Counter.TrySpend();
		}

		public static void Refund()
		{
			Counter.Refund();
		}

		public static int StartingCountFor(int cruciballLevel)
		{
			return RerollRules.StartingCount(Plugin.StartingRerolls.Value, Plugin.CruciballPenaltyPerLevel.Value, RerollRules.ParsePenaltyLevels(Plugin.CruciballPenaltyLevels.Value), cruciballLevel);
		}

		public static void Commit()
		{
			try
			{
				File.WriteAllText(FilePath, Counter.Snapshot(StaticGameData.currentSeed).Serialize());
				string path = Path.Combine(Paths.ConfigPath, "PeglinRerolls.state");
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not write " + FilePath + ": " + ex.Message));
			}
		}

		public static void Restore()
		{
			string text = null;
			try
			{
				string text2 = Path.Combine(Paths.ConfigPath, "PeglinRerolls.state");
				string path = (File.Exists(FilePath) ? FilePath : text2);
				if (File.Exists(path))
				{
					text = File.ReadAllText(path);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read " + FilePath + ": " + ex.Message));
			}
			CruciballManager val = Resources.FindObjectsOfTypeAll<CruciballManager>().FirstOrDefault();
			int startingCount = StartingCountFor(((Object)(object)val != (Object)null) ? val.currentCruciballLevel : 0);
			string currentSeed = StaticGameData.currentSeed;
			RerollSnapshot snapshot = RerollSnapshot.ResolveOnContinue(text, currentSeed, startingCount);
			Counter.Restore(snapshot);
			if (RerollSnapshot.TryParse(text, out var snapshot2) && snapshot2.Seed == currentSeed)
			{
				ModLog.Info($"Continued run: rerolls restored to {Count}");
			}
			else
			{
				Plugin.Log.LogWarning((object)$"No saved rerolls for this run; using starting count {Count}");
			}
		}
	}
	internal static class RerollTooltip
	{
		public const string Title = "Reroll";

		public const string Description = "Gain <color=#3A9A2A>1</color> <color=#D2662E>Reroll</color>. Use it to swap the relics offered after minibosses and bosses, in chests, or in the shop.";

		private static Relic _relic;

		public static Relic Relic
		{
			get
			{
				if ((Object)(object)_relic == (Object)null)
				{
					_relic = ScriptableObject.CreateInstance<Relic>();
					((Object)_relic).name = "PeglinRelicRerollsReroll";
					_relic.locKey = "peglinrerolls_reroll";
					_relic.sprite = DieSprite.Get();
					((Object)_relic).hideFlags = (HideFlags)32;
				}
				return _relic;
			}
		}
	}
	[HarmonyPatch(typeof(Tooltip), "Initialize", new Type[] { typeof(Relic) })]
	internal static class RelicTooltipPatch
	{
		private static bool Prefix(Tooltip __instance, Relic relic)
		{
			Localize component = ((Component)__instance.descriptionText).GetComponent<Localize>();
			if ((Object)(object)relic == (Object)null || (Object)(object)relic != (Object)(object)RerollTooltip.Relic)
			{
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = true;
				}
				return true;
			}
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			((Component)__instance.nameText).gameObject.SetActive(true);
			__instance.damageInfo.gameObject.SetActive(false);
			((TMP_Text)__instance.nameText).text = "Reroll";
			((TMP_Text)__instance.descriptionText).text = "Gain <color=#3A9A2A>1</color> <color=#D2662E>Reroll</color>. Use it to swap the relics offered after minibosses and bosses, in chests, or in the shop.";
			TooltipKeywordDescriptions keywordDesc = __instance.keywordDesc;
			if (keywordDesc != null)
			{
				keywordDesc.UpdateString("none");
			}
			Traverse.Create((object)__instance).Field("_keywordDescCount").SetValue((object)0);
			((Component)__instance.cruciballIndicator).gameObject.SetActive(false);
			return false;
		}
	}
	[HarmonyPatch(typeof(GameInit), "Start")]
	internal static class NewRunPatch
	{
		private static void Prefix(GameInit __instance, CruciballManager ____cruciballManager)
		{
			if (Traverse.Create((object)__instance).Field("LoadData").Field("NewGame")
				.GetValue<bool>())
			{
				RerollState.ResetForNewRun(____cruciballManager);
				RelicRerollSession.EndInstance();
			}
		}
	}
	[HarmonyPatch(typeof(MapController), "Start")]
	internal static class NewRunMapPatch
	{
		private static void Prefix(MapController __instance, CruciballManager ____cruciballManager)
		{
			if (Traverse.Create((object)__instance).Field("_loadMapData").Field("NewGame")
				.GetValue<bool>())
			{
				RerollState.ResetForNewRun(____cruciballManager);
				RelicRerollSession.EndInstance();
			}
		}
	}
	[HarmonyPatch(typeof(MapController), "SaveData")]
	internal static class RunSavePatch
	{
		private static void Postfix()
		{
			RerollState.Commit();
			RelicRerollSession.EndInstance();
		}
	}
	[HarmonyPatch(typeof(SaveManager), "RequestLoad")]
	internal static class RunLoadPatch
	{
		private static void Postfix()
		{
			RerollState.Restore();
		}
	}
	internal class PurchasableReroll : IPurchasableItem
	{
		private readonly int _cost;

		public PurchasableReroll(int cost)
		{
			_cost = cost;
		}

		public void PurchaseItem()
		{
			RerollState.Add(1);
			ModLog.Info($"Bought a reroll. Rerolls: {RerollState.Count}");
		}

		public Sprite GetPurchasableImage()
		{
			return DieSprite.Get();
		}

		public Vector3 GetSpriteLocalScale()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Vector3.one;
		}

		public Color GetSpriteColor()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Color.white;
		}

		public int GetCost()
		{
			return _cost;
		}

		public void ShowTooltip(Vector3 position, Vector3 offset, bool followMousePosition = false)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			TooltipManager.Instance.ShowTooltipRelic(RerollTooltip.Relic, position, offset, followMousePosition);
		}

		public bool GetUnlocked()
		{
			return true;
		}
	}
	internal static class ShopRerollSession
	{
		private readonly struct ShopRelicSlot
		{
			public ShopItem ShopItem { get; }

			public PurchasableRelic Item { get; }

			public Relic Relic { get; }

			public bool ShopOnly { get; }

			public RelicRarity Rarity { get; }

			public ShopRelicSlot(ShopItem shopItem, PurchasableRelic item, Relic relic, bool shopOnly, RelicRarity rarity)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				ShopItem = shopItem;
				Item = item;
				Relic = relic;
				ShopOnly = shopOnly;
				Rarity = rarity;
			}
		}

		private static readonly RelicScreenInstance<Relic> Instance = new RelicScreenInstance<Relic>();

		private static ShopManager _shop;

		private static bool _anySlotCanChange;

		private static bool _hasUnboughtRelics;

		public static bool IsActive
		{
			get
			{
				if (!Plugin.EnableShopRelicReroll.Value || (Object)(object)_shop == (Object)null || !ShopManager.isOpen || PauseMenu.Paused || GameBlockingWindow.windowOpen)
				{
					return false;
				}
				Traverse val = Traverse.Create((object)_shop);
				bool flag = ((Object)(object)_shop.upgradeConfirmationRelic != (Object)null && ((Component)_shop.upgradeConfirmationRelic).gameObject.activeInHierarchy) || ((Object)(object)_shop.upgradeConfirmationOrbInspect != (Object)null && ((Component)_shop.upgradeConfirmationOrbInspect).gameObject.activeInHierarchy);
				if (!val.Field("_storeClosed").GetValue<bool>() && !flag)
				{
					return !val.Field("inventoryOpen").GetValue<bool>();
				}
				return false;
			}
		}

		public static int RemainingInShop => RerollRules.RemainingUnderLimit(Instance.RerollsUsed, Plugin.ShopRerollLimit.Value);

		public static bool CanRerollNow
		{
			get
			{
				if (RerollState.Count > 0 && RemainingInShop > 0)
				{
					return _anySlotCanChange;
				}
				return false;
			}
		}

		public static string DisabledReason
		{
			get
			{
				if (RemainingInShop <= 0)
				{
					if (Plugin.ShopRerollLimit.Value != 0)
					{
						return $"disabled, this shop's {Plugin.ShopRerollLimit.Value} rerolls have been used";
					}
					return "disabled in shops";
				}
				if (!_hasUnboughtRelics)
				{
					return "no relics left in this shop to reroll";
				}
				if (!_anySlotCanChange)
				{
					return "disabled, no more relics to reroll into";
				}
				return null;
			}
		}

		public static void Begin(ShopManager shop, Relic removedForDie)
		{
			_shop = shop;
			Instance.Enter(shop);
			Instance.MarkSeen(from slot in ShopRelics()
				select slot.Relic);
			if ((Object)(object)removedForDie != (Object)null)
			{
				Instance.MarkSeen((IEnumerable<Relic>)(object)new Relic[1] { removedForDie });
			}
			Refresh();
			ModLog.Info($"Shop opened: {ShopRelics().Count} relic(s) can be rerolled.");
		}

		public static void Refresh()
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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)
			List<ShopRelicSlot> list = ShopRelics();
			_hasUnboughtRelics = list.Count > 0;
			_anySlotCanChange = false;
			if ((Object)(object)_shop == (Object)null || list.Count == 0)
			{
				return;
			}
			RelicManager relicManager = _shop.relicManager;
			Relic[] exclude = list.Select((ShopRelicSlot slot) => slot.Relic).ToArray();
			foreach (IGrouping<bool, ShopRelicSlot> item in from slot in list
				group slot by slot.ShopOnly)
			{
				if (item.Key)
				{
					_anySlotCanChange |= RelicPool.AvailableShopOnly(relicManager, exclude).Count > 0;
					continue;
				}
				foreach (RelicRarity item2 in item.Select((ShopRelicSlot slot) => slot.Rarity).Distinct())
				{
					int unseenInPool = RelicPool.CountAvailable(relicManager, item2, Instance.Seen);
					int notOnScreenInPool = RelicPool.CountAvailable(relicManager, item2, exclude);
					_anySlotCanChange |= RerollRules.AvailableToReroll(unseenInPool, notOnScreenInPool) > 0;
				}
			}
		}

		public static void TryReroll()
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive || !CanRerollNow || !RerollState.TrySpend())
			{
				UIAudioManager.InvalidSelectionSfxRequested?.Invoke();
				return;
			}
			RelicManager relicManager = _shop.relicManager;
			List<ShopRelicSlot> list = ShopRelics();
			Relic[] array = list.Select((ShopRelicSlot slot) => slot.Relic).ToArray();
			if (!list.Any((ShopRelicSlot slot) => (!slot.ShopOnly) ? (RelicPool.CountAvailable(relicManager, slot.Rarity, Instance.Seen) > 0) : (RelicPool.AvailableShopOnly(relicManager, Instance.Seen).Count > 0)))
			{
				Instance.RecycleSeen(array);
				ModLog.Info("Shop do-not-offer list was full: recycled it, keeping only the relics on the shelf.");
			}
			List<Relic> list2 = new List<Relic>();
			int num = 0;
			TooltipManager instance = TooltipManager.Instance;
			if (instance != null)
			{
				instance.HideTooltip();
			}
			foreach (ShopRelicSlot item in list)
			{
				IEnumerable<Relic> exclude = Instance.Seen.Concat(array).Concat(list2);
				Relic val = (Relic)(item.ShopOnly ? ((object)RelicPool.DrawShopOnly(relicManager, exclude)) : ((object)RelicPool.Draw(relicManager, item.Rarity, 1, exclude).FirstOrDefault()));
				if (!((Object)(object)val == (Object)null))
				{
					ReplaceRelic(item, val);
					RerollAnimation.FlipIn(((Object)(object)item.ShopItem.itemImage != (Object)null) ? ((Component)item.ShopItem.itemImage).transform : ((Component)item.ShopItem).transform, num);
					list2.Add(val);
					num++;
				}
			}
			if (num == 0)
			{
				RerollState.Refund();
				UIAudioManager.InvalidSelectionSfxRequested?.Invoke();
				ModLog.Info("Shop reroll refunded: no new relics to offer.");
				Refresh();
			}
			else
			{
				RerollAnimation.PlaySound();
				Instance.MarkSeen(list2);
				Instance.RecordReroll();
				Refresh();
				ModLog.Info(string.Format("Shop reroll: {0} of {1} relic(s) changed: {2}. ", num, list.Count, string.Join(", ", list2.Select(RelicPool.DisplayName))) + string.Format("Rerolls left: {0}, shop rerolls left here: {1}", RerollState.Count, (RemainingInShop == int.MaxValue) ? "unlimited" : RemainingInShop.ToString()));
				ModLog.Info(string.Format("Shop do-not-offer list ({0}): {1}", Instance.Seen.Count, string.Join(", ", Instance.Seen.Select(RelicPool.DisplayName))));
			}
		}

		private static void ReplaceRelic(ShopRelicSlot slot, Relic relic)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			Traverse val = Traverse.Create((object)slot.Item);
			PurchasableRelic val2 = new PurchasableRelic(relic, _shop.relicManager, val.Field("_costMultiplier").GetValue<int>());
			Traverse obj = Traverse.Create((object)val2);
			obj.Field("_cost").SetValue((object)val.Field("_cost").GetValue<int>());
			obj.Field("_numPriceIncreases").SetValue((object)val.Field("_numPriceIncreases").GetValue<int>());
			Component component = ((Component)slot.ShopItem).GetComponent("MouseOverDetectorPointerHandler");
			if ((Object)(object)component != (Object)null)
			{
				Traverse.Create((object)component).Field("OnPointerEntered").SetValue((object)null);
				Traverse.Create((object)component).Field("OnPointerExited").SetValue((object)null);
			}
			SelectionEventListener componentInChildren = ((Component)slot.ShopItem).GetComponentInChildren<SelectionEventListener>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				Traverse.Create((object)componentInChildren).Field("OnSelectionEvent").SetValue((object)null);
				Traverse.Create((object)componentInChildren).Field("OnDeselectionEvent").SetValue((object)null);
			}
			if ((Object)(object)slot.ShopItem.itemBackground != (Object)null)
			{
				slot.ShopItem.itemBackground.transform.localRotation = Quaternion.identity;
			}
			Traverse val3 = Traverse.Create((object)_shop);
			slot.ShopItem.Initialize((IPurchasableItem)(object)val2, _shop, val3.Field("_playerHealthController").GetValue<PlayerHealthController>(), _shop.relicManager);
			IPurchasableItem[] value = val3.Field("_purchasableRelics").GetValue<IPurchasableItem[]>();
			int num = Array.IndexOf(value, (IPurchasableItem)(object)slot.Item);
			if (num >= 0)
			{
				value[num] = (IPurchasableItem)(object)val2;
			}
		}

		private static List<ShopRelicSlot> ShopRelics()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			List<ShopRelicSlot> list = new List<ShopRelicSlot>();
			List<ShopItem> list2 = (((Object)(object)_shop != (Object)null) ? Traverse.Create((object)_shop).Field("relicItems").GetValue<List<ShopItem>>() : null);
			if (list2 == null)
			{
				return list;
			}
			foreach (ShopItem item in list2)
			{
				if ((Object)(object)item == (Object)null || Traverse.Create((object)item).Field("_purchased").GetValue<bool>())
				{
					continue;
				}
				IPurchasableItem value = Traverse.Create((object)item).Field("_item").GetValue<IPurchasableItem>();
				PurchasableRelic val = (PurchasableRelic)(object)((value is PurchasableRelic) ? value : null);
				if (val != null)
				{
					Relic value2 = Traverse.Create((object)val).Field("_relic").GetValue<Relic>();
					if ((Object)(object)value2 != (Object)null)
					{
						bool shopOnly = _shop.relicManager.IsRelicShopOnlyRelic(value2);
						list.Add(new ShopRelicSlot(item, val, value2, shopOnly, RelicPool.RarityOf(_shop.relicManager, value2)));
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(ShopManager), "SetUpRelicOffer")]
	internal static class ShopRelicOfferPatch
	{
		private static void Postfix(ShopManager __instance, List<ShopItem> ___relicItems, IPurchasableItem[] ____purchasableRelics, PlayerHealthController ____playerHealthController)
		{
			RerollHud.Ensure();
			Relic removedForDie = (Plugin.EnableShopReroll.Value ? PlaceDie(__instance, ___relicItems, ____purchasableRelics, ____playerHealthController) : null);
			ShopRerollSession.Begin(__instance, removedForDie);
		}

		private static Relic PlaceDie(ShopManager shop, List<ShopItem> relicItems, IPurchasableItem[] purchasableRelics, PlayerHealthController playerHealthController)
		{
			RelicManager relicManager = shop.relicManager;
			List<ShopSlotKind> list = relicItems.Select((ShopItem item) => KindOf(relicManager, item)).ToList();
			ModLog.Info("Shop relic slots: " + string.Join(", ", list.Select((ShopSlotKind kind, int i) => $"{i + 1}={kind}")));
			int num = RerollRules.DieSlot(list);
			if (num < 0)
			{
				ModLog.Info("Shop has no common or rare relic to swap for the reroll die; no die this time.");
				return null;
			}
			ShopItem val = relicItems[num];
			IPurchasableItem value = Traverse.Create((object)val).Field("_item").GetValue<IPurchasableItem>();
			Relic val2 = ((value is PurchasableRelic) ? Traverse.Create((object)value).Field("_relic").GetValue<Relic>() : null);
			int num2 = Array.IndexOf(purchasableRelics, value);
			ArrowSelection componentInChildren = ((Component)val).GetComponentInChildren<ArrowSelection>();
			ShopItem component = Object.Instantiate<GameObject>(shop.purchasablePrefab, shop.relicContainer.transform).GetComponent<ShopItem>();
			((Component)component).transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex());
			((Component)val).gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)val).gameObject);
			bool act = (Object)(object)MapController.instance != (Object)null && MapController.instance.Act == 4;
			int num3 = RerollRules.ShopRerollCost(Plugin.ShopRerollCost.Value, relicManager.WandOfGreedEffectActive(), act);
			PurchasableReroll purchasableReroll = new PurchasableReroll(num3);
			component.Initialize((IPurchasableItem)(object)purchasableReroll, shop, playerHealthController, relicManager);
			ArrowSelection componentInChildren2 = ((Component)component).GetComponentInChildren<ArrowSelection>();
			if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)componentInChildren != (Object)null)
			{
				Traverse.Create((object)componentInChildren2).Field("rewiredEventSystem").SetValue(Traverse.Create((object)componentInChildren).Field("rewiredEventSystem").GetValue());
			}
			relicItems[num] = component;
			if (num2 >= 0)
			{
				purchasableRelics[num2] = (IPurchasableItem)(object)purchasableReroll;
			}
			ModLog.Info($"Reroll die placed in shop slot {num + 1} for {num3}g, replacing {RelicPool.DisplayName(val2)}.");
			return val2;
		}

		private static ShopSlotKind KindOf(RelicManager relicManager, ShopItem shopItem)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			IPurchasableItem value = Traverse.Create((object)shopItem).Field("_item").GetValue<IPurchasableItem>();
			PurchasableRelic val = (PurchasableRelic)(object)((value is PurchasableRelic) ? value : null);
			if (val == null)
			{
				return ShopSlotKind.Other;
			}
			Relic value2 = Traverse.Create((object)val).Field("_relic").GetValue<Relic>();
			if ((Object)(object)value2 == (Object)null)
			{
				return ShopSlotKind.Other;
			}
			if (relicManager.IsRelicShopOnlyRelic(value2))
			{
				return ShopSlotKind.ShopOnly;
			}
			RelicRarity val2 = RelicPool.RarityOf(relicManager, value2);
			if ((int)val2 != 2)
			{
				if ((int)val2 == 3)
				{
					return ShopSlotKind.Boss;
				}
				return ShopSlotKind.Common;
			}
			return ShopSlotKind.Rare;
		}
	}
	[HarmonyPatch(typeof(ShopItem), "PurchaseItem")]
	internal static class ShopPurchasePatch
	{
		private static void Postfix()
		{
			ShopRerollSession.Refresh();
		}
	}
	[HarmonyPatch(typeof(ShopItem), "ShowUpgradeInformation")]
	internal static class ShopItemClickPatch
	{
		private static bool Prefix(ShopItem __instance, IPurchasableItem ____item)
		{
			if (____item is PurchasableReroll)
			{
				__instance.PurchaseItem();
				return false;
			}
			return true;
		}
	}
}
namespace PeglinRelicRerolls.Core
{
	public class RelicScreenInstance<T>
	{
		private readonly HashSet<T> _seen = new HashSet<T>();

		private readonly List<T> _seenInOrder = new List<T>();

		private object _screenKey;

		private bool _started;

		public int RerollsUsed { get; private set; }

		public IReadOnlyList<T> Seen => _seenInOrder;

		public void Enter(object screenKey)
		{
			if (!_started || !object.Equals(_screenKey, screenKey))
			{
				Clear();
				_screenKey = screenKey;
				_started = true;
			}
		}

		public void Clear()
		{
			_seen.Clear();
			_seenInOrder.Clear();
			RerollsUsed = 0;
			_screenKey = null;
			_started = false;
		}

		public void MarkSeen(IEnumerable<T> items)
		{
			foreach (T item in items)
			{
				if (item != null && _seen.Add(item))
				{
					_seenInOrder.Add(item);
				}
			}
		}

		public bool HasSeen(T item)
		{
			return _seen.Contains(item);
		}

		public void RecycleSeen(IEnumerable<T> keep)
		{
			_seen.Clear();
			_seenInOrder.Clear();
			MarkSeen(keep);
		}

		public bool OffersSomethingNew(IEnumerable<T> offer)
		{
			foreach (T item in offer)
			{
				if (item != null && !_seen.Contains(item))
				{
					return true;
				}
			}
			return false;
		}

		public void RecordReroll()
		{
			RerollsUsed++;
		}
	}
	public class RerollCounter
	{
		public int Count { get; private set; }

		public int Used { get; private set; }

		public void Reset(int startingCount)
		{
			Count = Math.Max(0, startingCount);
			Used = 0;
		}

		public void Add(int amount)
		{
			if (amount < 0)
			{
				throw new ArgumentOutOfRangeException("amount", "Use TrySpend to remove rerolls.");
			}
			Count += amount;
		}

		public bool TrySpend()
		{
			if (Count <= 0)
			{
				return false;
			}
			Count--;
			Used++;
			return true;
		}

		public void Refund()
		{
			if (Used > 0)
			{
				Count++;
				Used--;
			}
		}

		public RerollSnapshot Snapshot(string seed)
		{
			return new RerollSnapshot(seed, Count, Used);
		}

		public void Restore(RerollSnapshot snapshot)
		{
			Count = Math.Max(0, snapshot.Count);
			Used = Math.Max(0, snapshot.Used);
		}
	}
	public enum ChestTier
	{
		Common,
		Rare,
		Boss
	}
	public enum ShopSlotKind
	{
		Common,
		Rare,
		Boss,
		ShopOnly,
		Other
	}
	public static class RerollRules
	{
		public const double RerollDebounceSeconds = 0.2;

		public static int DieSlot(IRead