Decompiled source of IHateRNG v1.0.13

BepInEx/plugins/IHateRNG/IHateRNG.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Assets.Scripts.Actors.Player;
using Assets.Scripts.Game.MapGeneration;
using Assets.Scripts.Game.Spawning;
using Assets.Scripts.Inventory.Stats;
using Assets.Scripts.Inventory__Items__Pickups;
using Assets.Scripts.Inventory__Items__Pickups.Chests;
using Assets.Scripts.Inventory__Items__Pickups.GoldAndMoney;
using Assets.Scripts.Inventory__Items__Pickups.Items;
using Assets.Scripts.Inventory__Items__Pickups.Items.ItemImplementations;
using Assets.Scripts.Inventory__Items__Pickups.Progression;
using Assets.Scripts.Inventory__Items__Pickups.Stats;
using Assets.Scripts.Inventory__Items__Pickups.Weapons;
using Assets.Scripts.Managers;
using Assets.Scripts.Menu.Shop;
using Assets.Scripts.Saves___Serialization.Progression.Achievements;
using Assets.Scripts.Saves___Serialization.Progression.Stats;
using Assets.Scripts.Saves___Serialization.Progression.Unlocks;
using Assets.Scripts._Data;
using Assets.Scripts._Data.Tomes;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using IHateRNG.Patches;
using IHateRNG.Systems;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using Utility;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("IHateRNG")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.13.0")]
[assembly: AssemblyInformationalVersion("1.0.13")]
[assembly: AssemblyProduct("IHateRNG")]
[assembly: AssemblyTitle("IHateRNG")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.13.0")]
[module: UnverifiableCode]
[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;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte value)
		{
			NullableFlags = new byte[1] { value };
		}

		public NullableAttribute(byte[] value)
		{
			NullableFlags = value;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte value)
		{
			Flag = value;
		}
	}
}
namespace IHateRNG
{
	[BepInPlugin("IHateRNG", "IHateRNG", "1.0.13")]
	public class Plugin : BasePlugin
	{
		public const string Guid = "IHateRNG";

		public const string Name = "IHateRNG";

		public const string Version = "1.0.13";

		internal static ManualLogSource Log = null;

		internal static ConfigEntry<bool> EnableDeterministicKey = null;

		internal static ConfigEntry<bool> EnableUpgradeShuffleBag = null;

		internal static ConfigEntry<bool> DebugLogging = null;

		private readonly Harmony harmony = new Harmony("IHateRNG");

		private static readonly HashSet<string> Warnings = new HashSet<string>();

		internal static bool KeyEnabled { get; private set; }

		internal static bool ForceCommonMicrowaves { get; private set; }

		internal static bool ForceTwoMicrowaves { get; private set; }

		internal static bool ForceKindShadyGuy { get; private set; }

		internal static bool ForceGreenCard { get; private set; }

		internal static float KeyScalingPercent { get; private set; }

		internal static float KeyBasePercent { get; private set; }

		internal static float KeyStagePercent { get; private set; }

		internal static bool KeyStageMultiplier { get; private set; }

		internal static bool KeyScalingMultiplier { get; private set; }

		public override void Load()
		{
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			EnableDeterministicKey = ((BasePlugin)this).Config.Bind<bool>("main", "enable key rework", true, "");
			ForceCommonMicrowaves = ((BasePlugin)this).Config.Bind<bool>("main", "force common microwaves", true, "whether the game should force one of the microwaves spawned to be of common rarity").Value;
			ForceTwoMicrowaves = ((BasePlugin)this).Config.Bind<bool>("main", "force two microwaves", true, "whether the game makes at least 2 microwaves spawn").Value;
			EnableUpgradeShuffleBag = ((BasePlugin)this).Config.Bind<bool>("main", "level up overhaul", true, "overhauled version prevents copies of new weapons/tomes from appearing until all have appeared in a cycle-ish manner");
			ForceKindShadyGuy = ((BasePlugin)this).Config.Bind<bool>("shady guy", "force kind shady guy", true, "whether the game should forcibly convert one of spawned shady guys to be of epic rarity").Value;
			ForceGreenCard = ((BasePlugin)this).Config.Bind<bool>("shady guy", "force green card", true, "whether the spawned kind shady guy has a green card as one of its inventory items 100% of the time, doesnt work with \"force kind shady guy\" disabled").Value;
			KeyScalingPercent = BindPercent("key scaling decrease", 25f, float.MaxValue, "how much the reworked key should nerf the scaling formula, accepts normal numbers, type 0 to disable");
			KeyBasePercent = BindPercent("key base price", 10f, 100f, "how much chest base price is lowered (compounding) per key, accepts normal numbers, type 0 to disable");
			KeyStagePercent = BindPercent("key stage change", 10f, float.MaxValue, "how much % a key lowers chest price on stage change, 100% is 2x cheaper, accepts normal numbers, type 0 to disable");
			KeyStageMultiplier = ((BasePlugin)this).Config.Bind<bool>("key", "key stage change mult", true, "whether the \"key stage change\" attribute gets a 2x multiplier when going into tier 3 (for balancing purposes)").Value;
			KeyScalingMultiplier = ((BasePlugin)this).Config.Bind<bool>("key", "key scaling mult", true, "whether \"key scaling decrease\" gets stronger the more expensive a chest is (made for balancing purposes)").Value;
			DebugLogging = ((BasePlugin)this).Config.Bind<bool>("diagnostics", "debug logging", false, "Log generation, pricing, and item selection details.");
			PitySettings.Initialize(((BasePlugin)this).Config);
			EnableUpgradeShuffleBag.SettingChanged += OnShuffleSettingChanged;
			KeyEnabled = EnableDeterministicKey.Value;
			try
			{
				harmony.PatchAll(typeof(Plugin).Assembly);
				PitySettings.BindItems(DataManager.Instance);
				if (KeyEnabled)
				{
					KeyStages.Subscribe();
				}
				if (KeyEnabled)
				{
					KeyStats.RefreshCurrentPlayer(enabled: true);
				}
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("IHateRNG");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.13");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded. Key=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(EnableDeterministicKey.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", shuffle bag=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(EnableUpgradeShuffleBag.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
			catch
			{
				harmony.UnpatchSelf();
				KeyStages.Unsubscribe();
				throw;
			}
		}

		private float BindPercent(string name, float defaultValue, float maximum, string description)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			ConfigEntry<float> val = ((BasePlugin)this).Config.Bind<float>("key", name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, maximum), Array.Empty<object>()));
			if (!float.IsFinite(val.Value))
			{
				val.Value = defaultValue;
			}
			return val.Value;
		}

		private static void OnShuffleSettingChanged(object? sender, EventArgs args)
		{
			UpgradeShuffleBag.Reset("configuration changed");
		}

		internal static void Debug(string message)
		{
			if (DebugLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		internal static void WarnOnce(string key, Exception error)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (Warnings.Add(key))
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(error);
				}
				log.LogWarning(val);
			}
		}

		public override bool Unload()
		{
			if (KeyEnabled)
			{
				KeyStats.RefreshCurrentPlayer(enabled: false);
			}
			KeyStages.Unsubscribe();
			harmony.UnpatchSelf();
			EnableUpgradeShuffleBag.SettingChanged -= OnShuffleSettingChanged;
			UpgradeShuffleBag.Reset("plugin unloaded");
			GuaranteedShadyGuy.Reset("plugin unloaded");
			ChestItemPity.Reset();
			MicrowaveGuarantee.Reset();
			return true;
		}
	}
}
namespace IHateRNG.Systems
{
	internal static class ChestItemPity
	{
		private static readonly Dictionary<EItemRarity, PityCounter> Counters = new Dictionary<EItemRarity, PityCounter>();

