Decompiled source of T4ylorTweaks v1.0.3

plugins/T4ylorTweaks/T4ylorTweaks.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using IL.RoR2;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using On.RoR2;
using On.RoR2.UI;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RoR2;
using RoR2.CharacterAI;
using RoR2.ExpansionManagement;
using RoR2.Projectile;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("T4ylorTweaks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("T4ylorTweaks gameplay tweaks, Simulacrum fog, Moon escape and selected Eclipse changes.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("T4ylorTweaks")]
[assembly: AssemblyTitle("T4ylorTweaks")]
[assembly: AssemblyVersion("1.0.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace T4ylorTweaks
{
	public struct BazaarRandom
	{
		public ulong State;

		public BazaarRandom(ulong state)
		{
			State = state;
		}

		public static BazaarRandom ForVisit(ulong runSeed, uint visit, bool heresy)
		{
			return new BazaarRandom(runSeed ^ (ulong)(visit * -3372029247567499371L) ^ (ulong)(heresy ? 6067572782258079285L : 6067572782258079284L));
		}

		public ulong Next()
		{
			ulong num = (State += 11400714819323198485uL);
			long num2 = (long)(num ^ (num >> 30)) * -4658895280553007687L;
			long num3 = (num2 ^ (num2 >>> 27)) * -7723592293110705685L;
			return (ulong)(num3 ^ (num3 >>> 31));
		}

		public double Fraction()
		{
			return (double)(Next() >> 11) * 1.1102230246251565E-16;
		}

		public int Index(int count)
		{
			if (count <= 0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			ulong num = (ulong)count;
			ulong num2 = (0 - num) % num;
			ulong num3;
			do
			{
				num3 = Next();
			}
			while (num3 < num2);
			return (int)(num3 % num);
		}
	}
	public static class HeresyRules
	{
		public static T Choose<T>(IReadOnlyList<T> heresy, IReadOnlyList<T> other, float probability, ref BazaarRandom rng)
		{
			if (heresy.Count == 0 && other.Count == 0)
			{
				throw new InvalidOperationException("No eligible lunar merchandise.");
			}
			if (float.IsNaN(probability) || float.IsInfinity(probability))
			{
				probability = 0.85f;
			}
			probability = Math.Max(0f, Math.Min(1f, probability));
			bool flag = rng.Fraction() < (double)probability;
			IReadOnlyList<T> readOnlyList = (flag ? heresy : other);
			if (readOnlyList.Count == 0)
			{
				readOnlyList = (flag ? other : heresy);
			}
			return readOnlyList[rng.Index(readOnlyList.Count)];
		}
	}
	public sealed class BazaarVisitGate<TPlayer> where TPlayer : notnull
	{
		private readonly HashSet<TPlayer> used = new HashSet<TPlayer>();

		private TPlayer current;

		public bool Busy { get; private set; }

		public bool HasUsed(TPlayer player)
		{
			return used.Contains(player);
		}

		public bool HasRemainingUse(IEnumerable<TPlayer> players)
		{
			foreach (TPlayer player in players)
			{
				if (!HasUsed(player))
				{
					return true;
				}
			}
			return false;
		}

		public bool TryBegin(TPlayer player)
		{
			if (Busy || HasUsed(player))
			{
				return false;
			}
			current = player;
			Busy = true;
			return true;
		}

		public void Finish(bool success)
		{
			if (!Busy)
			{
				throw new InvalidOperationException("No active refresh.");
			}
			if (success)
			{
				used.Add(current);
			}
			current = default(TPlayer);
			Busy = false;
		}

		public void Reset()
		{
			Busy = false;
			current = default(TPlayer);
			used.Clear();
		}
	}
	public static class BazaarVisitGate
	{
		public const int Cost = 3;

		public const int SlotCount = 5;
	}
	public enum ReplacementRule
	{
		Vanilla,
		Replacement
	}
	public enum AdjustmentRule
	{
		Vanilla,
		Adjusted
	}
	public enum IncomeStagePolicy
	{
		VerifiedOrdinaryStages,
		AllAdventureCombatStages
	}
	public sealed class Configuration
	{
		private readonly Dictionary<string, ConfigEntry<bool>> features = new Dictionary<string, ConfigEntry<bool>>();

		public static IReadOnlyList<string> FeatureIds { get; } = new ReadOnlyCollection<string>(new string[9] { "F01", "F02", "F03", "F04", "F05", "F06", "F07", "F08", "F09" });

		public ConfigEntry<IncomeStagePolicy> IncomeStages { get; }

		public ConfigEntry<float> DepartureWindowSeconds { get; }

		public ConfigEntry<float> HeresyProbability { get; }

		public ConfigEntry<float> AmbryCreditMultiplier { get; }

		public ConfigEntry<float> BoardingDebounceSeconds { get; }

		public ConfigEntry<float> FogInitialMultiplier { get; }

		public ConfigEntry<float> FogBlockGrowth { get; }

		public ConfigEntry<float> FogMaximumMultiplier { get; }

		public ConfigEntry<ReplacementRule> Eclipse1 { get; }

		public ConfigEntry<ReplacementRule> Eclipse2 { get; }

		public ConfigEntry<bool> Eclipse2Enabled { get; }

		public ConfigEntry<ReplacementRule> Eclipse5 { get; }

		public ConfigEntry<ReplacementRule> Eclipse6 { get; }

		public ConfigEntry<float> HealingRate { get; }

		public ConfigEntry<float> EnemyGoldExponent { get; }

		public ConfigEntry<AdjustmentRule> Eclipse8 { get; }

		public Configuration(ConfigFile file)
		{
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Expected O, but got Unknown
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Expected O, but got Unknown
			string[] array = new string[9] { "Enemy-free income", "Departure scanner", "Stage-wide teleporter", "Bazaar refresh", "Heresy bud", "Ambry density", "Ship boarding", "Simulacrum fog", "Automatic Deep Void portal" };
			for (int i = 0; i < FeatureIds.Count; i++)
			{
				features.Add(FeatureIds[i], file.Bind<bool>(FeatureIds[i] + " " + array[i], "Enabled", true, "Enable this feature. Server settings are frozen at run start; edits apply next run."));
			}
			IncomeStages = file.Bind<IncomeStagePolicy>("F01 Enemy-free income", "StagePolicy", IncomeStagePolicy.VerifiedOrdinaryStages, "VerifiedOrdinaryStages uses the installed normal-stage allowlist plus Gold Coast. AllAdventureCombatStages opts into all SceneType.Stage/UntimedStage scenes, including Moon/void combat scenes. Both exclude non-adventure runs.");
			DepartureWindowSeconds = Float(file, "F02 Departure scanner", "RevealWindowSeconds", 3f, 0f, 10f, "Minimum scanner window in seconds before this departure controller progresses. Money conversion and gameplay continue. Provisional default 3; zero adds no hold.");
			HeresyProbability = Float(file, "F05 Heresy bud", "HeresyProbability", 0.85f, 0f, 1f, "Overall probability, 0 to 1, for the asset-mapped customer-left lunar bud on initial stock and refresh. Fallback excludes Heresy. Live screenshot confirmation remains pending.");
			AmbryCreditMultiplier = Float(file, "F06 Ambry density", "CreditIncomeMultiplier", 1.5f, 1f, 10f, "Provisional active-trial enemy director income multiplier; not a guarantee of proportional enemy counts.");
			BoardingDebounceSeconds = Float(file, "F07 Ship boarding", "DebounceSeconds", 0.5f, 0f, 5f, "Seconds all eligible living participants must remain simultaneously inside the verified ship bay.");
			FogInitialMultiplier = Float(file, "F08 Simulacrum fog", "InitialMultiplier", 0.67f, 0f, 10f, "Multiplier on the vanilla player-team environmental fog hit at waves 1 through 5.");
			FogBlockGrowth = Float(file, "F08 Simulacrum fog", "FiveWaveGrowthMultiplier", 1.2f, 1f, 5f, "Multiplicative growth starting on waves 6, 11, 16, etc.; global run wave number.");
			FogMaximumMultiplier = Float(file, "F08 Simulacrum fog", "MaximumMultiplier", 0f, 0f, 1000f, "Zero means uncapped. Positive values cap the final multiplier relative to vanilla.");
			Eclipse1 = file.Bind<ReplacementRule>("Eclipse", "E1", ReplacementRule.Replacement, "Replacement: normal starting health and one ordinary-stage champion, with 20% gold. Vanilla retains half starting health. Applies next run.");
			Eclipse2 = file.Bind<ReplacementRule>("Eclipse", "E2", ReplacementRule.Replacement, "Replacement: normal teleporter radius and 1.20x event credits. Vanilla: original radius penalty. Both suppress F03 at Eclipse 2+. Applies next run.");
			Eclipse2Enabled = file.Bind<bool>("Eclipse", "E2Enabled", true, "False removes only E2's radius/credit rule and permits F03 at Eclipse 2+. Other Eclipse levels and progression are unchanged. Applies next run.");
			Eclipse5 = file.Bind<ReplacementRule>("Eclipse", "E5", ReplacementRule.Replacement, "Replacement admits 75% of eligible healing once and delivers over time. Includes regeneration; owned Rack/Corpsebloom bonuses apply once, with Corpsebloom imposing its slower cap. No overheal banking; resets on death/body/stage changes. Vanilla retains original E5. Applies next run.");
			Eclipse6 = file.Bind<ReplacementRule>("Eclipse", "E6", ReplacementRule.Replacement, "Replacement compresses verified enemy reward growth using GrowthExponent, preserves the player-count baseline and replaces native 20% reduction. F01, item gold and prices stay native. Unknown reward setup falls back to vanilla E6. Applies next run.");
			HealingRate = file.Bind<float>("Eclipse E5", "MaximumHealthPerSecond", 0.2f, new ConfigDescription("Selected default: 20% of current maximum health per second. Owned Corpsebloom caps delivery at the smaller of this rate and vanilla 10% divided by stack count: 10%, 5%, 3.33%, 2.5%, etc. Applies next run.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.101f, 1f), Array.Empty<object>()));
			EnemyGoldExponent = file.Bind<float>("Eclipse E6", "GrowthExponent", 0.75f, new ConfigDescription("Selected provisional exponent on enemy time/stage reward growth relative to the native player baseline. Default 0.75; gameplay affordability tuning remains pending. Applies next run.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 0.99f), Array.Empty<object>()));
			Eclipse8 = file.Bind<AdjustmentRule>("Eclipse", "E8", AdjustmentRule.Adjusted, "Adjusted exempts verified REX, Void Fiend, Seeker ability costs and Captain Diablo Strike self-hits from E8 curse only. Damage, enemy hits, falls, Blood Shrines and Void Cradles remain native. Vanilla retains all E8 curse. Applies next run.");
		}

		public ConfigEntry<bool> Feature(string id)
		{
			return features[id];
		}

		public RunSettings Snapshot()
		{
			return new RunSettings(this);
		}

		private static ConfigEntry<float> Float(ConfigFile file, string section, string key, float value, float minimum, float maximum, string description)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			return file.Bind<float>(section, key, value, new ConfigDescription(description + " Applies next run.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), Array.Empty<object>()));
		}
	}
	public sealed class RunSettings
	{
		public IReadOnlyDictionary<string, bool> Features { get; }

		public IncomeStagePolicy IncomeStages { get; }

		public float DepartureWindowSeconds { get; }

		public float HeresyProbability { get; }

		public float AmbryCreditMultiplier { get; }

		public float BoardingDebounceSeconds { get; }

		public float FogInitialMultiplier { get; }

		public float FogBlockGrowth { get; }

		public float FogMaximumMultiplier { get; }

		public ReplacementRule Eclipse1 { get; }

		public ReplacementRule Eclipse2 { get; }

		public bool Eclipse2Enabled { get; }

		public ReplacementRule Eclipse5 { get; }

		public ReplacementRule Eclipse6 { get; }

		public float HealingRate { get; }

		public float EnemyGoldExponent { get; }

		public AdjustmentRule Eclipse8 { get; }

		internal RunSettings(Configuration config)
		{
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
			foreach (string featureId in Configuration.FeatureIds)
			{
				dictionary.Add(featureId, config.Feature(featureId).Value);
			}
			Features = new ReadOnlyDictionary<string, bool>(dictionary);
			IncomeStages = config.IncomeStages.Value;
			DepartureWindowSeconds = config.DepartureWindowSeconds.Value;
			HeresyProbability = config.HeresyProbability.Value;
			AmbryCreditMultiplier = config.AmbryCreditMultiplier.Value;
			BoardingDebounceSeconds = config.BoardingDebounceSeconds.Value;
			FogInitialMultiplier = config.FogInitialMultiplier.Value;
			FogBlockGrowth = config.FogBlockGrowth.Value;
			FogMaximumMultiplier = config.FogMaximumMultiplier.Value;
			Eclipse1 = config.Eclipse1.Value;
			Eclipse2 = config.Eclipse2.Value;
			Eclipse2Enabled = config.Eclipse2Enabled.Value;
			Eclipse5 = config.Eclipse5.Value;
			Eclipse6 = config.Eclipse6.Value;
			HealingRate = config.HealingRate.Value;
			EnemyGoldExponent = config.EnemyGoldExponent.Value;
			Eclipse8 = config.Eclipse8.Value;
		}
	}
	public enum EclipseMedalTone
	{
		Unearned,
		Silver,
		Gold
	}
	public static class EclipseAccessRules
	{
		public static bool IsSelectableLevel(int level)
		{
			if (level >= 1)
			{
				return level <= 8;
			}
			return false;
		}

		public static int LobbyPenaltyLevel(int nativeLevel, int selectedLevel)
		{
			if (!IsSelectableLevel(selectedLevel))
			{
				return Math.Max(1, Math.Min(8, nativeLevel));
			}
			return selectedLevel;
		}

		public static EclipseMedalTone MedalTone(int completed, int allSurvivorMinimum, int level)
		{
			if (HasBadge(completed, level))
			{
				if (allSurvivorMinimum < level)
				{
					return EclipseMedalTone.Silver;
				}
				return EclipseMedalTone.Gold;
			}
			return EclipseMedalTone.Unearned;
		}

		public static bool HasBadge(int completed, int level)
		{
			if (IsSelectableLevel(level))
			{
				return completed >= level;
			}
			return false;
		}

		public static string ProgressNotice(string survivor, int completed, int selected)
		{
			if (!IsSelectableLevel(selected))
			{
				return "Select an Eclipse level. Wins advance one badge at a time.";
			}
			if (completed >= 8)
			{
				return survivor + " has already earned all Eclipse badges.";
			}
			if (selected <= completed)
			{
				return "A win at Eclipse " + selected + " will not award a new Eclipse badge for " + survivor + ".";
			}
			return "A win at Eclipse " + selected + " will only award the Eclipse " + (completed + 1) + " badge for " + survivor + ".";
		}

		public static int ProgressAfterWin(int completed, int played, bool won)
		{
			completed = Math.Max(0, Math.Min(8, completed));
			if (!won || played < completed + 1 || played > 8)
			{
				return completed;
			}
			return completed + 1;
		}
	}
	public sealed class EclipseAwardGate<T>
	{
		private readonly HashSet<T> processed = new HashSet<T>();

		public bool TryAward(T identity, int completed, int played, bool won, out int after)
		{
			after = EclipseAccessRules.ProgressAfterWin(completed, played, won);
			if (after > completed)
			{
				return processed.Add(identity);
			}
			return false;
		}
	}
	public static class EclipseDescriptionText
	{
		public const string Level1 = "Stages start with a boss enemy costing no credits that yields little gold.";

		public const string Level2 = "Teleporter credits increased +20%; removes stage-wide charging.";

		public const string Level5 = "Healing -25%; all healing delivered over time.";

		public const string Level6 = "Gold gain scales worse through runs";

		public const string Level8 = "Permanent health loss from damage; Self-damaging abilities excluded";

		public static string Highlight(string text)
		{
			return "<color=#C586FF><b>" + text + "</b></color>";
		}

		public static string Format(int level, string text)
		{
			if (level != 8 || !(text == "Permanent health loss from damage; Self-damaging abilities excluded"))
			{
				return Highlight(text);
			}
			return "Permanent health loss from damage; " + Highlight("Self-damaging abilities excluded");
		}

		public static string ReplaceLine(string text, int level, string replacement)
		{
			return Regex.Replace(text, "(<mspace=[^>]+>\\(" + level + "\\)</mspace>)[^\\r\\n]*", delegate(Match match)
			{
				int num = 0;
				StringBuilder stringBuilder = new StringBuilder();
				foreach (Match item in Regex.Matches(match.Value.Substring(match.Groups[1].Length), "<style(?:=[^>]+)?>|</style>"))
				{
					if (!item.Value.StartsWith("</"))
					{
						num++;
					}
					else if (num > 0)
					{
						num--;
					}
					else
					{
						stringBuilder.Append(item.Value);
					}
				}
				return match.Groups[1].Value + " " + Format(level, replacement) + stringBuilder;
			});
		}
	}
	public readonly struct EclipseOverviewLayout
	{
		public const double HeaderHeight = 44.0;

		public const double BadgePanelHeight = 120.0;

		public const double BadgeGap = 12.0;

		public const double PortraitSpacing = 8.0;

		public const double NormalBadgeSize = 64.0;

		public int Rows { get; }

		public double CellSize { get; }

		public double ContentHeight { get; }

		public double ViewportHeight { get; }

		public double BadgeTop => 44.0 + ViewportHeight + 12.0;

		public double BadgeSize { get; }

		public bool Scrolls => ContentHeight > ViewportHeight + 0.01;

		private EclipseOverviewLayout(int rows, double cell, double content, double viewport, double badge)
		{
			Rows = rows;
			CellSize = cell;
			ContentHeight = content;
			ViewportHeight = viewport;
			BadgeSize = badge;
		}

		public static EclipseOverviewLayout Calculate(double width, double height, int count, int columns, double horizontalPadding, double verticalPadding)
		{
			if (double.IsNaN(width) || double.IsInfinity(width) || width <= 0.0)
			{
				width = 1.0;
			}
			if (double.IsNaN(height) || double.IsInfinity(height) || height <= 0.0)
			{
				height = 1.0;
			}
			count = Math.Max(0, count);
			columns = Math.Max(1, columns);
			int num = count / columns + ((count % columns != 0) ? 1 : 0);
			double num2 = Math.Max(1.0, (width - horizontalPadding - (double)(columns - 1) * 8.0) / (double)columns);
			double num3 = verticalPadding + (double)num * num2 + (double)Math.Max(0, num - 1) * 8.0;
			double val = Math.Max(1.0, height - 44.0 - 120.0 - 12.0);
			double badge = Math.Min(64.0, Math.Max(1.0, (width - 28.0 - 84.0) / 8.0));
			return new EclipseOverviewLayout(num, num2, num3, Math.Min(Math.Max(1.0, num3), val), badge);
		}
	}
	internal sealed class AbilityCurseFeature : IDisposable
	{
		internal static readonly string[] StateSources = new string[9] { "EntityStates.FireFlower2|OnEnter", "EntityStates.Treebot.Proliferation|OnEnter", "EntityStates.Treebot.Weapon.AimFlower|OnProjectileFiredLocal", "EntityStates.Treebot.Weapon.AimMortar2|OnProjectileFiredLocal", "EntityStates.Treebot.Weapon.FireMortar2|OnEnter", "EntityStates.Treebot.Weapon.FireSonicBoom|OnEnter", "EntityStates.Treebot.Weapon.FirePlantSonicBoom|OnEnter", "EntityStates.VoidSurvivor.Weapon.CrushBase|OnEnter", "EntityStates.VoidSurvivor.Weapon.Suppress|FixedUpdate" };

		private readonly Func<PhaseSettings?> settings;

		private readonly Func<PhaseSettings?> descriptionSettings;

		private readonly ManualLogSource log;

		private readonly List<ILHook> hooks = new List<ILHook>();

		private readonly Dictionary<DamageInfo, HealthComponent> classified = new Dictionary<DamageInfo, HealthComponent>();

		private FieldInfo? passenger;

		private bool curseAttached;

		internal bool Ready { get; private set; }

		private bool Active
		{
			get
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Invalid comparison between Unknown and I4
				if (Ready)
				{
					PhaseSettings phaseSettings = settings();
					if (phaseSettings != null && phaseSettings.AbilityCurseExemption && NetworkServer.active && Run.instance is EclipseRun)
					{
						return (int)Run.instance.selectedDifficulty >= 10;
					}
				}
				return false;
			}
		}

		internal AbilityCurseFeature(Func<PhaseSettings?> settings, Func<PhaseSettings?> descriptionSettings, ManualLogSource log)
		{
			this.settings = settings;
			this.descriptionSettings = descriptionSettings;
			this.log = log;
		}

		internal void Enable()
		{
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			try
			{
				string[] stateSources = StateSources;
				for (int i = 0; i < stateSources.Length; i++)
				{
					string[] array = stateSources[i].Split('|');
					Type type = typeof(Run).Assembly.GetType(array[0], throwOnError: true);
					if (!typeof(EntityState).IsAssignableFrom(type))
					{
						throw new InvalidOperationException("Ability source is no longer a state.");
					}
					hooks.Add(new ILHook((MethodBase)Method(type, array[1]), (Manipulator)delegate(ILContext il)
					{
						ReplaceDamage(il, vehicle: false);
					}));
				}
				passenger = typeof(SojournVehicleBase).GetField("characterBody", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingFieldException("SojournVehicleBase.characterBody");
				if (passenger.FieldType != typeof(CharacterBody))
				{
					throw new InvalidOperationException("Sojourn passenger field changed.");
				}
				hooks.Add(new ILHook((MethodBase)Method(typeof(SojournVehicle), "OnFixedUpdateForTenthSecond"), (Manipulator)delegate(ILContext il)
				{
					ReplaceDamage(il, vehicle: true);
				}));
				HealthComponent.TakeDamageProcess += new Manipulator(Curse);
				curseAttached = true;
				Language.GetLocalizedStringByToken += new hook_GetLocalizedStringByToken(Description);
				Ready = true;
			}
			catch (Exception ex)
			{
				HealthComponent.TakeDamageProcess -= new Manipulator(Curse);
				Dispose();
				log.LogError((object)("E8 ability exemption unavailable; native persistent damage retained: " + ex));
			}
		}

		private static MethodInfo Method(Type type, string name)
		{
			return type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException(type.FullName, name);
		}

		private void ReplaceDamage(ILContext il, bool vehicle)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0035: 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)
			int num = HealingEconomyPatterns.DamageCall(il.Body.Instructions.ToArray());
			ILCursor val = new ILCursor(il)
			{
				Index = num
			};
			il.Body.Instructions[num].OpCode = OpCodes.Nop;
			il.Body.Instructions[num].Operand = null;
			val.Index = num + 1;
			val.Emit(OpCodes.Ldarg_0);
			if (vehicle)
			{
				val.EmitDelegate<Action<HealthComponent, DamageInfo, SojournVehicle>>((Action<HealthComponent, DamageInfo, SojournVehicle>)delegate(HealthComponent victim, DamageInfo info, SojournVehicle source)
				{
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_001e: Expected O, but got Unknown
					Deal(victim, info, (CharacterBody)passenger.GetValue(source), "SeekerBody");
				});
			}
			else
			{
				val.EmitDelegate<Action<HealthComponent, DamageInfo, EntityState>>((Action<HealthComponent, DamageInfo, EntityState>)delegate(HealthComponent victim, DamageInfo info, EntityState source)
				{
					Deal(victim, info, ((Component)source.outer).GetComponent<CharacterBody>(), ((object)source).GetType().FullName.Contains("VoidSurvivor") ? "VoidSurvivorBody" : "TreebotBody");
				});
			}
		}

		private void Deal(HealthComponent victim, DamageInfo info, CharacterBody? source, string bodyName)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)source == (Object)null || !Object.op_Implicit((Object)(object)source) || (Object)(object)source.healthComponent != (Object)(object)victim || source.bodyIndex != BodyCatalog.FindBodyIndex(bodyName))
			{
				victim.TakeDamage(info);
				return;
			}
			HealthComponent value;
			bool flag = classified.TryGetValue(info, out value);
			classified[info] = victim;
			try
			{
				victim.TakeDamage(info);
			}
			finally
			{
				if (flag)
				{
					classified[info] = value;
				}
				else
				{
					classified.Remove(info);
				}
			}
		}

		private bool Exempt(HealthComponent victim, DamageInfo info)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Invalid comparison between Unknown and I4
			if (!Active || !Object.op_Implicit((Object)(object)victim.body) || (int)victim.body.teamComponent.teamIndex != 1)
			{
				return false;
			}
			if (classified.TryGetValue(info, out HealthComponent value) && (Object)(object)value == (Object)(object)victim)
			{
				return true;
			}
			if (victim.body.bodyIndex != BodyCatalog.FindBodyIndex("CaptainBody") || (Object)(object)info.attacker != (Object)(object)((Component)victim).gameObject || !Object.op_Implicit((Object)(object)info.inflictor) || (int)info.damageType.damageSource != 4)
			{
				return false;
			}
			ProjectileController component = info.inflictor.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component) || (Object)(object)component.owner != (Object)(object)((Component)victim).gameObject)
			{
				return false;
			}
			int num = ProjectileCatalog.FindProjectileIndex("CaptainAirstrikeAltProjectile");
			if (num >= 0)
			{
				return component.catalogIndex == num;
			}
			return false;
		}

		private void Curse(ILContext il)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			int num = HealingEconomyPatterns.CurseCoefficient(il.Body.Instructions.ToArray());
			ILCursor val = new ILCursor(il)
			{
				Index = num + 1
			};
			val.Emit(OpCodes.Ldarg_0);
			val.Emit(OpCodes.Ldarg_1);
			val.EmitDelegate<Func<float, HealthComponent, DamageInfo, float>>((Func<float, HealthComponent, DamageInfo, float>)((float factor, HealthComponent victim, DamageInfo info) => (!Exempt(victim, info)) ? factor : 0f));
		}

		private string Description(orig_GetLocalizedStringByToken orig, Language self, string token)
		{
			string text = orig.Invoke(self, token);
			if (Ready && !(token != "ECLIPSE_8_DESCRIPTION"))
			{
				PhaseSettings phaseSettings = descriptionSettings();
				if (phaseSettings != null && phaseSettings.AbilityCurseExemption)
				{
					return Regex.Replace(text, "(<mspace=[^>]+>\\(8\\)</mspace>).*?</style>", "$1 Permanent damage; survivor ability self-damage adds no curse</style>");
				}
			}
			return text;
		}

		internal void Reset()
		{
			classified.Clear();
		}

		public void Dispose()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Language.GetLocalizedStringByToken -= new hook_GetLocalizedStringByToken(Description);
			if (curseAttached)
			{
				HealthComponent.TakeDamageProcess -= new Manipulator(Curse);
			}
			foreach (ILHook hook in hooks)
			{
				hook.Dispose();
			}
			hooks.Clear();
			Ready = false;
			curseAttached = false;
			Reset();
		}
	}
	internal sealed class AmbryFeature : IDisposable
	{
		private sealed class IncomeLease : IDisposable
		{
			private static readonly FieldInfo waves = typeof(CombatDirector).GetField("moneyWaves", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException("CombatDirector.moneyWaves");

			private static readonly FieldInfo multiplier = waves.FieldType.GetElementType().GetField("multiplier") ?? throw new MissingFieldException("DirectorMoneyWave.multiplier");

			private readonly CombatDirector director;

			private readonly object[] entries;

			private readonly float factor;

			private readonly UnityAction<GameObject> spawned;

			private bool disposed;

			internal static void Validate()
			{
				if (waves.FieldType.GetElementType().IsValueType || multiplier.FieldType != typeof(float))
				{
					throw new InvalidOperationException("Director income field changed.");
				}
			}

			internal IncomeLease(CombatDirector director, float factor, UnityAction<GameObject> spawned)
			{
				this.director = director;
				this.factor = factor;
				this.spawned = spawned;
				Array array = ((Array)waves.GetValue(director)) ?? throw new InvalidOperationException("Trial income waves are not initialized.");
				if (array.Length == 0)
				{
					throw new InvalidOperationException("Trial income waves are empty.");
				}
				entries = new object[array.Length];
				array.CopyTo(entries, 0);
				object[] array2 = entries;
				for (int i = 0; i < array2.Length; i++)
				{
					if (array2[i] == null)
					{
						throw new InvalidOperationException("Invalid trial income wave.");
					}
				}
				int num = 0;
				try
				{
					array2 = entries;
					foreach (object obj in array2)
					{
						multiplier.SetValue(obj, (float)multiplier.GetValue(obj) * factor);
						num++;
					}
					((UnityEvent<GameObject>)(object)director.onSpawnedServer).AddListener(spawned);
				}
				catch
				{
					for (int j = 0; j < num; j++)
					{
						multiplier.SetValue(entries[j], (float)multiplier.GetValue(entries[j]) / factor);
					}
					throw;
				}
			}

			public void Dispose()
			{
				if (!disposed)
				{
					disposed = true;
					object[] array = entries;
					foreach (object obj in array)
					{
						multiplier.SetValue(obj, (float)multiplier.GetValue(obj) / factor);
					}
					if (Object.op_Implicit((Object)(object)director))
					{
						((UnityEvent<GameObject>)(object)director.onSpawnedServer).RemoveListener(spawned);
					}
				}
			}
		}

		private readonly Func<PhaseSettings?> settings;

		private readonly ManualLogSource log;

		private readonly List<IncomeLease> leases = new List<IncomeLease>();

		private ILHook? enter;

		private ILHook? exit;

		private EntityState? activeState;

		private float started;

		private int spawnCount;

		internal bool Ready { get; private set; }

		internal AmbryFeature(Func<PhaseSettings?> settings, ManualLogSource log)
		{
			this.settings = settings;
			this.log = log;
		}

		internal void Enable()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			try
			{
				IncomeLease.Validate();
				Type type = typeof(ArtifactTrialMissionController).GetNestedType("CombatState", BindingFlags.NonPublic) ?? throw new MissingMemberException("ArtifactTrialMissionController.CombatState");
				enter = new ILHook((MethodBase)type.GetMethod("OnEnter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public), (Manipulator)delegate(ILContext il)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Expected O, but got Unknown
					//IL_0044: Unknown result type (might be due to invalid IL or missing references)
					ILCursor val = new ILCursor(il);
					if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
					{
						delegate(Instruction instruction)
						{
							object operand = instruction.Operand;
							MethodReference val2 = (MethodReference)((operand is MethodReference) ? operand : null);
							return val2 != null && ((MemberReference)val2).Name == "OnEnter" && ((MemberReference)((MemberReference)val2).DeclaringType).Name == "ArtifactTrialMissionControllerBaseState";
						}
					}))
					{
						throw new InvalidOperationException("Trial base enter call changed.");
					}
					val.Emit(OpCodes.Ldarg_0);
					val.EmitDelegate<Action<EntityState>>((Action<EntityState>)Enter);
				});
				exit = new ILHook((MethodBase)type.GetMethod("OnExit", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public), (Manipulator)delegate(ILContext il)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					ILCursor val = new ILCursor(il);
					val.Emit(OpCodes.Ldarg_0);
					val.EmitDelegate<Action<EntityState>>((Action<EntityState>)delegate(EntityState state)
					{
						if (activeState == state)
						{
							Reset();
						}
					});
				});
				Ready = true;
			}
			catch (Exception ex)
			{
				Dispose();
				log.LogError((object)("F06 unavailable; vanilla Ambry spawning retained: " + ex));
			}
		}

		private void Enter(EntityState state)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Invalid comparison between Unknown and I4
			PhaseSettings phaseSettings = settings();
			SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
			if (!NetworkServer.active || phaseSettings == null || !phaseSettings.Ambry || !Object.op_Implicit((Object)(object)sceneDefForCurrentScene) || !SpawningRules.AmbryScene(sceneDefForCurrentScene.cachedName))
			{
				return;
			}
			Reset();
			try
			{
				ArtifactTrialMissionController component = ((Component)state.outer).GetComponent<ArtifactTrialMissionController>();
				if (!Object.op_Implicit((Object)(object)component) || component.combatDirectors == null)
				{
					throw new InvalidOperationException("Active trial has no director references.");
				}
				HashSet<CombatDirector> hashSet = new HashSet<CombatDirector>();
				CombatDirector[] combatDirectors = component.combatDirectors;
				foreach (CombatDirector val in combatDirectors)
				{
					if (Object.op_Implicit((Object)(object)val) && ((Behaviour)val).enabled && (int)val.teamIndex == 2 && hashSet.Add(val))
					{
						leases.Add(new IncomeLease(val, phaseSettings.AmbryMultiplier, delegate
						{
							spawnCount++;
						}));
					}
				}
				if (leases.Count == 0)
				{
					throw new InvalidOperationException("No active Ambry enemy directors were found.");
				}
				activeState = state;
				started = Time.fixedTime;
				spawnCount = 0;
				log.LogInfo((object)$"F06: {leases.Count} trial-owned directors use {phaseSettings.AmbryMultiplier:0.##}x income. Spawn cadence, key drops and population limits remain native.");
			}
			catch (Exception ex)
			{
				Reset();
				log.LogError((object)("F06 trial adjustment unavailable; income restored: " + ex));
			}
		}

		internal void Reset()
		{
			foreach (IncomeLease lease in leases)
			{
				lease.Dispose();
			}
			leases.Clear();
			if (activeState != null)
			{
				log.LogInfo((object)$"F06 trial measurement: {spawnCount} spawned masters in {Time.fixedTime - started:0.00}s of gameplay time. Compare matched seeds; budget does not guarantee proportional density.");
			}
			activeState = null;
			spawnCount = 0;
		}

		public void Dispose()
		{
			ILHook? obj = enter;
			if (obj != null)
			{
				obj.Dispose();
			}
			ILHook? obj2 = exit;
			if (obj2 != null)
			{
				obj2.Dispose();
			}
			Reset();
			Ready = false;
			enter = null;
			exit = null;
		}
	}
	internal sealed class BazaarFeature : IDisposable
	{
		private sealed class RefreshPlan
		{
			internal readonly NetworkUser Payer;

			internal readonly List<SlotSnapshot> Slots = new List<SlotSnapshot>();

			internal readonly List<GameObject> Created = new List<GameObject>();

			internal BazaarRandom Heresy;

			internal BazaarRandom Refresh;

			internal bool CallbackReached;

			internal bool Cancelled;

			internal uint Paid;

			internal Vector3 EffectOrigin;

			internal EffectIndex SweepIndex;

			internal EffectIndex SlotIndex;

			internal RefreshPlan(NetworkUser payer, BazaarRandom heresy, BazaarRandom refresh)
			{
				Payer = payer;
				Heresy = heresy;
				Refresh = refresh;
			}
		}

		private sealed class SlotSnapshot
		{
			internal readonly ShopTerminalBehavior Terminal;

			internal readonly PurchaseInteraction Purchase;

			internal readonly UniquePickup Pickup;

			internal UniquePickup Offer;

			internal readonly bool Hidden;

			internal readonly bool Purchased;

			internal readonly bool Available;

			internal readonly bool Created;

			internal readonly int Cost;

			internal readonly int NormalCost;

			internal readonly Vector3 EffectOrigin;

			internal bool Revealed;

			internal SlotSnapshot(ShopTerminalBehavior terminal, PurchaseInteraction purchase, bool created, int normalCost)
			{
				//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_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				Terminal = terminal;
				Purchase = purchase;
				Created = created;
				NormalCost = normalCost;
				Pickup = terminal.CurrentPickup();
				Hidden = terminal.pickupIndexIsHidden;
				Purchased = terminal.NetworkhasBeenPurchased;
				Available = purchase.available;
				Cost = purchase.cost;
				Transform val = ((Component)terminal).transform.Find("RerollEffectRoot");
				if (!Object.op_Implicit((Object)(object)val))
				{
					throw new InvalidOperationException("Native lunar terminal effect origin is missing.");
				}
				EffectOrigin = val.position;
			}
		}

		private readonly Func<PhaseSettings?> settings;

		private readonly ManualLogSource log;

		private readonly BazaarVisitGate<NetworkUserId> gate = new BazaarVisitGate<NetworkUserId>();

		private readonly Func<PhaseMessage?> remote;

		private readonly Action changed;

		private Transform? root;

		private uint visits;

		private ulong seed;

		private BazaarRandom heresy;

		private BazaarRandom refresh;

		private RefreshPlan? pending;

		internal const string LunarTerminalAddress = "RoR2/Base/LunarShopTerminal/LunarShopTerminal.prefab";

		private AsyncOperationHandle<GameObject>? terminalAsset;

		internal const string RerollEffectAddress = "RoR2/Base/LunarRecycler/LunarRerollEffect.prefab";

		internal const string SweepEffectAddress = "RoR2/Base/LunarRecycler/LunarRecyclerFX.prefab";

		private AsyncOperationHandle<GameObject>? rerollEffect;

		private AsyncOperationHandle<GameObject>? sweepEffect;

		private RefreshPlan? sweeping;

		private float sweepStarted;

		private Action<ShopTerminalBehavior> updateDisplay;

		private bool poolWarning;

		private bool refreshUnavailable;

		private bool visitInitialized;

		private PurchaseInteraction? refresher;

		private int originalRefresherCost;

		private readonly HashSet<string> failures = new HashSet<string>();

		internal bool Ready { get; private set; }

		internal uint RefresherId
		{
			get
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)refresher))
				{
					return 0u;
				}
				NetworkInstanceId netId = ((Component)refresher).GetComponent<NetworkIdentity>().netId;
				return ((NetworkInstanceId)(ref netId)).Value;
			}
		}

		internal uint[] UsedUserIds => NetworkUser.readOnlyInstancesList.Where((NetworkUser user) => Object.op_Implicit((Object)(object)user) && gate.HasUsed(user.id)).Select(delegate(NetworkUser user)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			NetworkInstanceId netId = ((NetworkBehaviour)user).netId;
			return ((NetworkInstanceId)(ref netId)).Value;
		}).ToArray();

		internal BazaarFeature(Func<PhaseSettings?> settings, Func<PhaseMessage?> remote, Action changed, ManualLogSource log)
		{
			this.settings = settings;
			this.remote = remote;
			this.changed = changed;
			this.log = log;
		}

		private static NetworkUser? Payer(Interactor who)
		{
			CharacterBody val = (Object.op_Implicit((Object)(object)who) ? ((Component)who).GetComponent<CharacterBody>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			CharacterMaster master = val.master;
			if (!Object.op_Implicit((Object)(object)master))
			{
				return null;
			}
			return ((IEnumerable<NetworkUser>)NetworkUser.readOnlyInstancesList).FirstOrDefault((Func<NetworkUser, bool>)((NetworkUser user) => Object.op_Implicit((Object)(object)user) && (Object)(object)user.master == (Object)(object)master));
		}

		private bool HasUsed(PurchaseInteraction self, NetworkUser? payer)
		{
			//IL_0018: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)payer))
			{
				return false;
			}
			if (NetworkServer.active)
			{
				return gate.HasUsed(payer.id);
			}
			PhaseMessage phaseMessage = remote();
			NetworkIdentity component = ((Component)self).GetComponent<NetworkIdentity>();
			if (phaseMessage != null && Object.op_Implicit((Object)(object)component))
			{
				uint bazaarRefresherId = phaseMessage.BazaarRefresherId;
				NetworkInstanceId netId = component.netId;
				if (bazaarRefresherId == ((NetworkInstanceId)(ref netId)).Value)
				{
					uint[] bazaarUsedUserIds = phaseMessage.BazaarUsedUserIds;
					netId = ((NetworkBehaviour)payer).netId;
					return bazaarUsedUserIds.Contains(((NetworkInstanceId)(ref netId)).Value);
				}
			}
			return false;
		}

		internal void Enable()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = typeof(ShopTerminalBehavior).GetMethod("UpdatePickupDisplayAndAnimations", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingMethodException("ShopTerminalBehavior.UpdatePickupDisplayAndAnimations");
				updateDisplay = (Action<ShopTerminalBehavior>)methodInfo.CreateDelegate(typeof(Action<ShopTerminalBehavior>));
				ShopTerminalBehavior.GenerateNewPickupServer_bool += new hook_GenerateNewPickupServer_bool(Generate);
				ShopTerminalBehavior.RerollPickup += new hook_RerollPickup(Reroll);
				PurchaseInteraction.Start += new hook_Start(PurchaseStarted);
				PurchaseInteraction.SetAvailable += new hook_SetAvailable(SetAvailable);
				PurchaseInteraction.OnInteractionBegin += new hook_OnInteractionBegin(Purchase);
				PurchaseInteraction.GetInteractability += new hook_GetInteractability(Interactability);
				PurchaseInteraction.GetDisplayName += new hook_GetDisplayName(DisplayName);
				PurchaseInteraction.GetContextString += new hook_GetContextString(Context);
				NetworkUser.DeductLunarCoins += new hook_DeductLunarCoins(Deduct);
				RoR2Application.onFixedUpdate += UpdateSweep;
				Ready = true;
			}
			catch (Exception ex)
			{
				Dispose();
				log.LogError((object)("F04/F05 unavailable; vanilla Bazaar retained: " + ex));
			}
		}

		internal void BeginRun(ulong runSeed)
		{
			ResetVisit();
			seed = runSeed;
			visits = 0u;
		}

		internal void ResetVisit()
		{
			if (pending != null)
			{
				pending.Cancelled = true;
			}
			sweeping = null;
			root = null;
			refresher = null;
			gate.Reset();
			poolWarning = false;
			refreshUnavailable = false;
			visitInitialized = false;
			failures.Clear();
		}

		private static bool ShopRoot(Transform? candidate)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)candidate != (Object)null && ((Object)candidate).name == "LunarShop")
			{
				Scene scene = ((Component)candidate).gameObject.scene;
				if (((Scene)(ref scene)).name == "bazaar" && Vector3.SqrMagnitude(candidate.localPosition - new Vector3(11.239998f, -7.76f, -10.86f)) < 0.01f && Quaternion.Angle(candidate.localRotation, new Quaternion(0f, 0.14248678f, 0f, 0.9897967f)) < 2f)
				{
					return Vector3.SqrMagnitude(candidate.localScale - Vector3.one) < 0.0001f;
				}
			}
			return false;
		}

		private static bool Refresher(PurchaseInteraction purchase)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)purchase != (Object)null && purchase.displayNameToken == "LUNAR_REROLL_NAME" && ShopRoot(((Component)purchase).transform.parent))
			{
				return Vector3.SqrMagnitude(((Component)purchase).transform.localPosition - new Vector3(-5.551644f, -7.301207f, -10.852246f)) < 0.01f;
			}
			return false;
		}

		private static bool Bud(ShopTerminalBehavior terminal)
		{
			if ((Object)(object)terminal != (Object)null && ShopRoot(((Component)terminal).transform.parent))
			{
				return BazaarLayout.Slot(((Component)terminal).transform) >= 0;
			}
			return false;
		}

		private bool RefreshActive(PurchaseInteraction purchase)
		{
			PhaseSettings phaseSettings = settings();
			if (phaseSettings != null && phaseSettings.BazaarRefresh && Refresher(purchase))
			{
				if (NetworkServer.active)
				{
					return !refreshUnavailable;
				}
				return true;
			}
			return false;
		}

		private void EnsureVisit(Transform shop)
		{
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if (!ShopRoot(shop))
			{
				throw new InvalidOperationException("Bazaar layout root differs from inspected scene.");
			}
			HashSet<int> hashSet = new HashSet<int>();
			ShopTerminalBehavior[] componentsInChildren = ((Component)shop).GetComponentsInChildren<ShopTerminalBehavior>(true);
			foreach (ShopTerminalBehavior obj in componentsInChildren)
			{
				int num = BazaarLayout.Slot(((Component)obj).transform);
				PurchaseInteraction component = ((Component)obj).GetComponent<PurchaseInteraction>();
				if (num < 0 && Object.op_Implicit((Object)(object)component) && component.displayNameToken == "LUNAR_TERMINAL_NAME")
				{
					throw new InvalidOperationException("Lunar merchandise layout moved or gained unclassified slots; re-audit required.");
				}
				if (num >= 0 && !hashSet.Add(num))
				{
					throw new InvalidOperationException("Duplicate lunar merchandise slot.");
				}
			}
			if (!((Object)(object)root == (Object)(object)shop))
			{
				if (visitInitialized)
				{
					throw new InvalidOperationException("A second/replaced lunar shop root cannot reset this visit's player uses.");
				}
				root = shop;
				visitInitialized = true;
				visits++;
				gate.Reset();
				heresy = BazaarRandom.ForVisit(seed, visits, heresy: true);
				refresh = BazaarRandom.ForVisit(seed, visits, heresy: false);
				log.LogInfo((object)$"Bazaar visit {visits}: mapped left bud at local {BazaarLayout.Positions[0]}; live screenshot confirmation remains pending.");
			}
		}

		private void Generate(orig_GenerateNewPickupServer_bool orig, ShopTerminalBehavior self, bool hidden)
		{
			//IL_0066: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			PhaseSettings phaseSettings = settings();
			if (!NetworkServer.active || phaseSettings == null || !phaseSettings.Heresy || !Bud(self) || BazaarLayout.Slot(((Component)self).transform) != 0 || self.NetworkhasBeenPurchased)
			{
				orig.Invoke(self, hidden);
				return;
			}
			try
			{
				EnsureVisit(((Component)self).transform.parent);
				BazaarRandom random = heresy;
				PickupIndex val = ChooseHeresy(phaseSettings.HeresyProbability, ref random);
				self.SetPickup(new UniquePickup(val), hidden);
				heresy = random;
			}
			catch (Exception error)
			{
				Failure("F05 stock roll failed; using vanilla stock", error);
				orig.Invoke(self, hidden);
			}
		}

		private void Reroll(orig_RerollPickup orig, ShopTerminalBehavior self)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Generate((orig_GenerateNewPickupServer_bool)delegate(ShopTerminalBehavior terminal, bool hidden)
			{
				orig.Invoke(terminal);
			}, self, self.pickupIndexIsHidden);
		}

		private PickupIndex ChooseHeresy(float probability, ref BazaarRandom random)
		{
			//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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Invalid comparison between Unknown and I4
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Run.instance))
			{
				throw new InvalidOperationException("No active run.");
			}
			HashSet<PickupIndex> targets = new HashSet<PickupIndex>();
			string[] array = new string[4] { "LunarPrimaryReplacement", "LunarSecondaryReplacement", "LunarUtilityReplacement", "LunarSpecialReplacement" };
			for (int i = 0; i < array.Length; i++)
			{
				ItemIndex val = ItemCatalog.FindItemIndex(array[i]);
				if ((int)val != -1)
				{
					targets.Add(PickupCatalog.FindPickupIndex(val));
				}
			}
			PickupIndex[] source = Run.instance.availableLunarCombinedDropList.Distinct().ToArray();
			PickupIndex[] array2 = source.Where(targets.Contains).ToArray();
			PickupIndex[] array3 = source.Where((PickupIndex pickup) => !targets.Contains(pickup)).ToArray();
			if ((array2.Length == 0 || array3.Length == 0) && !poolWarning)
			{
				poolWarning = true;
				log.LogWarning((object)"F05: one lunar branch has no eligible stock; using the available branch. Exact configured probability requires both pools.");
			}
			return HeresyRules.Choose(array2, array3, probability, ref random);
		}

		private void PurchaseStarted(orig_Start orig, PurchaseInteraction self)
		{
			orig.Invoke(self);
			if (NetworkServer.active && RefreshActive(self))
			{
				try
				{
					RememberRefresher(self);
					EnsureVisit(((Component)self).transform.parent);
					self.Networkcost = 3;
					self.SetAvailable(RefresherAvailable());
				}
				catch (Exception error)
				{
					DisableRefresh(self, error);
				}
			}
		}

		private bool RefresherAvailable()
		{
			if (!gate.Busy && sweeping == null)
			{
				return gate.HasRemainingUse(from user in NetworkUser.readOnlyInstancesList
					where Object.op_Implicit((Object)(object)user)
					select user.id);
			}
			return false;
		}

		private void SetAvailable(orig_SetAvailable orig, PurchaseInteraction self, bool available)
		{
			if (NetworkServer.active && RefreshActive(self))
			{
				available = RefresherAvailable();
			}
			orig.Invoke(self, available);
		}

		private void RememberRefresher(PurchaseInteraction self)
		{
			if ((Object)(object)refresher != (Object)(object)self)
			{
				refresher = self;
				originalRefresherCost = self.cost;
			}
		}

		private void DisableRefresh(PurchaseInteraction self, Exception error)
		{
			refreshUnavailable = true;
			if ((Object)(object)refresher == (Object)(object)self)
			{
				self.Networkcost = originalRefresherCost;
			}
			Failure("F04 layout unavailable; vanilla refresher retained for this visit", error);
		}

		private void Purchase(orig_OnInteractionBegin orig, PurchaseInteraction self, Interactor activator)
		{
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: 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_03a6: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Invalid comparison between Unknown and I4
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Invalid comparison between Unknown and I4
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			PhaseSettings phaseSettings = settings();
			if (!NetworkServer.active || phaseSettings == null || !phaseSettings.BazaarRefresh || refreshUnavailable)
			{
				orig.Invoke(self, activator);
				return;
			}
			ShopTerminalBehavior component = ((Component)self).GetComponent<ShopTerminalBehavior>();
			if (gate.Busy && Object.op_Implicit((Object)(object)component) && Bud(component))
			{
				return;
			}
			if (!Refresher(self))
			{
				orig.Invoke(self, activator);
				return;
			}
			try
			{
				RememberRefresher(self);
				EnsureVisit(((Component)self).transform.parent);
			}
			catch (Exception error)
			{
				DisableRefresh(self, error);
				orig.Invoke(self, activator);
				return;
			}
			if (gate.Busy || sweeping != null || !self.available || !Object.op_Implicit((Object)(object)activator))
			{
				return;
			}
			self.Networkcost = 3;
			if ((int)self.costType != 3 || !self.CanBeAffordedByInteractor(activator) || (int)self.GetInteractability(activator) != 2)
			{
				return;
			}
			NetworkUser val = Payer(activator);
			if ((Object)(object)val == (Object)null || !gate.TryBegin(val.id))
			{
				return;
			}
			RefreshPlan plan = new RefreshPlan(val, heresy, refresh);
			PurchaseEvent onPurchase = self.onPurchase;
			UnityAction<Interactor> val2 = delegate
			{
				plan.CallbackReached = true;
			};
			bool flag = false;
			try
			{
				Prepare(plan, phaseSettings);
				if (!rerollEffect.HasValue)
				{
					rerollEffect = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/LunarRecycler/LunarRerollEffect.prefab");
				}
				if (!sweepEffect.HasValue)
				{
					sweepEffect = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/LunarRecycler/LunarRecyclerFX.prefab");
				}
				plan.SweepIndex = ResolveEffect(sweepEffect.Value.WaitForCompletion(), "LunarRecyclerFX", "Play_lunar_reroller_activate");
				plan.SlotIndex = ResolveEffect(rerollEffect.Value.WaitForCompletion(), "LunarRerollEffect", "Play_lunar_reroller_item_change");
				Transform val3 = ((Component)self).transform.Find("UseEffectRoot");
				if (!Object.op_Implicit((Object)(object)val3))
				{
					throw new InvalidOperationException("Native lunar recycler effect origin is missing.");
				}
				plan.EffectOrigin = val3.position;
				Apply(plan);
				self.onPurchase = new PurchaseEvent();
				((UnityEvent<Interactor>)(object)self.onPurchase).AddListener(val2);
				pending = plan;
				try
				{
					orig.Invoke(self, activator);
				}
				catch (Exception ex)
				{
					if (!plan.CallbackReached || plan.Paid != 3)
					{
						throw;
					}
					log.LogError((object)("F04 purchase completed; a downstream native/mod callback failed: " + ex));
				}
				if (!plan.CallbackReached || plan.Paid != 3 || plan.Cancelled)
				{
					throw new InvalidOperationException("Native purchase did not complete an exact three-coin transaction.");
				}
				flag = true;
			}
			catch (Exception error2)
			{
				Failure("F04 refresh rolled back", error2);
			}
			finally
			{
				pending = null;
				if ((Object)(object)self != (Object)null)
				{
					self.onPurchase = onPurchase;
				}
				if (flag)
				{
					heresy = plan.Heresy;
					refresh = plan.Refresh;
					if (gate.Busy)
					{
						gate.Finish(success: true);
					}
					if ((Object)(object)self != (Object)null)
					{
						self.Networkcost = 3;
					}
					sweeping = plan;
					sweepStarted = Time.fixedTime;
					if ((Object)(object)self != (Object)null)
					{
						self.SetAvailable(false);
					}
					EffectManager.SpawnEffect(plan.SweepIndex, new EffectData
					{
						origin = plan.EffectOrigin
					}, true);
					changed();
					log.LogInfo((object)"F04: refreshed all five lunar slots; charged the interacting player 3 Lunar Coins; that player's visit use exhausted.");
				}
				else
				{
					try
					{
						Rollback(plan);
						if (plan.Paid != 0 && (Object)(object)plan.Payer != (Object)null)
						{
							plan.Payer.AwardLunarCoins(plan.Paid);
						}
					}
					catch (Exception ex2)
					{
						log.LogError((object)("F04 refund/recovery failed; inspect the player's coins and stock: " + ex2));
					}
					finally
					{
						if (gate.Busy)
						{
							gate.Finish(success: false);
						}
					}
				}
			}
		}

		private static EffectIndex ResolveEffect(GameObject prefab, string name, string sound)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)prefab) || ((Object)prefab).name != name)
			{
				throw new InvalidOperationException("Unexpected Bazaar effect asset: " + name);
			}
			EffectIndex val = EffectCatalog.FindEffectIndex(name);
			EffectDef effectDef = EffectCatalog.GetEffectDef(val);
			if (effectDef == null || effectDef.prefabName != name || !Object.op_Implicit((Object)(object)effectDef.prefab) || effectDef.spawnSoundEventName != sound)
			{
				throw new InvalidOperationException("Native Bazaar effect or sound is unavailable in the live catalog: " + name);
			}
			return val;
		}

		private void UpdateSweep()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			if (!NetworkServer.active)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)refresher) && RefreshActive(refresher) && refresher.available != RefresherAvailable())
			{
				refresher.SetAvailable(RefresherAvailable());
			}
			if (sweeping == null)
			{
				return;
			}
			RefreshPlan refreshPlan = sweeping;
			float num = Time.fixedTime - sweepStarted;
			for (int i = 0; i < refreshPlan.Slots.Count; i++)
			{
				SlotSnapshot slotSnapshot = refreshPlan.Slots[i];
				if (!slotSnapshot.Revealed && !(num < 0.9f - 0.1f * (float)i))
				{
					slotSnapshot.Revealed = true;
					if (Object.op_Implicit((Object)(object)slotSnapshot.Terminal) && Object.op_Implicit((Object)(object)slotSnapshot.Purchase))
					{
						slotSnapshot.Terminal.SetPickup(slotSnapshot.Offer, false);
						slotSnapshot.Terminal.SetHasBeenPurchased(false);
						updateDisplay(slotSnapshot.Terminal);
						slotSnapshot.Purchase.SetAvailable(true);
						EffectManager.SpawnEffect(refreshPlan.SlotIndex, new EffectData
						{
							origin = slotSnapshot.EffectOrigin
						}, true);
					}
				}
			}
			if (!(num < 1f))
			{
				sweeping = null;
				if (Object.op_Implicit((Object)(object)refresher))
				{
					refresher.SetAvailable(RefresherAvailable());
				}
			}
		}

		private void Deduct(orig_DeductLunarCoins orig, NetworkUser self, uint amount)
		{
			orig.Invoke(self, amount);
			if (pending != null && (Object)(object)pending.Payer == (Object)(object)self && !pending.CallbackReached)
			{
				pending.Paid = checked(pending.Paid + amount);
			}
		}

		private void Prepare(RefreshPlan plan, PhaseSettings active)
		{
			//IL_0041: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Invalid comparison between Unknown and I4
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: 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_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: 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)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				throw new InvalidOperationException("Bazaar visit ended.");
			}
			if (!terminalAsset.HasValue)
			{
				terminalAsset = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/LunarShopTerminal/LunarShopTerminal.prefab");
			}
			GameObject val = terminalAsset.Value.WaitForCompletion();
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Vanilla lunar terminal prefab is unavailable.");
			}
			PurchaseInteraction component = val.GetComponent<PurchaseInteraction>();
			if (!Object.op_Implicit((Object)(object)component) || (int)component.costType != 3)
			{
				throw new InvalidOperationException("Unexpected lunar terminal currency.");
			}
			ShopTerminalBehavior[] array = (ShopTerminalBehavior[])(object)new ShopTerminalBehavior[5];
			ShopTerminalBehavior[] componentsInChildren = ((Component)root).GetComponentsInChildren<ShopTerminalBehavior>(true);
			foreach (ShopTerminalBehavior val2 in componentsInChildren)
			{
				int num = BazaarLayout.Slot(((Component)val2).transform);
				if (num >= 0)
				{
					if ((Object)(object)array[num] != (Object)null)
					{
						throw new InvalidOperationException("Duplicate lunar merchandise slot.");
					}
					array[num] = val2;
				}
			}
			for (int j = 0; j < array.Length; j++)
			{
				ShopTerminalBehavior val3 = array[j];
				bool flag = (Object)(object)val3 == (Object)null;
				if (flag)
				{
					GameObject val4 = Object.Instantiate<GameObject>(val, root);
					plan.Created.Add(val4);
					val4.transform.localPosition = BazaarLayout.Positions[j];
					val4.transform.localRotation = BazaarLayout.Rotations[j];
					val3 = val4.GetComponent<ShopTerminalBehavior>();
					if ((Object)(object)val3 == (Object)null)
					{
						throw new InvalidOperationException("Replacement has no stock component.");
					}
					val3.selfGeneratePickup = false;
				}
				PurchaseInteraction component2 = ((Component)val3).GetComponent<PurchaseInteraction>();
				if (!Object.op_Implicit((Object)(object)component2) || (int)component2.costType != 3)
				{
					throw new InvalidOperationException("Invalid lunar purchase component.");
				}
				SlotSnapshot slotSnapshot = new SlotSnapshot(val3, component2, flag, component.cost);
				plan.Slots.Add(slotSnapshot);
				if (active.Heresy && j == 0)
				{
					slotSnapshot.Offer = new UniquePickup(ChooseHeresy(active.HeresyProbability, ref plan.Heresy));
				}
				else
				{
					if (!Object.op_Implicit((Object)(object)val3.dropTable) || val3.dropTable.GetPickupCount() == 0)
					{
						throw new InvalidOperationException("No eligible normal lunar stock.");
					}
					Xoroshiro128Plus val5 = new Xoroshiro128Plus(plan.Refresh.Next());
					slotSnapshot.Offer = (UniquePickup)((!((UniquePickup)(ref slotSnapshot.Pickup)).isValid) ? val3.dropTable.GeneratePickup(val5) : (((??)ShopTerminalBehavior.GenerateReroll(val3.dropTable, val5, slotSnapshot.Pickup)) ?? val3.dropTable.GeneratePickup(val5)));
				}
				if (!((UniquePickup)(ref slotSnapshot.Offer)).isValid || !Run.instance.availableLunarCombinedDropList.Contains(slotSnapshot.Offer.pickupIndex))
				{
					throw new InvalidOperationException("Offer is unavailable for this run.");
				}
			}
		}

		private static void Apply(RefreshPlan plan)
		{
			foreach (SlotSnapshot slot in plan.Slots)
			{
				slot.Terminal.SetHasBeenPurchased(false);
				slot.Purchase.Networkcost = slot.NormalCost;
				slot.Purchase.SetAvailable(false);
				if (slot.Created)
				{
					NetworkServer.Spawn(((Component)slot.Terminal).gameObject);
				}
				if (slot.Terminal.NetworkhasBeenPurchased)
				{
					throw new InvalidOperationException("A lunar slot could not be restored.");
				}
			}
		}

		private void Rollback(RefreshPlan plan)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in plan.Created)
			{
				try
				{
					if (Object.op_Implicit((Object)(object)item))
					{
						item.transform.SetParent((Transform)null, true);
						item.SetActive(false);
						NetworkIdentity component = item.GetComponent<NetworkIdentity>();
						if (!Object.op_Implicit((Object)(object)component))
						{
							goto IL_005b;
						}
						NetworkInstanceId netId = component.netId;
						if (((NetworkInstanceId)(ref netId)).Value == 0)
						{
							goto IL_005b;
						}
						NetworkServer.Destroy(item);
					}
					goto end_IL_0016;
					IL_005b:
					Object.Destroy((Object)(object)item);
					end_IL_0016:;
				}
				catch (Exception ex)
				{
					log.LogError((object)("F04 rollback could not remove a replacement slot: " + ex));
				}
			}
			foreach (SlotSnapshot slot in plan.Slots)
			{
				try
				{
					if (!slot.Created && !((Object)(object)slot.Terminal == (Object)null))
					{
						slot.Terminal.SetPickup(slot.Pickup, slot.Hidden);
						slot.Terminal.SetHasBeenPurchased(slot.Purchased);
						slot.Purchase.Networkcost = slot.Cost;
						slot.Purchase.SetAvailable(slot.Available);
					}
				}
				catch (Exception ex2)
				{
					log.LogError((object)("F04 rollback could not restore a lunar slot: " + ex2));
				}
			}
		}

		private Interactability Interactability(orig_GetInteractability orig, PurchaseInteraction self, Interactor who)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (RefreshActive(self) && (!self.available || HasUsed(self, Payer(who)) || (NetworkServer.active && (gate.Busy || sweeping != null))))
			{
				return (Interactability)0;
			}
			return orig.Invoke(self, who);
		}

		private string DisplayName(orig_GetDisplayName orig, PurchaseInteraction self)
		{
			if (!RefreshActive(self) || self.cost != 3)
			{
				return orig.Invoke(self);
			}
			return "Refresh all lunar stock";
		}

		private string Context(orig_GetContextString orig, PurchaseInteraction self, Interactor who)
		{
			if (!RefreshActive(self) || self.cost != 3)
			{
				return orig.Invoke(self, who);
			}
			if (!HasUsed(self, Payer(who)))
			{
				return "Refresh all lunar stock — 3 Lunar Coins — 1 use per player per visit";
			}
			return "Refresh all lunar stock — your use is exhausted";
		}

		private void Failure(string message, Exception error)
		{
			if (failures.Add(message))
			{
				log.LogError((object)(message + ": " + error));
			}
		}

		public void Dispose()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00bd: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			ShopTerminalBehavior.GenerateNewPickupServer_bool -= new hook_GenerateNewPickupServer_bool(Generate);
			ShopTerminalBehavior.RerollPickup -= new hook_RerollPickup(Reroll);
			PurchaseInteraction.Start -= new hook_Start(PurchaseStarted);
			PurchaseInteraction.SetAvailable -= new hook_SetAvailable(SetAvailable);
			PurchaseInteraction.OnInteractionBegin -= new hook_OnInteractionBegin(Purchase);
			PurchaseInteraction.GetInteractability -= new hook_GetInteractability(Interactability);
			PurchaseInteraction.GetDisplayName -= new hook_GetDisplayName(DisplayName);
			PurchaseInteraction.GetContextString -= new hook_GetContextString(Context);
			NetworkUser.DeductLunarCoins -= new hook_DeductLunarCoins(Deduct);
			RoR2Application.onFixedUpdate -= UpdateSweep;
			if (rerollEffect.HasValue)
			{
				Addressables.Release<GameObject>(rerollEffect.Value);
				rerollEffect = null;
			}
			if (sweepEffect.HasValue)
			{
				Addressables.Release<GameObject>(sweepEffect.Value);
				sweepEffect = null;
			}
			if (terminalAsset.HasValue)
			{
				Addressables.Release<GameObject>(terminalAsset.Value);
				terminalAsset = null;
			}
			ResetVisit();
			Ready = false;
		}
	}
	internal static class BazaarLayout
	{
		internal static readonly Vector3[] Positions = (Vector3[])(object)new Vector3[5]
		{
			new Vector3(4.398342f, -6.118f, 0.959436f),
			new Vector3(0.865416f, -6.117998f, 0.413354f),
			new Vector3(-1.130224f, -6.117998f, -2.028714f),
			new Vector3(-0.873811f, -6.117998f, -4.964099f),
			new Vector3(1.362406f, -6.117998f, -7.57685f)
		};

		internal static readonly Quaternion[] Rotations = (Quaternion[])(object)new Quaternion[5]
		{
			new Quaternion(0f, -0.2051369f, 0f, 0.97873336f),
			new Quaternion(0f, -0.39634863f, 0f, 0.9181001f),
			new Quaternion(0f, -0.5726467f, 0f, 0.8198023f),
			new Quaternion(0f, -0.85562456f, 0f, 0.5175969f),
			new Quaternion(0f, -0.98170954f, 0f, 0.19038475f)
		};

		internal static int Slot(Transform terminal)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			if (!Object.op_Implicit((Object)(object)terminal.parent) || ((Object)terminal.parent).name != "LunarShop")
			{
				return -1;
			}
			int num = -1;
			for (int i = 0; i < Positions.Length; i++)
			{
				if (Vector3.SqrMagnitude(terminal.localPosition - Positions[i]) < 0.01f && Quaternion.Angle(terminal.localRotation, Rotations[i]) < 2f)
				{
					if (num >= 0)
					{
						throw new InvalidOperationException("Ambiguous Bazaar slot identity.");
					}
					num = i;
				}
			}
			return num;
		}
	}
	internal sealed class DepartureFeature : IDisposable
	{
		private readonly Func<PhaseSettings?> settings;

		private readonly ManualLogSource log;

		private readonly DepartureGate gate = new DepartureGate();

		private FieldInfo? standardState;

		private FieldInfo? colossusState;

		private MonoBehaviour? owner;

		private GameObject? scannerPrefab;

		private bool scannerFailureLogged;

		internal bool Ready { get; private set; }

		internal bool Committed => gate.Committed;

		private static FieldInfo StateField(Type type)
		{
			return type.GetField("exitState", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException(type.FullName, "exitState");
		}

		internal DepartureFeature(Func<PhaseSettings?> settings, ManualLogSource log)
		{
			this.settings = settings;
			this.log = log;
		}

		internal void Enable()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			try
			{
				standardState = StateField(typeof(SceneExitController));
				colossusState = StateField(typeof(SceneExitControllerColossusPortal));
				SceneExitController.Begin += new hook_Begin(Begin);
				SceneExitController.UpdateServer += new hook_UpdateServer(Update);
				SceneExitControllerColossusPortal.Begin += new hook_Begin(BeginColossus);
				SceneExitControllerColossusPortal.UpdateServer += new hook_UpdateServer(UpdateColossus);
				Ready = true;
			}
			catch (Exception ex)
			{
				Dispose();
				log.LogError((object)("F01/F02 departure tracking unavailable; vanilla exits retained: " + ex));
			}
		}

		private void Begin(orig_Begin orig, SceneExitController self)
		{
			HandleBegin((MonoBehaviour)(object)self, standardState, delegate
			{
				orig.Invoke(self);
			});
		}

		private void BeginColossus(orig_Begin orig, SceneExitControllerColossusPortal self)
		{
			HandleBegin((MonoBehaviour)(object)self, colossusState, delegate
			{
				orig.Invoke(self);
			});
		}

		private void HandleBegin(MonoBehaviour self, FieldInfo state, Action original)
		{
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			PhaseSettings phaseSettings = settings();
			if (!NetworkServer.active || phaseSettings == null || (!phaseSettings.Income && !phaseSettings.Scanner))
			{
				original();
			}
			else
			{
				if (gate.Committed)
				{
					return;
				}
				if (Convert.ToInt32(state.GetValue(self)) != 0)
				{
					original();
					return;
				}
				SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
				bool num = phaseSettings.Scanner && Object.op_Implicit((Object)(object)sceneDefForCurrentScene) && GameplayRules.CanScanDeparture(sceneDefForCurrentScene.cachedName) && Object.op_Implicit((Object)(object)Run.instance) && (((object)Run.instance).GetType() == typeof(Run) || Run.instance is EclipseRun);
				gate.TryCommit(0.0);
				owner = self;
				float num2 = 0f;
				if (num)
				{
					try
					{
						if (!Object.op_Implicit((Object)(object)scannerPrefab))
						{
							scannerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/ChestScanner");
						}
						if (!Object.op_Implicit((Object)(object)scannerPrefab))
						{
							throw new InvalidOperationException("Vanilla ChestScanner prefab was not found.");
						}
						NetworkServer.Spawn(Object.Instantiate<GameObject>(scannerPrefab, ((Component)self).transform.position, Quaternion.identity));
						num2 = phaseSettings.ScanWindow;
						log.LogInfo((object)$"F02: departure scan committed; minimum reveal window {num2:0.##}s.");
					}
					catch (Exception ex)
					{
						if (!scannerFailureLogged)
						{
							scannerFailureLogged = true;
							log.LogError((object)("F02 scanner unavailable; departure proceeds normally: " + ex));
						}
					}
				}
				gate.Reset();
				gate.TryCommit(num2);
				original();
			}
		}

		private bool Holding(MonoBehaviour self)
		{
			if ((Object)(object)owner == (Object)(object)self)
			{
				return gate.Remaining > 0.0;
			}
			return false;
		}

		private void Update(orig_UpdateServer orig, SceneExitController self)
		{
			if (!Holding((MonoBehaviour)(object)self))
			{
				orig.Invoke(self);
			}
		}

		private void UpdateColossus(orig_UpdateServer orig, SceneExitControllerColossusPortal self)
		{
			if (!Holding((MonoBehaviour)(object)self))
			{
				orig.Invoke(self);
			}
		}

		internal void Tick(float delta)
		{
			gate.Tick(delta);
		}

		internal void Reset()
		{
			owner = null;
			gate.Reset();
		}

		public void Dispose()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			SceneExitController.Begin -= new hook_Begin(Begin);
			SceneExitController.UpdateServer -= new hook_UpdateServer(Update);
			SceneExitControllerColossusPortal.Begin -= new hook_Begin(BeginColossus);
			SceneExitControllerColossusPortal.UpdateServer -= new hook_UpdateServer(UpdateColossus);
			Ready = false;
			Reset();
		}
	}
	internal sealed class EclipseAccessFeature : IDisposable
	{
		private sealed class RunState
		{
			public readonly EclipseAwardGate<(UserProfile, SurvivorDef)> Awards = new EclipseAwardGate<(UserProfile, SurvivorDef)>();
		}

		private readonly ManualLogSource log;

		private readonly EclipseBadgeIcons badgeIcons;

		private readonly HashSet<EclipseDifficultyIcon> difficultyIcons = new HashSet<EclipseDifficultyIcon>();

		private readonly ConditionalWeakTable<EclipseRun, RunState> runs = new ConditionalWeakTable<EclipseRun, RunState>();

		private readonly Dictionary<EclipseRunScreenController, EclipseOverviewView> views = new Dictionary<EclipseRunScreenController, EclipseOverviewView>();

		private readonly HashSet<EclipseLobbyNote> notes = new HashSet<EclipseLobbyNote>();

		private Func<SurvivorDef, List<UnlockableDef>>? unlocksForSurvivor;

		private Action<PreGameController>? recalculate;

		private PreGameController? lastLobby;

		private int lastLobbyLevel;

		private bool uiWarning;

		internal bool Ready { get; private set; }

		internal static bool IsEclipseLobby
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)PreGameController.instance))
				{
					return GameModeCatalog.GetGameModePrefabComponent(PreGameController.instance.gameModeIndex) is EclipseRun;
				}
				return false;
			}
		}

		internal EclipseAccessFeature(ManualLogSource log)
		{
			this.log = log;
			badgeIcons = new EclipseBadgeIcons(log);
		}

		internal void Enable()
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = typeof(EclipseRun).GetMethod("GetEclipseLevelUnlockablesForSurvivor", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException("Eclipse survivor unlock list");
				unlocksForSurvivor = (Func<SurvivorDef, List<UnlockableDef>>)methodInfo.CreateDelegate(typeof(Func<SurvivorDef, List<UnlockableDef>>));
				MethodInfo methodInfo2 = typeof(PreGameController).GetMethod("RecalculateModifierAvailability", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMethodException("Lobby modifier recalculation");
				recalculate = (Action<PreGameController>)methodInfo2.CreateDelegate(typeof(Action<PreGameController>));
				EclipseRun.OnClientGameOver += new Manipulator(PatchAward);
				EclipseRun.OverrideRuleChoices += new Manipulator(PatchSelection);
				EclipseRun.OverrideRuleChoices += new hook_OverrideRuleChoices(Choices);
				EclipseRunScreenController.UpdateDisplayedSurvivor += new hook_UpdateDisplayedSurvivor(Display);
				EclipseRunScreenController.OnDisable += new hook_OnDisable(Hide);
				RuleCategoryController.SetData += new hook_SetData(Category);
				PreGameController.StartRun += new hook_StartRun(StartRun);
				RuleChoiceController.UpdateChoiceDisplay += new hook_UpdateChoiceDisplay(ChoiceDisplay);
				Ready = true;
			}
			catch (Exception ex)
			{
				Dispose();
				log.LogError((object)("Eclipse access unavailable; native selection/progression retained: " + ex));
			}
		}

		private void PatchSelection(ILContext il)
		{
			EclipseAccessPatchEmitter.Selection(il, delegate(ILCursor cursor)
			{
				cursor.EmitDelegate<Func<int, EclipseRun, int>>((Func<int, EclipseRun, int>)delegate(int native, EclipseRun run)
				{
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					int selectedLevel = (Object.op_Implicit((Object)(object)PreGameController.instance) ? (PreGameController.instance.readOnlyRuleBook.FindDifficulty() - 3 + 1) : 0);
					return EclipseAccessRules.LobbyPenaltyLevel(native, selectedLevel);
				});
			});
		}

		private void Choices(orig_OverrideRuleChoices orig, EclipseRun self, RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong seed)
		{
			//IL_002c: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected I4, but got Unknown
			orig.Invoke(self, mustInclude, mustExclude, seed);
			foreach (RuleChoiceDef choice in RuleCatalog.FindRuleDef("Difficulty").choices)
			{
				bool flag = EclipseAccessRules.IsSelectableLevel(choice.difficultyIndex - 3 + 1);
				((SerializableBitArray)mustInclude)[choice.globalIndex] = flag;
				((SerializableBitArray)mustExclude)[choice.globalIndex] = !flag;
			}
		}

		private void PatchAward(ILContext il)
		{
			EclipseAccessPatchEmitter.Award(il, delegate(ILCursor cursor)
			{
				cursor.EmitDelegate<Action<UserProfile, UnlockableDef, SurvivorDef, EclipseRun>>((Action<UserProfile, UnlockableDef, SurvivorDef, EclipseRun>)Award);
			});
		}

		private void Award(UserProfile profile, UnlockableDef nativeAward, SurvivorDef survivor, EclipseRun run)
		{
			if (profile == null || !Object.op_Implicit((Object)(object)survivor) || !Object.op_Implicit((Object)(object)nativeAward) || !Object.op_Implicit((Object)(object)run))
			{
				return;
			}
			RunState value = runs.GetValue(run, (EclipseRun _) => new RunState());
			(UserProfile, SurvivorDef) identity = (profile, survivor);
			List<UnlockableDef> list = unlocksForSurvivor(survivor);
			int num = list.IndexOf(nativeAward) + EclipseRun.minUnlockableEclipseLevel - 1;
			if (!list.Contains(nativeAward))
			{
				log.LogWarning((object)"Unknown Eclipse award; no progression was granted.");
				return;
			}
			int num2 = 0;
			foreach (UnlockableDef item in list)
			{
				if (!Object.op_Implicit((Object)(object)item) || !profile.HasUnlockable(item))
				{
					break;
				}
				num2++;
			}
			if (value.Awards.TryAward(identity, num2, num, won: true, out var after))
			{
				int num3 = after + 1 - EclipseRun.minUnlockableEclipseLevel;
				if (num3 < 0 || num3 >= list.Count || !Object.op_Implicit((Object)(object)list[num3]))
				{
					log.LogWarning((object)"Next Eclipse badge is unavailable; no progression was granted.");
					return;
				}
				profile.GrantUnlockable(list[num3]);
				log.LogInfo((object)$"Eclipse victory at E{num}: this survivor's progress advanced E{num2} -> E{after}.");
			}
		}

		private void Display(orig_UpdateDisplayedSurvivor orig, EclipseRunScreenController self)
		{
			orig.Invoke(self);
			if (!Ready || views.ContainsKey(self))
			{
				return;
			}
			try
			{
				views.Add(self, new EclipseOverviewView(self));
			}
			catch (Exception ex)
			{
				if (!uiWarning)
				{
					uiWarning = true;
					log.LogError((object)("Eclipse overview could not be built: " + ex));
				}
			}
		}

		private void Hide(orig_OnDisable orig, EclipseRunScreenController self)
		{
			if (views.TryGetValue(self, out EclipseOverviewView value))
			{
				views.Remove(self);
				value.Dispose();
			}
			orig.Invoke(self);
		}

		private void Category(orig_SetData orig, RuleCategoryController self, RuleCategoryDef category, RuleChoiceMask availability, RuleBook book)
		{
			orig.Invoke(self, category, availability, book);
			EclipseLobbyNote eclipseLobbyNote = ((Component)self).GetComponent<EclipseLobbyNote>();
			bool flag = Ready && IsEclipseLobby && category.children.Any((RuleDef rule) => rule.globalName == "Difficulty");
			if (flag && !Object.op_Implicit((Object)(object)eclipseLobbyNote))
			{
				eclipseLobbyNote = ((Component)self).gameObject.AddComponent<EclipseLobbyNote>();
				notes.Add(eclipseLobbyNote);
			}
			if (Object.op_Implicit((Object)(object)eclipseLobbyNote))
			{
				eclipseLobbyNote.Configure(flag ? self : null);
			}
		}

		private void ChoiceDisplay(orig_UpdateChoiceDisplay orig, RuleChoiceController self, RuleChoiceDef choice)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			orig.Invoke(self, choice);
			EclipseDifficultyIcon eclipseDifficultyIcon = ((Component)self).GetComponent<EclipseDifficultyIcon>();
			if (choice == null)
			{
				if (Object.op_Implicit((Object)(object)eclipseDifficultyIcon))
				{
					eclipseDifficultyIcon.Clear();
				}
				return;
			}
			int level = choice.difficultyIndex - 3 + 1;
			if (!Ready || !IsEclipseLobby || !EclipseAccessRules.IsSelectableLevel(level))
			{
				if (Object.op_Implicit((Object)(object)eclipseDifficultyIcon))
				{
					eclipseDifficultyIcon.Clear();
				}
				return;
			}
			if (!Object.op_Implicit((Object)(object)eclipseDifficultyIcon))
			{
				eclipseDifficultyIcon = ((Component)self).gameObject.AddComponent<EclipseDifficultyIcon>();
				difficultyIcons.Add(eclipseDifficultyIcon);
			}
			eclipseDifficultyIcon.Configure(self, choice, badgeIcons);
		}

		private void StartRun(orig_StartRun orig, PreGameController self)
		{
			if (Ready && NetworkServer.active && IsEclipseLobby)
			{
				recalculate(self);
			}
			orig.Invoke(self);
		}

		internal void Tick()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected I4, but got Unknown
			if (!Ready)
			{
				return;
			}
			foreach (KeyValuePair<EclipseRunScreenController, EclipseOverviewView> view in views)
			{
				if (!Object.op_Implicit((Object)(object)view.Key) || !((Behaviour)view.Key).isActiveAndEnabled)
				{
					continue;
				}
				try
				{
					view.Value.Tick();
				}
				catch (Exception ex)
				{
					view.Value.Dispose();
					if (!uiWarning)
					{
						uiWarning = true;
						log.LogError((object)("Eclipse overview update failed; native layout restored: " + ex));
					}
				}
			}
			PreGameController instance = PreGameController.instance;
			if (!NetworkServer.active || !IsEclipseLobby)
			{
				lastLobby = null;
				lastLobbyLevel = 0;
				return;
			}
			int num = instance.readOnlyRuleBook.FindDifficulty() - 3 + 1;
			if (EclipseAccessRules.IsSelectableLevel(num) && ((Object)(object)lastLobby != (Object)(object)instance || num != lastLobbyLevel))
			{
				lastLobby = instance;
				lastLobbyLevel = num;
				recalculate(instance);
				log.LogInfo((object)$"Eclipse lobby native difficulty selection: E{num}; E1-E8 remain available.");
			}
		}

		public void Dispose()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			Ready = false;
			RuleChoiceController.UpdateChoiceDisplay -= new hook_UpdateChoiceDisplay(ChoiceDisplay);
			RuleCategoryController.SetData -= new hook_SetData(Category);
			PreGameController.StartRun -= new hook_StartRun(StartRun);
			EclipseRunScreenController.UpdateDisplayedSurvivor -= new hook_UpdateDisplayedSurvivor(Display);
			EclipseRunScreenController.OnDisable -= new hook_OnDisable(Hide);
			EclipseRun.OverrideRuleChoices -= new hook_OverrideRuleChoices(Choices);
			EclipseRun.OverrideRuleChoices -= new Manipulator(PatchSelection);
			EclipseRun.OnClientGameOver -= new Manipulator(PatchAward);
			foreach (EclipseOverviewView value in views.Values)
			{
				value.Dispose();
			}
			views.Clear();
			foreach (EclipseLobbyNote note in notes)
			{
				if (Object.op_Implicit((Object)(object)note))
				{
					Object.Destroy((Object)(object)note);
				}
			}
			notes.Clear();
			foreach (EclipseDifficultyIcon difficultyIcon in difficultyIcons)
			{
				if (Object.op_Implicit((Object)(object)difficultyIcon))
				{
					Object.DestroyImmediate((Object)(object)difficultyIcon);
				}
			}
			difficultyIcons.Clear();
			badgeIcons.Dispose();
		}
	}
	internal static class EclipseAccessPatchEmitter
	{
		internal static void Selection(ILContext il, Action<ILCursor> emitSelect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			val.Goto(EclipseAccessPatterns.Selection(il.Method), (MoveType)0, false);
			val.Emit(OpCodes.Ldarg_0);
			emitSelect(val);
		}

		internal static void Award(ILContext il, Action<ILCursor> emitAward)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_004c: 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)
			ILCursor val = new ILCursor(il);
			val.Goto(EclipseAccessPatterns.Award(il.Method), (MoveType)0, false);
			VariableDefinition val2 = ((IEnumerable<VariableDefinition>)il.Body.Variables).Single((VariableDefinition variable) => ((MemberReference)((VariableReference)variable).VariableType).FullName == "RoR2.SurvivorDef");
			val.Emit(OpCodes.Ldloc, val2);
			val.Emit(OpCodes.Ldarg_0);
			val.Remove();
			emitAward(val);
		}
	}
	internal static class EclipseAccessPatterns
	{
		internal static Instruction Selection(MethodDefinition method)
		{
			Instruction[] array = ((IEnumerable<Instruction>)method.Body.Instructions).Where(delegate(Instruction instruction)
			{
				//IL_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				object operand = instruction.Operand;
				FieldReference val = (FieldReference)((operand is FieldReference) ? operand : null);
				if (val != null && ((MemberReference)val).FullName == "System.Int32 RoR2.EclipseRun::maxEclipseLevel")
				{
					Instruction next = instruction.Next;
					object obj = ((next != null) ? next.Operand : null);
					MethodReference val2 = (MethodReference)((obj is MethodReference) ? obj : null);
					if (val2 != null && ((MemberReference)val2).FullName == "System.Int32 System.Math::Min(System.Int32,System.Int32)")
					{
						Instruction next2 = instruction.Next.Next;
						OpCode? val3 = ((next2 != null) ? new OpCode?(next2.OpCode) : ((OpCode?)null));
						OpCode stloc_ = OpCodes.Stloc_0;
						if (!val3.HasValue)
						{
							return false;
						}
						return val3.GetValueOrDefault() == stloc_;
					}
				}
				return false;
			}).ToArray();
			if (array.Length != 1)
			{
				throw new InvalidOperationException("Expected one native Eclipse level cap.");
			}
			return array[0].Next.Next;
		}

		internal static Instruction Award(MethodDefinition method)
		{
			if (((IEnumerable<Instruction>)method.Body.Instr