		internal static void Apply(ref ItemData result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)result == (Object)null) && PitySettings.TryGet(result.rarity, out var item, out var count))
			{
				Apply(ref result, item, count - 1);
			}
		}

		private static void Apply(ref ItemData result, EItem targetId, int allowedMisses)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_00fe: 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_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: 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_0181: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)result == (Object)null)
			{
				return;
			}
			MyPlayer instance = MyPlayer.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				PlayerInventory inventory = instance.inventory;
				obj = ((inventory != null) ? inventory.itemInventory : null);
			}
			ItemInventory val = (ItemInventory)obj;
			if (val == null || val.GetAmount(targetId) > 0)
			{
				return;
			}
			DataManager instance2 = DataManager.Instance;
			if ((Object)(object)instance2 == (Object)null)
			{
				return;
			}
			ItemData item = instance2.GetItem(targetId);
			if ((Object)(object)item == (Object)null || item.rarity != result.rarity || !item.inItemPool || !MyAchievements.IsAvailable((UnlockableBase)(object)item))
			{
				return;
			}
			HashSet<ItemData> banishedItems = RunUnlockables.banishedItems;
			Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
			if (banishedItems == null || availableItems == null || banishedItems.Contains(item) || !availableItems.ContainsKey(result.rarity))
			{
				return;
			}
			List<ItemData> val2 = availableItems[result.rarity];
			if (val2 != null && val2.Contains(item))
			{
				if (!Counters.TryGetValue(result.rarity, out PityCounter value))
				{
					Counters.Add(result.rarity, value = new PityCounter());
				}
				if (!value.ShouldReplace(allowedMisses, eligible: true, result.eItem == targetId))
				{
					Plugin.Debug($"Chest pity {result.rarity}/{targetId}: {value.Misses}/{allowedMisses} misses; vanilla {result.eItem}");
				}
				else
				{
					EItem eItem = result.eItem;
					result = item;
					value.Consume();
					Plugin.Debug($"Chest pity {result.rarity}: replaced {eItem} with {targetId}; progress reset to 0");
				}
			}
		}

		internal static void Reset(EItemRarity rarity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Counters.Remove(rarity);
		}

		internal static void Reset()
		{
			Counters.Clear();
			Plugin.Debug("Chest pity counters reset");
		}
	}
	internal static class ChestPricing
	{
		private static readonly (int Price, float Power)[] PowerPoints = new(int, float)[11]
		{
			(10000, 6f),
			(15000, 7f),
			(25000, 8f),
			(40000, 9f),
			(70000, 10f),
			(100000, 12f),
			(150000, 15f),
			(200000, 20f),
			(250000, 25f),
			(300000, 30f),
			(500000, 50f)
		};

		internal const string Description = "Chests: Lowers scaling by 25%, price by 10% and again on stage change";

		internal static float BaseMultiplier(int keys, float percent = 10f)
		{
			return (float)Math.Pow(1.0 - (double)percent / 100.0, Math.Max(0, keys));
		}

		internal static float ScalingMultiplier(int keys, float power = 1f, float percent = 25f)
		{
			return (float)(1.0 / (1.0 + (double)percent / 100.0 * (double)power * (double)Math.Max(0, keys)));
		}

		internal static float KeyPower(int price)
		{
			if (price < 200)
			{
				return 1f;
			}
			if (price <= 10000)
			{
				return 1f + (float)price / 2000f;
			}
			for (int i = 1; i < PowerPoints.Length; i++)
			{
				(int, float) tuple = PowerPoints[i - 1];
				(int, float) tuple2 = PowerPoints[i];
				if (price <= tuple2.Item1)
				{
					return tuple.Item2 + (tuple2.Item2 - tuple.Item2) * ((float)(price - tuple.Item1) / (float)(tuple2.Item1 - tuple.Item1));
				}
			}
			return 50f;
		}

		internal static float GreenCardPerCopy(int keys)
		{
			return (float)(10 - Math.Clamp(keys, 0, 5)) / 100f;
		}

		internal static float FinalPrice(float initialBase, float discountedGrowth, float chestPriceStat, float stageFactor)
		{
			return (initialBase + discountedGrowth) * chestPriceStat * stageFactor;
		}

		internal static int LinearIncrease(int count, int perChest, int over10, int over20, int over30, int over40, int over50)
		{
			int num = count * perChest;
			if (count > 10)
			{
				num += (count - 10) * over10;
			}
			if (count > 20)
			{
				num += (count - 20) * over20;
			}
			if (count > 30)
			{
				num += (count - 30) * over30;
			}
			if (count > 40)
			{
				num += (count - 30) * over40;
			}
			if (count > 50)
			{
				num += (count - 30) * over50;
			}
			return num;
		}

		internal static string Describe(float scaling, float price, float stage)
		{
			string text = Number(scaling);
			string text2 = Number(price);
			string text3 = Number(stage);
			if (scaling <= 0f && price <= 0f && stage <= 0f)
			{
				return "does nothing lmao";
			}
			if (scaling > 0f && price > 0f)
			{
				return $"Chests: Lowers scaling by {text}%, price by {text2}%" + ((stage <= 0f) ? "" : ((price == stage) ? " and again on stage change" : (" and by " + text3 + "% again on stage change")));
			}
			if (scaling > 0f)
			{
				return "Chests: Lowers scaling by " + text + "%" + ((stage > 0f) ? (" and price by " + text3 + "% on stage change") : "");
			}
			if (price > 0f)
			{
				return "Chests: Lowers price by " + text2 + "%" + ((stage <= 0f) ? "" : ((price == stage) ? " and again on stage change" : (" and by " + text3 + "% again on stage change")));
			}
			return "Chests: Lowers price by " + text3 + "% on stage change";
			static string Number(float n)
			{
				return n.ToString("G", CultureInfo.InvariantCulture);
			}
		}
	}
	internal static class GuaranteedShadyGuy
	{
		private static bool assigned;

		private static InteractableShadyGuy? selected;

		private static int? stageScene;

		internal static void ObserveSpawn(InteractableShadyGuy instance)
		{
			//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 (Plugin.ForceKindShadyGuy)
			{
				Scene scene = ((Component)instance).gameObject.scene;
				BeginStage(((Scene)(ref scene)).handle);
				Plugin.Debug("Shady Guy spawned");
				if (!assigned)
				{
					assigned = true;
					selected = instance;
					Plugin.Debug("Designated guaranteed Shady Guy");
				}
			}
		}

		internal static bool IsSelected(InteractableShadyGuy instance)
		{
			if (Plugin.ForceKindShadyGuy && assigned && (Object)(object)selected != (Object)null)
			{
				return ((Il2CppObjectBase)selected).Pointer == ((Il2CppObjectBase)instance).Pointer;
			}
			return false;
		}

		internal static void EnsureCard(InteractableShadyGuy instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Invalid comparison between Unknown and I4
			if (!Plugin.ForceGreenCard || !IsSelected(instance))
			{
				return;
			}
			List<ItemData> items = instance.items;
			if (items == null || items.Count == 0)
			{
				Plugin.Debug("Guaranteed Shady Guy inventory is null or empty; left unchanged");
				return;
			}
			for (int i = 0; i < items.Count; i++)
			{
				if ((Object)(object)items[i] != (Object)null && (int)items[i].eItem == 64)
				{
					Plugin.Debug("Green Card already present; inventory unchanged");
					return;
				}
			}
			DataManager instance2 = DataManager.Instance;
			ItemData val = (((Object)(object)instance2 == (Object)null) ? null : instance2.GetItem((EItem)64));
			if ((Object)(object)val == (Object)null || !ShadyOffers.IsEligible(val))
			{
				Plugin.Debug("Green Card unavailable, disabled, or banished; keeping Epic shop without forcing card");
				return;
			}
			int num = Random.Range(0, items.Count);
			ItemData val2 = items[num];
			items[num] = val;
			try
			{
				instance.UpdatePrices();
			}
			catch
			{
				items[num] = val2;
				instance.UpdatePrices();
				throw;
			}
			Plugin.Debug($"Replaced Shady Guy slot {num + 1} with CreditCardGreen");
		}

		internal static void Reset(string reason)
		{
			assigned = false;
			selected = null;
			stageScene = null;
			Plugin.Debug("Shady Guy guarantee reset: " + reason);
		}

		internal static void BeginStage(int sceneHandle)
		{
			if (stageScene != sceneHandle)
			{
				Reset("new stage scene");
				stageScene = sceneHandle;
			}
		}
	}
	internal sealed class KeyChestGrowth
	{
		private int lastCount;

		private float lastRawGrowth;

		internal float DiscountedGrowth { get; private set; }

		internal int LastPrice { get; set; }

		internal float LastPower { get; private set; } = 1f;

		internal void Observe(int count, float rawGrowth, int keys, float scalingPercent = 25f, bool powerEnabled = true)
		{
			if (count < lastCount)
			{
				Reset();
			}
			if (count != lastCount)
			{
				LastPower = (powerEnabled ? ChestPricing.KeyPower(LastPrice) : 1f);
				DiscountedGrowth += (rawGrowth - lastRawGrowth) * ChestPricing.ScalingMultiplier(keys, LastPower, scalingPercent);
				lastRawGrowth = rawGrowth;
				lastCount = count;
			}
		}

		internal void Reset()
		{
			lastCount = 0;
			lastRawGrowth = 0f;
			DiscountedGrowth = 0f;
			LastPrice = 0;
			LastPower = 1f;
		}
	}
	internal static class KeyGreenCard
	{
		internal static float PerCopy(int keys)
		{
			return ChestPricing.GreenCardPerCopy(keys);
		}

		internal static void Refresh(ItemInventory? inventory)
		{
			if (inventory == null)
			{
				return;
			}
			try
			{
				ItemBase item = inventory.GetItem((EItem)64);
				if (item != null)
				{
					ItemCreditCardGreen obj = ((Il2CppObjectBase)item).TryCast<ItemCreditCardGreen>();
					if (obj != null)
					{
						((ItemBase)obj).OnInitOrAmountChanged();
					}
				}
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Key Green Card refresh", error);
			}
		}
	}
	internal sealed class KeyStageDiscount
	{
		private int? lastStage;

		internal double Multiplier { get; private set; } = 1.0;

		internal bool BeginStage(int stage, int keys, float percent = 10f, bool tierMultiplier = true)
		{
			if (stage < 0 || (lastStage.HasValue && stage <= lastStage.Value))
			{
				return false;
			}
			bool hasValue = lastStage.HasValue;
			bool flag = tierMultiplier && lastStage == 1 && stage == 2;
			lastStage = stage;
			if (!hasValue || keys <= 0)
			{
				return false;
			}
			Multiplier /= 1.0 + (double)percent / 100.0 * (flag ? 2.0 : 1.0) * (double)keys;
			return true;
		}

		internal void Reset()
		{
			lastStage = null;
			Multiplier = 1.0;
		}
	}
	internal static class KeyStages
	{
		private static readonly KeyStageDiscount State = new KeyStageDiscount();

		private static Action? preGeneration;

		internal static float BaseMultiplier => (float)State.Multiplier;

		internal static void Subscribe()
		{
			if (!((Delegate)(object)preGeneration != (Delegate)null))
			{
				preGeneration = DelegateSupport.ConvertDelegate<Action>((Delegate)new Action(BeforeGeneration));
				MapGenerationController.A_PreGeneration = ((Il2CppObjectBase)Delegate.Combine((Delegate)(object)MapGenerationController.A_PreGeneration, (Delegate)(object)preGeneration)).Cast<Action>();
			}
		}

		internal static void Unsubscribe()
		{
			if (!((Delegate)(object)preGeneration == (Delegate)null))
			{
				Delegate obj = Delegate.Remove((Delegate)(object)MapGenerationController.A_PreGeneration, (Delegate)(object)preGeneration);
				MapGenerationController.A_PreGeneration = ((obj != null) ? ((Il2CppObjectBase)obj).Cast<Action>() : null);
				preGeneration = null;
				Reset();
			}
		}

		internal static void Reset()
		{
			State.Reset();
			KeyPricePatch.Reset();
		}

		private static void BeforeGeneration()
		{
			if (!Plugin.KeyEnabled)
			{
				return;
			}
			try
			{
				PlayerInventory inventory = MapController.inventory;
				int? obj;
				if (inventory == null)
				{
					obj = null;
				}
				else
				{
					ItemInventory itemInventory = inventory.itemInventory;
					if (itemInventory == null)
					{
						obj = null;
					}
					else
					{
						ItemBase item = itemInventory.GetItem((EItem)0);
						obj = ((item != null) ? new int?(item.amount) : ((int?)null));
					}
				}
				int? num = obj;
				int valueOrDefault = num.GetValueOrDefault();
				int stageIndex = MapController.GetStageIndex();
				bool value = State.BeginStage(stageIndex, valueOrDefault, Plugin.KeyStagePercent, Plugin.KeyStageMultiplier);
				Plugin.Debug($"Key stage discount: stage={stageIndex}, keys={valueOrDefault}, applied={value}, cumulativeFinalPriceMultiplier={State.Multiplier:R}");
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Key stage discount", error);
			}
		}
	}
	internal static class KeyStats
	{
		internal static void Apply(ItemKey key, bool enabled)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			if (((ItemBase)key).itemInventoryRef != null)
			{
				float num = (enabled ? ChestPricing.BaseMultiplier(((ItemBase)key).amount, Plugin.KeyBasePercent) : 1f);
				((ItemBase)key).SetStat(new StatModifier
				{
					stat = (EStat)34,
					modifyType = (EStatModifyType)1,
					modification = num
				});
				Plugin.Debug($"Key count: {((ItemBase)key).amount}; ChestPriceMultiplier contribution: {num:R}");
			}
		}

		internal static void RefreshCurrentPlayer(bool enabled)
		{
			//IL_003d: 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)
			//IL_004a: 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_008b: Expected O, but got Unknown
			MyPlayer instance = MyPlayer.Instance;
			PlayerInventory val = ((instance != null) ? instance.inventory : null);
			object obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				ItemInventory itemInventory = val.itemInventory;
				if (itemInventory == null)
				{
					obj = null;
				}
				else
				{
					ItemBase item = itemInventory.GetItem((EItem)64);
					obj = ((item != null) ? ((Il2CppObjectBase)item).TryCast<ItemCreditCardGreen>() : null);
				}
			}
			ItemCreditCardGreen val2 = (ItemCreditCardGreen)obj;
			if (val2 != null)
			{
				StatModifier val3 = new StatModifier
				{
					stat = (EStat)34,
					modifyType = (EStatModifyType)2
				};
				float num;
				if (!enabled)
				{
					num = 0.1f;
				}
				else
				{
					ItemBase item2 = val.itemInventory.GetItem((EItem)0);
					num = KeyGreenCard.PerCopy((item2 != null) ? item2.amount : 0);
				}
				val3.modification = num * (float)((ItemBase)val2).amount;
				((ItemBase)val2).SetStat(val3);
			}
			object obj2;
			if (val == null)
			{
				obj2 = null;
			}
			else
			{
				ItemInventory itemInventory2 = val.itemInventory;
				if (itemInventory2 == null)
				{
					obj2 = null;
				}
				else
				{
					ItemBase item3 = itemInventory2.GetItem((EItem)0);
					obj2 = ((item3 != null) ? ((Il2CppObjectBase)item3).TryCast<ItemKey>() : null);
				}
			}
			ItemKey val4 = (ItemKey)obj2;
			if (val4 != null)
			{
				Apply(val4, enabled);
			}
			if (val != null)
			{
				PlayerStatsNew playerStats = val.playerStats;
				if (playerStats != null)
				{
					playerStats.ForceUpdateStats();
				}
			}
		}
	}
	internal static class MicrowaveDiagnostics
	{
		internal static bool Watching;

		[Conditional("MICROWAVE_DIAGNOSTICS")]
		internal static void Log(string message)
		{
		}

		[Conditional("MICROWAVE_DIAGNOSTICS")]
		internal static void Observe(string label, GameObject? go, bool components = false)
		{
		}

		[Conditional("MICROWAVE_DIAGNOSTICS")]
		internal static void Snapshot(string label, bool changesOnly = false)
		{
		}
	}
	internal static class MicrowaveGuarantee
	{
		private static int? stageScene;

		private static int guaranteedCount;

		private static InteractableMicrowave? commonMicrowave;

		private static GameObject? microwavePrefab;

		internal static void BeginStage(int scene)
		{
			if (stageScene != scene)
			{
				Reset();
				stageScene = scene;
			}
		}

		internal static void Reset()
		{
			stageScene = null;
			guaranteedCount = 0;
			commonMicrowave = null;
			microwavePrefab = null;
		}

		internal static bool IsCommonTarget(InteractableMicrowave instance)
		{
			if (Plugin.ForceCommonMicrowaves && (Object)(object)commonMicrowave != (Object)null)
			{
				return ((Il2CppObjectBase)commonMicrowave).Pointer == ((Il2CppObjectBase)instance).Pointer;
			}
			return false;
		}

		internal static void ObserveStart(InteractableMicrowave instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Scene scene = ((Component)instance).gameObject.scene;
			BeginStage(((Scene)(ref scene)).handle);
			if (Plugin.ForceCommonMicrowaves && (Object)(object)commonMicrowave == (Object)null)
			{
				commonMicrowave = instance;
			}
		}

		internal static void CapturePrefab(RandomMapObject entry, int scene)
		{
			BeginStage(scene);
			if (Object.op_Implicit((Object)(object)microwavePrefab) || entry == null || entry.prefabs == null)
			{
				return;
			}
			foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)entry.prefabs)
			{
				if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.GetComponentInChildren<InteractableMicrowave>()))
				{
					microwavePrefab = item;
					Plugin.Debug($"Cached Microwave prefab from RandomObjectSpawner: {((Object)item).name}, scene {scene}");
					break;
				}
			}
		}

		internal static HashSet<int> GetStageRootIds(int scene)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			HashSet<int> hashSet = new HashSet<int>();
			foreach (InteractableMicrowave item in Resources.FindObjectsOfTypeAll<InteractableMicrowave>())
			{
				if (!Object.op_Implicit((Object)(object)item))
				{
					continue;
				}
				GameObject gameObject = ((Component)item).gameObject;
				Scene scene2 = gameObject.scene;
				if (!((Scene)(ref scene2)).IsValid())
				{
					continue;
				}
				scene2 = gameObject.scene;
				if (((Scene)(ref scene2)).isLoaded)
				{
					scene2 = gameObject.scene;
					if (((Scene)(ref scene2)).handle == scene)
					{
						hashSet.Add(((Object)((Component)((Component)item).transform.root).gameObject).GetInstanceID());
					}
				}
			}
			return hashSet;
		}

		internal static bool SpawnShrines(SpawnInteractables spawner)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: 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_0212: 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_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ForceTwoMicrowaves)
			{
				return true;
			}
			MicrowaveDiagnostics.Watching = true;
			Scene scene = ((Component)spawner).gameObject.scene;
			BeginStage(((Scene)(ref scene)).handle);
			MapData currentMap = MapController.currentMap;
			if ((Object)(object)currentMap == (Object)null || currentMap.shrines == null || (Object)(object)GameManager.Instance == (Object)null || (Object)(object)spawner.chest == (Object)null)
			{
				return true;
			}
			scene = ((Component)spawner).gameObject.scene;
			HashSet<int> stageRootIds = GetStageRootIds(((Scene)(ref scene)).handle);
			int num = Math.Max(0, 2 - stageRootIds.Count);
			Plugin.Debug($"Microwave minimum: existing={stageRootIds.Count} roots=[{string.Join(",", stageRootIds)}] needed={num}");
			if (num == 0)
			{
				return true;
			}
			if (!Object.op_Implicit((Object)(object)microwavePrefab))
			{
				StageData currentStage = MapController.currentStage;
				if (((currentStage != null) ? currentStage.randomMapObjects : null) != null)
				{
					foreach (RandomMapObject item in (Il2CppArrayBase<RandomMapObject>)(object)MapController.currentStage.randomMapObjects)
					{
						scene = ((Component)spawner).gameObject.scene;
						CapturePrefab(item, ((Scene)(ref scene)).handle);
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)microwavePrefab) && currentMap.randomObjectsOverride != null)
			{
				foreach (RandomMapObject item2 in (Il2CppArrayBase<RandomMapObject>)(object)currentMap.randomObjectsOverride)
				{
					scene = ((Component)spawner).gameObject.scene;
					CapturePrefab(item2, ((Scene)(ref scene)).handle);
				}
			}
			if (!Object.op_Implicit((Object)(object)microwavePrefab) && currentMap.stages != null)
			{
				foreach (StageData item3 in (Il2CppArrayBase<StageData>)(object)currentMap.stages)
				{
					if (((item3 != null) ? item3.randomMapObjects : null) == null)
					{
						continue;
					}
					foreach (RandomMapObject item4 in (Il2CppArrayBase<RandomMapObject>)(object)item3.randomMapObjects)
					{
						scene = ((Component)spawner).gameObject.scene;
						CapturePrefab(item4, ((Scene)(ref scene)).handle);
					}
					if (Object.op_Implicit((Object)(object)microwavePrefab))
					{
						break;
					}
				}
			}
			List<GameObject> list = new List<GameObject>();
			foreach (GameObject item5 in (Il2CppArrayBase<GameObject>)(object)currentMap.shrines)
			{
				if (!(MyStats.GetStat(((object)(EMyStat)22/*cast due to .constrained prefix*/).ToString()) <= 2f) || !Object.op_Implicit((Object)(object)item5.GetComponentInChildren<InteractableShrineCursed>()))
				{
					list.Add(item5);
				}
			}
			Plugin.Debug($"Eligible shrine prefabs: {list.Count}");
			if (!Object.op_Implicit((Object)(object)microwavePrefab))
			{
				Plugin.WarnOnce("Microwave guarantee unavailable; using vanilla shrines", new InvalidOperationException("No Microwave prefab found in the stage RandomObjectSpawner inputs or StageData.randomMapObjects"));
				return true;
			}
			int num2 = (int)(14f * currentMap.numShrinesMultiplier);
			if (list.Count == 0)
			{
				return true;
			}
			int num3 = 0;
			int num4 = 0;
			try
			{
				Vector3 val = default(Vector3);
				for (int i = 0; i < num2; i++)
				{
					Vector3 objectSpawnPosition = SpawnPositions.GetObjectSpawnPosition(spawner.worldCenter, spawner.worldArea, 0.5f, LayerMask.op_Implicit(GameManager.Instance.whatIsGroundAndObjects), ref val, 50, true, true, false, 44f, 0f);
					if (objectSpawnPosition == SpawnPositions.INVALID_POS)
					{
						continue;
					}
					bool flag = num4 < num;
					GameObject val2 = list[MyRandom.random.Next(0, list.Count)];
					GameObject val3 = Object.Instantiate<GameObject>((GameObject)(flag ? ((object)microwavePrefab) : ((object)val2)), objectSpawnPosition, spawner.chest.transform.rotation);
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					num3++;
					if (flag)
					{
						InteractableMicrowave componentInChildren = val3.GetComponentInChildren<InteractableMicrowave>();
						if ((Object)(object)componentInChildren == (Object)null)
						{
							throw new InvalidOperationException("Spawned Microwave prefab has no Microwave component");
						}
						if (guaranteedCount == 0 && (Object)(object)commonMicrowave == (Object)null)
						{
							commonMicrowave = componentInChildren;
						}
						guaranteedCount++;
						num4++;
						Plugin.Debug($"Guaranteed Microwave {guaranteedCount} instantiated at shrine slot {num3}");
					}
					val3.transform.rotation = Quaternion.LookRotation(val);
					Vector3 forward = val3.transform.forward;
					float num5 = Random.Range(0f, 360f);
					val3.transform.Rotate(forward, num5, (Space)0);
				}
				Plugin.Debug($"Successful shrine placements: {num3}; guaranteed Microwaves this stage: {guaranteedCount}");
				if (num4 < num)
				{
					Plugin.Debug("Microwave guarantee shortfall: insufficient valid shrine placements; no extra objects spawned");
				}
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Microwave shrine generation failed after allocation began", error);
			}
			return false;
		}
	}
	internal sealed class PityCounter
	{
		internal int Misses { get; private set; }

		internal bool ShouldReplace(int allowedMisses, bool eligible, bool naturalTarget)
		{
			if (!eligible || naturalTarget)
			{
				return false;
			}
			if (Misses >= allowedMisses)
			{
				return true;
			}
			Misses++;
			return false;
		}

		internal void Consume()
		{
			Misses = 0;
		}
	}
	internal static class PitySettings
	{
		private const string ItemDescription = "what pity item to roll if enough of the same rarity drops didnt give said item";

		private const string CounterDescription = "how many drops of that rarity until the pity item is forced, put 0 to disable";

		private static readonly (EItemRarity Rarity, EItem Item, int Count)[] Defaults = new(EItemRarity, EItem, int)[4]
		{
			((EItemRarity)0, (EItem)0, 8),
			((EItemRarity)1, (EItem)32, 7),
			((EItemRarity)2, (EItem)64, 5),
			((EItemRarity)3, (EItem)41, 3)
		};

		private static readonly Dictionary<EItemRarity, ConfigEntry<int>> Counts = new Dictionary<EItemRarity, ConfigEntry<int>>();

		private static readonly Dictionary<EItemRarity, ConfigEntry<string>> Items = new Dictionary<EItemRarity, ConfigEntry<string>>();

		private static ConfigFile? config;

		internal unsafe static void Initialize(ConfigFile file)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			config = file;
			Counts.Clear();
			Items.Clear();
			(EItemRarity, EItem, int)[] defaults = Defaults;
			for (int i = 0; i < defaults.Length; i++)
			{
				(EItemRarity, EItem, int) tuple = defaults[i];
				Dictionary<EItemRarity, ConfigEntry<int>> counts = Counts;
				EItemRarity item = tuple.Item1;
				var (val, _, _) = tuple;
				counts.Add(item, file.Bind<int>("pity counters", ((object)(*(EItemRarity*)(&val))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant() + " pity counter", tuple.Item3, new ConfigDescription("how many drops of that rarity until the pity item is forced, put 0 to disable", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>())));
			}
		}

		internal unsafe static void BindItems(DataManager database)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: 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_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			if (config == null || (Object)(object)database == (Object)null || database.unsortedItems == null)
			{
				return;
			}
			(EItemRarity, EItem, int)[] defaults = Defaults;
			for (int i = 0; i < defaults.Length; i++)
			{
				(EItemRarity Rarity, EItem Item, int Count) rule = defaults[i];
				if (Items.ContainsKey(rule.Rarity))
				{
					continue;
				}
				HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
				Enumerator<ItemData> enumerator = database.unsortedItems.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ItemData current = enumerator.Current;
					if ((Object)(object)current != (Object)null && current.rarity == rule.Rarity)
					{
						hashSet.Add(((object)current.eItem/*cast due to .constrained prefix*/).ToString());
					}
				}
				EItem item = rule.Item;
				if (!hashSet.Contains(((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString()))
				{
					Plugin.WarnOnce($"Pity item catalog incomplete for {rule.Rarity}", new InvalidOperationException("Default item missing; leaving this rarity's pity inactive until the database is ready."));
					continue;
				}
				string[] array = new string[1];
				item = rule.Item;
				array[0] = ((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString();
				string[] array2 = array.Concat(hashSet.Where(delegate(string s)
				{
					//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)
					EItem item3 = rule.Item;
					return s != ((object)(*(EItem*)(&item3))/*cast due to .constrained prefix*/).ToString();
				}).OrderBy<string, string>((string s) => s, StringComparer.Ordinal)).ToArray();
				ConfigFile? obj = config;
				EItemRarity item2 = rule.Rarity;
				string text = ((object)(*(EItemRarity*)(&item2))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant() + " pity item";
				item = rule.Item;
				ConfigEntry<string> val = obj.Bind<string>("pity items", text, ((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString(), new ConfigDescription("what pity item to roll if enough of the same rarity drops didnt give said item", (AcceptableValueBase)(object)new AcceptableValueList<string>(array2), Array.Empty<object>()));
				EItemRarity rarity = rule.Rarity;
				val.SettingChanged += delegate
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					ChestItemPity.Reset(rarity);
				};
				Items.Add(rarity, val);
				Plugin.Debug($"Pity config {rarity}: {array2.Length} item choices, target={val.Value}, counter={Counts[rarity].Value}");
			}
		}

		internal static bool TryGet(EItemRarity rarity, out EItem item, out int count)
		{
			//IL_000b: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			item = (EItem)0;
			count = 0;
			if (!Counts.TryGetValue(rarity, out ConfigEntry<int> value) || value.Value <= 0)
			{
				return false;
			}
			if (!Items.ContainsKey(rarity))
			{
				BindItems(DataManager.Instance);
			}
			if (!Items.TryGetValue(rarity, out ConfigEntry<string> value2) || !Enum.TryParse<EItem>(value2.Value, out item))
			{
				return false;
			}
			count = value.Value;
			return true;
		}
	}
	internal static class ShadyOffers
	{
		internal static bool IsEligible(ItemData item)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || !item.inItemPool || !MyAchievements.IsAvailable((UnlockableBase)(object)item))
			{
				return false;
			}
			Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
			HashSet<ItemData> banishedItems = RunUnlockables.banishedItems;
			if (availableItems != null && banishedItems != null && !banishedItems.Contains(item) && availableItems.ContainsKey(item.rarity) && availableItems[item.rarity] != null)
			{
				return availableItems[item.rarity].Contains(item);
			}
			return false;
		}

		internal static void FillMissing(List<ItemData> items)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (items == null || items.Count >= 3)
			{
				return;
			}
			HashSet<EItem> hashSet = new HashSet<EItem>();
			Enumerator<ItemData> enumerator = items.GetEnumerator();
			while (enumerator.MoveNext())
			{
				ItemData current = enumerator.Current;
				if ((Object)(object)current != (Object)null)
				{
					hashSet.Add(current.eItem);
				}
			}
			Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
			if (availableItems == null)
			{
				return;
			}
			EItemRarity[] array = (EItemRarity[])(object)new EItemRarity[2]
			{
				(EItemRarity)2,
				(EItemRarity)3
			};
			foreach (EItemRarity val in array)
			{
				if (!availableItems.ContainsKey(val) || availableItems[val] == null)
				{
					continue;
				}
				List<ItemData> list = new List<ItemData>();
				enumerator = availableItems[val].GetEnumerator();
				while (enumerator.MoveNext())
				{
					ItemData current2 = enumerator.Current;
					if (IsEligible(current2) && hashSet.Add(current2.eItem))
					{
						list.Add(current2);
					}
				}
				while (items.Count < 3 && list.Count > 0)
				{
					int index = Random.Range(0, list.Count);
					items.Add(list[index]);
					list.RemoveAt(index);
				}
				if (items.Count >= 3)
				{
					break;
				}
			}
			Plugin.Debug($"Guaranteed Epic Shady Guy offers after eligible-pool fallback: {items.Count}/3");
		}
	}
	internal sealed class ShuffleCycle<T> where T : notnull
	{
		private readonly IReadOnlyList<T> eligible;

		private readonly HashSet<T> eligibleSet;

		private readonly HashSet<T> screen = new HashSet<T>();

		internal HashSet<T> Seen { get; }

		internal int Resets { get; private set; }

		internal ShuffleCycle(IEnumerable<T> seen, IReadOnlyList<T> eligible)
		{
			Seen = new HashSet<T>(seen);
			this.eligible = eligible;
			eligibleSet = new HashSet<T>(eligible);
			if (eligibleSet.Count != eligible.Count)
			{
				throw new ArgumentException("Duplicate eligible IDs.");
			}
		}

		internal T Draw(T preferred, Func<int, int> randomIndex)
		{
			if (!eligibleSet.Contains(preferred))
			{
				throw new InvalidOperationException($"Vanilla offered {preferred}, absent from the verified eligible pool.");
			}
			if (eligibleSet.IsSubsetOf(Seen))
			{
				Seen.Clear();
				Resets++;
			}
			T val;
			if (!Seen.Contains(preferred) && !screen.Contains(preferred))
			{
				val = preferred;
			}
			else
			{
				List<T> list = new List<T>();
				for (int i = 0; i < eligible.Count; i++)
				{
					if (!Seen.Contains(eligible[i]) && !screen.Contains(eligible[i]))
					{
						list.Add(eligible[i]);
					}
				}
				if (list.Count == 0)
				{
					throw new InvalidOperationException("Insufficient unique eligible entries for this screen.");
				}
				val = list[randomIndex(list.Count)];
			}
			Seen.Add(val);
			screen.Add(val);
			return val;
		}
	}
	internal static class UpgradeShuffleBag
	{
		internal sealed record OfferPlan(List<IUpgradable> Offers, ShuffleCycle<EWeapon> Weapons, ShuffleCycle<ETome> Tomes, int Revision);

		private static HashSet<EWeapon> seenWeapons = new HashSet<EWeapon>();

		private static HashSet<ETome> seenTomes = new HashSet<ETome>();

		private static IntPtr inventoryPointer;

		private static int revision;

		private static readonly Random Random = new Random();

		internal static void Reset(string reason)
		{
			seenWeapons.Clear();
			seenTomes.Clear();
			inventoryPointer = IntPtr.Zero;
			revision++;
			Plugin.Debug("Reset weapon and tome shuffle bags: " + reason);
		}

		internal static void ObserveInventory(PlayerInventory inventory)
		{
			if (!(inventoryPointer == ((Il2CppObjectBase)inventory).Pointer))
			{
				Reset("new run inventory");
				inventoryPointer = ((Il2CppObjectBase)inventory).Pointer;
			}
		}

		internal static void CleanupInventory(PlayerInventory inventory)
		{
			if (inventoryPointer == ((Il2CppObjectBase)inventory).Pointer)
			{
				Reset("run inventory cleaned up");
			}
		}

		internal static OfferPlan? Plan(List<IUpgradable> original)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			MyPlayer instance = MyPlayer.Instance;
			if ((Object)(object)instance == (Object)null || instance.inventory == null || (Object)(object)DataManager.Instance == (Object)null)
			{
				return null;
			}
			PlayerInventory inventory = instance.inventory;
			ObserveInventory(inventory);
			WeaponInventory weaponInventory = inventory.weaponInventory;
			if (((weaponInventory != null) ? weaponInventory.weapons : null) != null)
			{
				TomeInventory tomeInventory = inventory.tomeInventory;
				if (((tomeInventory != null) ? tomeInventory.tomeLevels : null) != null)
				{
					List<WeaponData> availableWeapons = UnlockUtility.GetAvailableWeapons();
					HashSet<TomeData> availableTomes = UnlockUtility.GetAvailableTomes();
					List<WeaponData> allWeapons = DataManager.Instance.GetAllWeapons();
					List<TomeData> allTomes = DataManager.Instance.GetAllTomes();
					Dictionary<EWeapon, IUpgradable> dictionary = new Dictionary<EWeapon, IUpgradable>();
					Dictionary<ETome, IUpgradable> dictionary2 = new Dictionary<ETome, IUpgradable>();
					for (int i = 0; i < allWeapons.Count; i++)
					{
						WeaponData val = allWeapons[i];
						if (!((Object)(object)val == (Object)null) && availableWeapons.Contains(val) && !Owns(inventory, val))
						{
							IUpgradable val2 = ((Il2CppObjectBase)val).Cast<IUpgradable>();
							if (val2.GetLevel() < val2.GetMaxLevel() && InventoryUtility.CanUnlockItem(val2))
							{
								dictionary.TryAdd(val.eWeapon, val2);
							}
						}
					}
					for (int j = 0; j < allTomes.Count; j++)
					{
						TomeData val3 = allTomes[j];
						if (!((Object)(object)val3 == (Object)null) && availableTomes.Contains(val3) && !Owns(inventory, val3))
						{
							IUpgradable val4 = ((Il2CppObjectBase)val3).Cast<IUpgradable>();
							if (val4.GetLevel() < val4.GetMaxLevel() && InventoryUtility.CanUnlockItem(val4))
							{
								dictionary2.TryAdd(val3.eTome, val4);
							}
						}
					}
					ShuffleCycle<EWeapon> shuffleCycle = new ShuffleCycle<EWeapon>(seenWeapons, new List<EWeapon>(dictionary.Keys));
					ShuffleCycle<ETome> shuffleCycle2 = new ShuffleCycle<ETome>(seenTomes, new List<ETome>(dictionary2.Keys));
					List<IUpgradable> val5 = new List<IUpgradable>();
					for (int k = 0; k < original.Count; k++)
					{
						IUpgradable val6 = original[k];
						WeaponData val7 = ((val6 != null) ? ((Il2CppObjectBase)val6).TryCast<WeaponData>() : null);
						TomeData val8 = ((val6 != null) ? ((Il2CppObjectBase)val6).TryCast<TomeData>() : null);
						if ((Object)(object)val7 != (Object)null && !Owns(inventory, val7))
						{
							val5.Add(dictionary[shuffleCycle.Draw(val7.eWeapon, Random.Next)]);
						}
						else if ((Object)(object)val8 != (Object)null && !Owns(inventory, val8))
						{
							val5.Add(dictionary2[shuffleCycle2.Draw(val8.eTome, Random.Next)]);
						}
						else
						{
							val5.Add(val6);
						}
					}
					Plugin.Debug($"Eligible unowned pool: {dictionary.Count} weapons, {dictionary2.Count} tomes.");
					return new OfferPlan(val5, shuffleCycle, shuffleCycle2, revision);
				}
			}
			return null;
		}

		internal static void CommitDisplayed(OfferPlan plan, UpgradePicker picker)
		{
			if (plan.Revision != revision || !Plugin.EnableUpgradeShuffleBag.Value)
			{
				return;
			}
			Il2CppReferenceArray<UpgradeButton> buttons = picker.buttons;
			if (buttons == null || picker.numUpgrades != plan.Offers.Count || ((Il2CppArrayBase<UpgradeButton>)(object)buttons).Length < plan.Offers.Count)
			{
				throw new InvalidOperationException("Displayed offer count differs from plan; cycle not consumed.");
			}
			int num = 0;
			while (num < plan.Offers.Count)
			{
				UpgradeButton val = ((Il2CppArrayBase<UpgradeButton>)(object)buttons)[num];
				if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeSelf && !val.isItem)
				{
					IUpgradable upgradable = val.upgradable;
					IntPtr? intPtr = ((upgradable != null) ? new IntPtr?(((Il2CppObjectBase)upgradable).Pointer) : ((IntPtr?)null));
					IUpgradable obj = plan.Offers[num];
					if (!(intPtr != ((obj != null) ? new IntPtr?(((Il2CppObjectBase)obj).Pointer) : ((IntPtr?)null))))
					{
						num++;
						continue;
					}
				}
				throw new InvalidOperationException("Displayed offer differs from plan; cycle not consumed.");
			}
			seenWeapons = plan.Weapons.Seen;
			seenTomes = plan.Tomes.Seen;
			revision++;
			if (plan.Weapons.Resets > 0)
			{
				Plugin.Debug($"Reset weapon shuffle bag ({plan.Weapons.Resets} cycle boundaries).");
			}
			if (plan.Tomes.Resets > 0)
			{
				Plugin.Debug($"Reset tome shuffle bag ({plan.Tomes.Resets} cycle boundaries).");
			}
			LogOffers(plan.Offers, "displayed / unowned entries marked seen");
		}

		internal static bool Owns(PlayerInventory inventory, WeaponData weapon)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return inventory.weaponInventory.weapons.ContainsKey(weapon.eWeapon);
		}

		internal static bool Owns(PlayerInventory inventory, TomeData tome)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return inventory.tomeInventory.HasTome(tome.eTome);
		}

		internal static void LogOffers(List<IUpgradable> offers, string phase)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.DebugLogging.Value)
			{
				return;
			}
			MyPlayer instance = MyPlayer.Instance;
			PlayerInventory val = ((instance != null) ? instance.inventory : null);
			for (int i = 0; i < offers.Count; i++)
			{
				IUpgradable val2 = offers[i];
				if (val2 == null)
				{
					Plugin.Debug($"{phase}: offer {i} is null");
					continue;
				}
				WeaponData val3 = ((Il2CppObjectBase)val2).TryCast<WeaponData>();
				TomeData val4 = ((Il2CppObjectBase)val2).TryCast<TomeData>();
				string value = (((Object)(object)val3 != (Object)null) ? $"weapon {val3.eWeapon}" : (((Object)(object)val4 != (Object)null) ? $"tome {val4.eTome}" : "other"));
				string value2 = ((val == null) ? "unknown" : ((!((Object)(object)val3 != (Object)null)) ? ((!((Object)(object)val4 != (Object)null)) ? "not tracked" : (Owns(val, val4) ? "owned" : "unowned")) : (Owns(val, val3) ? "owned" : "unowned")));
				Plugin.Debug($"{phase}: {((Il2CppObjectBase)val2).Cast<Object>().GetIl2CppType().FullName}; {value}; level {val2.GetLevel()}/{val2.GetMaxLevel()}; [{value2}]");
			}
		}
	}
}
namespace IHateRNG.Patches
{
	[HarmonyPatch(typeof(ItemUtility), "GetRandomChestItem")]
	internal static class ChestItemPityPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref ItemData __result)
		{
			try
			{
				ChestItemPity.Apply(ref __result);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Chest item pity failed", error);
			}
		}
	}
	[HarmonyPatch(typeof(RunUnlockables), "OnNewRunStarted")]
	internal static class ChestPityNewRunPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			ChestItemPity.Reset();
		}
	}
	[HarmonyPatch(typeof(PlayerInventory), "Cleanup")]
	internal static class ChestPityCleanupPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			ChestItemPity.Reset();
		}
	}
	[HarmonyPatch(typeof(InteractableChest), "OnChestWindowClose")]
	internal static class KeyChancePatch
	{
		internal sealed record SavedChance(ItemKey Key, float Chance);

		[HarmonyPrefix]
		private static void Prefix(out SavedChance? __state)
		{
			__state = null;
			if (Plugin.KeyEnabled)
			{
				MyPlayer instance = MyPlayer.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					PlayerInventory inventory = instance.inventory;
					obj = ((inventory != null) ? inventory.itemInventory : null);
				}
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					ItemBase item = ((ItemInventory)obj).GetItem((EItem)0);
					obj2 = ((item != null) ? ((Il2CppObjectBase)item).TryCast<ItemKey>() : null);
				}
				ItemKey val = (ItemKey)obj2;
				if (val != null)
				{
					__state = new SavedChance(val, val.currentChance);
					val.currentChance = 0f;
					Plugin.Debug("Suppressed Key free-chest chance during chest settlement.");
				}
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(SavedChance? __state)
		{
			if (__state != null)
			{
				__state.Key.currentChance = __state.Chance;
			}
		}
	}
	[HarmonyPatch(typeof(ItemKey), "GetDescription")]
	internal static class KeyDescriptionPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref string __result)
		{
			if (!Plugin.KeyEnabled)
			{
				return true;
			}
			__result = ChestPricing.Describe(Plugin.KeyScalingPercent, Plugin.KeyBasePercent, Plugin.KeyStagePercent);
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemCreditCardGreen), "OnInitOrAmountChanged")]
	internal static class KeyGreenCardStatPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ItemCreditCardGreen __instance, out float? __state)
		{
			__state = null;
			if (Plugin.KeyEnabled && ((ItemBase)__instance).itemInventoryRef != null)
			{
				__state = __instance.chestPriceIncreasePerAmount;
				ItemBase item = ((ItemBase)__instance).itemInventoryRef.GetItem((EItem)0);
				int keys = ((item != null) ? item.amount : 0);
				__instance.chestPriceIncreasePerAmount = KeyGreenCard.PerCopy(keys);
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(ItemCreditCardGreen __instance, float? __state)
		{
			if (__state.HasValue)
			{
				__instance.chestPriceIncreasePerAmount = __state.Value;
			}
		}
	}
	[HarmonyPatch(typeof(ItemInventory), "AddItem", new Type[] { typeof(EItem) })]
	internal static class KeyGreenCardAddedPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemInventory __instance, EItem __0)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.KeyEnabled && (int)__0 == 0)
			{
				KeyGreenCard.Refresh(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ItemInventory), "RemoveItem")]
	internal static class KeyGreenCardRemovedPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemInventory __instance, EItem __0)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.KeyEnabled && (int)__0 == 0)
			{
				KeyGreenCard.Refresh(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "GetChestPrice")]
	internal static class KeyPricePatch
	{
		private static readonly KeyChestGrowth Growth = new KeyChestGrowth();

		internal static void Reset()
		{
			Growth.Reset();
		}

		[HarmonyPrefix]
		private static bool Prefix(ref int __result)
		{
			if (!Plugin.KeyEnabled)
			{
				return true;
			}
			try
			{
				MyPlayer instance = MyPlayer.Instance;
				int? obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					PlayerInventory inventory = instance.inventory;
					if (inventory == null)
					{
						obj = null;
					}
					else
					{
						ItemInventory itemInventory = inventory.itemInventory;
						if (itemInventory == null)
						{
							obj = null;
						}
						else
						{
							ItemBase item = itemInventory.GetItem((EItem)0);
							obj = ((item != null) ? new int?(item.amount) : ((int?)null));
						}
					}
				}
				int? num = obj;
				int valueOrDefault = num.GetValueOrDefault();
				__result = CalculatePrice(valueOrDefault);
				return false;
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Key split chest pricing", error);
				return true;
			}
		}

		internal static int CalculatePrice(int keys)
		{
			int chestsPurchased = MoneyUtility.chestsPurchased;
			float num = Mathf.Pow(MoneyUtility.chestPriceIncrease, (float)chestsPurchased);
			int num2 = ChestPricing.LinearIncrease(chestsPurchased, MoneyUtility.priceIncreasePerChest, MoneyUtility.priceIncreasePerChestOver10, MoneyUtility.priceIncreasePerChestOver20, MoneyUtility.priceIncreasePerChestOver30, MoneyUtility.priceIncreasePerChestOver40, MoneyUtility.priceIncreasePerChestOver50);
			float num3 = MoneyUtility.chestBasePrice;
			float rawGrowth = num3 * (num - 1f) + (float)num2;
			Growth.Observe(chestsPurchased, rawGrowth, keys, Plugin.KeyScalingPercent, Plugin.KeyScalingMultiplier);
			int num4 = Mathf.RoundToInt(ChestPricing.FinalPrice(chestPriceStat: PlayerStats.GetStat((EStat)34), initialBase: num3, discountedGrowth: Growth.DiscountedGrowth, stageFactor: KeyStages.BaseMultiplier));
			Growth.LastPrice = num4;
			return num4;
		}
	}
	[HarmonyPatch(typeof(InteractableChest), "OnChestWindowClose")]
	internal static class KeyChestPriceCapturePatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			if (Plugin.KeyEnabled)
			{
				MoneyUtility.GetChestPrice();
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			Prefix();
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "IncreaseChestPrice")]
	internal static class KeyPriceIncreaseCapturePatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			if (Plugin.KeyEnabled)
			{
				MoneyUtility.GetChestPrice();
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			Prefix();
		}
	}
	[HarmonyPatch(typeof(MapController), "StartNewMap")]
	internal static class KeyStageRunPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			KeyStages.Reset();
		}
	}
	[HarmonyPatch(typeof(MapController), "RestartRun")]
	internal static class KeyStageRestartPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			KeyStages.Reset();
		}
	}
	[HarmonyPatch(typeof(ItemKey), "OnInitOrAmountChanged")]
	internal static class KeyStatPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemKey __instance)
		{
			if (Plugin.KeyEnabled)
			{
				KeyStats.Apply(__instance, enabled: true);
			}
		}
	}
	[HarmonyPatch(typeof(RandomObjectPlacer), "RandomObjectSpawner")]
	internal static class MicrowavePrefabCapturePatch
	{
		[HarmonyPrefix]
		private static void Prefix(RandomObjectPlacer __instance, RandomMapObject __0)
		{
			//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)
			try
			{
				Scene scene = ((Component)__instance).gameObject.scene;
				MicrowaveGuarantee.CapturePrefab(__0, ((Scene)(ref scene)).handle);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Microwave prefab capture failed", error);
			}
		}
	}
	[HarmonyPatch(typeof(SpawnInteractables), "SpawnShrines")]
	internal static class MicrowaveSpawnPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(SpawnInteractables __instance)
		{
			try
			{
				return MicrowaveGuarantee.SpawnShrines(__instance);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Microwave guarantee preparation failed; using vanilla shrines", error);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(InteractableMicrowave), "Start")]
	internal static class MicrowaveStartPatch
	{
		[ThreadStatic]
		internal static bool ForceCommon;

		[HarmonyPrefix]
		private static void Prefix(InteractableMicrowave __instance, out bool __state)
		{
			__state = ForceCommon;
			MicrowaveGuarantee.ObserveStart(__instance);
			ForceCommon = MicrowaveGuarantee.IsCommonTarget(__instance);
		}

		[HarmonyFinalizer]
		private static void Finalizer(bool __state)
		{
			ForceCommon = __state;
		}
	}
	[HarmonyPatch(typeof(Rarity), "GetShadyGuyRarity")]
	internal static class MicrowaveRarityPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref EItemRarity __result)
		{
			if (MicrowaveStartPatch.ForceCommon)
			{
				__result = (EItemRarity)0;
				Plugin.Debug("First guaranteed Microwave initialized as Common; vanilla applies material and 3 uses");
			}
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "OnNewStage")]
	internal static class MicrowaveStagePatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			MicrowaveGuarantee.BeginStage(((Scene)(ref activeScene)).handle);
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
	internal static class MicrowaveRunPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			MicrowaveGuarantee.BeginStage(((Scene)(ref activeScene)).handle);
		}
	}
	[HarmonyPatch(typeof(DataManager), "Load")]
	internal static class PityConfigPatch
	{
		[HarmonyPostfix]
		private static void Postfix(DataManager __instance)
		{
			try
			{
				PitySettings.BindItems(__instance);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Pity configuration catalog failed", error);
			}
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
	internal static class NewRunPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			UpgradeShuffleBag.Reset("new run started");
		}
	}
	[HarmonyPatch(typeof(MapController), "GetPlayerInventory")]
	internal static class InventoryInitializedPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerInventory __result)
		{
			if (__result != null)
			{
				UpgradeShuffleBag.ObserveInventory(__result);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerInventory), "Cleanup")]
	internal static class InventoryCleanupPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerInventory __instance)
		{
			UpgradeShuffleBag.CleanupInventory(__instance);
		}
	}
	[HarmonyPatch(typeof(InteractableShadyGuy), "Start")]
	internal static class ShadyGuyStartPatch
	{
		[ThreadStatic]
		internal static InteractableShadyGuy? Starting;

		[HarmonyPrefix]
		private static void Prefix(InteractableShadyGuy __instance, out InteractableShadyGuy? __state)
		{
			__state = Starting;
			Starting = __instance;
			GuaranteedShadyGuy.ObserveSpawn(__instance);
		}

		[HarmonyFinalizer]
		private static void Finalizer(InteractableShadyGuy? __state)
		{
			Starting = __state;
		}
	}
	[HarmonyPatch(typeof(Rarity), "GetShadyGuyRarity")]
	internal static class ShadyGuyRarityPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref EItemRarity __result)
		{
			InteractableShadyGuy starting = ShadyGuyStartPatch.Starting;
			if (!((Object)(object)starting == (Object)null) && GuaranteedShadyGuy.IsSelected(starting))
			{
				__result = (EItemRarity)2;
				Plugin.Debug("Forced Shady Guy rarity to Epic");
			}
		}
	}
	[HarmonyPatch(typeof(InteractableShadyGuy), "FindItems")]
	internal static class ShadyGuyItemsPatch
	{
		[ThreadStatic]
		internal static InteractableShadyGuy? Generating;

		[HarmonyPrefix]
		private static void Prefix(InteractableShadyGuy __instance, out InteractableShadyGuy? __state)
		{
			__state = Generating;
			Generating = __instance;
		}

		[HarmonyFinalizer]
		private static void Finalizer(InteractableShadyGuy? __state)
		{
			Generating = __state;
		}

		[HarmonyPostfix]
		private static void Postfix(InteractableShadyGuy __instance)
		{
			try
			{
				GuaranteedShadyGuy.EnsureCard(__instance);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Shady Guy guarantee failed", error);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryUtility), "GetRandomItemsShadyGuy")]
	internal static class ShadyGuyShortInventoryPatch
	{
		[HarmonyPostfix]
		private static void Postfix(List<ItemData> __result)
		{
			InteractableShadyGuy val = ShadyGuyItemsPatch.Generating ?? ShadyGuyStartPatch.Starting;
			if ((Object)(object)val == (Object)null || !GuaranteedShadyGuy.IsSelected(val))
			{
				return;
			}
			try
			{
				ShadyOffers.FillMissing(__result);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Shady Guy missing offer repair", error);
			}
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "OnNewStage")]
	internal static class ShadyGuyNewStagePatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GuaranteedShadyGuy.BeginStage(((Scene)(ref activeScene)).handle);
		}
	}
	[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
	internal static class ShadyGuyNewRunPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GuaranteedShadyGuy.BeginStage(((Scene)(ref activeScene)).handle);
		}
	}
	[HarmonyPatch(typeof(InventoryUtility), "GetRandomUpgrades")]
	internal static class UpgradeOfferPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref List<IUpgradable> __result)
		{
			if (__result == null)
			{
				return;
			}
			try
			{
				UpgradeShuffleBag.LogOffers(__result, "vanilla generated");
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Offer diagnostics failed", error);
			}
			OfferDisplayPatch.Frame current = OfferDisplayPatch.Current;
			if (!Plugin.EnableUpgradeShuffleBag.Value || current == null)
			{
				return;
			}
			current.Plan = null;
			try
			{
				UpgradeShuffleBag.OfferPlan offerPlan = UpgradeShuffleBag.Plan(__result);
				if (!(offerPlan == null))
				{
					current.Plan = offerPlan;
					__result = offerPlan.Offers;
				}
			}
			catch (Exception error2)
			{
				Plugin.WarnOnce("Shuffle planning failed; preserving vanilla offers", error2);
			}
		}
	}
	[HarmonyPatch(typeof(UpgradePicker), "ShuffleUpgrades")]
	internal static class OfferDisplayPatch
	{
		internal sealed class Frame
		{
			internal Frame? Parent;

			internal UpgradeShuffleBag.OfferPlan? Plan;
		}

		[ThreadStatic]
		internal static Frame? Current;

		[HarmonyPrefix]
		private static void Prefix(out Frame __state)
		{
			__state = new Frame
			{
				Parent = Current
			};
			Current = __state;
		}

		[HarmonyPostfix]
		private static void Postfix(UpgradePicker __instance, Frame __state)
		{
			if (__state.Plan == null)
			{
				return;
			}
			try
			{
				UpgradeShuffleBag.CommitDisplayed(__state.Plan, __instance);
			}
			catch (Exception error)
			{
				Plugin.WarnOnce("Offer display verification failed", error);
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(Frame? __state)
		{
			Current = __state?.Parent;
		}
	}
}