Decompiled source of CrestsEvolve v0.58.9

CrestsEvolve/CrestsEvolve.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrestsEvolve.Bootstrap;
using CrestsEvolve.Core.Balance;
using CrestsEvolve.Core.Buffs;
using CrestsEvolve.Core.Charms;
using CrestsEvolve.Core.Combat;
using CrestsEvolve.Core.Events;
using CrestsEvolve.Core.Infrastructure;
using CrestsEvolve.Core.Input;
using CrestsEvolve.Core.Random;
using CrestsEvolve.Core.Time;
using CrestsEvolve.Core.Tools;
using CrestsEvolve.Core.UI;
using CrestsEvolve.Features;
using CrestsEvolve.Features.StatusIcons;
using CrestsEvolve.Features.Tools;
using CrestsEvolve.GameInterop;
using CrestsEvolve.GameInterop.Binding;
using CrestsEvolve.GameInterop.Input;
using CrestsEvolve.GameInterop.Patches;
using CrestsEvolve.GameInterop.Reflection;
using CrestsEvolve.UI;
using GlobalEnums;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using InControl;
using Microsoft.CodeAnalysis;
using Needleforge;
using Needleforge.Data;
using Newtonsoft.Json;
using TeamCherry.Localization;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("CrestsEvolve.LegendsNeverDie")]
[assembly: InternalsVisibleTo("CrestsEvolve.RageOfTheGoner")]
[assembly: InternalsVisibleTo("CrestsEvolve.ToolsAscension")]
[assembly: InternalsVisibleTo("CrestsEvolve.InsectMayCry")]
[assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CrestsEvolve")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")]
[assembly: AssemblyProduct("CrestsEvolve")]
[assembly: AssemblyTitle("CrestsEvolve")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace CrestsEvolve
{
	[BepInPlugin("local.crestsevolve", "CrestsEvolve", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "local.crestsevolve";

		public const string PluginName = "CrestsEvolve";

		public const string PluginVersion = "0.1.0";

		private Harmony? _harmony;

		private ModBootstrap? _bootstrap;

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("local.crestsevolve");
			_bootstrap = new ModBootstrap(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config, _harmony);
			_bootstrap.Start();
		}

		private void OnDestroy()
		{
			try
			{
				_bootstrap?.Dispose();
			}
			finally
			{
				Harmony? harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
		}
	}
}
namespace CrestsEvolve.UI
{
	public sealed class LogStatusIconPresenter : IStatusIconPresenter
	{
		private readonly ManualLogSource _log;

		public static bool Verbose { get; set; }

		public LogStatusIconPresenter(ManualLogSource log)
		{
			_log = log;
		}

		public void Present(StatusIconProjection projection)
		{
			if (Verbose)
			{
				_log.LogDebug((object)($"[StatusIcons] rev={projection.Revision} " + string.Join("; ", projection.Icons.Select((StatusIconState i) => $"{i.Key}={i.Current}/{i.Max}"))));
			}
		}

		public void Hide()
		{
			_log.LogDebug((object)"[StatusIcons] hidden");
		}
	}
	public sealed class LogUiPresenter : IUiPresenter
	{
		private readonly ManualLogSource _log;

		public static bool Verbose { get; set; }

		public LogUiPresenter(ManualLogSource log)
		{
			_log = log;
		}

		public void Present(UiProjection projection)
		{
			if (Verbose)
			{
				_log.LogDebug((object)($"[UiProjection] crest={projection.CrestId} rev={projection.Revision} " + $"stacks={projection.EnhancementStacks} remaining={projection.RemainingSeconds:F1} " + $"rage={projection.Rage} superRage={projection.SuperRage} special={projection.SpecialMode} " + $"charmOffset={projection.CharmLevelOffset} shield={projection.SilkShieldRemaining} " + $"rageRemaining={projection.RageRemainingSeconds:F1}"));
			}
		}

		public void Hide()
		{
			if (Verbose)
			{
				_log.LogDebug((object)"[UiProjection] hidden");
			}
		}
	}
	public sealed record StatusIconState(string Key, int Current, int Max, bool Visible = true, string? ColorOverride = null, string? CenterText = null, bool Dimmed = false);
	public sealed record StatusIconProjection(long Revision, IReadOnlyList<StatusIconState> Icons);
	public interface IStatusIconPresenter
	{
		void Present(StatusIconProjection projection);

		void Hide();
	}
	public sealed class StatusIconProjector : IDisposable
	{
		private readonly StatusIconLedger _ledger;

		private readonly IStatusIconPresenter _presenter;

		private long _lastRevision = -1L;

		public static StatusIconProjector? Current { get; private set; }

		public StatusIconProjector(StatusIconLedger ledger, IStatusIconPresenter presenter)
		{
			_ledger = ledger ?? throw new ArgumentNullException("ledger");
			_presenter = presenter ?? throw new ArgumentNullException("presenter");
			if (Current != null)
			{
				throw new InvalidOperationException("A StatusIconProjector is already active.");
			}
			Current = this;
			_ledger.Changed += OnChanged;
			OnChanged(_ledger.Snapshot());
		}

		public void Refresh()
		{
			StatusIconSnapshot statusIconSnapshot = _ledger.Snapshot();
			_lastRevision = statusIconSnapshot.Revision;
			Present(statusIconSnapshot);
		}

		private void OnChanged(StatusIconSnapshot snapshot)
		{
			if (snapshot.Revision != _lastRevision)
			{
				_lastRevision = snapshot.Revision;
				Present(snapshot);
			}
		}

		private void Present(StatusIconSnapshot snapshot)
		{
			List<StatusIconState> list = new List<StatusIconState>(snapshot.Icons.Count);
			foreach (StatusIconValue icon in snapshot.Icons)
			{
				bool flag = icon.Visible;
				if (flag && icon.Current <= 0 && !StatusIconProjectionRules.ZeroValueVisible(icon.Key))
				{
					flag = false;
				}
				list.Add(new StatusIconState(icon.Key, icon.Current, icon.Max, flag, icon.ColorOverride, icon.Text, icon.Dimmed));
			}
			_presenter.Present(new StatusIconProjection(snapshot.Revision, list));
		}

		public void Dispose()
		{
			if (Current == this)
			{
				Current = null;
			}
			_ledger.Changed -= OnChanged;
			_presenter.Hide();
		}
	}
	public sealed class CompositeStatusIconPresenter : IStatusIconPresenter
	{
		private readonly IStatusIconPresenter _always;

		private readonly Func<IStatusIconPresenter?> _dynamic;

		public CompositeStatusIconPresenter(IStatusIconPresenter always, Func<IStatusIconPresenter?> dynamic)
		{
			_always = always ?? throw new ArgumentNullException("always");
			_dynamic = dynamic ?? throw new ArgumentNullException("dynamic");
		}

		public void Present(StatusIconProjection projection)
		{
			_always.Present(projection);
			_dynamic()?.Present(projection);
		}

		public void Hide()
		{
			_always.Hide();
			_dynamic()?.Hide();
		}
	}
	public sealed record UiProjection(string CrestId, int EnhancementStacks, double RemainingSeconds, double NormalAttackDamage, bool Rage, bool SuperRage, bool SpecialMode, int CharmLevelOffset, int SilkShieldRemaining, double RageRemainingSeconds, long Revision);
	public interface IUiPresenter
	{
		void Present(UiProjection projection);

		void Hide();
	}
}
namespace CrestsEvolve.GameInterop
{
	public static class ArchitectRuneBridge
	{
		public static Func<bool> IsToolRepairActive { get; set; } = () => false;

		public static Func<bool> IsToolTransformActive { get; set; } = () => false;
	}
	public static class AttackKindMapping
	{
		public static AttackKind FromAttackType(AttackTypes attackType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected I4, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			switch ((int)attackType)
			{
			default:
				if ((int)attackType != 16)
				{
					break;
				}
				return AttackKind.Charge;
			case 0:
				return AttackKind.Normal;
			case 1:
				return AttackKind.Normal;
			case 2:
				return AttackKind.Skill;
			case 10:
				return AttackKind.Skill;
			case 6:
				return AttackKind.Dash;
			case 7:
				return AttackKind.Projectile;
			case 11:
				return AttackKind.Additional;
			case 3:
			case 4:
			case 5:
			case 8:
			case 9:
				break;
			}
			return AttackKind.Additional;
		}
	}
	public static class BeastRuneBridge
	{
		public static Func<bool> IsEnhancementActive { get; set; } = () => false;

		public static Func<bool> IsDamageProtectActive { get; set; } = () => false;

		public static Func<bool> IsPredatorCharged { get; set; } = () => false;

		public static Action? AcquireChargeSlashInvulnerability { get; set; }
	}
	public sealed class BeastStateAccessor
	{
		private readonly ManualLogSource _log;

		private readonly FieldInfo? _warriorStateField;

		private bool _warned;

		public BeastStateAccessor(ManualLogSource log)
		{
			_log = log;
			_warriorStateField = AccessTools.Field(typeof(HeroController), "warriorState");
			if (_warriorStateField == null)
			{
				_log.LogWarning((object)"[BeastState] warriorState field not found; kill duration extension disabled.");
			}
		}

		public void AddRageTime(float seconds, float max)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (_warriorStateField == null || seconds <= 0f)
			{
				return;
			}
			try
			{
				HeroController instance = HeroController.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					WarriorCrestStateInfo val = (WarriorCrestStateInfo)_warriorStateField.GetValue(instance);
					if (val.IsInRageMode)
					{
						val.RageEffectTimeLeft = Math.Min(max, val.RageEffectTimeLeft + seconds);
						_warriorStateField.SetValue(instance, val);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public bool IsInRageMode()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (_warriorStateField == null)
			{
				return false;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			try
			{
				return ((WarriorCrestStateInfo)_warriorStateField.GetValue(instance)).IsInRageMode;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return false;
			}
		}

		public void SetRageStateActive(bool active)
		{
			//IL_002f: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!active || _warriorStateField == null)
			{
				return;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				WarriorCrestStateInfo val = (WarriorCrestStateInfo)_warriorStateField.GetValue(instance);
				val.IsInRageMode = true;
				val.RageEffectTimeLeft = Gameplay.WarriorRageDuration;
				val.RageHealTimeLeft = Gameplay.WarriorRageDuration + Gameplay.WarriorRageGraceTime;
				_warriorStateField.SetValue(instance, val);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public void SetRageHealBlocked(bool blocked)
		{
			//IL_002f: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!blocked || _warriorStateField == null)
			{
				return;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				WarriorCrestStateInfo val = (WarriorCrestStateInfo)_warriorStateField.GetValue(instance);
				val.RageModeHealCount = instance.GetRageModeHealCap();
				_warriorStateField.SetValue(instance, val);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[BeastState] access failed (" + ex.GetType().Name + ": " + ex.Message + "); suppressing further warnings."));
			}
		}
	}
	public static class CloaklessRuneBridge
	{
		public static Func<bool> IsFreeBindCharged { get; set; } = () => false;

		public static Func<bool> TryConsumeFreeBind { get; set; } = () => false;

		public static Func<bool> IsGlacialAugmentCharged { get; set; } = () => false;

		public static Func<bool> TryConsumeGlacialAugment { get; set; } = () => false;
	}
	public static class CursedRuneBridge
	{
		private sealed class NullLease : IDisposable
		{
			public void Dispose()
			{
			}
		}

		public static Func<bool> IsBindEnabled { get; set; } = () => false;

		public static Func<bool> IsBindInvulnerabilityActive { get; set; } = () => false;

		public static Func<IDisposable> AcquireBindInvulnerability { get; set; } = () => new NullLease();

		public static Func<double> BindInvulnerabilitySeconds { get; set; } = () => 2.0;
	}
	public sealed class DashStateAccessor
	{
		private readonly ManualLogSource _log;

		private bool _warned;

		public DashStateAccessor(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
		}

		public bool IsDashSprintActive()
		{
			try
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance == (Object)null || instance.cState == null)
				{
					return false;
				}
				if (instance.cState.isSprinting || instance.cState.dashing)
				{
					return IsDashPressed();
				}
				return false;
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					_log.LogWarning((object)("[DashState] dash sprint query failed: " + ex.Message));
				}
				return false;
			}
		}

		private static bool IsDashPressed()
		{
			InputHandler instance = ManagerSingleton<InputHandler>.Instance;
			if ((Object)(object)instance == (Object)null || instance.inputActions == null || instance.inputActions.Dash == null)
			{
				return true;
			}
			return ((OneAxisInputControl)instance.inputActions.Dash).IsPressed;
		}
	}
	public sealed class FleaBrewApplicator
	{
		public const string FleaBrewToolId = "Flea Brew";

		private readonly ManualLogSource _log;

		private readonly BuffState _buff;

		private bool _warned;

		public bool IsBrewActive => _buff.IsActive;

		public double BrewRemainingSeconds => _buff.RemainingSeconds;

		public FleaBrewApplicator(ManualLogSource log, IClock clock, double durationSeconds = 3.0)
		{
			_log = log ?? throw new ArgumentNullException("log");
			if (durationSeconds <= 0.0)
			{
				throw new ArgumentOutOfRangeException("durationSeconds");
			}
			_buff = new BuffState(BuffKind.Meade, 1, durationSeconds, clock ?? throw new ArgumentNullException("clock"));
		}

		public void Apply()
		{
			if (!TryApplyVanilla())
			{
				_buff.Add();
				WarnOnce("vanilla Flea Brew application path is unconfirmed; fell back to internal buff timer (U).");
			}
		}

		private bool TryApplyVanilla()
		{
			try
			{
				ToolItem toolByName = ToolItemManager.GetToolByName("Flea Brew");
				if ((Object)(object)toolByName == (Object)null)
				{
					return false;
				}
				_log.LogInfo((object)("[FleaBrew][probe] tool='" + toolByName.name + "' type='" + ((object)toolByName).GetType().FullName + "' (U; FSM/object path pending probe, no event sent until confirmed)."));
				return false;
			}
			catch (Exception ex)
			{
				WarnOnce(ex.Message);
				return false;
			}
		}

		private void WarnOnce(string message)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[FleaBrew] " + message));
			}
		}
	}
	public static class FracturedMaskBridge
	{
		public static Func<bool>? IsEquipped { get; set; } = () => false;

		public static Func<bool>? TryRepair { get; set; } = () => false;
	}
	public sealed class GameEventPatches : IDisposable
	{
		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly DynamicPatchResolver _resolver;

		private readonly Harmony _harmony;

		private readonly DamageNegotiationService _negotiation;

		private readonly IGameApi _game;

		private readonly List<string> _installed = new List<string>();

		private static GameEventPatches? _active;

		private static readonly FieldInfo LastHitInstanceField = AccessTools.Field(typeof(HealthManager), "lastHitInstance");

		private static bool _spellKillWarned;

		private static readonly (string BindingId, string? Prefix, string? Postfix)[] EventBindings = new(string, string, string)[14]
		{
			("player.attack.resolved", null, "NailHitEnemyPostfix"),
			("enemy.damage.resolved", null, "ApplyDamageScalingPostfix"),
			("player.damage.before", "TakeDamagePrefix", null),
			("player.damage.after", null, "TakeDamagePostfix"),
			("player.heal.request", "AddHealthPrefix", null),
			("player.heal.resolved", null, "AddHealthPostfix"),
			("player.silk.get", "AddSilkPrefix", "AddSilkPostfix"),
			("player.silk.spend", "TakeSilkPrefix", "TakeSilkPostfix"),
			("player.crest.changed", null, "SendEquippedChangedEventPostfix"),
			("enemy.killed", null, "SendDeathEventPostfix"),
			("player.bench.rested", null, "SetOnBenchPostfix"),
			("player.died", "DiePrefix", null),
			("scene.changed", null, "SceneInitPostfix"),
			("player.reaper.bind.completed", null, "BindCompletedPostfix")
		};

		private static string? _lastCrestId;

		private static bool _benchWasOnBench;

		public GameEventPatches(ManualLogSource log, GameEventHub events, DynamicPatchResolver resolver, Harmony harmony, DamageNegotiationService negotiation, IGameApi game)
		{
			_log = log;
			_events = events;
			_resolver = resolver;
			_harmony = harmony;
			_negotiation = negotiation;
			_game = game;
		}

		public void Install()
		{
			_active = this;
			_benchWasOnBench = false;
			(string, string, string)[] eventBindings = EventBindings;
			for (int i = 0; i < eventBindings.Length; i++)
			{
				(string, string, string) tuple = eventBindings[i];
				if (tuple.Item2 != null && tuple.Item3 != null)
				{
					PatchBoth(tuple.Item1, tuple.Item2, tuple.Item3);
				}
				else if (tuple.Item2 != null)
				{
					PatchPrefix(tuple.Item1, tuple.Item2);
				}
				else
				{
					PatchPostfix(tuple.Item1, tuple.Item3);
				}
			}
			_log.LogInfo((object)("Game event patches installed: " + string.Join(", ", _installed)));
		}

		public void Dispose()
		{
			_active = null;
			_benchWasOnBench = false;
			_installed.Clear();
		}

		private void PatchPrefix(string bindingId, string patchMethod)
		{
			PatchWith(bindingId, delegate(MethodBase method)
			{
				_harmony.Patch(method, HarmonyMethod(patchMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			});
		}

		private void PatchPostfix(string bindingId, string patchMethod)
		{
			PatchWith(bindingId, delegate(MethodBase method)
			{
				_harmony.Patch(method, (HarmonyMethod)null, HarmonyMethod(patchMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			});
		}

		private void PatchBoth(string bindingId, string prefixMethod, string postfixMethod)
		{
			PatchWith(bindingId, delegate(MethodBase method)
			{
				_harmony.Patch(method, HarmonyMethod(prefixMethod), HarmonyMethod(postfixMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			});
		}

		private void PatchWith(string bindingId, Action<MethodBase> apply)
		{
			MethodBase methodBase = _resolver.Resolve(bindingId);
			if ((object)methodBase == null)
			{
				_log.LogWarning((object)("Event patch disabled (binding unresolved): " + bindingId));
				return;
			}
			apply(methodBase);
			_installed.Add(bindingId);
			_log.LogInfo((object)("Event patch installed: " + bindingId + " -> " + GeneralExtensions.FullDescription(methodBase)));
		}

		private static HarmonyMethod HarmonyMethod(string name)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			return new HarmonyMethod(AccessTools.DeclaredMethod(typeof(GameEventPatches), name, (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(GameEventPatches).FullName, name));
		}

		private unsafe static void NailHitEnemyPostfix(HeroController __instance, HealthManager enemyHealth, HitInstance hitInstance)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			_active?._events.Publish(new AttackEvent(((long)Time.frameCount << 16) ^ ((Object)enemyHealth).GetInstanceID(), ((Object)__instance).GetInstanceID(), ((Object)enemyHealth).GetInstanceID(), AttackKindMapping.FromAttackType(hitInstance.AttackType), "attack." + ((object)(*(AttackTypes*)(&hitInstance.AttackType))/*cast due to .constrained prefix*/).ToString(), hitInstance.DamageDealt, (!hitInstance.IsFirstHit) ? 1 : 0, IsAdditionalDamage: false, IsHeroDamage: true, ((Component)enemyHealth).transform.position.x, ((Component)enemyHealth).transform.position.y, ((Component)enemyHealth).transform.position.z));
		}

		private unsafe static void ApplyDamageScalingPostfix(HealthManager __instance, HitInstance hitInstance, HitInstance __result)
		{
			//IL_0021: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			_active?._events.PublishEnemyDamageResolved(new AttackEvent(((long)Time.frameCount << 16) ^ ((Object)__instance).GetInstanceID(), ((Object)(object)hitInstance.Source != (Object)null) ? ((Object)hitInstance.Source).GetInstanceID() : 0, ((Object)__instance).GetInstanceID(), AttackKindMapping.FromAttackType(hitInstance.AttackType), "enemy.damage." + ((object)(*(AttackTypes*)(&hitInstance.AttackType))/*cast due to .constrained prefix*/).ToString(), __result.DamageDealt, (!__result.IsFirstHit) ? 1 : 0, IsAdditionalDamage: false, hitInstance.IsHeroDamage, ((Component)__instance).transform.position.x, ((Component)__instance).transform.position.y, ((Component)__instance).transform.position.z));
		}

		private unsafe static bool TakeDamagePrefix(ref int damageAmount, HazardType hazardType)
		{
			GameEventPatches active = _active;
			if (active == null || damageAmount <= 0)
			{
				return true;
			}
			active._events.PublishBefore(new PlayerDamageEvent(damageAmount, "hazard." + ((object)(*(HazardType*)(&hazardType))/*cast due to .constrained prefix*/).ToString()));
			int num = damageAmount;
			DamageDecision damageDecision = active._negotiation.Negotiate(num, "hazard." + ((object)(*(HazardType*)(&hazardType))/*cast due to .constrained prefix*/).ToString());
			if (damageDecision.SilkToSpend > 0)
			{
				active._game.TrySpendSilk(damageDecision.SilkToSpend, damageDecision.Reason ?? "damage-negotiation");
			}
			damageAmount = damageDecision.RemainingMaskDamage;
			if (damageDecision.Verdict != DamageVerdict.Allow || damageAmount <= 0)
			{
				active._log.LogInfo((object)("Damage cancelled by negotiation: " + (damageDecision.Reason ?? "unknown") + " " + $"(incoming={num}, remaining={damageDecision.RemainingMaskDamage}, silk={damageDecision.SilkToSpend})"));
				return false;
			}
			return true;
		}

		private unsafe static void TakeDamagePostfix(int damageAmount, HazardType hazardType)
		{
			GameEventPatches active = _active;
			if (active != null && damageAmount > 0)
			{
				active._events.PublishAfter(new PlayerDamageEvent(damageAmount, "hazard." + ((object)(*(HazardType*)(&hazardType))/*cast due to .constrained prefix*/).ToString()));
			}
		}

		private static bool AddHealthPrefix(HeroController __instance, int amount, ref int __state)
		{
			GameEventPatches active = _active;
			if (active == null || amount <= 0)
			{
				return true;
			}
			PlayerData val = __instance?.playerData;
			int num = val?.health ?? 0;
			int missingWhiteHealth = Math.Max(0, Math.Max(1, val?.maxHealth ?? 0) - num);
			__state = num;
			HealEvent healEvent = new HealEvent(amount, 0, "heal.addhealth", missingWhiteHealth);
			active._events.PublishRequested(healEvent);
			if (active._events.InterceptHeal(healEvent))
			{
				active._log.LogInfo((object)$"[Heal] consumed by interceptor (amount={amount})");
				return false;
			}
			return true;
		}

		private static void AddHealthPostfix(HeroController __instance, int amount, ref int __state)
		{
			GameEventPatches active = _active;
			if (active != null && amount > 0)
			{
				PlayerData val = __instance?.playerData;
				int num = __state;
				int num2 = val?.health ?? num;
				int applied = Math.Max(0, num2 - num);
				int missingWhiteHealth = Math.Max(0, Math.Max(1, val?.maxHealth ?? 0) - num);
				active._events.PublishResolved(new HealEvent(amount, applied, "heal.addhealth", missingWhiteHealth));
			}
		}

		private static void AddSilkPrefix(HeroController __instance, ref int __state)
		{
			__state = __instance.playerData?.silk ?? 0;
		}

		private unsafe static void AddSilkPostfix(HeroController __instance, SilkAddSource source, int __state)
		{
			GameEventPatches active = _active;
			int num = __instance.playerData?.silk ?? 0;
			if (active != null && num != __state)
			{
				active._events.Publish(new ResourceEvent(__state, num, num - __state, "silk.add." + ((object)(*(SilkAddSource*)(&source))/*cast due to .constrained prefix*/).ToString()));
			}
		}

		private static void TakeSilkPrefix(HeroController __instance, ref int __state)
		{
			__state = __instance.playerData?.silk ?? 0;
		}

		private unsafe static void TakeSilkPostfix(HeroController __instance, SilkTakeSource source, int __state)
		{
			GameEventPatches active = _active;
			int num = __instance.playerData?.silk ?? 0;
			if (active != null && num != __state)
			{
				active._events.Publish(new ResourceEvent(__state, num, num - __state, "silk.take." + ((object)(*(SilkTakeSource*)(&source))/*cast due to .constrained prefix*/).ToString()));
			}
		}

		private static void SendEquippedChangedEventPostfix()
		{
			GameEventPatches active = _active;
			if (active == null)
			{
				return;
			}
			active._events.PublishToolEquipsChanged();
			string text = HeroController.instance?.playerData?.CurrentCrestID;
			if (!string.IsNullOrEmpty(text))
			{
				string lastCrestId = _lastCrestId;
				_lastCrestId = text;
				if (lastCrestId == null)
				{
					active._events.Publish(new CrestChangedEvent("", text));
				}
				else if (!(lastCrestId == text))
				{
					active._events.Publish(new CrestChangedEvent(lastCrestId, text));
				}
			}
		}

		private static void SendDeathEventPostfix(HealthManager __instance)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Invalid comparison between Unknown and I4
			GameEventPatches active = _active;
			if (active == null)
			{
				return;
			}
			string enemyName;
			try
			{
				enemyName = (((Object)(object)((Component)__instance).gameObject != (Object)null) ? ((Object)((Component)__instance).gameObject).name : "unknown");
			}
			catch
			{
				enemyName = "unknown";
			}
			active._events.Publish(new EnemyKilledEvent(((Object)__instance).GetInstanceID(), enemyName));
			if (!(LastHitInstanceField != null))
			{
				return;
			}
			try
			{
				if (LastHitInstanceField.GetValue(__instance) is HitInstance val && val.IsHeroDamage && (int)val.AttackType == 2)
				{
					active._events.PublishSpellKilled();
				}
			}
			catch (Exception ex)
			{
				if (!_spellKillWarned)
				{
					_spellKillWarned = true;
					active._log.LogWarning((object)("[SpellKill] lastHitInstance read failed: " + ex.Message));
				}
			}
		}

		private static void SetOnBenchPostfix(bool onBench)
		{
			GameEventPatches active = _active;
			if (active == null)
			{
				_benchWasOnBench = onBench;
				return;
			}
			if (onBench && !_benchWasOnBench)
			{
				active._events.PublishBenchRested();
			}
			_benchWasOnBench = onBench;
		}

		private static void DiePrefix(bool nonLethal)
		{
			_active?._events.PublishPlayerDied();
		}

		private static void SceneInitPostfix()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			GameEventPatches active = _active;
			if (active != null)
			{
				GameEventHub events = active._events;
				Scene activeScene = SceneManager.GetActiveScene();
				events.PublishSceneChanged(((Scene)(ref activeScene)).name);
			}
		}

		private static void BindCompletedPostfix()
		{
			_active?._events.PublishBindCompleted();
		}
	}
	public static class HudIconCloneSanitizer
	{
		public enum ComponentDisposition
		{
			Keep,
			DisableThenDestroy,
			DestroyImmediate
		}

		public static ComponentDisposition Classify(Type type)
		{
			if (type == null)
			{
				return ComponentDisposition.DestroyImmediate;
			}
			if (typeof(RadialHudIcon).IsAssignableFrom(type))
			{
				return ComponentDisposition.DisableThenDestroy;
			}
			if (typeof(Animator).IsAssignableFrom(type))
			{
				return ComponentDisposition.DisableThenDestroy;
			}
			if (typeof(UnityMessageListener).IsAssignableFrom(type))
			{
				return ComponentDisposition.DisableThenDestroy;
			}
			if (typeof(RadialHudSwitchModeSettings).IsAssignableFrom(type))
			{
				return ComponentDisposition.DisableThenDestroy;
			}
			if (typeof(EventRegister).IsAssignableFrom(type))
			{
				return ComponentDisposition.DestroyImmediate;
			}
			if (typeof(EventResponder).IsAssignableFrom(type))
			{
				return ComponentDisposition.DestroyImmediate;
			}
			return ComponentDisposition.Keep;
		}

		public static bool IsArrowName(string? objectName)
		{
			if (objectName != null)
			{
				return objectName.IndexOf("Arrow", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		public static bool ShouldKeepRenderer(string? objectName, bool isCenterIcon, bool isArrow)
		{
			if (!(isCenterIcon || isArrow))
			{
				return IsArrowName(objectName);
			}
			return true;
		}

		public static bool ShouldKeepGraphic(string? objectName, bool isFill, bool isBg)
		{
			return isFill || isBg;
		}

		public static int Sanitize(GameObject root, string key, ManualLogSource? log, bool immediate = false)
		{
			if ((Object)(object)root == (Object)null)
			{
				return 0;
			}
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return 0;
			}
			Dictionary<Type, int> dictionary = new Dictionary<Type, int>();
			int num = 0;
			foreach (MonoBehaviour item in new List<MonoBehaviour>(componentsInChildren))
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				Type type = ((object)item).GetType();
				ComponentDisposition componentDisposition = Classify(type);
				if (componentDisposition == ComponentDisposition.Keep)
				{
					continue;
				}
				if (componentDisposition == ComponentDisposition.DestroyImmediate)
				{
					Object.DestroyImmediate((Object)(object)item);
				}
				else
				{
					Behaviour val = (Behaviour)(object)item;
					if (val != null)
					{
						val.enabled = false;
					}
					if (immediate)
					{
						Object.DestroyImmediate((Object)(object)item);
					}
					else
					{
						Object.Destroy((Object)(object)item);
					}
				}
				dictionary[type] = ((!dictionary.TryGetValue(type, out var value)) ? 1 : (value + 1));
				num++;
			}
			if (num > 0 && log != null)
			{
				foreach (KeyValuePair<Type, int> item2 in dictionary)
				{
					log.LogInfo((object)string.Format("[HudIconCloneSanitizer] '{0}' removed {1}x {2}{3}", key, item2.Value, item2.Key.FullName, immediate ? " (immediate)" : ""));
				}
			}
			return num;
		}
	}
	internal static class HudRootInstaller
	{
		private static StatusIconHostConfig? _config;

		private static StatusIconTextureService? _textures;

		private static ManualLogSource? _log;

		public static void Configure(StatusIconHostConfig config, StatusIconTextureService textures, ManualLogSource log)
		{
			_config = config;
			_textures = textures;
			_log = log;
		}

		public static void Postfix(BindOrbHudFrame __instance)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (_config == null || _textures == null)
			{
				return;
			}
			Transform val = ToolRowLocator.Resolve(_config.RowAnchorPath, ((Component)__instance).transform);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.AddComponent<HudStatusIconHost>().Configure(_config, ((Component)__instance).transform, _textures, _log, val);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[HudStatusIconHost] attached to row container: " + BuildPath(val)));
				}
				return;
			}
			GameObject val2 = new GameObject("CrestsEvolveHUDRoot")
			{
				layer = 5
			};
			val2.transform.SetParent(((Component)__instance).transform, false);
			val2.transform.localScale = Vector3.one;
			val2.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
			Vector3 localPosition = val2.transform.localPosition;
			localPosition.z = -0.0001f;
			val2.transform.localPosition = localPosition;
			val2.AddComponent<HudStatusIconHost>().Configure(_config, ((Component)__instance).transform, _textures, _log, null);
			ManualLogSource? log2 = _log;
			if (log2 != null)
			{
				log2.LogInfo((object)"[HudStatusIconHost] no row container found; created CrestsEvolveHUDRoot fallback under BindOrbHudFrame.");
			}
		}

		private static string BuildPath(Transform transform)
		{
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
	public sealed class StatusIconHostConfig
	{
		public string RowAnchorPath { get; set; } = "auto";

		public Vector3 FallbackOffset { get; set; } = new Vector3(0f, -2.2f, 0f);

		public float Spacing { get; set; } = 1.1f;

		public bool LogHierarchyProbe { get; set; } = true;

		public static bool TryParseOffset(string text, out Vector3 offset)
		{
			//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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			offset = Vector3.zero;
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			string[] array = text.Split(',');
			if (array.Length < 2 || !float.TryParse(array[0], out var result) || !float.TryParse(array[1], out var result2))
			{
				return false;
			}
			float result3;
			float num = ((array.Length > 2 && float.TryParse(array[2], out result3)) ? result3 : 0f);
			offset = new Vector3(result, result2, num);
			return true;
		}
	}
	public sealed class HudStatusIconHost : MonoBehaviour, IStatusIconPresenter
	{
		private sealed class NativeIconTemplate
		{
			public Transform Root;

			public string IconPath;

			public string FillPath;

			public string BgPath;

			public Color? InactiveColor { get; set; }
		}

		private sealed class IconView
		{
			private readonly Color _iconTint;

			private readonly string _key;

			private readonly StatusIconTextureService? _textures;

			private readonly Color? _nativeInactiveColor;

			private Text? _centerLabel;

			private static Font? _centerFont;

			public GameObject Root { get; }

			public SpriteRenderer Icon { get; }

			public Image RingFill { get; }

			public Image RingBg { get; }

			public Color RingColor { get; }

			public IconView(GameObject root, SpriteRenderer icon, Image ringFill, Image ringBg, Color ringColor, Color iconTint, string key, StatusIconTextureService? textures, Color? nativeInactiveColor = null)
			{
				//IL_0024: 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_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				Root = root;
				Icon = icon;
				RingFill = ringFill;
				RingBg = ringBg;
				RingColor = ringColor;
				_iconTint = iconTint;
				_key = key;
				_textures = textures;
				_nativeInactiveColor = nativeInactiveColor;
			}

			public void Set(StatusIconState state)
			{
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_011e: Unknown result type (might be due to invalid IL or missing references)
				//IL_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: 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_016c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0174: Unknown result type (might be due to invalid IL or missing references)
				//IL_0173: Unknown result type (might be due to invalid IL or missing references)
				//IL_017e: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_018e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
				Root.SetActive(state.Visible);
				if (!state.Visible)
				{
					return;
				}
				((Renderer)Icon).enabled = true;
				if (!((Component)Icon).gameObject.activeSelf)
				{
					((Component)Icon).gameObject.SetActive(true);
				}
				if (_textures != null && !string.IsNullOrEmpty(_key))
				{
					Sprite iconSprite = _textures.GetIconSprite(_key);
					if ((Object)(object)iconSprite != (Object)null)
					{
						Icon.sprite = iconSprite;
					}
					float iconScale = _textures.GetIconScale(_key);
					((Component)Icon).transform.localScale = new Vector3(iconScale, iconScale, 1f);
				}
				float num = ((state.Max <= 0) ? 1f : Mathf.Clamp01((float)state.Current / (float)state.Max));
				RingFill.fillAmount = num;
				RingBg.fillAmount = 1f - num;
				bool flag = state.Dimmed || state.Current <= 0;
				Icon.color = (Color)((!flag) ? _iconTint : (((??)_nativeInactiveColor) ?? Dim(_iconTint, 0.45f)));
				Color val2 = default(Color);
				Color val = ((state.ColorOverride != null && ColorUtility.TryParseHtmlString(state.ColorOverride, ref val2)) ? val2 : RingColor);
				((Graphic)RingFill).color = ((!flag) ? val : (_nativeInactiveColor.HasValue ? Multiply(val, _nativeInactiveColor.Value) : Dim(val, 0.45f)));
				((Graphic)RingBg).color = Dim(val, 0.3f);
				if (state.CenterText != null)
				{
					Text val3 = EnsureCenterText();
					if ((Object)(object)val3 != (Object)null)
					{
						val3.text = state.CenterText;
					}
				}
				else if ((Object)(object)_centerLabel != (Object)null)
				{
					((Component)_centerLabel).gameObject.SetActive(false);
				}
			}

			private Text? EnsureCenterText()
			{
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_centerLabel != (Object)null)
				{
					((Component)_centerLabel).gameObject.SetActive(true);
					return _centerLabel;
				}
				Font centerFont = GetCenterFont();
				if ((Object)(object)centerFont == (Object)null)
				{
					return null;
				}
				GameObject val = new GameObject("CenterText", new Type[3]
				{
					typeof(RectTransform),
					typeof(CanvasRenderer),
					typeof(Text)
				})
				{
					layer = Root.layer
				};
				val.transform.SetParent(Root.transform, false);
				RectTransform component = val.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(0.5f, 0.5f);
				component.anchorMax = new Vector2(0.5f, 0.5f);
				component.pivot = new Vector2(0.5f, 0.5f);
				component.sizeDelta = new Vector2(1.8f, 1f);
				((Transform)component).localPosition = Vector3.zero;
				Text component2 = val.GetComponent<Text>();
				component2.font = centerFont;
				component2.fontSize = 42;
				component2.alignment = (TextAnchor)4;
				((Graphic)component2).color = Color.white;
				((Graphic)component2).raycastTarget = false;
				component2.horizontalOverflow = (HorizontalWrapMode)1;
				component2.verticalOverflow = (VerticalWrapMode)1;
				_centerLabel = component2;
				return component2;
			}

			private static Font? GetCenterFont()
			{
				if ((Object)(object)_centerFont != (Object)null)
				{
					return _centerFont;
				}
				try
				{
					_centerFont = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("[HudStatusIconHost] LegacyRuntime.ttf unavailable: " + ex.Message));
				}
				if ((Object)(object)_centerFont == (Object)null)
				{
					try
					{
						_centerFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
					}
					catch (Exception ex2)
					{
						Debug.LogWarning((object)("[HudStatusIconHost] Arial.ttf unavailable; center text disabled. " + ex2.Message));
					}
				}
				return _centerFont;
			}
		}

		private StatusIconHostConfig _config = new StatusIconHostConfig();

		private Transform? _hudFrame;

		private Transform? _rowAnchor;

		private TransformLayoutGrid? _grid;

		private bool _gridManaged;

		private StatusIconTextureService? _textures;

		private ManualLogSource? _log;

		private readonly Dictionary<string, IconView> _icons = new Dictionary<string, IconView>(StringComparer.Ordinal);

		private HashSet<string> _visibleKeys = new HashSet<string>(StringComparer.Ordinal);

		private long _lastRevision = -1L;

		private Sprite? _nativeRingSprite;

		private readonly Dictionary<string, NativeIconTemplate> _nativeTemplates = new Dictionary<string, NativeIconTemplate>(StringComparer.Ordinal);

		private NativeIconTemplate? _defaultTemplate;

		private bool _rowProbeLogged;

		private bool _toolsAppeared;

		private static readonly HashSet<string> _nativeCloneHierarchyLogged = new HashSet<string>(StringComparer.Ordinal);

		public static HudStatusIconHost? Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			((EventBase)EventRegister.GetRegisterGuaranteed(((Component)this).gameObject, "TOOL EQUIPS CHANGED")).ReceivedEvent += RebuildLayout;
			((EventBase)EventRegister.GetRegisterGuaranteed(((Component)this).gameObject, "POST TOOL EQUIPS CHANGED")).ReceivedEvent += RebuildLayout;
			((EventBase)EventRegister.GetRegisterGuaranteed(((Component)this).gameObject, "TOOLS APPEAR")).ReceivedEvent += OnToolsAppear;
		}

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

		public void Configure(StatusIconHostConfig config, Transform hudFrame, StatusIconTextureService textures, ManualLogSource log, Transform? rowAnchor)
		{
			//IL_00e8: 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_009d: Expected O, but got Unknown
			_config = config ?? new StatusIconHostConfig();
			_hudFrame = hudFrame;
			_textures = textures;
			_log = log;
			if (_config.LogHierarchyProbe)
			{
				LogHierarchy(hudFrame, 0, 3);
				LogSiblingOverview(hudFrame.parent, "Bind Orb parent");
				Transform parent = hudFrame.parent;
				LogSiblingOverview((parent != null) ? parent.parent : null, "Bind Orb grandparent");
			}
			if ((Object)(object)rowAnchor != (Object)null)
			{
				AttachToRow(rowAnchor);
				LogRowStructure("hud-created");
				foreach (Transform item in rowAnchor)
				{
					Transform val = item;
					if ((Object)(object)((Component)val).GetComponent<ToolHudIcon>() != (Object)null && ((Component)val).gameObject.activeInHierarchy)
					{
						_toolsAppeared = true;
						break;
					}
				}
			}
			else
			{
				((Component)this).transform.localPosition = _config.FallbackOffset;
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[HudStatusIconHost][probe] no vanilla tool row detected; using fallback offset.");
				}
			}
			StatusIconProjector.Current?.Refresh();
		}

		public void Present(StatusIconProjection projection)
		{
			if (projection.Revision == _lastRevision || !_toolsAppeared)
			{
				return;
			}
			_lastRevision = projection.Revision;
			List<StatusIconState> list = projection.Icons.Where((StatusIconState state) => _textures == null || _textures.IsIconEnabled(state.Key)).ToList();
			HashSet<string> hashSet = new HashSet<string>(list.Select((StatusIconState i) => i.Key), StringComparer.Ordinal);
			foreach (string item in _icons.Keys.ToList())
			{
				if (!hashSet.Contains(item))
				{
					Object.Destroy((Object)(object)_icons[item].Root);
					_icons.Remove(item);
				}
			}
			HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
			foreach (StatusIconState item2 in list)
			{
				IconView value2;
				if (item2.Visible)
				{
					hashSet2.Add(item2.Key);
					EnsureIcon(item2.Key);
					if (_icons.TryGetValue(item2.Key, out IconView value))
					{
						value.Set(item2);
					}
				}
				else if (_icons.TryGetValue(item2.Key, out value2))
				{
					Object.Destroy((Object)(object)value2.Root);
					_icons.Remove(item2.Key);
				}
			}
			if (!_visibleKeys.SetEquals(hashSet2))
			{
				_visibleKeys = hashSet2;
				RebuildLayout();
			}
		}

		public void Hide()
		{
			foreach (IconView value in _icons.Values)
			{
				Object.Destroy((Object)(object)value.Root);
			}
			_icons.Clear();
			_visibleKeys.Clear();
			_lastRevision = -1L;
		}

		private void OnToolsAppear()
		{
			_toolsAppeared = true;
			if (_nativeTemplates.Count == 0 && (Object)(object)_rowAnchor != (Object)null)
			{
				CaptureNativeRing(_rowAnchor);
			}
			StatusIconProjector.Current?.Refresh();
			RebuildLayout();
		}

		private void EnsureIcon(string key)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0073: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			if (!_icons.ContainsKey(key) && _textures != null && !TryCreateNativeIcon(key))
			{
				int layer = (((Object)(object)_hudFrame != (Object)null) ? ((Component)_hudFrame).gameObject.layer : 5);
				GameObject val = new GameObject("CE_Icon_" + key)
				{
					layer = layer
				};
				val.transform.SetParent(((Component)this).transform, false);
				val.transform.localScale = Vector3.one;
				GameObject val2 = new GameObject("Icon")
				{
					layer = layer
				};
				val2.transform.SetParent(val.transform, false);
				SpriteRenderer val3 = val2.AddComponent<SpriteRenderer>();
				val3.sprite = _textures.GetIconSprite(key);
				((Renderer)val3).sortingOrder = 10;
				float iconScale = _textures.GetIconScale(key);
				val2.transform.localScale = new Vector3(iconScale, iconScale, 1f);
				Image ringBg = CreateRingImage(val.transform, layer);
				Image ringFill = CreateRingImage(val.transform, layer);
				_icons[key] = new IconView(val, val3, ringFill, ringBg, _textures.GetRingColor(key), _textures.GetIconTint(key), key, _textures);
			}
		}

		private bool TryCreateNativeIcon(string key)
		{
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			NativeIconTemplate nativeIconTemplate = ResolveTemplate(key);
			if (nativeIconTemplate == null)
			{
				return false;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)nativeIconTemplate.Root).gameObject, ((Component)this).transform);
			((Object)val).name = "CE_Icon_" + key;
			val.SetActive(true);
			HudIconCloneSanitizer.Sanitize(val, key, _log, immediate: true);
			Transform obj = val.transform.Find(nativeIconTemplate.IconPath);
			SpriteRenderer val2 = ((obj != null) ? ((Component)obj).GetComponent<SpriteRenderer>() : null);
			Transform obj2 = val.transform.Find(nativeIconTemplate.FillPath);
			Image val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
			Transform obj3 = val.transform.Find(nativeIconTemplate.BgPath);
			Image val4 = ((obj3 != null) ? ((Component)obj3).GetComponent<Image>() : null);
			if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[HudStatusIconHost] native icon clone failed for '" + key + "'; falling back to custom build."));
				}
				return false;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				GameObject val5 = new GameObject("CE Center Icon")
				{
					layer = val.layer
				};
				val5.transform.SetParent(val.transform, false);
				val2 = val5.AddComponent<SpriteRenderer>();
				((Renderer)val2).sortingOrder = 10;
			}
			SanitizeNativeCloneContent(val, val2, val3, val4);
			LogNativeCloneHierarchy(key, val, val2);
			((Component)val2).gameObject.SetActive(true);
			((Renderer)val2).enabled = true;
			val2.sprite = _textures.GetIconSprite(key);
			float iconScale = _textures.GetIconScale(key);
			((Component)val2).transform.localScale = new Vector3(iconScale, iconScale, 1f);
			_icons[key] = new IconView(val, val2, val3, val4, _textures.GetRingColor(key), _textures.GetIconTint(key), key, _textures, nativeIconTemplate.InactiveColor);
			ManualLogSource? log2 = _log;
			if (log2 != null)
			{
				log2.LogInfo((object)("[HudStatusIconHost][probe] native icon cloned for '" + key + "' from " + BuildPath(nativeIconTemplate.Root)));
			}
			return true;
		}

		private static void SanitizeNativeCloneContent(GameObject cloneGo, SpriteRenderer icon, Image fill, Image bg)
		{
			Renderer[] componentsInChildren = cloneGo.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)icon))
				{
					SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null);
					if (val2 == null || !HudIconCloneSanitizer.ShouldKeepRenderer(((Object)val2).name, isCenterIcon: false, isArrow: false))
					{
						val.enabled = false;
					}
				}
			}
			Graphic[] componentsInChildren2 = cloneGo.GetComponentsInChildren<Graphic>(true);
			foreach (Graphic val3 in componentsInChildren2)
			{
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)fill) && !((Object)(object)val3 == (Object)(object)bg))
				{
					((Behaviour)val3).enabled = false;
				}
			}
		}

		private void LogNativeCloneHierarchy(string key, GameObject cloneGo, SpriteRenderer icon)
		{
			if (_log != null && _nativeCloneHierarchyLogged.Add(key))
			{
				_log.LogInfo((object)("[HudStatusIconHost][probe] native clone hierarchy '" + key + "' (center=" + ((Object)((Component)icon).transform).name + "):"));
				LogCloneNode(cloneGo.transform, 1);
			}
		}

		private void LogCloneNode(Transform node, int depth)
		{
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			if ((Object)(object)node == (Object)null)
			{
				return;
			}
			List<string> list = new List<string>();
			Component[] components = ((Component)node).GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null);
				if (val2 == null)
				{
					Image val3 = (Image)(object)((val is Image) ? val : null);
					if (val3 == null)
					{
						RawImage val4 = (RawImage)(object)((val is RawImage) ? val : null);
						if (val4 == null)
						{
							Text val5 = (Text)(object)((val is Text) ? val : null);
							if (val5 == null)
							{
								MeshRenderer val6 = (MeshRenderer)(object)((val is MeshRenderer) ? val : null);
								if (val6 != null)
								{
									list.Add($"MeshRenderer(enabled={((Renderer)val6).enabled})");
								}
								else
								{
									list.Add(((object)val).GetType().Name);
								}
							}
							else
							{
								list.Add($"Text(enabled={((Behaviour)val5).enabled})");
							}
						}
						else
						{
							object arg = ((Behaviour)val4).enabled;
							Texture texture = val4.texture;
							list.Add(string.Format("RawImage(enabled={0},tex={1})", arg, ((texture != null) ? ((Object)texture).name : null) ?? "null"));
						}
					}
					else
					{
						object arg2 = ((Behaviour)val3).enabled;
						Sprite sprite = val3.sprite;
						list.Add(string.Format("Image(enabled={0},sprite={1})", arg2, ((sprite != null) ? ((Object)sprite).name : null) ?? "null"));
					}
				}
				else
				{
					object arg3 = ((Renderer)val2).enabled;
					Sprite sprite2 = val2.sprite;
					list.Add(string.Format("SpriteRenderer(enabled={0},sprite={1})", arg3, ((sprite2 != null) ? ((Object)sprite2).name : null) ?? "null"));
				}
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)("[HudStatusIconHost][probe]   " + new string(' ', (depth - 1) * 2) + ((Object)node).name + " " + string.Format("active={0} [{1}]", ((Component)node).gameObject.activeSelf, string.Join(",", list))));
			}
			foreach (Transform item in node)
			{
				Transform node2 = item;
				LogCloneNode(node2, depth + 1);
			}
		}

		private Image CreateRingImage(Transform parent, int layer)
		{
			//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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Ring", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			})
			{
				layer = layer
			};
			val.transform.SetParent(parent, false);
			val.GetComponent<RectTransform>().sizeDelta = new Vector2(1f, 1f);
			Image component = val.GetComponent<Image>();
			component.sprite = _nativeRingSprite ?? _textures.RingSprite;
			component.type = (Type)3;
			component.fillMethod = (FillMethod)4;
			component.fillOrigin = 2;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private void RebuildLayout()
		{
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_00cd: 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)
			if (_icons.Count == 0)
			{
				return;
			}
			if (_gridManaged)
			{
				TransformLayoutGrid? grid = _grid;
				if (grid != null)
				{
					((TransformLayout)grid).UpdatePositions();
				}
				LogRowStructureCompact(null);
				return;
			}
			List<float> list = new List<float>();
			float? referenceY = null;
			if ((Object)(object)_rowAnchor != (Object)null)
			{
				foreach (Transform item in _rowAnchor)
				{
					Transform val = item;
					if (!((Object)(object)val == (Object)(object)((Component)this).transform) && !val.IsChildOf(((Component)this).transform) && ((Component)val).gameObject.activeInHierarchy && (!((Object)(object)((Component)val).GetComponent<ToolHudIcon>() == (Object)null) || !((Object)(object)((Component)val).GetComponent<Image>() == (Object)null) || !((Object)(object)((Component)val).GetComponent<SpriteRenderer>() == (Object)null)))
					{
						list.Add(val.localPosition.x);
						if (!referenceY.HasValue && (Object)(object)((Component)val).GetComponent<ToolHudIcon>() != (Object)null)
						{
							referenceY = val.localPosition.y;
						}
					}
				}
			}
			ToolRowLayout toolRowLayout = ToolRowLayoutCalculator.Calculate(list, referenceY, _config.Spacing, _config.FallbackOffset.x);
			int num = 0;
			foreach (IconView value in _icons.Values)
			{
				value.Root.transform.localPosition = new Vector3(toolRowLayout.StartX + (float)num * toolRowLayout.Spacing, toolRowLayout.RowY, 0f);
				num++;
			}
			LogRowStructureCompact(toolRowLayout);
		}

		private void AttachToRow(Transform anchor)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			_rowAnchor = anchor;
			_grid = ((Component)anchor).GetComponent<TransformLayoutGrid>();
			_gridManaged = (Object)(object)_grid != (Object)null;
			if ((Object)(object)anchor != (Object)(object)((Component)this).transform)
			{
				((Component)this).transform.SetParent(anchor, false);
				((Component)this).transform.localPosition = Vector3.zero;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[HudStatusIconHost][probe] row anchor: {BuildPath(anchor)} gridManaged={_gridManaged}");
			}
			CaptureNativeRing(anchor);
		}

		private void CaptureNativeRing(Transform anchor)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)anchor == (Object)null)
			{
				return;
			}
			foreach (Transform item in anchor)
			{
				Transform val = item;
				ToolHudIcon component = ((Component)val).GetComponent<ToolHudIcon>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				string text = ResolveTemplateKey(val, component);
				if (text == null || _nativeTemplates.ContainsKey(text))
				{
					continue;
				}
				FieldInfo fieldInfo = AccessTools.Field(typeof(RadialHudIcon), "icon");
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(RadialHudIcon), "radialImage");
				FieldInfo fieldInfo3 = AccessTools.Field(typeof(RadialHudIcon), "radialImageBg");
				FieldInfo fieldInfo4 = AccessTools.Field(typeof(RadialHudIcon), "inactiveColor");
				object? obj = fieldInfo?.GetValue(component);
				SpriteRenderer val2 = (SpriteRenderer)((obj is SpriteRenderer) ? obj : null);
				if (val2 == null)
				{
					continue;
				}
				object? obj2 = fieldInfo2?.GetValue(component);
				Image val3 = (Image)((obj2 is Image) ? obj2 : null);
				if (val3 == null)
				{
					continue;
				}
				object? obj3 = fieldInfo3?.GetValue(component);
				Image val4 = (Image)((obj3 is Image) ? obj3 : null);
				if (val4 != null)
				{
					Color? inactiveColor = ((fieldInfo4?.GetValue(component) is Color value) ? new Color?(value) : ((Color?)null));
					if ((Object)(object)_nativeRingSprite == (Object)null && (Object)(object)val3.sprite != (Object)null)
					{
						_nativeRingSprite = val3.sprite;
					}
					GameObject val5 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)this).transform);
					((Object)val5).name = "CE_OwnedTemplate_" + text;
					val5.SetActive(false);
					HudIconCloneSanitizer.Sanitize(val5, "<template>", _log);
					NativeIconTemplate nativeIconTemplate = new NativeIconTemplate
					{
						Root = val5.transform,
						IconPath = GetRelativePath(val, ((Component)val2).transform),
						FillPath = GetRelativePath(val, ((Component)val3).transform),
						BgPath = GetRelativePath(val, ((Component)val4).transform),
						InactiveColor = inactiveColor
					};
					_nativeTemplates[text] = nativeIconTemplate;
					if (_defaultTemplate == null || text == "N")
					{
						_defaultTemplate = nativeIconTemplate;
					}
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogInfo((object)("[HudStatusIconHost][probe] owned icon template captured (" + text + ") from " + BuildPath(val)));
					}
				}
			}
			if (_defaultTemplate == null && _nativeTemplates.Count > 0)
			{
				_defaultTemplate = _nativeTemplates.Values.First();
			}
		}

		private static string? ResolveTemplateKey(Transform child, ToolHudIcon toolHudIcon)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Invalid comparison between Unknown and I4
			string name = ((Object)child).name;
			if (name.EndsWith("U", StringComparison.Ordinal) || name.IndexOf(" Up", StringComparison.Ordinal) >= 0)
			{
				return "U";
			}
			if (name.EndsWith("D", StringComparison.Ordinal) || name.IndexOf(" Down", StringComparison.Ordinal) >= 0)
			{
				return "D";
			}
			if (name.EndsWith("N", StringComparison.Ordinal) || name.IndexOf(" Neutral", StringComparison.Ordinal) >= 0)
			{
				return "N";
			}
			if (AccessTools.Field(typeof(ToolHudIcon), "binding")?.GetValue(toolHudIcon) is AttackToolBinding val)
			{
				if ((int)val != 1)
				{
					if ((int)val == 2)
					{
						return "D";
					}
					return "N";
				}
				return "U";
			}
			return null;
		}

		private NativeIconTemplate? ResolveTemplate(string key)
		{
			if (key.EndsWith(".up", StringComparison.OrdinalIgnoreCase) && _nativeTemplates.TryGetValue("U", out NativeIconTemplate value))
			{
				return value;
			}
			if (key.EndsWith(".down", StringComparison.OrdinalIgnoreCase) && _nativeTemplates.TryGetValue("D", out NativeIconTemplate value2))
			{
				return value2;
			}
			if (key.EndsWith(".neutral", StringComparison.OrdinalIgnoreCase) && _nativeTemplates.TryGetValue("N", out NativeIconTemplate value3))
			{
				return value3;
			}
			return _defaultTemplate;
		}

		private static string? GetRelativePath(Transform root, Transform target)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null)
			{
				return null;
			}
			List<string> list = new List<string>();
			Transform val = target;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			if ((Object)(object)val != (Object)(object)root)
			{
				return null;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private void LogHierarchy(Transform parent, int depth, int maxDepth)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if ((Object)(object)parent == (Object)null || depth > maxDepth)
			{
				return;
			}
			foreach (Transform item in parent)
			{
				Transform val = item;
				string arg = string.Join(",", from c in ((Component)val).GetComponents<Component>()
					select ((object)c).GetType().Name);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[HudStatusIconHost][probe] {BuildPath(val)} layer={((Component)val).gameObject.layer} [{arg}]");
				}
				LogHierarchy(val, depth + 1, maxDepth);
			}
		}

		private void LogSiblingOverview(Transform? parent, string label)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)("[HudStatusIconHost][probe] " + label + " sibling overview:"));
			}
			foreach (Transform item in parent)
			{
				Transform val = item;
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"[HudStatusIconHost][probe]   {((Object)val).name} layer={((Component)val).gameObject.layer}");
				}
			}
		}

		private void LogRowStructure(string reason)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			if ((Object)(object)_rowAnchor == (Object)null || _log == null || !_config.LogHierarchyProbe)
			{
				return;
			}
			string text = string.Join(",", from c in ((Component)_rowAnchor).GetComponents<Component>()
				select ((object)c).GetType().Name);
			_log.LogInfo((object)("[HudStatusIconHost][probe] row structure (" + reason + ") anchor=" + BuildPath(_rowAnchor) + " [" + text + "]"));
			foreach (Transform item in _rowAnchor)
			{
				Transform val = item;
				string text2 = string.Join(",", from c in ((Component)val).GetComponents<Component>()
					select ((object)c).GetType().Name);
				_log.LogInfo((object)($"[HudStatusIconHost][probe]   {((Object)val).name} layer={((Component)val).gameObject.layer} " + $"active={((Component)val).gameObject.activeSelf} pos={val.localPosition} scale={val.localScale} [{text2}]"));
			}
			Transform parent = _rowAnchor.parent;
			if (!((Object)(object)parent != (Object)null))
			{
				return;
			}
			string text3 = string.Join(",", from c in ((Component)parent).GetComponents<Component>()
				select ((object)c).GetType().Name);
			_log.LogInfo((object)("[HudStatusIconHost][probe] row parent '" + ((Object)parent).name + "' [" + text3 + "] siblings:"));
			foreach (Transform item2 in parent)
			{
				Transform val2 = item2;
				string arg = string.Join(",", from c in ((Component)val2).GetComponents<Component>()
					select ((object)c).GetType().Name);
				_log.LogInfo((object)$"[HudStatusIconHost][probe]   {((Object)val2).name} layer={((Component)val2).gameObject.layer} [{arg}]");
			}
		}

		private void LogRowStructureCompact(ToolRowLayout? layout)
		{
			if (!((Object)(object)_rowAnchor == (Object)null) && _log != null && _config.LogHierarchyProbe && !_rowProbeLogged)
			{
				_rowProbeLogged = true;
				string text = string.Join("; ", from Transform c in (IEnumerable)_rowAnchor
					where (Object)(object)c != (Object)(object)((Component)this).transform
					select $"{((Object)c).name}(active={((Component)c).gameObject.activeSelf},x={c.localPosition.x:F2})");
				string text2 = ((layout == null) ? "grid-managed" : $"startX={layout.StartX:F2} y={layout.RowY:F2} spacing={layout.Spacing:F2}");
				_log.LogInfo((object)("[HudStatusIconHost][probe] row relayout " + text2 + " children=[" + text + "]"));
			}
		}

		private static string BuildPath(Transform transform)
		{
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private static Color Dim(Color color, float factor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return new Color(color.r * factor, color.g * factor, color.b * factor, color.a);
		}

		private static Color Multiply(Color a, Color b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			return new Color(a.r * b.r, a.g * b.g, a.b * b.b, a.a * b.a);
		}
	}
	public sealed class HunterStateAccessor
	{
		private readonly ManualLogSource _log;

		private readonly FieldInfo? _hunterStateField;

		private int? _savedMeterHits;

		private bool _forceActive;

		private bool _warned;

		public bool IsReady => _hunterStateField != null;

		public HunterStateAccessor(ManualLogSource log)
		{
			_log = log;
			_hunterStateField = AccessTools.Field(typeof(HeroController), "hunterUpgState");
			if (_hunterStateField == null)
			{
				_log.LogWarning((object)"[HunterState] hunterUpgState field not found; rage focus forcing disabled.");
			}
		}

		public int CurrentMeterHits()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (_hunterStateField == null)
			{
				return 0;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0;
			}
			try
			{
				return ((HunterUpgCrestStateInfo)_hunterStateField.GetValue(instance)).CurrentMeterHits;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return 0;
			}
		}

		public void SetFocusActive(bool active, int forcedMeterHits)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if (_hunterStateField == null || forcedMeterHits <= 0)
			{
				return;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				HunterUpgCrestStateInfo val = (HunterUpgCrestStateInfo)_hunterStateField.GetValue(instance);
				if (active)
				{
					if (!_forceActive)
					{
						_savedMeterHits = val.CurrentMeterHits;
						_forceActive = true;
					}
					val.CurrentMeterHits = forcedMeterHits;
				}
				else
				{
					if (!_forceActive)
					{
						return;
					}
					val.CurrentMeterHits = _savedMeterHits.GetValueOrDefault();
					_forceActive = false;
					_savedMeterHits = null;
				}
				_hunterStateField.SetValue(instance, val);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[HunterState] access failed (" + ex.GetType().Name + ": " + ex.Message + "); suppressing further warnings."));
			}
		}
	}
	public interface IGameApi : IDisposable
	{
		string CurrentCrestId { get; }

		int CurrentSilk { get; }

		int CurrentHealth { get; }

		int MaxHealth { get; }

		bool TryHeal(int amount, string reason);

		bool TrySpendSilk(int amount, string reason);

		void AddSilk(int amount, string reason);

		void AddShards(int amount, string reason);

		void SetTemporaryCharmLevelOffset(int offset, string source);

		void SetTemporaryMaxHealth(int? maxHealth);

		void ClearBlueHealth(string reason);

		IDisposable AcquireInvulnerability(string source, double maxDurationSeconds);

		bool TryInvokeVanillaAction(string bindingId);

		void SpawnAdditionalDamage(AdditionalDamageCommand command);

		bool SpawnPlayerExplosion(double damage, string sourceTag, float radius);

		bool SpawnPlayerExplosionAt(double damage, string sourceTag, float radius, Vector3 position);

		bool SpawnNativeExplosion();

		bool SpawnNativeExplosionAt(Vector3 position);

		bool TryGetToolColor(string toolId, out ToolColorKind color);
	}
	public static class MaxHealthHudSync
	{
		private static ManualLogSource? _log;

		private static bool _warned;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void Apply(int? projectedMax)
		{
			try
			{
				Transform val = FindHealthRoot();
				if ((Object)(object)val == (Object)null)
				{
					WarnOnce("[MaxHealthHudSync] 'Hud Canvas/Health' not found; mask sync skipped (HEALTH UPDATE fallback still sent).");
					return;
				}
				PlayMakerFSM[] componentsInChildren = ((Component)val).GetComponentsInChildren<PlayMakerFSM>(true);
				foreach (PlayMakerFSM val2 in componentsInChildren)
				{
					if ((Object)(object)val2 == (Object)null || !string.Equals(val2.FsmName, "health_display", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					FsmVariables fsmVariables = val2.FsmVariables;
					FsmInt val3 = ((fsmVariables != null) ? fsmVariables.FindFsmInt("Health Number") : null);
					if (val3 != null && val3.Value > 1)
					{
						bool flag = !projectedMax.HasValue || val3.Value <= projectedMax.Value;
						GameObject gameObject = ((Component)val2).gameObject;
						if (!((Object)(object)gameObject == (Object)null) && gameObject.activeSelf != flag)
						{
							gameObject.SetActive(flag);
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce("[MaxHealthHudSync] Apply failed: " + ex.Message);
			}
		}

		private static Transform? FindHealthRoot()
		{
			GameObject val = GameObject.Find("Hud Canvas");
			if ((Object)(object)val != (Object)null)
			{
				Transform val2 = val.transform.Find("Health");
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			GameObject obj = GameObject.Find("Hud Canvas/Health");
			if (obj == null)
			{
				return null;
			}
			return obj.transform;
		}

		private static void WarnOnce(string message)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)message);
				}
			}
		}
	}
	public sealed class NeedleforgeAdapter : IDisposable
	{
		public const string PluginGuid = "io.github.needleforge";

		private readonly ManualLogSource _log;

		public bool IsAvailable { get; private set; }

		public string? InstalledVersion { get; private set; }

		public ColorData? WhiteColorData { get; private set; }

		public NeedleforgeAdapter(ManualLogSource log)
		{
			_log = log;
		}

		public void Initialize()
		{
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				if (!(value.Metadata.GUID != "io.github.needleforge"))
				{
					IsAvailable = true;
					InstalledVersion = value.Metadata.Version.ToString();
					_log.LogInfo((object)("Needleforge adapter bound: version=" + InstalledVersion));
					return;
				}
			}
			_log.LogWarning((object)"Needleforge (io.github.needleforge) not found; custom crest/tool registration is disabled.");
		}

		public bool TryAddCrest(string name)
		{
			if (!IsAvailable || string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			try
			{
				NeedleforgePlugin.AddCrest(name);
				_log.LogInfo((object)("Needleforge crest registered: " + name));
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Needleforge AddCrest failed for '{name}': {arg}");
				return false;
			}
		}

		public bool TryAddTool(string name, ToolItemType type)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!IsAvailable || string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			try
			{
				NeedleforgePlugin.AddTool(name, type);
				_log.LogInfo((object)$"Needleforge tool registered: {name} ({type})");
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Needleforge AddTool failed for '{name}': {arg}");
				return false;
			}
		}

		public bool TryAddToolColor(string name, Color color, bool isAttackType = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!IsAvailable || string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			try
			{
				NeedleforgePlugin.AddToolColor(name, color, isAttackType);
				_log.LogInfo((object)("Needleforge tool color registered: " + name));
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Needleforge AddToolColor failed for '{name}': {arg}");
				return false;
			}
		}

		public bool TryAddWhiteToolColor(out ToolItemType type)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected I4, but got Unknown
			type = (ToolItemType)2;
			if (!IsAvailable)
			{
				return false;
			}
			try
			{
				ColorData val = NeedleforgePlugin.AddToolColor("White", Color.white, false);
				type = (ToolItemType)(int)val.Type;
				WhiteColorData = val;
				val.AddValidTypes((ToolItemType[])(object)new ToolItemType[2]
				{
					(ToolItemType)1,
					(ToolItemType)2
				});
				_log.LogInfo((object)$"Needleforge white tool color registered: type={type}");
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Needleforge AddToolColor(White) failed: {arg}");
				return false;
			}
		}

		public bool TrySetWhiteToolHeader(Sprite sprite)
		{
			if (!IsAvailable || WhiteColorData == null || (Object)(object)sprite == (Object)null)
			{
				return false;
			}
			try
			{
				WhiteColorData.header = sprite;
				_log.LogInfo((object)"Needleforge white tool section header set.");
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Needleforge white tool header failed: {arg}");
				return false;
			}
		}

		public ToolData? GetToolDataByName(string name)
		{
			if (!IsAvailable)
			{
				return null;
			}
			return NeedleforgePlugin.GetToolDataByName(name);
		}

		public void Dispose()
		{
		}
	}
	public sealed class PimpiloExplosionSpawner
	{
		public const string PrefabName = "Tool_pinpilo_explosion";

		private readonly ManualLogSource _log;

		private GameObject? _prefab;

		private bool _warnedResolve;

		private bool _warnedSpawn;

		public PimpiloExplosionSpawner(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
		}

		public bool Spawn(Vector3 position)
		{
			//IL_0033: 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)
			GameObject val = ResolvePrefab();
			if ((Object)(object)val == (Object)null)
			{
				if (!_warnedResolve)
				{
					_warnedResolve = true;
					_log.LogWarning((object)"[PimpiloExplosion] Tool_pinpilo_explosion prefab not resolved; shared native explosion disabled.");
				}
				return false;
			}
			try
			{
				GameObject val2 = ObjectPoolExtensions.Spawn(val, position, Quaternion.identity);
				if ((Object)(object)val2 == (Object)null)
				{
					return false;
				}
				val2.SetActive(true);
				return true;
			}
			catch (Exception ex)
			{
				if (!_warnedSpawn)
				{
					_warnedSpawn = true;
					_log.LogWarning((object)("[PimpiloExplosion] spawn failed: " + ex.Message));
				}
				return false;
			}
		}

		private GameObject? ResolvePrefab()
		{
			if ((Object)(object)_prefab != (Object)null)
			{
				return _prefab;
			}
			_prefab = LoadViaAddressables();
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = FindUniqueRuntimeObject();
			}
			if ((Object)(object)_prefab != (Object)null)
			{
				_log.LogInfo((object)("[PimpiloExplosion] prefab resolved: " + ((Object)_prefab).name));
			}
			return _prefab;
		}

		private GameObject? LoadViaAddressables()
		{
			try
			{
				object? obj = LoadAddressableObject(typeof(GameObject), "Tool_pinpilo_explosion");
				return (GameObject?)((obj is GameObject) ? obj : null);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[PimpiloExplosion] Addressables load failed for 'Tool_pinpilo_explosion': " + ex.Message));
				return null;
			}
		}

		private object? LoadAddressableObject(Type assetType, string key)
		{
			try
			{
				Type type = (from a in AppDomain.CurrentDomain.GetAssemblies()
					select a.GetType("UnityEngine.AddressableAssets.Addressables", throwOnError: false)).FirstOrDefault((Type t) => t != null);
				if (type == null)
				{
					return null;
				}
				MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
					where m.Name == "LoadAssetAsync" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string)
					select m).Take(2).ToArray();
				if (array.Length != 1)
				{
					return null;
				}
				object obj = array[0].MakeGenericMethod(assetType).Invoke(null, new object[1] { key });
				if (obj == null)
				{
					return null;
				}
				MethodInfo method = obj.GetType().GetMethod("WaitForCompletion", Type.EmptyTypes);
				if (method == null)
				{
					return null;
				}
				return method.Invoke(obj, null);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[PimpiloExplosion] Addressables load failed for '" + key + "': " + ex.Message));
				return null;
			}
		}

		private GameObject? FindUniqueRuntimeObject()
		{
			try
			{
				return ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => (Object)(object)go != (Object)null && ((Object)go).name == "Tool_pinpilo_explosion"));
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[PimpiloExplosion] runtime object search failed: " + ex.Message));
				return null;
			}
		}
	}
	public sealed class PlayerExplosionSpawner
	{
		private readonly ManualLogSource _log;

		private readonly MethodInfo? _hit;

		private bool _warned;

		public PlayerExplosionSpawner(ManualLogSource log, DynamicPatchResolver resolver)
		{
			_log = log;
			_hit = resolver.Resolve("player.explosion.apply") as MethodInfo;
			if (_hit == null)
			{
				_log.LogWarning((object)"[Explosion] HealthManager.Hit(HitInstance) unresolved; explosions are log-only.");
			}
		}

		public bool Spawn(double damage, float radius)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			return SpawnAt(damage, radius, ((Component)instance).transform.position);
		}

		public bool SpawnAt(double damage, float radius, Vector3 position)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_00ae: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if (_hit == null || damage <= 0.0)
			{
				return false;
			}
			try
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				Collider2D[] array = Physics2D.OverlapCircleAll(new Vector2(position.x, position.y), radius);
				bool result = false;
				Collider2D[] array2 = array;
				foreach (Collider2D val in array2)
				{
					if (!((Object)(object)val == (Object)null))
					{
						HealthManager componentInParent = ((Component)val).GetComponentInParent<HealthManager>();
						if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)((Component)componentInParent).gameObject == (Object)(object)((Component)instance).gameObject))
						{
							HitInstance val2 = new HitInstance
							{
								Source = ((Component)instance).gameObject,
								AttackType = (AttackTypes)11,
								DamageDealt = (int)Math.Round(damage),
								IsHeroDamage = true,
								IsFirstHit = true,
								DamageScalingLevel = 1,
								MagnitudeMultiplier = 1f,
								Multiplier = 1f
							};
							_hit.Invoke(componentInParent, new object[1] { val2 });
							result = true;
						}
					}
				}
				return result;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return false;
			}
		}

		private void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[Explosion] spawn failed (" + ex.GetType().Name + ": " + ex.Message + "); suppressing further warnings."));
			}
		}
	}
	public static class ReaperRuneBridge
	{
		public static Func<bool> IsDropRateOverrideActive { get; set; } = () => false;

		public static Func<bool> IsAutoCollectEnabled { get; set; } = () => false;

		public static Func<int> SubBladeChargedAttacksRemaining { get; set; } = () => 0;

		public static Func<bool> IsHailOfBladesFullLayers { get; set; } = () => false;

		public static Func<bool> IsChargeSlashEnhanced { get; set; } = () => false;

		public static bool IsDropRateWindowActive()
		{
			return IsDropRateOverrideActive();
		}

		public static bool IsSubBladeCharged()
		{
			return SubBladeChargedAttacksRemaining() > 0;
		}
	}
	public sealed class ReaperStateAccessor
	{
		private readonly ManualLogSource _log;

		private readonly MethodInfo? _stateGetter;

		private readonly PropertyInfo? _modeProperty;

		private readonly FieldInfo? _modeField;

		private readonly PropertyInfo? _durationProperty;

		private readonly FieldInfo? _durationField;

		private readonly FieldInfo? _stateField;

		private bool _rageForced;

		private bool _disabled;

		private bool _warned;

		private float _extraDuration;

		public ReaperStateAccessor(ManualLogSource log, DynamicPatchResolver resolver)
		{
			_log = log;
			_stateGetter = resolver.Resolve("player.reaper.state.mode") as MethodInfo;
			_stateField = AccessTools.Field(typeof(HeroController), "reaperState");
			if (_stateGetter == null)
			{
				_disabled = true;
				_log.LogWarning((object)"[ReaperState] binding 'player.reaper.state.mode' unresolved; strong icon disabled.");
				return;
			}
			Type returnType = _stateGetter.ReturnType;
			_modeProperty = AccessTools.Property(returnType, "IsInReaperMode");
			_modeField = ((_modeProperty == null) ? AccessTools.Field(returnType, "IsInReaperMode") : null);
			_durationProperty = AccessTools.Property(returnType, "ReaperModeDurationLeft");
			_durationField = ((_durationProperty == null) ? AccessTools.Field(returnType, "ReaperModeDurationLeft") : null);
			if (_modeProperty == null && _modeField == null)
			{
				_disabled = true;
				_log.LogWarning((object)("[ReaperState] member 'IsInReaperMode' not found on " + returnType.FullName + "; strong icon disabled."));
			}
			else if (_durationProperty == null && _durationField == null)
			{
				_disabled = true;
				_log.LogWarning((object)("[ReaperState] member 'ReaperModeDurationLeft' not found on " + returnType.FullName + "; countdown disabled."));
			}
			else
			{
				_disabled = false;
				_log.LogInfo((object)("[ReaperState] accessor ready: " + returnType.FullName + "."));
			}
		}

		public bool IsInReaperMode()
		{
			if (_disabled || _stateGetter == null)
			{
				return false;
			}
			object state = GetState();
			if (state == null)
			{
				return false;
			}
			try
			{
				return Convert.ToBoolean(GetValue(_modeProperty, _modeField, state));
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return false;
			}
		}

		public float SecondsLeft()
		{
			if (_disabled || _stateGetter == null)
			{
				return 0f;
			}
			object state = GetState();
			if (state == null)
			{
				return 0f;
			}
			try
			{
				return Convert.ToSingle(GetValue(_durationProperty, _durationField, state));
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return 0f;
			}
		}

		public void AddReaperModeDuration(float seconds)
		{
			if (_disabled || seconds <= 0f)
			{
				return;
			}
			_extraDuration += seconds;
			WriteState(delegate(ReaperCrestStateInfo state)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if (state.IsInReaperMode)
				{
					state.ReaperModeDurationLeft = Math.Max(0f, state.ReaperModeDurationLeft) + seconds;
				}
			});
			_log.LogDebug((object)$"[ReaperState] extra duration += {seconds} (total extra {_extraDuration}).");
		}

		public void ResetExtraDuration()
		{
			if (_extraDuration != 0f)
			{
				_extraDuration = 0f;
				_log.LogDebug((object)"[ReaperState] extra duration reset.");
			}
		}

		public void SetRageModeActive(bool active)
		{
			if (active)
			{
				_rageForced = true;
				WriteState(delegate(ReaperCrestStateInfo state)
				{
					state.IsInReaperMode = true;
					state.ReaperModeDurationLeft = Gameplay.ReaperModeDuration + _extraDuration;
				});
			}
			else
			{
				_rageForced = false;
			}
		}

		public void RefreshRageDuration()
		{
			if (_rageForced)
			{
				WriteState(delegate(ReaperCrestStateInfo state)
				{
					state.ReaperModeDurationLeft = Gameplay.ReaperModeDuration + _extraDuration;
				});
			}
		}

		private void WriteState(Action<ReaperCrestStateInfo> change)
		{
			//IL_002c: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (_stateField == null)
			{
				return;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				ReaperCrestStateInfo val = (ReaperCrestStateInfo)_stateField.GetValue(instance);
				change(val);
				_stateField.SetValue(instance, val);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private object? GetState()
		{
			try
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				return _stateGetter.Invoke(instance, null);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return null;
			}
		}

		private static object? GetValue(PropertyInfo? property, FieldInfo? field, object instance)
		{
			if (!(property != null))
			{
				return field.GetValue(instance);
			}
			return property.GetValue(instance, null);
		}

		private void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[ReaperState] access failed (" + ex.GetType().Name + ": " + ex.Message + "); suppressing further warnings."));
			}
		}
	}
	public sealed class ReflectionGameApi : IGameApi, IDisposable
	{
		private sealed class NoopDisposable : IDisposable
		{
			public void Dispose()
			{
			}
		}

		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly DynamicPatchResolver _resolver;

		private readonly InvulnerabilityLeaseService _leases;

		private readonly FieldInfo? _healthField;

		private readonly FieldInfo? _maxHealthField;

		private readonly PlayerExplosionSpawner? _explosions;

		private readonly PimpiloExplosionSpawner? _nativeExplosions;

		private int _trackedHealth;

		private int _trackedMaxHealth = 1;

		private int _lastPublishedHealth = -1;

		private int _lastPublishedMaxHealth = -1;

		private int? _originalMaxHealthBase;

		private int? _originalHealth;

		private bool _maxHealthProjected;

		public string CurrentCrestId => HeroController.instance?.playerData?.CurrentCrestID ?? "unbound";

		public int CurrentSilk => (HeroController.instance?.playerData?.silk).GetValueOrDefault();

		public int CurrentHealth => ReadHealth(_healthField, _trackedHealth, isHealth: true);

		public int MaxHealth => Math.Max(1, ReadHealth(_maxHealthField, _trackedMaxHealth, isHealth: false));

		public ReflectionGameApi(ManualLogSource log, GameEventHub events, DynamicPatchResolver resolver, InvulnerabilityLeaseService leases)
		{
			_log = log;
			_events = events;
			_resolver = resolver;
			_leases = leases;
			_healthField = _resolver.ResolveField("player.health.get");
			_maxHealthField = _resolver.ResolveField("player.maxhealth.get");
			_explosions = new PlayerExplosionSpawner(log, resolver);
			_nativeExplosions = new PimpiloExplosionSpawner(log);
			MaxHealthHudSync.Configure(log);
			if (_healthField == null || _maxHealthField == null)
			{
				_log.LogWarning((object)"Health field binding is not fully resolved; rage UI will fall back to event-tracked health (unverified).");
				_events.PlayerDamageAfter += OnTrackedDamage;
				_events.HealResolved += OnTrackedHeal;
				_events.BenchRested += OnTrackedBench;
				_events.PlayerDied += OnTrackedDeath;
			}
			_events.PlayerDamageAfter += OnHealthSource;
			_events.HealResolved += OnHealthSource;
			_events.BenchRested += OnHealthSource;
			_events.PlayerDied += OnHealthSource;
			_events.SceneChanged += OnHealthSource;
		}

		public bool TryHeal(int amount, string reason)
		{
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null || amount <= 0)
			{
				return false;
			}
			try
			{
				instance.AddHealth(amount);
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"TryHeal failed: amount={amount}, reason={reason}, error={arg}");
				return false;
			}
		}

		public bool TrySpendSilk(int amount, string reason)
		{
			HeroController instance = HeroController.instance;
			if (instance?.playerData == null)
			{
				return false;
			}
			if (amount < 0)
			{
				return false;
			}
			if (instance.playerData.silk < amount)
			{
				return false;
			}
			try
			{
				instance.TakeSilk(amount, (SilkTakeSource)4);
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"TrySpendSilk failed: amount={amount}, reason={reason}, error={arg}");
				return false;
			}
		}

		public void AddSilk(int amount, string reason)
		{
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null || amount <= 0)
			{
				return;
			}
			try
			{
				instance.AddSilk(amount, false, (SilkAddSource)0, false);
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"AddSilk failed: amount={amount}, reason={reason}, error={arg}");
			}
		}

		public void AddShards(int amount, string reason)
		{
			if (amount <= 0)
			{
				return;
			}
			PlayerData instance = PlayerData.instance;
			if (instance == null)
			{
				return;
			}
			try
			{
				instance.AddShards(amount);
			}
			catch (Exception arg)
			{
				_l

CrestsEvolve.InsectMayCry/CrestsEvolve.InsectMayCry.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrestsEvolve.Core.CrestSwitching;
using CrestsEvolve.Core.Events;
using CrestsEvolve.Core.State;
using CrestsEvolve.Core.UI;
using CrestsEvolve.Features;
using CrestsEvolve.Features.CrestSwitching;
using CrestsEvolve.Features.StatusIcons;
using CrestsEvolve.GameInterop;
using CrestsEvolve.GameInterop.CrestSwitching;
using CrestsEvolve.GameInterop.Input;
using CrestsEvolve.InsectMayCry.Features.AttackModules;
using CrestsEvolve.InsectMayCry.Features.CrossStitch;
using CrestsEvolve.InsectMayCry.Features.SecondToolSet;
using CrestsEvolve.InsectMayCry.Features.Vergil;
using CrestsEvolve.InsectMayCry.Features.WindBlade;
using CrestsEvolve.InsectMayCry.GameInterop;
using CrestsEvolve.Patches;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using InControl;
using Microsoft.CodeAnalysis;
using Needleforge;
using Needleforge.Data;
using Silksong.FsmUtil;
using TeamCherry.Localization;
using TeamCherry.SharedUtils;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CrestsEvolve.InsectMayCry")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")]
[assembly: AssemblyProduct("CrestsEvolve.InsectMayCry")]
[assembly: AssemblyTitle("CrestsEvolve.InsectMayCry")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace CrestsEvolve.Patches
{
	[HarmonyPatch(typeof(HeroController), "Awake")]
	internal static class CrestQuickSwitchHeroAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(HeroController __instance)
		{
			CrestQuickSwitchIntegration.Instance?.AttachHero(__instance);
		}
	}
	[HarmonyPatch(typeof(HeroController), "Update")]
	internal static class CrestQuickSwitchHeroUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(HeroController __instance)
		{
			CrestQuickSwitchIntegration.Instance?.OnHeroUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(ToolItemManager), "TryReplenishTools")]
	internal static class CrestQuickSwitchBenchReplenishPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool doReplenish, ReplenishMethod method)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return CrestQuickSwitchIntegration.Instance?.TryReplenishAllCrestsAtBench(ref doReplenish, method) ?? true;
		}
	}
}
namespace CrestsEvolve.GameInterop.CrestSwitching
{
	public sealed class CrestNameProvider
	{
		private readonly ConfigEntry<string> _queenCrestId;

		public string? Toolmaster => SafeCrestName(() => Gameplay.ToolmasterCrest);

		public string Queen => _queenCrestId.Value;

		public string? Spell => SafeCrestName(() => Gameplay.SpellCrest);

		public string? Hunter => GetBestHunterName();

		public string? Reaper => SafeCrestName(() => Gameplay.ReaperCrest);

		public string? Warrior => SafeCrestName(() => Gameplay.WarriorCrest);

		public string? Wanderer => SafeCrestName(() => Gameplay.WandererCrest);

		public string? Witch => SafeCrestName(() => Gameplay.WitchCrest);

		public CrestNameProvider(ConfigEntry<string> queenCrestId)
		{
			_queenCrestId = queenCrestId;
		}

		public string[] AllCrestNames()
		{
			return new string[8] { Toolmaster, Queen, Spell, Hunter, Reaper, Warrior, Wanderer, Witch }.Where((string x) => !string.IsNullOrWhiteSpace(x)).Distinct<string>(StringComparer.Ordinal).ToArray();
		}

		public string? ResolveDirectionTarget(string current, int directionMask, bool isLong)
		{
			return directionMask switch
			{
				1 => ToggleLogic(current, isLong, Toolmaster, Queen), 
				2 => ToggleLogic(current, isLong, Spell, Hunter), 
				4 => ToggleLogic(current, isLong, Reaper, Warrior), 
				8 => ToggleLogic(current, isLong, Wanderer, Witch), 
				_ => null, 
			};
		}

		private static string? ToggleLogic(string current, bool isLong, string? primary, string? secondary)
		{
			if (string.IsNullOrWhiteSpace(primary) || string.IsNullOrWhiteSpace(secondary))
			{
				return null;
			}
			if (!isLong)
			{
				if (!(current == primary))
				{
					return primary;
				}
				return secondary;
			}
			if (!(current == secondary))
			{
				return secondary;
			}
			return primary;
		}

		private static string? SafeCrestName(Func<ToolCrest> getter)
		{
			try
			{
				ToolCrest obj = getter();
				return (obj != null) ? obj.name : null;
			}
			catch
			{
				return null;
			}
		}

		private string? GetBestHunterName()
		{
			try
			{
				if ((Object)(object)Gameplay.HunterCrest3 != (Object)null && Gameplay.HunterCrest3.IsUnlocked)
				{
					return Gameplay.HunterCrest3.name;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)Gameplay.HunterCrest2 != (Object)null && Gameplay.HunterCrest2.IsUnlocked)
				{
					return Gameplay.HunterCrest2.name;
				}
			}
			catch
			{
			}
			return SafeCrestName(() => Gameplay.HunterCrest);
		}
	}
	public sealed class CrestSwitchService
	{
		private readonly ManualLogSource _log;

		private readonly HeroReflectionCache _heroReflection;

		private readonly ConfigEntry<float> _invulnerabilitySeconds;

		private readonly ConfigEntry<bool> _replenishAllCrestsAtBench;

		private readonly ConfigEntry<string> _queenCrestId;

		private readonly ConfigEntry<int> _postSwapRecoveryFrames;

		public bool IsApplyingSwap { get; private set; }

		public bool IsReplenishLooping { get; private set; }

		public bool PostSwapWasFromDash { get; private set; }

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

		public CrestSwitchService(ManualLogSource log, HeroReflectionCache heroReflection, ConfigEntry<float> invulnerabilitySeconds, ConfigEntry<bool> replenishAllCrestsAtBench, ConfigEntry<string> queenCrestId, ConfigEntry<int> postSwapRecoveryFrames)
		{
			_log = log;
			_heroReflection = heroReflection;
			_invulnerabilitySeconds = invulnerabilitySeconds;
			_replenishAllCrestsAtBench = replenishAllCrestsAtBench;
			_queenCrestId = queenCrestId;
			_postSwapRecoveryFrames = postSwapRecoveryFrames;
		}

		public bool IsSafeToSwapNow(HeroController hero)
		{
			if ((Object)(object)hero == (Object)null || hero.playerData == null)
			{
				return false;
			}
			if (_heroReflection.IsDashLikeActive(hero))
			{
				return false;
			}
			if (_heroReflection.IsAttackOrChargeActive(hero))
			{
				return false;
			}
			if (!_heroReflection.HasControl(hero))
			{
				return false;
			}
			return true;
		}

		public bool TryApply(string targetName, string reason, bool fromDash, HeroController hero)
		{
			if (IsApplyingSwap || hero?.playerData == null)
			{
				return false;
			}
			IsApplyingSwap = true;
			try
			{
				ToolCrest crestByName = ToolItemManager.GetCrestByName(targetName);
				if ((Object)(object)crestByName == (Object)null)
				{
					_log.LogWarning((object)("Crest quick switch target not found: " + targetName));
					return false;
				}
				int silk = hero.playerData.silk;
				if (fromDash)
				{
					_heroReflection.NormalizeDashExit(hero, true);
				}
				ToolEquipsSnapshot.Log(_log, "switch-before:" + reason + ":" + crestByName.name);
				_heroReflection.ApplyInvincibility(hero, Math.Max(0f, _invulnerabilitySeconds.Value));
				hero.ResetAllCrestState();
				ToolItemManager.SetEquippedCrest(crestByName.name);
				ToolItemManager.SendEquippedChangedEvent(true);
				ToolEquipsSnapshot.Log(_log, "switch-after:" + reason + ":" + crestByName.name);
				hero.playerData.silk = silk;
				if (fromDash)
				{
					PostSwapWasFromDash = true;
					PostSwapRecoveryUntilFrame = Time.frameCount + Math.Max(1, _postSwapRecoveryFrames.Value);
					_heroReflection.NormalizeDashExit(hero, true);
				}
				_log.LogInfo((object)("Crest switched -> " + crestByName.name + " [" + reason + "]"));
				return true;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Crest switch failed: target={targetName}, reason={reason}, error={arg}");
				return false;
			}
			finally
			{
				IsApplyingSwap = false;
			}
		}

		public void EndPostSwapRecovery()
		{
			PostSwapWasFromDash = false;
			PostSwapRecoveryUntilFrame = -1;
		}

		public unsafe bool TryReplenishAllCrestsAtBench(ref bool doReplenish, ReplenishMethod method, HeroController hero, CrestNameProvider names)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!_replenishAllCrestsAtBench.Value)
			{
				return true;
			}
			if (hero?.playerData == null)
			{
				return true;
			}
			if (((object)(*(ReplenishMethod*)(&method))/*cast due to .constrained prefix*/).ToString().IndexOf("Bench", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return true;
			}
			if (IsReplenishLooping)
			{
				return true;
			}
			string currentCrestID = hero.playerData.CurrentCrestID;
			string[] array = names.AllCrestNames();
			try
			{
				IsReplenishLooping = true;
				string[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					ToolCrest crestByName = ToolItemManager.GetCrestByName(array2[i]);
					if (!((Object)(object)crestByName == (Object)null) && crestByName.IsUnlocked && !crestByName.IsHidden)
					{
						hero.ResetAllCrestState();
						ToolItemManager.SetEquippedCrest(crestByName.name);
						ToolItemManager.TryReplenishTools(true, method);
					}
				}
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Replenish-all-crests-at-bench failed: {arg}");
			}
			finally
			{
				try
				{
					hero.ResetAllCrestState();
					ToolItemManager.SetEquippedCrest(currentCrestID);
					ToolItemManager.SendEquippedChangedEvent(true);
				}
				catch (Exception arg2)
				{
					_log.LogError((object)$"Failed to restore crest after bench replenishment: {arg2}");
				}
				IsReplenishLooping = false;
			}
			return true;
		}
	}
}
namespace CrestsEvolve.Features.CrestSwitching
{
	public sealed class CrestQuickSwitchIntegration : IDisposable
	{
		private const int UpMask = 1;

		private const int DownMask = 2;

		private const int LeftMask = 4;

		private const int RightMask = 8;

		private static CrestQuickSwitchIntegration? _instance;

		private readonly ManualLogSource _log;

		private readonly Harmony _harmony;

		private readonly NativeInputAdapter _input;

		private readonly HeroReflectionCache _heroReflection;

		private readonly DashSafetyPolicy _safety;

		private readonly CrestSwapQueue _queue = new CrestSwapQueue();

		private readonly CrestNameProvider _names;

		private readonly CrestSwitchService _switchService;

		private readonly ConfigEntry<bool> _enabled;

		private readonly ConfigEntry<float> _longPressThreshold;

		private readonly ConfigEntry<float> _specialPressThreshold;

		private readonly ConfigEntry<float> _cooldownSeconds;

		private readonly ConfigEntry<int> _dashSettleFrames;

		private readonly ConfigEntry<string> _mainActionCandidates;

		private readonly ConfigEntry<bool> _verboseLogging;

		private HeroController? _hero;

		private bool _disposed;

		private float _nextSwapTime;

		private float _mainKeyDownTime = -1f;

		private int _lastChosenDirMask;

		private bool _swappedThisPress;

		private bool _specialTriggeredThisPress;

		private int _lastTriggeredDirMask;

		private bool _lastTriggeredLong;

		private bool _previousMainHeld;

		private int _previousDirectionMask;

		private long _nextRequestId = 1L;

		internal static CrestQuickSwitchIntegration? Instance => _instance;

		private CrestQuickSwitchIntegration(ManualLogSource log, ConfigFile config, Harmony harmony)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			_log = log;
			_harmony = harmony;
			_enabled = config.Bind<bool>("CrestQuickSwitch", "Enabled", true, "Enable directional crest quick switching.");
			_longPressThreshold = config.Bind<float>("CrestQuickSwitch", "LongPressThresholdSeconds", 0.2f, "Holding the main action for at least this duration selects the secondary crest.");
			_specialPressThreshold = config.Bind<float>("CrestQuickSwitch", "SpecialPressThresholdSeconds", 3f, "Holding the main action without a direction toggles Cursed/Cloakless crest.");
			_cooldownSeconds = config.Bind<float>("CrestQuickSwitch", "CooldownSeconds", 0.3f, "Minimum time between two crest switches.");
			ConfigEntry<float> invulnerabilitySeconds = config.Bind<float>("CrestQuickSwitch", "SwapInvulnerabilitySeconds", 0.1f, "Short protection applied when a queued switch is committed.");
			_dashSettleFrames = config.Bind<int>("CrestQuickSwitch", "DashSettleFrames", 3, "Frames to wait after the final dash frame before changing crest. Increase to 4-5 if another movement mod still leaves dash velocity behind.");
			ConfigEntry<int> postSwapRecoveryFrames = config.Bind<int>("CrestQuickSwitch", "PostSwapRecoveryFrames", 2, "Frames after a dash-origin switch during which stale dash flags and horizontal velocity are cleared.");
			ConfigEntry<string> queenCrestId = config.Bind<string>("CrestQuickSwitch", "QueenCrestId", "Vergil", "Internal ID/name used by the custom Silk Mother/Queen crest.");
			_mainActionCandidates = config.Bind<string>("CrestQuickSwitch", "MainActionCandidates", "taunt,ringTaunt,quickMap,dreamNail,inventory,cast", "Comma-separated game inputActions member names. The first existing action is used as the quick-switch modifier.");
			ConfigEntry<bool> replenishAllCrestsAtBench = config.Bind<bool>("CrestQuickSwitch", "ReplenishAllCrestsAtBench", false, "Legacy behavior from the standalone mod. Disabled by default because the overhaul should eventually replenish virtual tool inventories without temporarily changing crests.");
			_verboseLogging = config.Bind<bool>("CrestQuickSwitch", "VerboseLogging", false, "Write input binding, queue, dash recovery, and switch diagnostics.");
			_heroReflection = new HeroReflectionCache(log);
			_input = new NativeInputAdapter(log);
			_safety = new DashSafetyPolicy(() => Math.Max(1, _dashSettleFrames.Value));
			_names = new CrestNameProvider(queenCrestId);
			_switchService = new CrestSwitchService(log, _heroReflection, invulnerabilitySeconds, replenishAllCrestsAtBench, queenCrestId, postSwapRecoveryFrames);
		}

		public static CrestQuickSwitchIntegration Install(ManualLogSource log, ConfigFile config, Harmony harmony)
		{
			if (_instance != null)
			{
				return _instance;
			}
			CrestQuickSwitchIntegration? crestQuickSwitchIntegration = (_instance = new CrestQuickSwitchIntegration(log, config, harmony));
			harmony.CreateClassProcessor(typeof(CrestQuickSwitchHeroAwakePatch)).Patch();
			harmony.CreateClassProcessor(typeof(CrestQuickSwitchHeroUpdatePatch)).Patch();
			harmony.CreateClassProcessor(typeof(CrestQuickSwitchBenchReplenishPatch)).Patch();
			crestQuickSwitchIntegration.AttachHero(HeroController.instance);
			log.LogInfo((object)"Crest quick switch integrated into CrestsEvolve.");
			return crestQuickSwitchIntegration;
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_input.Reset();
				_queue.Cancel();
				_safety.Reset();
				_hero = null;
				_instance = null;
			}
		}

		internal void AttachHero(HeroController? hero)
		{
			if (!_disposed && !((Object)(object)hero == (Object)null) && _hero != hero)
			{
				_hero = hero;
				_heroReflection.Initialize(hero);
				_input.Bind(hero, (IReadOnlyList<string>)ParseCandidates(_mainActionCandidates.Value));
				ResetPressState();
				_previousMainHeld = false;
				_previousDirectionMask = 0;
				Trace("Attached HeroController and refreshed native input bindings.");
			}
		}

		internal void OnHeroUpdate(HeroController hero)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || !_enabled.Value)
			{
				return;
			}
			AttachHero(hero);
			if (!((Object)(object)_hero == (Object)null) && _hero.playerData != null)
			{
				_input.RefreshIfActionSetChanged(_hero, (IReadOnlyList<string>)ParseCandidates(_mainActionCandidates.Value));
				TrackUnsafeFrames();
				RunPostSwapRecovery();
				TryConsumeQueuedSwap();
				if (!_switchService.IsReplenishLooping && !_switchService.IsApplyingSwap && _input.IsReady)
				{
					InputFrame frame = _input.ReadFrame();
					ProcessInputFrame(frame);
				}
			}
		}

		internal bool TryReplenishAllCrestsAtBench(ref bool doReplenish, ReplenishMethod method)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_hero == (Object)null))
			{
				return _switchService.TryReplenishAllCrestsAtBench(ref doReplenish, method, _hero, _names);
			}
			return true;
		}

		private void ProcessInputFrame(InputFrame frame)
		{
			bool num = ((InputFrame)(ref frame)).MainPressed || (((InputFrame)(ref frame)).MainHeld && !_previousMainHeld);
			bool flag = ((InputFrame)(ref frame)).MainReleased || (!((InputFrame)(ref frame)).MainHeld && _previousMainHeld);
			int downMask = ((InputFrame)(ref frame)).DirectionMask & ~_previousDirectionMask;
			_previousMainHeld = ((InputFrame)(ref frame)).MainHeld;
			_previousDirectionMask = ((InputFrame)(ref frame)).DirectionMask;
			if (num)
			{
				_mainKeyDownTime = Time.unscaledTime;
				ResetPressState();
			}
			if (flag || (_mainKeyDownTime >= 0f && !((InputFrame)(ref frame)).MainHeld))
			{
				_mainKeyDownTime = -1f;
				ResetPressState();
			}
			else
			{
				if (!((InputFrame)(ref frame)).MainHeld)
				{
					return;
				}
				if (_mainKeyDownTime < 0f)
				{
					_mainKeyDownTime = Time.unscaledTime;
				}
				int num2 = ChooseDirection(((InputFrame)(ref frame)).DirectionMask, downMask);
				float num3 = Time.unscaledTime - _mainKeyDownTime;
				if (num2 == 0 && !_specialTriggeredThisPress && num3 >= Math.Max(0.1f, _specialPressThreshold.Value))
				{
					HandleSpecialSwap();
					_specialTriggeredThisPress = true;
					_nextSwapTime = Time.unscaledTime + Math.Max(0f, _cooldownSeconds.Value);
				}
				else if (num2 != 0 && !(Time.unscaledTime < _nextSwapTime))
				{
					bool flag2 = num3 >= Math.Max(0.01f, _longPressThreshold.Value);
					bool num4 = num2 != _lastTriggeredDirMask;
					bool flag3 = !num4 && flag2 != _lastTriggeredLong;
					if (num4 || (!_swappedThisPress && flag3))
					{
						PerformDirectionalSwap(num2, flag2);
					}
				}
			}
		}

		private void ResetPressState()
		{
			_lastChosenDirMask = 0;
			_lastTriggeredDirMask = 0;
			_lastTriggeredLong = false;
			_swappedThisPress = false;
			_specialTriggeredThisPress = false;
		}

		private void HandleSpecialSwap()
		{
			if (_hero?.playerData != null)
			{
				string currentCrestID = _hero.playerData.CurrentCrestID;
				string text = SafeCrestName(() => Gameplay.CursedCrest);
				string text2 = SafeCrestName(() => Gameplay.CloaklessCrest) ?? "Cloakless Crest";
				if (!string.IsNullOrWhiteSpace(text))
				{
					RequestSwap((currentCrestID == text) ? text2 : text, "SPECIAL_3S");
				}
			}
		}

		private void PerformDirectionalSwap(int directionMask, bool isLong)
		{
			if (_hero?.playerData != null)
			{
				string currentCrestID = _hero.playerData.CurrentCrestID;
				string text = _names.ResolveDirectionTarget(currentCrestID, directionMask, isLong);
				if (!string.IsNullOrWhiteSpace(text) && !(text == currentCrestID))
				{
					RequestSwap(text, isLong ? "LONG" : "SHORT");
					_lastTriggeredDirMask = directionMask;
					_lastTriggeredLong = isLong;
					_swappedThisPress = true;
					_nextSwapTime = Time.unscaledTime + Math.Max(0f, _cooldownSeconds.Value);
				}
			}
		}

		private void RequestSwap(string targetName, string reason)
		{
			if (_hero?.playerData != null && !string.IsNullOrWhiteSpace(targetName))
			{
				bool flag = _heroReflection.IsDashLikeActive(_hero);
				bool num = _switchService.IsSafeToSwapNow(_hero);
				bool flag2 = _safety.HasDashSettled(Time.frameCount);
				if (num && flag2)
				{
					_switchService.TryApply(targetName, reason, fromDash: false, _hero);
					return;
				}
				SwapOrigin origin = ((flag || Time.frameCount - _safety.LastDashFrame <= Math.Max(1, _dashSettleFrames.Value)) ? SwapOrigin.Dash : (_heroReflection.IsAttackOrChargeActive(_hero) ? SwapOrigin.Attack : SwapOrigin.Unknown));
				_queue.Enqueue(new SwapRequest(_nextRequestId++, _hero.playerData.CurrentCrestID, targetName, origin, Time.frameCount, Time.unscaledTime, _safety.EarliestFrame(Time.frameCount), 3600.0, PreserveSilk: true, PreserveMarkedHealth: false, reason));
				Trace("Queued crest switch -> " + targetName + "; reason=" + reason + "; " + $"dash={_queue.IsDashOrigin}; earliestFrame={_safety.EarliestFrame(Time.frameCount)}");
			}
		}

		private void TryConsumeQueuedSwap()
		{
			if (_hero?.playerData != null)
			{
				SwapRequest swapRequest = _queue.TryDequeue(Time.frameCount, Time.unscaledTime, (SwapRequest _) => _switchService.IsSafeToSwapNow(_hero) && _safety.HasDashSettled(Time.frameCount));
				if ((object)swapRequest != null && !string.IsNullOrWhiteSpace(swapRequest.ToCrest) && !(swapRequest.ToCrest == _hero.playerData.CurrentCrestID))
				{
					SwapOrigin origin = swapRequest.Origin;
					bool flag = (uint)(origin - 5) <= 2u;
					bool flag2 = flag;
					string reason = (swapRequest.Reason ?? "QUEUED") + (flag2 ? "_DASH_SAFE" : "_SAFE");
					_switchService.TryApply(swapRequest.ToCrest, reason, flag2, _hero);
				}
			}
		}

		private void TrackUnsafeFrames()
		{
			if (!((Object)(object)_hero == (Object)null))
			{
				bool flag = _heroReflection.IsDashLikeActive(_hero);
				bool unsafeNow = flag || _heroReflection.IsAttackOrChargeActive(_hero) || !_heroReflection.HasControl(_hero);
				_safety.RecordFrame(Time.frameCount, flag, unsafeNow);
			}
		}

		private void RunPostSwapRecovery()
		{
			if (_switchService.PostSwapWasFromDash && !((Object)(object)_hero == (Object)null))
			{
				if (Time.frameCount > _switchService.PostSwapRecoveryUntilFrame)
				{
					_switchService.EndPostSwapRecovery();
					return;
				}
				_heroReflection.NormalizeDashExit(_hero, true);
				Trace($"Dash post-swap recovery frame {Time.frameCount}/{_switchService.PostSwapRecoveryUntilFrame}");
			}
		}

		private static string? SafeCrestName(Func<ToolCrest> getter)
		{
			try
			{
				ToolCrest obj = getter();
				return (obj != null) ? obj.name : null;
			}
			catch
			{
				return null;
			}
		}

		private int ChooseDirection(int heldMask, int downMask)
		{
			if (BitCount(downMask) == 1)
			{
				_lastChosenDirMask = downMask;
				return downMask;
			}
			if (BitCount(heldMask) == 1)
			{
				_lastChosenDirMask = heldMask;
				return heldMask;
			}
			if (heldMask != 0 && _lastChosenDirMask != 0 && (heldMask & _lastChosenDirMask) != 0)
			{
				return _lastChosenDirMask;
			}
			return 0;
		}

		private static int BitCount(int value)
		{
			int num = 0;
			while (value != 0)
			{
				value &= value - 1;
				num++;
			}
			return num;
		}

		private static string[] ParseCandidates(string value)
		{
			return (from x in (value ?? string.Empty).Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries)
				select x.Trim() into x
				where x.Length > 0
				select x).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
		}

		private void Trace(string message)
		{
			if (_verboseLogging.Value)
			{
				_log.LogInfo((object)("[CrestQuickSwitch] " + message));
			}
		}
	}
}
namespace CrestsEvolve.InsectMayCry
{
	[BepInPlugin("local.crestsevolve.insectmaycry", "Insect May Cry", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "local.crestsevolve.insectmaycry";

		public const string PluginName = "Insect May Cry";

		public const string PluginVersion = "0.1.0";

		private Harmony? _harmony;

		private CrestQuickSwitchIntegration? _quickSwitch;

		private AttackModuleCatalog? _attackModules;

		private VergilCrestFeature? _vergil;

		private SecondToolSetFeature? _secondToolSet;

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (FoundationServices.Current == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[InsectMayCry] foundation not loaded; quick switch disabled.");
				return;
			}
			_harmony = new Harmony("local.crestsevolve.insectmaycry");
			_quickSwitch = CrestQuickSwitchIntegration.Install(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config, _harmony);
			AttackModuleOptions options = new AttackModuleOptions(((BaseUnityPlugin)this).Config);
			_attackModules = new AttackModuleCatalog(((BaseUnityPlugin)this).Logger, _harmony, options);
			_vergil = VergilCrestFeature.Install(((BaseUnityPlugin)this).Logger, _harmony, options);
			_secondToolSet = new SecondToolSetFeature(((BaseUnityPlugin)this).Logger, _harmony, FoundationServices.Current);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[InsectMayCry] loaded: crest quick switch + 11 attack modules + Dante/Vergil/Nero crest family.");
		}

		private void OnDestroy()
		{
			_secondToolSet?.Dispose();
			_vergil?.Dispose();
			_attackModules?.Dispose();
			_quickSwitch?.Dispose();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace CrestsEvolve.InsectMayCry.GameInterop
{
	public static class SecondToolSetGameBridge
	{
		public static string? CurrentCrestId()
		{
			try
			{
				return PlayerData.instance?.CurrentCrestID;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[SecondToolSet] current crest query failed: " + ex.Message));
				return null;
			}
		}

		public static string? GetEquippedToolName(string crestId, int slotIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			try
			{
				PlayerData instance = PlayerData.instance;
				if (instance == null || instance.ToolEquips == null)
				{
					return null;
				}
				Data data = ((SerializableNamedList<Data, NamedData>)(object)instance.ToolEquips).GetData(crestId);
				if (data.Slots == null || slotIndex < 0 || slotIndex >= data.Slots.Count)
				{
					return null;
				}
				string equippedTool = data.Slots[slotIndex].EquippedTool;
				return string.IsNullOrWhiteSpace(equippedTool) ? null : equippedTool;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[SecondToolSet] equipped tool query failed: " + ex.Message));
				return null;
			}
		}

		public static SecondToolSnapshot? GetToolSnapshot(string toolName)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ToolItem toolByName = ToolItemManager.GetToolByName(toolName);
				if ((Object)(object)toolByName == (Object)null)
				{
					return null;
				}
				bool flag = (int)toolByName.Type == 3;
				PlayerData instance = PlayerData.instance;
				int num = ((flag && instance != null) ? instance.SilkSkillCost : 0);
				int num2 = ((flag && instance != null) ? instance.silk : 0);
				bool flag2 = !flag || num2 >= num;
				ToolItemSkill val = (ToolItemSkill)(object)((toolByName is ToolItemSkill) ? toolByName : null);
				Sprite val2 = ((val != null && flag2 && (Object)(object)val.HudGlowSprite != (Object)null) ? val.HudGlowSprite : toolByName.HudSpriteModified);
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = toolByName.InventorySpriteModified;
				}
				int amountLeft = 0;
				int storage = 0;
				if (!flag)
				{
					amountLeft = ((instance != null) ? instance.GetToolData(toolName).AmountLeft : 0);
					storage = ToolItemManager.GetToolStorageAmount(toolByName);
				}
				return new SecondToolSnapshot(val2, amountLeft, storage, flag, flag2);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[SecondToolSet] tool snapshot failed for '" + toolName + "': " + ex.Message));
				return null;
			}
		}
	}
	public static class SecondToolSetPatches
	{
		private sealed class NeroShamanBindMarker : MonoBehaviour
		{
		}

		private sealed class NeroShamanBindGateAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					HeroController instance = HeroController.instance;
					if (instance?.playerData == null || !VergilCrestRules.IsNeroCrest(instance.playerData.CurrentCrestID))
					{
						((FsmStateAction)this).Finish();
						return;
					}
					if (SecondToolSetRules.FindSpecialAction(SecondToolSetRegistry.TryGet(instance.playerData.CurrentCrestID), GetPressedBinding()) != SecondSpecialAction.ShamanBind)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					Fsm fsm = ((FsmStateAction)this).Fsm;
					object obj;
					if (fsm == null)
					{
						obj = null;
					}
					else
					{
						FsmVariables variables = fsm.Variables;
						obj = ((variables != null) ? variables.GetFsmBool("Is Shaman Equipped") : null);
					}
					FsmBool val = (FsmBool)obj;
					if (val != null)
					{
						val.Value = true;
					}
				}
				catch (Exception ex)
				{
					WarnOnce(ex, "shaman bind gate action");
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed record ResolvedSlot(int Index, AttackToolBinding Binding)
		{
			[CompilerGenerated]
			public void Deconstruct(out int Index, out AttackToolBinding Binding)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Expected I4, but got Unknown
				Index = this.Index;
				Binding = (AttackToolBinding)(int)this.Binding;
			}
		}

		private static ManualLogSource? _log;

		private static bool _installed;

		private static bool _ok;

		private static bool _warned;

		private static FieldInfo? _acceptingInputField;

		private static FieldInfo? _queueStepsLimitField;

		private static FieldInfo? _customOverrideField;

		private static MethodInfo? _throwToolMethod;

		private static HeroController? _queueHero;

		private static bool _castQueueing;

		private static int _castQueueSteps;

		public static bool Install(Harmony harmony, ManualLogSource log)
		{
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Expected O, but got Unknown
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Expected O, but got Unknown
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Expected O, but got Unknown
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			if (_installed)
			{
				return _ok;
			}
			_installed = true;
			_log = log;
			MethodInfo methodInfo = AccessTools.Method(typeof(ToolItemManager), "GetBoundAttackTool", new Type[3]
			{
				typeof(AttackToolBinding),
				typeof(ToolEquippedReadSource),
				typeof(AttackToolBinding).MakeByRefType()
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(HeroController), "CanBind", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(HeroController), "LookForQueueInput", (Type[])null, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(typeof(HeroController), "ResetInputQueues", (Type[])null, (Type[])null);
			MethodInfo methodInfo5 = AccessTools.Method(typeof(PlayMakerFSM), "Start", (Type[])null, (Type[])null);
			_acceptingInputField = AccessTools.Field(typeof(HeroController), "acceptingInput");
			_queueStepsLimitField = AccessTools.Field(typeof(HeroController), "TOOLTHROW_QUEUE_STEPS");
			_customOverrideField = AccessTools.Field(typeof(ToolItemManager), "customToolOverride");
			_throwToolMethod = AccessTools.Method(typeof(HeroController), "ThrowTool", new Type[1] { typeof(bool) }, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || _acceptingInputField == null || _queueStepsLimitField == null || _throwToolMethod == null)
			{
				_log.LogWarning((object)("[InsectMayCry][SecondToolSet] required members missing; second tool set disabled " + $"(GetBoundAttackTool={methodInfo != null}, CanBind={methodInfo2 != null}, " + $"LookForQueueInput={methodInfo3 != null}, acceptingInput={_acceptingInputField != null}, " + $"TOOLTHROW_QUEUE_STEPS={_queueStepsLimitField != null}, ThrowTool={_throwToolMethod != null})."));
				return false;
			}
			_ok = true;
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(Declared("OnGetBoundAttackTool")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(Declared("OnCanBind")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(Declared("OnLookForQueueInput")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			if (methodInfo5 != null)
			{
				harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(Declared("OnFsmStart")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				_log.LogWarning((object)"[InsectMayCry][SecondToolSet] PlayMakerFSM.Start not found; Shaman-bind special action will fall back to normal bind.");
			}
			if (methodInfo4 != null)
			{
				harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(Declared("OnResetInputQueues")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			_log.LogInfo((object)"[InsectMayCry][SecondToolSet] input routing + bind suppression installed (dormant until a crest layout is registered).");
			return true;
		}

		public static void Reset()
		{
			_queueHero = null;
			_castQueueing = false;
			_castQueueSteps = 0;
		}

		private static MethodInfo Declared(string name)
		{
			return AccessTools.DeclaredMethod(typeof(SecondToolSetPatches), name, (Type[])null, (Type[])null);
		}

		private static bool IsCastPressed()
		{
			try
			{
				InputHandler instance = ManagerSingleton<InputHandler>.Instance;
				return (Object)(object)instance != (Object)null && instance.inputActions != null && instance.inputActions.Cast != null && ((OneAxisInputControl)instance.inputActions.Cast).IsPressed;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "cast input query");
				return false;
			}
		}

		private static bool IsCustomToolOverrideActive()
		{
			if (_customOverrideField == null)
			{
				WarnOnce(new InvalidOperationException("customToolOverride field not resolved"), "custom override check");
				return true;
			}
			try
			{
				return _customOverrideField.GetValue(ManagerSingleton<ToolItemManager>.Instance) != null;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "custom override query");
				return true;
			}
		}

		public static bool OnGetBoundAttackTool(AttackToolBinding binding, ToolEquippedReadSource readSource, ref AttackToolBinding usedBinding, ref ToolItem __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected I4, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected I4, but got Unknown
			try
			{
				if ((int)readSource != 0 && (int)readSource != 1)
				{
					return true;
				}
				if ((Object)(object)ManagerSingleton<ToolItemManager>.Instance == (Object)null)
				{
					return true;
				}
				ToolsActiveStates activeState = ToolItemManager.ActiveState;
				if ((int)activeState == 2)
				{
					return true;
				}
				if ((int)activeState == 1 && (int)readSource == 0)
				{
					return true;
				}
				if (CollectableItemManager.IsInHiddenMode())
				{
					return true;
				}
				PlayerData instance = PlayerData.instance;
				if (instance == null || string.IsNullOrEmpty(instance.CurrentCrestID))
				{
					return true;
				}
				SecondToolSetLayout secondToolSetLayout = SecondToolSetRegistry.TryGet(instance.CurrentCrestID);
				if (secondToolSetLayout == null || secondToolSetLayout.SecondSlots.Count == 0)
				{
					return true;
				}
				if (IsCustomToolOverrideActive())
				{
					return true;
				}
				bool second = (int)readSource == 0 && IsCastPressed();
				ResolvedSlot resolvedSlot = ResolveSlot(instance.CurrentCrestID, secondToolSetLayout, binding, second);
				if (resolvedSlot == null)
				{
					usedBinding = (AttackToolBinding)(int)binding;
					__result = null;
					return false;
				}
				usedBinding = (AttackToolBinding)(int)resolvedSlot.Binding;
				__result = GetEquippedTool(instance, resolvedSlot.Index);
				return false;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "bound tool resolve");
				return true;
			}
		}

		public static bool OnCanBind(ref bool __result)
		{
			try
			{
				HeroController instance = HeroController.instance;
				if (instance?.playerData == null)
				{
					return true;
				}
				SecondToolSetLayout layout = SecondToolSetRegistry.TryGet(instance.playerData.CurrentCrestID);
				if (!SecondToolSetRules.ShouldSuppressBind(layout))
				{
					return true;
				}
				SecondToolBinding pressedBinding = GetPressedBinding();
				if (SecondToolSetRules.FindSpecialAction(layout, pressedBinding) == SecondSpecialAction.ShamanBind)
				{
					__result = true;
					return false;
				}
				__result = false;
				return false;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "bind suppression");
				return true;
			}
		}

		public static void OnLookForQueueInput(HeroController __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				if ((Object)(object)_queueHero != (Object)(object)__instance)
				{
					_queueHero = __instance;
					_castQueueing = false;
					_castQueueSteps = 0;
				}
				SecondToolSetLayout secondToolSetLayout = SecondToolSetRegistry.TryGet(__instance.playerData?.CurrentCrestID);
				if (secondToolSetLayout == null || secondToolSetLayout.SecondSlots.Count == 0)
				{
					_castQueueing = false;
					return;
				}
				if (_castQueueing)
				{
					_castQueueSteps++;
				}
				PlayerAction val = (ManagerSingleton<InputHandler>.Instance?.inputActions)?.Cast;
				if (val == null)
				{
					return;
				}
				if (((OneAxisInputControl)val).WasPressed)
				{
					if (HasSpecialForPressed(secondToolSetLayout))
					{
						_castQueueing = false;
						return;
					}
					if (ReadAcceptingInput(__instance) && __instance.CanThrowTool(false))
					{
						if (__instance.GetWillThrowTool(true))
						{
							InvokeThrowTool(__instance, isAutoThrow: false);
						}
					}
					else
					{
						_castQueueSteps = 0;
						_castQueueing = true;
					}
				}
				if (ReadAcceptingInput(__instance) && ((OneAxisInputControl)val).IsPressed && _castQueueing && _castQueueSteps <= ReadQueueStepsLimit(__instance) && __instance.CanThrowTool())
				{
					InvokeThrowTool(__instance, isAutoThrow: false);
				}
				if (!((OneAxisInputControl)val).IsPressed)
				{
					_castQueueing = false;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "cast tool queue");
			}
		}

		public static void OnResetInputQueues()
		{
			_castQueueing = false;
			_castQueueSteps = 0;
		}

		public static void OnFsmStart(PlayMakerFSM __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null)
				{
					return;
				}
				string fsmName = __instance.FsmName;
				if ((string.Equals(fsmName, "Bind", StringComparison.Ordinal) || string.Equals(fsmName, "Spell Control", StringComparison.Ordinal)) && !((Object)(object)((Component)__instance).GetComponent<NeroShamanBindMarker>() != (Object)null))
				{
					FsmState state = FsmUtil.GetState(__instance, "Bind Type");
					if (state == null)
					{
						WarnOnce(new InvalidOperationException("Bind FSM state 'Bind Type' missing"), "shaman bind fsm gate");
						return;
					}
					FsmUtil.InsertAction(state, 0, (FsmStateAction)(object)new NeroShamanBindGateAction());
					((Component)__instance).gameObject.AddComponent<NeroShamanBindMarker>();
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "shaman bind fsm gate install");
			}
		}

		public static SecondToolBinding GetPressedBinding()
		{
			try
			{
				HeroActions val = ManagerSingleton<InputHandler>.Instance?.inputActions;
				if (val != null && val.Up != null && ((OneAxisInputControl)val.Up).IsPressed)
				{
					return SecondToolBinding.Up;
				}
				if (val != null && val.Down != null && ((OneAxisInputControl)val.Down).IsPressed)
				{
					return SecondToolBinding.Down;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "pressed binding");
			}
			return SecondToolBinding.Neutral;
		}

		private static bool HasSpecialForPressed(SecondToolSetLayout layout)
		{
			return SecondToolSetRules.FindSpecialAction(layout, GetPressedBinding()).HasValue;
		}

		private static ResolvedSlot? ResolveSlot(string crestId, SecondToolSetLayout layout, AttackToolBinding binding, bool second)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			ToolCrest crestByName = ToolItemManager.GetCrestByName(crestId);
			if ((Object)(object)crestByName == (Object)null || crestByName.Slots == null)
			{
				return null;
			}
			PlayerData instance = PlayerData.instance;
			if (instance == null || instance.ToolEquips == null)
			{
				return null;
			}
			Data data = ((SerializableNamedList<Data, NamedData>)(object)instance.ToolEquips).GetData(crestId);
			if (data.Slots == null)
			{
				return null;
			}
			int num = Math.Min(crestByName.Slots.Length, data.Slots.Count);
			if (second)
			{
				SecondToolBinding? secondToolBinding = MapBinding(binding);
				if (!secondToolBinding.HasValue)
				{
					return null;
				}
				SecondSlotSpec secondSlotSpec = SecondToolSetRules.FindSecondSlot(layout, secondToolBinding.Value);
				if (secondSlotSpec == null)
				{
					return null;
				}
				int num2 = secondSlotSpec.Index - 1;
				if (num2 >= num)
				{
					return null;
				}
				if (string.IsNullOrEmpty(data.Slots[num2].EquippedTool))
				{
					return null;
				}
				ToolItem toolByName = ToolItemManager.GetToolByName(data.Slots[num2].EquippedTool);
				if ((Object)(object)toolByName == (Object)null || !ToolItemTypeExtensions.IsAttackType(toolByName.Type))
				{
					return null;
				}
				return new ResolvedSlot(num2, binding);
			}
			for (int i = 0; i < num && i < 3; i++)
			{
				if (crestByName.Slots[i].AttackBinding == binding && ToolItemTypeExtensions.IsAttackType(crestByName.Slots[i].Type) && !string.IsNullOrEmpty(data.Slots[i].EquippedTool))
				{
					ToolItem toolByName2 = ToolItemManager.GetToolByName(data.Slots[i].EquippedTool);
					if (!((Object)(object)toolByName2 == (Object)null) && ToolItemTypeExtensions.IsAttackType(toolByName2.Type))
					{
						return new ResolvedSlot(i, binding);
					}
				}
			}
			return null;
		}

		private static SecondToolBinding? MapBinding(AttackToolBinding binding)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			return (int)binding switch
			{
				1 => SecondToolBinding.Up, 
				0 => SecondToolBinding.Neutral, 
				2 => SecondToolBinding.Down, 
				_ => null, 
			};
		}

		private static ToolItem? GetEquippedTool(PlayerData playerData, int index)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (playerData == null || playerData.ToolEquips == null)
			{
				return null;
			}
			Data data = ((SerializableNamedList<Data, NamedData>)(object)playerData.ToolEquips).GetData(playerData.CurrentCrestID);
			if (data.Slots == null || index < 0 || index >= data.Slots.Count)
			{
				return null;
			}
			string equippedTool = data.Slots[index].EquippedTool;
			if (!string.IsNullOrEmpty(equippedTool))
			{
				return ToolItemManager.GetToolByName(equippedTool);
			}
			return null;
		}

		private static bool ReadAcceptingInput(HeroController hero)
		{
			if (_acceptingInputField == null)
			{
				return false;
			}
			try
			{
				object value = _acceptingInputField.GetValue(hero);
				return value is bool && (bool)value;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "acceptingInput");
				return false;
			}
		}

		private static int ReadQueueStepsLimit(HeroController hero)
		{
			if (_queueStepsLimitField == null)
			{
				return 5;
			}
			try
			{
				return (_queueStepsLimitField.GetValue(hero) is int num) ? num : 5;
			}
			catch (Exception ex)
			{
				WarnOnce(ex, "TOOLTHROW_QUEUE_STEPS");
				return 5;
			}
		}

		private static void InvokeThrowTool(HeroController hero, bool isAutoThrow)
		{
			if (!(_throwToolMethod == null))
			{
				_throwToolMethod.Invoke(hero, new object[1] { isAutoThrow });
			}
		}

		private static void WarnOnce(Exception ex, string context)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[InsectMayCry][SecondToolSet] " + context + " failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
}
namespace CrestsEvolve.InsectMayCry.Features.WindBlade
{
	public sealed class HunterWindBladeFeature : IDisposable
	{
		private sealed class NailArtsFsmMarker : MonoBehaviour
		{
		}

		private sealed class SpawnWindBladeAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					_instance?.SpawnBarrage();
				}
				catch (Exception ex)
				{
					HunterWindBladeFeature? instance = _instance;
					if (instance != null)
					{
						instance._log.LogWarning((object)("[WindBlade] action threw: " + ex.Message));
					}
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class WindBladeTimeout : MonoBehaviour
		{
			private float _lifetime;

			private float _age;

			public void Init(float lifetime)
			{
				_lifetime = Mathf.Max(0.1f, lifetime);
				_age = 0f;
			}

			private void OnEnable()
			{
				_age = 0f;
			}

			private void Update()
			{
				_age += Time.deltaTime;
				if (_age >= _lifetime)
				{
					_age = 0f;
					ObjectPool.Recycle(((Component)this).gameObject);
				}
			}
		}

		private readonly ManualLogSource _log;

		private readonly Harmony _harmony;

		private readonly AttackModuleOptions _options;

		private static HunterWindBladeFeature? _instance;

		private bool _disposed;

		private GameObject? _projectilePrefab;

		private AssetBundle? _projectileBundle;

		private bool _prefabTried;

		private bool _warnedNoPrefab;

		private const string ProjectilePrefabName = "Song Knight Projectile";

		private const string ProjectilePrefabPath = "Assets/Prefabs/Hornet Enemies/Song Knight Projectile.prefab";

		private const string ProjectileBundleFileName = "localpoolprefabs_assets_areahangareasong.bundle";

		private const string ProjectileBundleRelPath = "aa/StandaloneWindows64/localpoolprefabs_assets_areahangareasong.bundle";

		public HunterWindBladeFeature(ManualLogSource log, Harmony harmony, AttackModuleOptions options)
		{
			_log = log ?? throw new ArgumentNullException("log");
			_harmony = harmony ?? throw new ArgumentNullException("harmony");
			_options = options ?? throw new ArgumentNullException("options");
		}

		public static HunterWindBladeFeature Install(ManualLogSource log, Harmony harmony, AttackModuleOptions options)
		{
			if (_instance != null)
			{
				return _instance;
			}
			HunterWindBladeFeature hunterWindBladeFeature = new HunterWindBladeFeature(log, harmony, options);
			hunterWindBladeFeature.InstallPatch();
			_instance = hunterWindBladeFeature;
			log.LogInfo((object)"[InsectMayCry][WindBlade] hunter charge-slash wind-blade feature installed.");
			return hunterWindBladeFeature;
		}

		private void InstallPatch()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayMakerFSM), "Start", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				_log.LogWarning((object)"[WindBlade] PlayMakerFSM.Start not found; feature disabled.");
				return;
			}
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(HunterWindBladeFeature), "OnFsmStart", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_log.LogInfo((object)("[WindBlade] patched " + GeneralExtensions.FullDescription((MethodBase)methodInfo) + "."));
		}

		public static void OnFsmStart(PlayMakerFSM __instance)
		{
			HunterWindBladeFeature instance = _instance;
			if (instance == null || !instance._options.WindBladeEnabled || (Object)(object)__instance == (Object)null || __instance.Fsm == null || __instance.FsmName != "Nail Arts" || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal) || (Object)(object)((Component)__instance).GetComponent<NailArtsFsmMarker>() != (Object)null)
			{
				return;
			}
			try
			{
				FsmState state = FsmUtil.GetState(__instance, "Do Slash");
				if (state == null)
				{
					instance._log.LogWarning((object)"[WindBlade] Nail Arts FSM 'Do Slash' state not found.");
					return;
				}
				FsmUtil.InsertAction(state, state.Actions.Length, (FsmStateAction)(object)new SpawnWindBladeAction());
				((Component)__instance).gameObject.AddComponent<NailArtsFsmMarker>();
				instance._log.LogInfo((object)"[WindBlade] Nail Arts FSM hook installed (Do Slash -> spawn wind blades).");
			}
			catch (Exception ex)
			{
				instance._log.LogWarning((object)("[WindBlade] FSM hook failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void SpawnBarrage()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null || instance.playerData == null)
			{
				return;
			}
			if (!VergilChargeVariantState.IsImcEquipped() || !VergilCrestRules.IsDanteCrest(instance.playerData.CurrentCrestID) || VergilChargeVariantState.Current != ChargeVariant.Up)
			{
				_log.LogDebug((object)"[WindBlade] skipped: not D up-variant charge.");
				return;
			}
			int num;
			float num2;
			if (instance.cState != null)
			{
				num = (instance.cState.facingRight ? 1 : 0);
				if (num != 0)
				{
					num2 = 0f;
					goto IL_006f;
				}
			}
			else
			{
				num = 0;
			}
			num2 = 180f;
			goto IL_006f;
			IL_006f:
			float baseAngle = num2;
			int windBladeCount = _options.WindBladeCount;
			Vector3 position = ((Component)instance).transform.position;
			Vector2 val = ((num != 0) ? Vector2.right : Vector2.left);
			position += Vector2.op_Implicit(val * _options.WindBladeSpawnForwardOffset);
			if (windBladeCount > 1 && _options.WindBladeBladeDelaySeconds > 0f)
			{
				((MonoBehaviour)instance).StartCoroutine(SpawnBladeSequence(position, baseAngle, windBladeCount));
				return;
			}
			Vector2 dir = default(Vector2);
			for (int i = 0; i < windBladeCount; i++)
			{
				float num3 = SpreadAngle(baseAngle, windBladeCount, i);
				((Vector2)(ref dir))..ctor(Mathf.Cos(num3 * (MathF.PI / 180f)), Mathf.Sin(num3 * (MathF.PI / 180f)));
				SpawnBlade(position, dir);
			}
			_log.LogInfo((object)$"[WindBlade] hunter charge slash spawned {windBladeCount} wind blade(s).");
		}

		private IEnumerator SpawnBladeSequence(Vector3 origin, float baseAngle, int count)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 dir = default(Vector2);
			for (int i = 0; i < count; i++)
			{
				float num = SpreadAngle(baseAngle, count, i);
				((Vector2)(ref dir))..ctor(Mathf.Cos(num * (MathF.PI / 180f)), Mathf.Sin(num * (MathF.PI / 180f)));
				SpawnBlade(origin, dir);
				if (i < count - 1)
				{
					yield return (object)new WaitForSeconds(_options.WindBladeBladeDelaySeconds);
				}
			}
			_log.LogInfo((object)$"[WindBlade] hunter charge slash spawned {count} wind blade(s) sequentially.");
		}

		private float SpreadAngle(float baseAngle, int count, int index)
		{
			if (count <= 1)
			{
				return baseAngle;
			}
			float windBladeSpreadDegrees = _options.WindBladeSpreadDegrees;
			if (windBladeSpreadDegrees <= 0f)
			{
				return baseAngle;
			}
			float num = baseAngle - windBladeSpreadDegrees / 2f;
			float num2 = ((count > 1) ? (windBladeSpreadDegrees / (float)(count - 1)) : 0f);
			return num + num2 * (float)index;
		}

		private void SpawnBlade(Vector3 origin, Vector2 dir)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnsurePrefabLoaded();
				if ((Object)(object)_projectilePrefab == (Object)null)
				{
					if (!_warnedNoPrefab)
					{
						_warnedNoPrefab = true;
						_log.LogWarning((object)"[WindBlade] Song Knight Projectile prefab unavailable; charge-slash wind blades skipped.");
					}
				}
				else
				{
					SpawnFromSongKnightPrefab(origin, dir);
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[WindBlade] blade spawn failed: " + ex.Message));
			}
		}

		private void EnsurePrefabLoaded()
		{
			if (_prefabTried)
			{
				return;
			}
			_prefabTried = true;
			try
			{
				_projectileBundle = FindLoadedBundle("localpoolprefabs_assets_areahangareasong.bundle");
				if ((Object)(object)_projectileBundle == (Object)null)
				{
					string text = Path.Combine(Application.streamingAssetsPath, "aa/StandaloneWindows64/localpoolprefabs_assets_areahangareasong.bundle");
					if (File.Exists(text))
					{
						_projectileBundle = AssetBundle.LoadFromFile(text);
					}
					else
					{
						_log.LogWarning((object)("[WindBlade] bundle not found at " + text));
					}
				}
				if ((Object)(object)_projectileBundle == (Object)null)
				{
					_log.LogWarning((object)"[WindBlade] Song Knight Projectile bundle unavailable; wind blades disabled.");
					return;
				}
				_projectilePrefab = _projectileBundle.LoadAsset<GameObject>("Assets/Prefabs/Hornet Enemies/Song Knight Projectile.prefab") ?? _projectileBundle.LoadAsset<GameObject>("Song Knight Projectile");
				if ((Object)(object)_projectilePrefab != (Object)null)
				{
					_log.LogInfo((object)("[WindBlade] loaded Song Knight Projectile prefab from " + ((Object)_projectileBundle).name + " (" + ((Object)_projectilePrefab).name + ")."));
				}
				else
				{
					_log.LogWarning((object)("[WindBlade] 'Assets/Prefabs/Hornet Enemies/Song Knight Projectile.prefab' not found in " + ((Object)_projectileBundle).name + "; wind blades disabled."));
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[WindBlade] prefab lookup failed: " + ex.Message));
			}
		}

		private AssetBundle? FindLoadedBundle(string fileName)
		{
			try
			{
				foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
				{
					if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, fileName, StringComparison.OrdinalIgnoreCase))
					{
						return allLoadedAssetBundle;
					}
				}
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
				foreach (AssetBundle allLoadedAssetBundle2 in AssetBundle.GetAllLoadedAssetBundles())
				{
					if ((Object)(object)allLoadedAssetBundle2 != (Object)null && ((Object)allLoadedAssetBundle2).name.IndexOf(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return allLoadedAssetBundle2;
					}
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[WindBlade] loaded-bundle search failed: " + ex.Message));
			}
			return null;
		}

		private void SpawnFromSongKnightPrefab(Vector3 origin, Vector2 dir)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_projectilePrefab == (Object)null)
			{
				return;
			}
			GameObject val = ObjectPoolExtensions.Spawn(_projectilePrefab, origin, Quaternion.identity);
			if (!((Object)(object)val == (Object)null))
			{
				((Object)val).name = "HunterWindBlade";
				tk2dSprite[] componentsInChildren = val.GetComponentsInChildren<tk2dSprite>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					((tk2dBaseSprite)componentsInChildren[i]).ForceBuild();
				}
				Vector3 localScale = val.transform.localScale;
				localScale.x = Mathf.Abs(localScale.x) * ((dir.x >= 0f) ? (-1f) : 1f);
				val.transform.localScale = localScale;
				val.layer = 17;
				Transform val2 = val.transform.Find("Terrain Detector");
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2).gameObject.SetActive(false);
				}
				DamageHero component = val.GetComponent<DamageHero>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				val.tag = "Nail Attack";
				DamageEnemies val3 = val.GetComponent<DamageEnemies>();
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = val.AddComponent<DamageEnemies>();
				}
				ConfigurePlayerDamager(val3);
				Rigidbody2D component2 = val.GetComponent<Rigidbody2D>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.linearVelocity = dir * _options.WindBladeSpeed;
				}
				WindBladeTimeout windBladeTimeout = val.GetComponent<WindBladeTimeout>();
				if ((Object)(object)windBladeTimeout == (Object)null)
				{
					windBladeTimeout = val.AddComponent<WindBladeTimeout>();
				}
				windBladeTimeout.Init(_options.WindBladeLifetime);
			}
		}

		private void ConfigurePlayerDamager(DamageEnemies damager)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			if ((Object)(object)damager == (Object)null)
			{
				return;
			}
			damager.useNailDamage = true;
			damager.nailDamageMultiplier = (float)_options.WindBladeDamage;
			damager.attackType = (AttackTypes)7;
			damager.stunDamage = 1f;
			damager.canWeakHit = false;
			damager.magnitudeMult = 1f;
			damager.direction = 0f;
			damager.moveDirection = false;
			damager.contactFSMEvent = "";
			damager.damageFSMEvent = "";
			damager.slashEffectOverrides = Array.Empty<GameObject>();
			damager.corpseDirection = new OverrideFloat();
			damager.corpseMagnitudeMult = new OverrideFloat();
			damager.currencyMagnitudeMult = new OverrideFloat();
			damager.DealtDamage = new UnityEvent();
			damager.Tinked = new UnityEvent();
			try
			{
				typeof(DamageEnemies).GetField("isHeroDamage", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(damager, true);
			}
			catch (Exception)
			{
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_harmony.UnpatchSelf();
				if (_instance == this)
				{
					_instance = null;
				}
			}
		}
	}
}
namespace CrestsEvolve.InsectMayCry.Features.Vergil
{
	public static class DanteCrossStitchRuneRules
	{
		public static float FirstCastMinSpawnRadius => 3.5f;

		public static float FirstCastMaxSpawnRadius => 8f;

		public static bool ShouldRequestRuneRage(bool enabled, string? crestId, ChargeVariant variant)
		{
			if (enabled && VergilCrestRules.IsDanteCrest(crestId))
			{
				return variant == ChargeVariant.Default;
			}
			return false;
		}

		public static bool ShouldRedirect(bool enabled, string? crestId, bool requested, double now, double until)
		{
			if (enabled && VergilCrestRules.IsDanteCrest(crestId) && requested)
			{
				return now <= until;
			}
			return false;
		}

		public static int ClampCasts(int casts)
		{
			return Math.Clamp(casts, 1, 3);
		}

		public static double ClampInvulnerabilitySeconds(double seconds)
		{
			return Math.Max(0.0, seconds);
		}
	}
	public static class DvnSlotLayouts
	{
		public static SecondToolSetLayout Dante { get; } = new SecondToolSetLayout("Dante", new SecondSlotSpec[3]
		{
			Attack(4, SecondToolBinding.Up, -1.2f, 1.6f),
			Attack(5, SecondToolBinding.Neutral, -1.6f, -0.7f),
			Attack(6, SecondToolBinding.Down, -1.5f, -1.6f)
		}, new SecondSlotSpec[3]
		{
			Attack(1, SecondToolBinding.Up, 1.2f, 1.8f),
			Attack(2, SecondToolBinding.Neutral, 1.5f, -0.8f),
			Attack(3, SecondToolBinding.Down, 1.2f, -1.6f)
		}, null, new UtilitySlotSpec[3]
		{
			Utility(7, UtilitySlotKind.Yellow, -0.8f, 0.5f),
			Utility(8, UtilitySlotKind.Yellow, 0.8f, 0.5f),
			Utility(9, UtilitySlotKind.Blue, 0f, -2.1f)
		});

		public static SecondToolSetLayout Vergil { get; } = new SecondToolSetLayout("Vergil", new SecondSlotSpec[3]
		{
			Attack(4, SecondToolBinding.Up, -1.8f, 0.2f, SecondSlotKind.Skill),
			Attack(5, SecondToolBinding.Neutral, -1.5f, -0.7f, SecondSlotKind.Skill),
			Attack(6, SecondToolBinding.Down, -0.8f, -1.5f, SecondSlotKind.Skill)
		}, new SecondSlotSpec[3]
		{
			Attack(1, SecondToolBinding.Up, 1.5f, 0.2f, SecondSlotKind.Skill),
			Attack(2, SecondToolBinding.Neutral, 1.1f, -0.7f, SecondSlotKind.Skill),
			Attack(3, SecondToolBinding.Down, 0.7f, -1.5f, SecondSlotKind.Skill)
		}, null, new UtilitySlotSpec[4]
		{
			Utility(7, UtilitySlotKind.Yellow, 1.6f, 1.1f),
			Utility(8, UtilitySlotKind.Blue, 0.5f, 1.6f),
			Utility(9, UtilitySlotKind.Blue, -1f, 1.6f),
			Utility(10, UtilitySlotKind.Yellow, -2f, 1.1f)
		});

		public static SecondToolSetLayout Nero { get; } = new SecondToolSetLayout("Nero", new SecondSlotSpec[2]
		{
			Attack(4, SecondToolBinding.Up, -0.7f, 1.2f, SecondSlotKind.Skill),
			Attack(5, SecondToolBinding.Neutral, -1.6f, 0.4f, SecondSlotKind.Skill)
		}, new SecondSlotSpec[3]
		{
			Attack(1, SecondToolBinding.Up, 1.3f, 0.4f),
			Attack(2, SecondToolBinding.Neutral, 0f, 0f),
			Attack(3, SecondToolBinding.Down, -1.2f, -0.4f)
		}, new SecondSpecialBinding[1]
		{
			new SecondSpecialBinding(SecondToolBinding.Down, SecondSpecialAction.ShamanBind)
		}, new UtilitySlotSpec[4]
		{
			Utility(7, UtilitySlotKind.Yellow, 1.5f, -0.8f),
			Utility(8, UtilitySlotKind.Blue, 0.6f, -1.1f),
			Utility(9, UtilitySlotKind.Blue, -0.5f, -1.5f),
			Utility(10, UtilitySlotKind.Yellow, -1.5f, -1.2f)
		});

		public static void RegisterAll(Action<string>? warn = null)
		{
			SecondToolSetRegistry.Register(Dante, warn);
			SecondToolSetRegistry.Register(Vergil, warn);
			SecondToolSetRegistry.Register(Nero, warn);
		}

		private static SecondSlotSpec Attack(int index, SecondToolBinding binding, float x, float y, SecondSlotKind kind = SecondSlotKind.Red)
		{
			return new SecondSlotSpec(index, binding, kind, x, y, IsLocked: false);
		}

		private static UtilitySlotSpec Utility(int index, UtilitySlotKind kind, float x, float y)
		{
			return new UtilitySlotSpec(index, kind, x, y, IsLocked: false);
		}
	}
	public static class VergilChargeToolPatches
	{
		private static ManualLogSource? _log;

		private static Harmony? _harmony;

		private static bool _installed;

		private static bool _warned;

		public static void Install(Harmony harmony, ManualLogSource log)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Expected O, but got Unknown
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Expected O, but got Unknown
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Expected O, but got Unknown
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Expected O, but got Unknown
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Expected O, but got Unknown
			if (!_installed)
			{
				_installed = true;
				_harmony = harmony;
				_log = log;
				MethodInfo methodInfo = AccessTools.Method(typeof(HeroController), "CanThrowTool", new Type[3]
				{
					typeof(ToolItem),
					typeof(AttackToolBinding),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo == null)
				{
					Warn("HeroController.CanThrowTool not found; free charge throw may fail when silk/ammo is empty.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnCanThrowTool", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo2 = AccessTools.PropertyGetter(typeof(PlayerData), "SilkSkillCost");
				if (methodInfo2 == null)
				{
					Warn("PlayerData.SilkSkillCost getter not found; free skill charge may consume silk.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnSilkSkillCost", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo3 = AccessTools.Method(typeof(ToolItemManager), "GetAttackToolBinding", new Type[1] { typeof(ToolItem) }, (Type[])null);
				if (methodInfo3 == null)
				{
					Warn("ToolItemManager.GetAttackToolBinding(ToolItem) not found; free charge throw may fail when tool not equipped.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnGetAttackToolBinding", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo4 = AccessTools.Method(typeof(HeroController), "DidUseAttackTool", new Type[1] { typeof(Data) }, (Type[])null);
				if (methodInfo4 == null)
				{
					Warn("HeroController.DidUseAttackTool not found; free charge may consume tool ammo.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnDidUseAttackTool", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo5 = AccessTools.Method(typeof(ToolItemManager), "SetEquippedTools", new Type[2]
				{
					typeof(string),
					typeof(List<string>)
				}, (Type[])null);
				if (methodInfo5 == null)
				{
					Warn("ToolItemManager.SetEquippedTools(string,List<string>) not found; free charge slot guard disabled.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnSetEquippedTools", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo6 = AccessTools.Method(typeof(ToolItemManager), "SetExtraEquippedTool", new Type[2]
				{
					typeof(string),
					typeof(string)
				}, (Type[])null);
				if (methodInfo6 == null)
				{
					Warn("ToolItemManager.SetExtraEquippedTool(string,string) not found; free charge slot guard (extra) disabled.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnSetExtraEquippedTool", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo7 = AccessTools.Method(typeof(ToolItemManager), "ReplaceToolEquips", new Type[2]
				{
					typeof(string),
					typeof(string)
				}, (Type[])null);
				if (methodInfo7 == null)
				{
					Warn("ToolItemManager.ReplaceToolEquips(string,string) not found; free charge slot guard (replace) disabled.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnReplaceToolEquips", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo8 = AccessTools.Method(typeof(HeroController), "TakeSilk", new Type[1] { typeof(int) }, (Type[])null);
				if (methodInfo8 == null)
				{
					Warn("HeroController.TakeSilk(int) not found; free silk-shot may consume 1 silk.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnTakeSilk", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo9 = AccessTools.Method(typeof(DamageEnemies), "DoDamage", new Type[2]
				{
					typeof(GameObject),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo9 == null)
				{
					Warn("DamageEnemies.DoDamage(GameObject,bool) not found; silk-shot explosion disabled.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(VergilChargeToolPatches), "OnDoDamage", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				log.LogInfo((object)"[InsectMayCry][Vergil] charge tool patches installed (free throw + silk-shot explosion).");
			}
		}

		private static bool IsFreeWindowActive()
		{
			if (VergilChargeVariantState.FreeChargeToolName == null)
			{
				return false;
			}
			if (VergilChargeVariantState.FreeChargeToolUntil > 0.0 && Time.timeAsDouble > VergilChargeVariantState.FreeChargeToolUntil)
			{
				VergilChargeVariantState.FreeChargeToolName = null;
				VergilChargeVariantState.FreeChargeToolUntil = 0.0;
				return false;
			}
			return true;
		}

		public static bool OnCanThrowTool(ToolItem tool, ref bool __result)
		{
			if (!IsFreeWindowActive())
			{
				return true;
			}
			string freeChargeToolName = VergilChargeVariantState.FreeChargeToolName;
			if ((Object)(object)tool == (Object)null || !string.Equals(tool.name, freeChargeToolName, StringComparison.Ordinal))
			{
				return true;
			}
			__result = true;
			return false;
		}

		public static bool OnSilkSkillCost(ref int __result)
		{
			if (!IsFreeWindowActive())
			{
				return true;
			}
			__result = 0;
			return false;
		}

		public static bool OnGetAttackToolBinding(ToolItem tool, ref AttackToolBinding? __result)
		{
			if (!IsFreeWindowActive())
			{
				return true;
			}
			string freeChargeToolName = VergilChargeVariantState.FreeChargeToolName;
			if ((Object)(object)tool == (Object)null || !string.Equals(tool.name, freeChargeToolName, StringComparison.Ordinal))
			{
				return true;
			}
			__result = (AttackToolBinding)0;
			return false;
		}

		public static bool OnDidUseAttackTool()
		{
			return !IsFreeWindowActive();
		}

		public static void OnSetEquippedTools(string crestId, List<string> equippedTools)
		{
			try
			{
				string freeToolName = GetFreeToolName();
				if (freeToolName != null && equippedTools != null)
				{
					List<string> collection = VergilFreeToolSlotGuardRules.SanitizeEquippedList(ReadCurrentSlots(crestId), equippedTools, freeToolName);
					equippedTools.Clear();
					equippedTools.AddRange(collection);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void OnSetExtraEquippedTool(string slotId, ref string toolName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string freeToolName = GetFreeToolName();
				if (freeToolName != null && PlayerData.instance != null)
				{
					string equippedTool = ((SerializableNamedList<SlotData, NamedData>)(object)PlayerData.instance.ExtraToolEquips).GetData(slotId).EquippedTool;
					toolName = VergilFreeToolSlotGuardRules.SanitizeSlotValue(equippedTool, toolName, freeToolName);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static bool OnReplaceToolEquips(string newToolName)
		{
			string freeToolName = GetFreeToolName();
			if (freeToolName == null)
			{
				return true;
			}
			return !string.Equals(newToolName, freeToolName, StringComparison.Ordinal);
		}

		public static bool OnTakeSilk()
		{
			return !IsFreeWindowActive();
		}

		public static void OnDoDamage(DamageEnemies __instance, GameObject target)
		{
			//IL_006a: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				string chargeExplosionToolName = VergilChargeVariantState.ChargeExplosionToolName;
				if (chargeExplosionToolName == null || Time.timeAsDouble > VergilChargeVariantState.ChargeExplosionUntil)
				{
					return;
				}
				ToolItem representingTool = __instance.RepresentingTool;
				if ((Object)(object)representingTool == (Object)null || !string.Equals(representingTool.name, chargeExplosionToolName, StringComparison.Ordinal))
				{
					return;
				}
				Vector3 val = (((Object)(object)target != (Object)null) ? target.transform.position : ((Component)__instance).transform.position);
				FoundationServices current = FoundationServices.Current;
				if (current != null)
				{
					IGameApi game = current.Game;
					if (game != null)
					{
						game.SpawnNativeExplosionAt(val);
					}
				}
				VergilChargeVariantState.ChargeExplosionToolName = null;
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[InsectMayCry][Vergil] silk-shot explosion failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static void Warn(string message)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[InsectMayCry][Vergil] " + message));
				}
			}
		}

		private static string? GetFreeToolName()
		{
			if (!IsFreeWindowActive())
			{
				return null;
			}
			return VergilChargeVariantState.FreeChargeToolName;
		}

		private static List<string?>? ReadCurrentSlots(string crestId)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_003a: 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)
			if (PlayerData.instance == null)
			{
				return null;
			}
			Data data = ((SerializableNamedList<Data, NamedData>)(object)PlayerData.instance.ToolEquips).GetData(crestId);
			if (data.Slots == null)
			{
				return null;
			}
			List<string> list = new List<string>(data.Slots.Count);
			for (int i = 0; i < data.Slots.Count; i++)
			{
				list.Add(data.Slots[i].EquippedTool);
			}
			return list;
		}

		private static void WarnOnce(Exception ex)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogWarning((object)("[InsectMayCry][Vergil] free charge slot guard failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
	public static class VergilChargeVariantState
	{
		public static ChargeVariant Current { get; set; }

		public static bool LungeActive { get; set; }

		public static bool ReleaseWasDashing { get; set; }

		public static string? FreeChargeToolName { get; set; }

		public static double FreeChargeToolUntil { get; set; }

		public static string? ChargeExplosionToolName { get; set; }

		public static double ChargeExplosionUntil { get; set; }

		public static bool CrossStitchRequested { get; set; }

		public static double CrossStitchUntil { get; set; }

		public static bool CrossStitchRequireRealParry { get; set; }

		public static bool RuneRageRequested { get; set; }

		public static double RuneRageUntil { get; set; }

		public static bool IsImcEquipped()
		{
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance != (Object)null && instance.playerData != null)
			{
				return VergilCrestRules.IsImcCrest(instance.playerData.CurrentCrestID);
			}
			return false;
		}
	}
	public sealed class VergilCrestFeature : IDisposable
	{
		private sealed class CrossStitchTriggerMarker : MonoBehaviour
		{
		}

		private sealed class CrossStitchTriggerAction : FsmStateAction
		{
			private static bool _warnedNoParryWait;

			public override void OnEnter()
			{
				try
				{
					if (!VergilChargeVariantState.CrossStitchRequested)
					{
						return;
					}
					if (Time.timeAsDouble > VergilChargeVariantState.CrossStitchUntil)
					{
						VergilChargeVariantState.CrossStitchRequested = false;
						VergilChargeVariantState.CrossStitchRequireRealParry = false;
						return;
					}
					HeroController instance = HeroController.instance;
					if (DanteCrossStitchRuneRules.ShouldRequestRuneRage(_options?.DanteCrossStitchRuneEnabled ?? false, instance?.playerData?.CurrentCrestID, VergilChargeVariantState.Current))
					{
						VergilChargeVariantState.RuneRageRequested = true;
						VergilChargeVariantState.RuneRageUntil = Time.timeAsDouble + (_options?.DanteCrossStitchRuneRequestTimeoutSeconds ?? 2.0);
					}
					if (VergilChargeVariantState.CrossStitchRequireRealParry)
					{
						Wait val = null;
						Fsm fsm = ((FsmStateAction)this).Fsm;
						FsmState val2 = ((fsm != null) ? fsm.GetState("Parry Stance") : null);
						if (((val2 != null) ? val2.Actions : null) != null)
						{
							FsmStateAction[] actions = val2.Actions;
							foreach (FsmStateAction obj in actions)
							{
								Wait val3 = (Wait)(object)((obj is Wait) ? obj : null);
								if (val3 != null)
								{
									val = val3;
									break;
								}
							}
						}
						if (val != null)
						{
							val.time = FsmFloat.op_Implicit(_options?.DanteChargeCrossStitchParryWindowSeconds ?? 0.25f);
						}
						else if (!_warnedNoParryWait)
						{
							_warnedNoParryWait = true;
							VergilCrestFeature? instance2 = _instance;
							if (instance2 != null)
							{
								instance2._log.LogWarning((object)"[InsectMayCry][Vergil] Parry Stance Wait not found; parry window override skipped.");
							}
						}
						((FsmStateAction)this).Finish();
						return;
					}
					VergilChargeVariantState.CrossStitchRequested = false;
					VergilChargeVariantState.CrossStitchRequireRealParry = false;
					Fsm fsm2 = ((FsmStateAction)this).Fsm;
					if (fsm2 != null)
					{
						fsm2.Event("PARRIED");
					}
				}
				catch (Exception)
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class CrossStitchEffectRedirectAction : FsmStateAction
		{
			private const string RuneRageTargetState = "Initial Silk Cost";

			private const string SharpdartTargetState = "Silk Charge Begin";

			private static bool _warned;

			public override void OnEnter()
			{
				try
				{
					Fsm fsm = ((FsmStateAction)this).Fsm;
					AttackModuleOptions options = _options;
					if (fsm == null || options == null)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					HeroController instance = HeroController.instance;
					if ((Object)(object)instance == (Object)null || instance.playerData == null)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					string currentCrestID = instance.playerData.CurrentCrestID;
					if (DanteCrossStitchRuneRules.ShouldRedirect(options.DanteCrossStitchRuneEnabled, currentCrestID, VergilChargeVariantState.RuneRageRequested, Time.timeAsDouble, VergilChargeVariantState.RuneRageUntil))
					{
						VergilChargeVariantState.RuneRageRequested = false;
						RedirectToRuneRage(fsm, instance, options);
						((FsmStateAction)this).Finish();
						return;
					}
					VergilChargeVariantState.RuneRageRequested = false;
					if (VergilCrestRules.IsDanteCrest(currentCrestID))
					{
						RedirectToSharpdart(fsm, instance);
						((FsmStateAction)this).Finish();
						return;
					}
				}
				catch (Exception ex)
				{
					WarnOnce(ex.GetType().Name + ": " + ex.Message);
				}
				((FsmStateAction)this).Finish();
			}

			private static void RedirectToRuneRage(Fsm fsm, HeroController hero, AttackModuleOptions options)
			{
				if (fsm.GetState("Initial Silk Cost") == null)
				{
					WarnOnce("Silk Specials state 'Initial Silk Cost' not found; rune-rage redirect disabled.");
					return;
				}
				PlayMakerFSM val = ResolvePlayMakerFsm(fsm);
				if ((Object)(object)val == (Object)null)
				{
					WarnOnce("PlayMakerFSM component not found; rune-rage redirect disabled.");
					return;
				}
				if (hero.cState != null)
				{
					hero.cState.parrying = false;
					hero.cState.parryAttack = false;
				}
				SetFsmInt(fsm, "Casts Left", DanteCrossStitchRuneRules.ClampCasts(options.DanteCrossStitchRuneCasts));
				SetFsmFloat(fsm, "Min Spawn Radius", options.DanteCrossStitchRuneMinSpawnRadius);
				SetFsmFloat(fsm, "Max Spawn Radius", options.DanteCrossStitchRuneMaxSpawnRadius);
				SetFsmFloat(fsm, "Silk Bomb Cooldown", options.DanteCrossStitchRuneSilkBombCooldownSeconds);
				SetBindCanBreak(fsm.GameObject, value: true);
				double num = DanteCrossStitchRuneRules.ClampInvulnerabilitySeconds(options.DanteCrossStitchRuneInvulnerabilitySeconds);
				if (num > 0.0)
				{
					FoundationServices current = FoundationServices.Current;
					if (current != null)
					{
						IGameApi game = current.Game;
						if (game != null)
						{
							game.AcquireInvulnerability("dante.cross-stitch-rune", num);
						}
					}
				}
				val.SetState("Initial Silk Cost");
			}

			private static void RedirectToSharpdart(Fsm fsm, HeroController hero)
			{
				if (fsm.GetState("Silk Charge Begin") == null)
				{
					WarnOnce("Silk Specials state 'Silk Charge Begin' not found; sharpdart redirect disabled.");
					return;
				}
				PlayMakerFSM val = ResolvePlayMakerFsm(fsm);
				if ((Object)(object)val == (Object)null)
				{
					WarnOnce("PlayMakerFSM component not found; sharpdart redirect disabled.");
					return;
				}
				if (hero.cState != null)
				{
					hero.cState.parrying = false;
					hero.cState.parryAttack = false;
				}
				VergilChargeVariantState.FreeChargeToolName = "Parry";
				VergilChargeVariantState.FreeChargeToolUntil = Time.timeAsDouble + (_options?.DanteCrossStitchSharpdartFreeWindowSeconds ?? 0.5);
				val.SetState("Silk Charge Begin");
			}

			private static PlayMakerFSM? ResolvePlayMakerFsm(Fsm fsm)
			{
				if ((Object)(object)((fsm != null) ? fsm.GameObject : null) == (Object)null)
				{
					return null;
				}
				PlayMakerFSM[] components = fsm.GameObject.GetComponents<PlayMakerFSM>();
				foreach (PlayMakerFSM val in components)
				{
					if ((Object)(object)val != (Object)null && val.Fsm == fsm)
					{
						return val;
					}
				}
				return null;
			}

			private static void SetFsmInt(Fsm fsm, string variableName, int value)
			{
				object obj;
				if (fsm == null)
				{
					obj = null;
				}
				else
				{
					FsmVariables variables = fsm.Variables;
					obj = ((variables != null) ? variables.GetFsmInt(variableName) : null);
				}
				FsmInt val = (FsmInt)obj;
				if (val != null)
				{
					val.Value = value;
				}
			}

			private static void SetFsmFloat(Fsm fsm, string variableName, float value)
			{
				object obj;
				if (fsm == null)
				{
					obj = null;
				}
				else
				{
					FsmVariables variables = fsm.Variables;
					obj = ((variables != null) ? variables.GetFsmFloat(variableName) : null);
				}
				FsmFloat val = (FsmFloat)obj;
				if (val != null)
				{
					val.Value = value;
				}
			}

			private static void SetBindCanBreak(GameObject owner, bool value)
			{
				if ((Object)(object)owner == (Object)null)
				{
					return;
				}
				PlayMakerFSM[] components = owner.GetComponents<PlayMakerFSM>();
				foreach (PlayMakerFSM val in components)
				{
					if (!((Object)(object)val == (Object)null) && !(val.FsmName != "Bind"))
					{
						FsmVariables fsmVariables = val.FsmVariables;
						FsmBool val2 = ((fsmVariables != null) ? fsmVariables.GetFsmBool("Can Bind Break") : null);
						if (val2 != null)
						{
							val2.Value = value;
						}
						break;
					}
				}
			}

			private static void WarnOnce(string message)
			{
				if (!_warned)
				{
					_warned = true;
					VergilCrestFeature? instance = _instance;
					if (instance != null)
					{
						instance._log.LogWarning((object)("[InsectMayCry][Vergil] rune-rage redirect: " + message));
					}
				}
			}
		}

		private sealed class CrestSpec
		{
			public string Id = "";

			public CrestData? Crest;

			public Action? MovesetHandler;

			public GameObject? NormalSlash;

			public GameObject? AltSlash;

			public GameObject? DownSlash;

			public GameObject? AltDownSlash;

			public GameObject? DashStab;

			public GameObject? ChargeDash;

			public GameObject? ChargeWitch;

			public GameObject? ChargeHunter;

			public GameObject? ChargeShaman;

			public GameObject? ChargeWanderer;

			public GameObject? ChargeBeast;

			public GameObject? ChargeReaper;

			public GameObject? ChargeSpinSlash;

			public GameObject? ChargeNone;

			public GameObject? GetChargeInstance(ChargeVariant variant)
			{
				switch (Id)
				{
				case "Dante":
					switch (variant)
					{
					case ChargeVariant.Default:
						return ChargeNone;
					case ChargeVariant.Up:
						return ChargeHunter;
					case ChargeVariant.Down:
						return ChargeBeast;
					case ChargeVariant.Dash:
						return ChargeDash ?? ChargeWanderer;
					}
					break;
				case "Vergil":
					switch (variant)
					{
					case ChargeVariant.Default:
						return ChargeNone;
					case ChargeVariant.Up:
						return ChargeShaman;
					case ChargeVariant.Down:
						return ChargeWitch;
					case ChargeVariant.Dash:
						return ChargeDash ?? ChargeWanderer;
					}
					break;
				case "Nero":
					switch (variant)
					{
					case ChargeVariant.Default:
						return ChargeNone;
					case ChargeVariant.Up:
						return ChargeReaper;
					case ChargeVariant.Down:
						return ChargeNone;
					case ChargeVariant.Dash:
						return ChargeDash ?? ChargeWanderer;
					}
					break;
				}
				return null;
			}
		}

		private sealed class VergilNailArtsMarker : MonoBehaviour
		{
			private FsmTransition? _anticFinishTransition;

			private FsmState? _anticOriginalTarget;

			public void CaptureAnticFinish(FsmState? antic)
			{
				if (antic == null || antic.Transitions == null)
				{
					return;
				}
				FsmTransition[] transitions = antic.Transitions;
				foreach (FsmTransition val in transitions)
				{
					if (val != null && string.Equals(val.EventName, "FINISHED", StringComparison.Ordinal))
					{
						_anticFinishTransition = val;
						_anticOriginalTarget = val.ToFsmState;
						break;
					}
				}
			}

			public void RouteAnticFinish(FsmState? target)
			{
				if (_anticFinishTransition != null && target != null)
				{
					_anticFinishTransition.ToFsmState = target;
				}
			}

			private void OnDestroy()
			{
				if (_anticFinishTransition != null && _anticOriginalTarget != null)
				{
					_anticFinishTransition.ToFsmState = _anticOriginalTarget;
				}
			}
		}

		private sealed class SprintAirDashMarker : MonoBehaviour
		{
			private readonly List<(FsmTransition Transition, FsmState OriginalTarget)> _attackTransitions = new List<(FsmTransition, FsmState)>();

			public bool CaptureAttackTarget(FsmState state)
			{
				if (((state != null) ? state.Transitions : null) == null)
				{
					return false;
				}
				FsmTransition[] transitions = state.Transitions;
				foreach (FsmTransition val in transitions)
				{
					if (val != null && string.Equals(val.EventName, "ATTACK", StringComparison.Ordinal))
					{
						_attackTransitions.Add((val, val.ToFsmState));
						return true;
					}
				}
				return false;
			}

			public void ApplyFamilyTarget(FsmState? dashStabDir)
			{
				if (dashStabDir == null)
				{
					return;
				}
				foreach (var attackTransition in _attackTransitions)
				{
					attackTransition.Transition.ToFsmState = dashStabDir;
				}
			}

			public void Restore()
			{
				foreach (var (val, toFsmState) in _attackTransitions)
				{
					val.ToFsmState = toFsmState;
				}
			}

			private void OnDestroy()
			{
				Restore();
			}
		}

		private sealed class AirDashGateAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					Fsm fsm = ((FsmStateAction)this).Fsm;
					SprintAirDashMarker sprintAirDashMarker = ((fsm != null && (Object)(object)fsm.GameObject != (Object)null) ? fsm.GameObject.GetComponent<SprintAirDashMarker>() : null);
					if ((Object)(object)sprintAirDashMarker == (Object)null || fsm == null)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					string text = VergilCrestRules.ResolveAirDashTarget(HeroController.instance?.playerData?.CurrentCrestID, _options?.ShamanDashSlashEnabled ?? false, fsm.GetState("Shaman Antic") != null, fsm.GetState("Nero Start") != null);
					if (text.Length == 0)
					{
						sprintAirDashMarker.Restore();
					}
					else
					{
						sprintAirDashMarker.ApplyFamilyTarget(fsm.GetState(text));
					}
				}
				catch (Exception)
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class VergilReleaseDashCaptureAction : FsmStateAction
		{
			private static bool _warned;

			public override void OnEnter()
			{
				try
				{
					if (_instance == null)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					HeroController instance = HeroController.instance;
					VergilChargeVariantState.ReleaseWasDashing = (Object)(object)instance != (Object)null && instance.cState != null && instance.cState.dashing;
				}
				catch (Exception ex)
				{
					if (!_warned)
					{
						_warned = true;
						VergilCrestFeature? instance2 = _instance;
						if (instance2 != null)
						{
							instance2._log.LogWarning((object)("[InsectMayCry][Vergil] release-dash capture failed: " + ex.GetType().Name + ": " + ex.Message));
						}
					}
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class VergilChargeVariantPickAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					VergilCrestFeature? instance = _instance;
					Fsm fsm = ((FsmStateAction)this).Fsm;
					VergilNailArtsMarker vergilNailArtsMarker = ((fsm != null && (Object)(object)fsm.GameObject != (Object)null) ? fsm.GameObject.GetComponent<VergilNailArtsMarker>() : null);
					if (instance == null || fsm == null)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					if (!VergilChargeVariantState.IsImcEquipped())
					{
						VergilChargeVariantState.Current = ChargeVariant.None;
						vergilNailArtsMarker?.RouteAnticFinish(fsm.GetState("Lunge?"));
						((FsmStateAction)this).Finish();
						return;
					}
					string text = HeroController.instance?.playerData?.CurrentCrestID;
					HeroActions val = ManagerSingleton<InputHandler>.Instance?.inputActions;
					ChargeVariant chargeVariant = (VergilChargeVariantState.Current = ((val == null) ? ChargeVariant.Default : VergilCrestRules.ResolveChargeVariant(VergilChargeVariantState.ReleaseWasDashing, ((OneAxisInputControl)val.Up).IsPressed, ((OneAxisInputControl)val.Down).IsPressed)));
					FsmVariables variables = fsm.Variables;
					FsmString val2 = ((variables != null) ? variables.GetFsmString("Recoil Method") : null);
					if (val2 != null)
					{
						val2.Value = "";
					}
					GameObject val3 = FindChargeInstance(text, chargeVariant);
					HeroController instance2 = HeroController.instance;
					bool flag = chargeVariant == ChargeVariant.Down && VergilCrestRules.IsVergilCrest(text) && instance2?.cState != null && !instance2.cState.onGround;
					if (flag)
					{
						val3 = ((text != null && _specById.TryGetValue(text, out CrestSpec value)) ? value.ChargeNone : null);
					}
					if ((Object)(object)val3 != (Object)null && fsm.Variables != null)
					{
						FsmGameObject fsmGameObject = fsm.Variables.GetFsmGameObject("Current Charge Slash");
						if (fsmGameObject != null)
						{
							fsmGameObject.Value = val3;
						}
					}
					string text2 = (((chargeVariant == ChargeVariant.Down && VergilCrestRules.IsVergilCrest(text) && !flag) || (chargeVariant == ChargeVariant.Dash && VergilCrestRules.IsNeroCrest(text))) ? "Lunge?" : "Slash Recoil?");
					vergilNailArtsMarker?.RouteAnticFinish(fsm.GetState(text2));
				}
				catch (Exception)
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class ImcBeastChargeAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					HeroController instance = HeroController.instance;
					if (instance?.playerData == null || VergilChargeVariantState.Current != ChargeVariant.Down || !VergilCrestRules.IsDanteCrest(instance.playerData.CurrentCrestID))
					{
						return;
					}
					ApplyBeastChargeVelocity(instance);
				}
				catch (Exception)
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class VergilDefaultChargeAction : FsmStateAction
		{
			private static bool _warned;

			public override void OnEnter()
			{
				try
				{
					HeroController instance = HeroController.instance;
					if ((Object)(object)instance == (Object)null || instance.playerData == null || !VergilChargeVariantState.IsImcEquipped())
					{
						((FsmStateAction)this).Finish();
						return;
					}
					string currentCrestID = instance.playerData.CurrentCrestID;
					switch 

CrestsEvolve.LegendsNeverDie/CrestsEvolve.LegendsNeverDie.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrestsEvolve.Core.Combat;
using CrestsEvolve.Core.Events;
using CrestsEvolve.Core.Input;
using CrestsEvolve.Core.State;
using CrestsEvolve.Core.Time;
using CrestsEvolve.Core.UI;
using CrestsEvolve.Features;
using CrestsEvolve.Features.Plasma;
using CrestsEvolve.Features.Runa;
using CrestsEvolve.Features.StatusIcons;
using CrestsEvolve.GameInterop;
using CrestsEvolve.GameInterop.Patches;
using CrestsEvolve.LegendsNeverDie.Bootstrap;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using Microsoft.CodeAnalysis;
using Silksong.FsmUtil;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CrestsEvolve.LegendsNeverDie")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")]
[assembly: AssemblyProduct("CrestsEvolve.LegendsNeverDie")]
[assembly: AssemblyTitle("CrestsEvolve.LegendsNeverDie")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace CrestsEvolve.GameInterop
{
	public static class BlueHealthTintBridge
	{
		public const string PoisonVariableName = "Is Poison";

		private static readonly Color RedColor = new Color(0.78f, 0.16f, 0.16f, 1f);

		private static readonly Color GreenColor = new Color(0.28f, 0.78f, 0.36f, 1f);

		public static Func<bool>? IsBeastTintActive;

		public static Func<bool>? IsWitchTintActive;

		public static Func<bool>? IsCursedTintActive;

		private static ManualLogSource? _log;

		private static bool _warned;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void MarkActivePostfix(BlueHealth __instance)
		{
			ApplyTint(__instance);
		}

		public static void CheckPoisonPostfix(BlueHealth __instance)
		{
			ApplyTint(__instance);
		}

		public static void SetPoisonTintOverridePostfix(SetPoisonTintOverride __instance)
		{
			try
			{
				object obj;
				if (__instance == null)
				{
					obj = null;
				}
				else
				{
					Fsm fsm = ((FsmStateAction)__instance).Fsm;
					obj = ((fsm != null) ? fsm.GameObject : null);
				}
				GameObject val = (GameObject)obj;
				if (!((Object)(object)val == (Object)null))
				{
					BlueHealth component = val.GetComponent<BlueHealth>();
					if (!((Object)(object)component == (Object)null))
					{
						ApplyTint(component);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void RefreshAll()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				BlueHealth[] array = Resources.FindObjectsOfTypeAll<BlueHealth>();
				foreach (BlueHealth val in array)
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
					{
						Scene scene = ((Component)val).gameObject.scene;
						if (((Scene)(ref scene)).IsValid())
						{
							ApplyTint(val);
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void ApplyTint(BlueHealth mask)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				BlueHealthTintKind blueHealthTintKind = BlueHealthTintResolver.Resolve(IsBeastTintActive?.Invoke() ?? false, IsWitchTintActive?.Invoke() ?? false, IsCursedTintActive?.Invoke() ?? false, IsPoison(mask));
				bool flag = ApplyToSprite(mask, blueHealthTintKind switch
				{
					BlueHealthTintKind.Red => RedColor, 
					BlueHealthTintKind.Green => GreenColor, 
					_ => null, 
				});
				if (flag && blueHealthTintKind != BlueHealthTintKind.None)
				{
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogDebug((object)$"[BlueHealthTint][probe] tint applied: kind={blueHealthTintKind} go={((Object)mask).name}");
					}
				}
				else if (!flag && blueHealthTintKind != BlueHealthTintKind.None)
				{
					ManualLogSource? log2 = _log;
					if (log2 != null)
					{
						log2.LogDebug((object)$"[BlueHealthTint][probe] tint skipped (sprite not found): kind={blueHealthTintKind} go={((Object)mask).name}");
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static bool IsPoison(BlueHealth mask)
		{
			PlayMakerFSM[] components = ((Component)mask).GetComponents<PlayMakerFSM>();
			foreach (PlayMakerFSM val in components)
			{
				if (!((Object)(object)val == (Object)null) && val.FsmVariables != null)
				{
					FsmBool val2 = val.FsmVariables.FindFsmBool("Is Poison");
					if (val2 != null && val2.Value)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool ApplyToSprite(BlueHealth mask, Color? tint)
		{
			//IL_0038: 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)
			object obj = FindTk2dSprite(mask);
			if (obj != null)
			{
				return SetTk2dColor(obj, tint);
			}
			SpriteRenderer componentInChildren = ((Component)mask).GetComponentInChildren<SpriteRenderer>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.color = (Color)(((??)tint) ?? Color.white);
				return true;
			}
			return false;
		}

		private static object? FindTk2dSprite(BlueHealth mask)
		{
			Component[] componentsInChildren = ((Component)mask).GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				string name = ((object)val).GetType().Name;
				if (name == "tk2dSpriteAnimator")
				{
					PropertyInfo property = ((object)val).GetType().GetProperty("Sprite");
					if (property != null)
					{
						object value = property.GetValue(val);
						if (value != null)
						{
							return value;
						}
					}
				}
				else if (name == "tk2dSprite")
				{
					return val;
				}
			}
			return null;
		}

		private static bool SetTk2dColor(object sprite, Color? tint)
		{
			//IL_0036: 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)
			Type type = sprite.GetType();
			PropertyInfo property = type.GetProperty("color", BindingFlags.Instance | BindingFlags.Public);
			if (property == null)
			{
				return false;
			}
			property.SetValue(sprite, (object)(Color)(((??)tint) ?? Color.white));
			(tint.HasValue ? type.GetMethod("EnableKeyword", BindingFlags.Instance | BindingFlags.Public) : type.GetMethod("DisableKeyword", BindingFlags.Instance | BindingFlags.Public))?.Invoke(sprite, new object[1] { "RECOLOUR" });
			return true;
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[BlueHealthTint] " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public enum HealSourceKind
	{
		Unknown,
		General,
		Bind,
		ChargedAttack
	}
	public sealed class HealClassificationBridge
	{
		private readonly ManualLogSource _log;

		private double _bindWindowEnd;

		private double _chargedWindowEnd;

		public HealClassificationBridge(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
		}

		public HealSourceKind Classify(string sourceTag)
		{
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance != (Object)null && instance.cState != null && (instance.cState.focusing || instance.cState.isBinding))
			{
				return HealSourceKind.Bind;
			}
			double unscaledTimeAsDouble = Time.unscaledTimeAsDouble;
			if (_bindWindowEnd > unscaledTimeAsDouble)
			{
				return HealSourceKind.Bind;
			}
			if (_chargedWindowEnd > unscaledTimeAsDouble)
			{
				return HealSourceKind.ChargedAttack;
			}
			if (Contains(sourceTag, "bind"))
			{
				return HealSourceKind.Bind;
			}
			if (Contains(sourceTag, "charge"))
			{
				return HealSourceKind.ChargedAttack;
			}
			return HealSourceKind.Unknown;
		}

		public void OpenBindHealWindow(double seconds)
		{
			if (!(seconds <= 0.0))
			{
				_bindWindowEnd = Math.Max(_bindWindowEnd, Time.unscaledTimeAsDouble + seconds);
				_log.LogDebug((object)$"[HealClassification] bind heal classification window opened ({seconds}s).");
			}
		}

		public void OpenChargedHealWindow(double seconds)
		{
			if (!(seconds <= 0.0))
			{
				_chargedWindowEnd = Math.Max(_chargedWindowEnd, Time.unscaledTimeAsDouble + seconds);
				_log.LogDebug((object)$"[HealClassification] charged heal classification window opened ({seconds}s).");
			}
		}

		public void NotifyBindCompleted()
		{
			_log.LogInfo((object)"[HealClassification][probe] BindCompleted fired; opening bind heal window.");
			OpenBindHealWindow(1.0);
		}

		private static bool Contains(string? value, string keyword)
		{
			if (value != null)
			{
				return value.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	public static class PlasmaBindGatePatch
	{
		public static Func<bool>? IsGreenPlasmaActive;

		private static ManualLogSource? _log;

		private static bool _warned;

		public static void Configure(ManualLogSource? log)
		{
			_log = log;
			_warned = false;
		}

		public static void Prefix(BoolTest __instance)
		{
			if (IsGreenPlasmaActive == null || !IsGreenPlasmaActive())
			{
				return;
			}
			try
			{
				if (((__instance != null) ? ((FsmStateAction)__instance).Fsm : null) != null && string.Equals(((FsmStateAction)__instance).Fsm.Name, "Spell Control", StringComparison.Ordinal) && ((FsmStateAction)__instance).State != null && string.Equals(((FsmStateAction)__instance).State.Name, "Lifeblood State?", StringComparison.Ordinal) && __instance.boolVariable != null && string.Equals(((NamedVariable)__instance.boolVariable).Name, "Chooser", StringComparison.Ordinal))
				{
					__instance.boolVariable.Value = false;
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogDebug((object)"[Plasma] green plasma bind gate unblocked.");
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[PlasmaBind] unblock disabled after error: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class PlasmaRegenSuppressor
	{
		public static Func<bool>? IsSuppressing;

		private static ManualLogSource? _log;

		private static bool _warned;

		public static void Configure(ManualLogSource? log)
		{
			_log = log;
			_warned = false;
		}

		public static bool Prefix(CallMethodProper __instance)
		{
			if (IsSuppressing == null || !IsSuppressing())
			{
				return true;
			}
			try
			{
				if (((__instance != null) ? ((FsmStateAction)__instance).Fsm : null) == null)
				{
					return true;
				}
				if (!string.Equals(((FsmStateAction)__instance).Fsm.Name, "Hive Health Regen", StringComparison.Ordinal))
				{
					return true;
				}
				if ((Object)(object)((FsmStateAction)__instance).Fsm.GameObject == (Object)null || !string.Equals(((Object)((FsmStateAction)__instance).Fsm.GameObject).name, "Health", StringComparison.Ordinal))
				{
					return true;
				}
				if (__instance.methodName == null || !string.Equals(__instance.methodName.Value, "AddHealth", StringComparison.Ordinal))
				{
					return true;
				}
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogDebug((object)"[Plasma] suppressed vanilla Hive Health Regen AddHealth.");
				}
				return false;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return true;
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[PlasmaRegen] suppression disabled after error: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class PlasmaStateBridge
	{
		public static Action? OnPlasmaEntered;

		public static Action? OnPlasmaExited;

		private static ManualLogSource? _log;

		private static bool _knownPlasma;

		public static void Configure(ManualLogSource? log)
		{
			_log = log;
		}

		public static void HitMaxBlueHealthPostfix(HeroController __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				SetPlasma(__instance.IsInLifebloodState);
			}
		}

		public static void ResetLifebloodStatePostfix(HeroController __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				SetPlasma(__instance.IsInLifebloodState);
			}
		}

		public static void SyncFromHero()
		{
			HeroController instance = HeroController.instance;
			SetPlasma((Object)(object)instance != (Object)null && instance.IsInLifebloodState);
		}

		public static void ResetTracking()
		{
			_knownPlasma = false;
		}

		private static void SetPlasma(bool active)
		{
			if (active != _knownPlasma)
			{
				_knownPlasma = active;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogDebug((object)("[PlasmaState] " + (active ? "entered" : "exited")));
				}
				if (active)
				{
					OnPlasmaEntered?.Invoke();
				}
				else
				{
					OnPlasmaExited?.Invoke();
				}
			}
		}
	}
	public static class PlasmaTintBridge
	{
		private static readonly Color RedColor = new Color(0.78f, 0.16f, 0.16f, 1f);

		private static readonly Color GreenColor = new Color(0.28f, 0.78f, 0.36f, 1f);

		public static Func<bool>? IsRedPlasmaActive;

		public static Func<bool>? IsGreenPlasmaActive;

		private static ManualLogSource? _log;

		private static bool _warned;

		private static bool _tinted;

		public static void Configure(ManualLogSource? log)
		{
			_log = log;
			_warned = false;
			_tinted = false;
		}

		public static void RefreshAll()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Color? val = ResolveColor();
				if (val.HasValue)
				{
					ApplyTint(val.Value);
					_tinted = true;
				}
				else if (_tinted)
				{
					RestoreTint();
					_tinted = false;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void RestoreAll()
		{
			try
			{
				if (_tinted)
				{
					RestoreTint();
					_tinted = false;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void HitMaxBlueHealthBurstPostfix(HeroController __instance)
		{
			RefreshAll();
		}

		public static void SpawnObjectFromGlobalPoolPostfix(SpawnObjectFromGlobalPool __instance)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			Color? val = ResolveColor();
			if (!val.HasValue)
			{
				return;
			}
			try
			{
				if (((__instance != null) ? ((FsmStateAction)__instance).Fsm : null) == null || !string.Equals(((FsmStateAction)__instance).Fsm.Name, "health_display", StringComparison.Ordinal))
				{
					return;
				}
				FsmGameObject gameObject = __instance.gameObject;
				GameObject val2 = ((gameObject != null) ? gameObject.Value : null);
				if ((Object)(object)val2 == (Object)null || !string.Equals(((Object)val2).name, "HP Up Particles HiveB", StringComparison.Ordinal))
				{
					return;
				}
				FsmGameObject storeObject = __instance.storeObject;
				GameObject val3 = ((storeObject != null) ? storeObject.Value : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					ApplyTintToHierarchy(val3, val.Value);
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogDebug((object)"[PlasmaTint][probe] heal particles tinted.");
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static Color? ResolveColor()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			bool num = IsRedPlasmaActive?.Invoke() ?? false;
			bool flag = IsGreenPlasmaActive?.Invoke() ?? false;
			if (num)
			{
				return RedColor;
			}
			if (flag)
			{
				return GreenColor;
			}
			return null;
		}

		private static void ApplyTint(Color color)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in FindRegularMasks())
			{
				ApplyTintToHierarchy(item, color);
			}
			ApplyTintToHierarchy(FindRecoveryBlob(), color);
		}

		private static void RestoreTint()
		{
			foreach (GameObject item in FindRegularMasks())
			{
				ApplyTintToHierarchy(item, null);
			}
			ApplyTintToHierarchy(FindRecoveryBlob(), null);
		}

		private static IEnumerable<GameObject> FindRegularMasks()
		{
			PlayMakerFSM[] array = Resources.FindObjectsOfTypeAll<PlayMakerFSM>();
			foreach (PlayMakerFSM val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && string.Equals(val.FsmName, "health_display", StringComparison.Ordinal) && !((Object)(object)((Component)val).gameObject.GetComponent<BlueHealth>() != (Object)null))
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						yield return ((Component)val).gameObject;
					}
				}
			}
		}

		private static GameObject? FindRecoveryBlob()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			PlayMakerFSM[] array = Resources.FindObjectsOfTypeAll<PlayMakerFSM>();
			foreach (PlayMakerFSM val in array)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !string.Equals(val.FsmName, "Hive Health Regen", StringComparison.Ordinal))
				{
					continue;
				}
				Scene scene = ((Component)val).gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					FsmVariables fsmVariables = val.FsmVariables;
					FsmGameObject val2 = ((fsmVariables != null) ? fsmVariables.FindFsmGameObject("Recovery Blob") : null);
					if ((Object)(object)((val2 != null) ? val2.Value : null) != (Object)null)
					{
						return val2.Value;
					}
				}
			}
			return null;
		}

		private static void ApplyTintToHierarchy(GameObject? root, Color? color)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					string name = ((object)val).GetType().Name;
					if (name == "tk2dSpriteAnimator")
					{
						PropertyInfo property = ((object)val).GetType().GetProperty("Sprite");
						if (property != null)
						{
							object value = property.GetValue(val);
							if (value != null)
							{
								SetTk2dColor(value, color);
							}
						}
					}
					else if (name == "tk2dSprite")
					{
						SetTk2dColor(val, color);
					}
					else
					{
						SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null);
						if (val2 != null)
						{
							val2.color = (Color)(((??)color) ?? Color.white);
						}
					}
				}
				catch (Exception ex)
				{
					WarnOnce(ex);
				}
			}
		}

		private static void SetTk2dColor(object sprite, Color? color)
		{
			//IL_0035: 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)
			Type type = sprite.GetType();
			PropertyInfo property = type.GetProperty("color", BindingFlags.Instance | BindingFlags.Public);
			if (!(property == null))
			{
				property.SetValue(sprite, (object)(Color)(((??)color) ?? Color.white));
				(color.HasValue ? type.GetMethod("EnableKeyword", BindingFlags.Instance | BindingFlags.Public) : type.GetMethod("DisableKeyword", BindingFlags.Instance | BindingFlags.Public))?.Invoke(sprite, new object[1] { "RECOLOUR" });
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[PlasmaTint] tint disabled after error: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class ReaperFireBladeBridge
	{
		public static Func<int> Layers { get; set; } = () => 0;

		public static Func<double> DamageMultiplier { get; set; } = () => 1.0;

		public static bool IsActive()
		{
			return Layers() > 0;
		}
	}
	public sealed class ShardGeoBridge
	{
		private readonly ManualLogSource _log;

		private bool _warned;

		public ShardGeoBridge(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
		}

		public int AddShardsReturningAdded(int amount)
		{
			if (amount <= 0)
			{
				return 0;
			}
			try
			{
				HeroController instance = HeroController.instance;
				if (instance?.playerData == null)
				{
					return 0;
				}
				int shellShards = instance.playerData.ShellShards;
				instance.playerData.AddShards(amount);
				return Math.Max(0, instance.playerData.ShellShards - shellShards);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
				return 0;
			}
		}

		public void AddGeo(int amount)
		{
			if (amount <= 0)
			{
				return;
			}
			try
			{
				HeroController instance = HeroController.instance;
				if (instance != null)
				{
					instance.AddGeo(amount);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[ShardGeoBridge] " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
	public sealed class SpiritFlameSpawner
	{
		private readonly ManualLogSource _log;

		private readonly FieldInfo? _wispPrefabField;

		private bool _warned;

		public SpiritFlameSpawner(ManualLogSource log)
		{
			_log = log;
			_wispPrefabField = AccessTools.Field(typeof(HeroWispLantern), "wispPrefab");
		}

		public void Spawn()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				HeroController instance = HeroController.instance;
				GameObject val = ResolveWispPrefab();
				if ((Object)(object)instance == (Object)null || (Object)(object)val == (Object)null)
				{
					WarnOnce("hero or spirit flame prefab is missing");
					return;
				}
				Object.Destroy((Object)(object)Object.Instantiate<GameObject>(val, ((Component)instance).transform.position, ((Component)instance).transform.rotation), 1f);
				_log.LogDebug((object)"[SpiritFlame] blue wisp flame spawned at player.");
			}
			catch (Exception ex)
			{
				WarnOnce(ex.Message);
			}
		}

		private GameObject? ResolveWispPrefab()
		{
			try
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null && _wispPrefabField != null)
				{
					HeroWispLantern componentInChildren = ((Component)instance).GetComponentInChildren<HeroWispLantern>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						object? value = _wispPrefabField.GetValue(componentInChildren);
						GameObject val = (GameObject)((value is GameObject) ? value : null);
						if (val != null)
						{
							_log.LogInfo((object)"[SpiritFlame][probe] using HeroWispLantern.wispPrefab (E1).");
							return val;
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex.Message);
			}
			GameObject lifebloodHealEffect = Effects.LifebloodHealEffect;
			if ((Object)(object)lifebloodHealEffect != (Object)null)
			{
				_log.LogInfo((object)"[SpiritFlame][probe] fallback Effects.LifebloodHealEffect.");
			}
			return lifebloodHealEffect;
		}

		private void WarnOnce(string message)
		{
			if (!_warned)
			{
				_warned = true;
				_log.LogWarning((object)("[SpiritFlame] " + message));
			}
		}
	}
}
namespace CrestsEvolve.GameInterop.Patches
{
	public static class ArchitectToolRepairPatch
	{
		private static ManualLogSource? _log;

		private static bool _warned;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void Postfix()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			if (!ArchitectRuneBridge.IsToolRepairActive())
			{
				return;
			}
			try
			{
				PlayerData instance = PlayerData.instance;
				if (instance == null || string.IsNullOrEmpty(instance.CurrentCrestID))
				{
					return;
				}
				List<ToolCrest> allCrests = ToolItemManager.GetAllCrests();
				if (allCrests == null)
				{
					return;
				}
				foreach (ToolCrest item in allCrests)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					string name = item.name;
					if (string.IsNullOrEmpty(name) || string.Equals(name, instance.CurrentCrestID, StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					List<ToolItem> equippedToolsForCrest = ToolItemManager.GetEquippedToolsForCrest(name);
					if (equippedToolsForCrest == null)
					{
						continue;
					}
					foreach (ToolItem item2 in equippedToolsForCrest)
					{
						if ((Object)(object)item2 == (Object)null)
						{
							continue;
						}
						Data toolData = instance.GetToolData(item2.name);
						int toolStorageAmount = ToolItemManager.GetToolStorageAmount(item2);
						ToolItemStatesLiquid val = (ToolItemStatesLiquid)(object)((item2 is ToolItemStatesLiquid) ? item2 : null);
						if (val != null)
						{
							val.RefillRefills(false);
							ManualLogSource? log = _log;
							if (log != null)
							{
								log.LogDebug((object)("[ArchitectToolRepair] liquid refills reset for " + item2.name + " (" + name + ")."));
							}
						}
						if (toolData.AmountLeft < toolStorageAmount)
						{
							toolData.AmountLeft = toolStorageAmount;
							instance.SetToolData(item2.name, toolData);
						}
						ManualLogSource? log2 = _log;
						if (log2 != null)
						{
							log2.LogDebug((object)$"[ArchitectToolRepair] repaired {item2.name} ({name}) to {toolStorageAmount}.");
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[ArchitectToolRepair] " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class ArchitectToolTransformPatch
	{
		public static void Prefix(ToolItemType promptToolType, CanChangeEquipsTypes changeType, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)changeType == 2 && ArchitectRuneBridge.IsToolTransformActive())
			{
				__result = true;
			}
		}
	}
	public static class AttackStartedSignalPatch
	{
		public static Action? AttackStarted;

		public static void Postfix()
		{
			AttackStarted?.Invoke();
		}
	}
	public static class BeastDownspikeInvulnPatch
	{
		public const int InvulnerabilitySteps = 15;

		public static void Postfix(Downspike __instance)
		{
			if (BeastRuneBridge.IsEnhancementActive())
			{
				HeroController instance = HeroController.instance;
				if (!((Object)(object)instance == (Object)null) && instance.cState != null)
				{
					instance.cState.downspikeInvulnerabilitySteps = Math.Max(instance.cState.downspikeInvulnerabilitySteps, 15);
				}
			}
		}
	}
	public static class BeastPredatorChargeSlashInvulnPatch
	{
		public static void Postfix(NailAttackBase __instance)
		{
			if (BeastRuneBridge.IsPredatorCharged())
			{
				Transform transform = ((Component)__instance).transform;
				if (!((Object)(object)transform == (Object)null) && ((Object)transform).name.IndexOf("Charge Slash", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					BeastRuneBridge.AcquireChargeSlashInvulnerability?.Invoke();
				}
			}
		}
	}
	public static class BeastPredatorDamagePatch
	{
		public static double DamageMultiplier { get; set; } = 1.2;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			if (BeastRuneBridge.IsPredatorCharged() && hitInstance.IsHeroDamage && (int)hitInstance.AttackType == 16)
			{
				hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * DamageMultiplier);
			}
		}
	}
	public static class BeastRageBindFsmPatch
	{
		private sealed class BindFsmMarker : MonoBehaviour
		{
		}

		private sealed class SkipWarriorKickupAction : FsmStateAction
		{
			public override void OnEnter()
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					HeroController instance = HeroController.instance;
					if ((Object)(object)instance != (Object)null && IsActive() && instance.WarriorState.IsInRageMode)
					{
						((FsmStateAction)this).Fsm.Event("FINISHED");
					}
				}
				catch
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private sealed class SuppressDazzleAction : FsmStateAction
		{
			public override void OnEnter()
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					HeroController instance = HeroController.instance;
					if ((Object)(object)instance != (Object)null && IsActive() && instance.WarriorState.IsInRageMode)
					{
						FsmBool val = ((FsmStateAction)this).Fsm.Variables.FindFsmBool("Is Dazzle Equipped");
						if (val != null)
						{
							val.Value = false;
						}
					}
				}
				catch
				{
				}
				((FsmStateAction)this).Finish();
			}
		}

		private static ManualLogSource? _log;

		private static bool _warned;

		public static bool Enabled { get; set; }

		public static Func<bool> IsActive { get; set; } = () => true;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void Postfix(PlayMakerFSM __instance)
		{
			if (!Enabled || (Object)(object)__instance == (Object)null || __instance.Fsm == null || __instance.FsmName != "Bind" || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal) || (Object)(object)((Component)__instance).GetComponent<BindFsmMarker>() != (Object)null)
			{
				return;
			}
			try
			{
				FsmState state = FsmUtil.GetState(__instance, "Warrior Kickup");
				FsmState state2 = FsmUtil.GetState(__instance, "Dazzle?");
				if (state == null || state2 == null)
				{
					WarnOnce(new InvalidOperationException($"Bind FSM states missing: Warrior Kickup={state != null}, Dazzle?={state2 != null}"));
					return;
				}
				FsmUtil.InsertAction(state, 0, (FsmStateAction)(object)new SkipWarriorKickupAction());
				FsmUtil.InsertAction(state2, 0, (FsmStateAction)(object)new SuppressDazzleAction());
				((Component)__instance).gameObject.AddComponent<BindFsmMarker>();
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)"[BeastRageBind] BEA-005 hooks installed: skip Warrior Kickup + suppress Dazzle? while in Rage mode.");
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[BeastRageBind] BEA-005 FSM hook disabled: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class BeastRageDamageProtectPatch
	{
		private static readonly FieldInfo _warriorStateField = AccessTools.Field(typeof(HeroController), "warriorState");

		private static ManualLogSource? _log;

		private static bool _warned;

		private static float _savedEffect;

		private static float _savedHeal;

		private static bool _saved;

		public static Func<bool> IsActive { get; set; } = () => false;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
		}

		public static void Prefix(HeroController __instance)
		{
			//IL_002c: 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)
			//IL_003c: 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)
			_saved = false;
			if (!IsActive() || _warriorStateField == null)
			{
				return;
			}
			try
			{
				WarriorCrestStateInfo val = (WarriorCrestStateInfo)_warriorStateField.GetValue(__instance);
				if (val.IsInRageMode)
				{
					_savedEffect = val.RageEffectTimeLeft;
					_savedHeal = val.RageHealTimeLeft;
					_saved = true;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void Postfix(HeroController __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!_saved || _warriorStateField == null)
			{
				return;
			}
			try
			{
				WarriorCrestStateInfo val = (WarriorCrestStateInfo)_warriorStateField.GetValue(__instance);
				val.RageEffectTimeLeft = _savedEffect;
				val.RageHealTimeLeft = _savedHeal;
				_warriorStateField.SetValue(__instance, val);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			finally
			{
				_saved = false;
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[BeastRageProtect] " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class BindCostPatch
	{
		public static bool Prefix(ref float __result)
		{
			if (CloaklessRuneBridge.IsFreeBindCharged())
			{
				__result = 0f;
				return false;
			}
			if (CursedRuneBridge.IsBindEnabled())
			{
				__result = 9f;
				return false;
			}
			return true;
		}
	}
	public static class CursedBindInvulnerabilityPatch
	{
		private sealed class CursedBindFsmMarker : MonoBehaviour
		{
		}

		private sealed class AcquireBindInvulnerabilityAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					if (!CursedRuneBridge.IsBindInvulnerabilityActive())
					{
						((FsmStateAction)this).Finish();
						return;
					}
					if (CursedRuneBridge.BindInvulnerabilitySeconds() <= 0.0)
					{
						((FsmStateAction)this).Finish();
						return;
					}
					_lease?.Dispose();
					_lease = CursedRuneBridge.AcquireBindInvulnerability();
				}
				catch (Exception ex)
				{
					WarnOnce(ex);
				}
				((FsmStateAction)this).Finish();
			}
		}

		private static readonly string[] BindStates = new string[4] { "Binding", "Cursed Bind Start", "Cursed Bind Mid", "Cursed Bind Wait" };

		private static ManualLogSource? _log;

		private static bool _warned;

		private static IDisposable? _lease;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void OnFsmStart(PlayMakerFSM __instance)
		{
			if ((Object)(object)__instance == (Object)null || __instance.Fsm == null || __instance.FsmName != "Spell Control" || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal) || (Object)(object)((Component)__instance).GetComponent<CursedBindFsmMarker>() != (Object)null)
			{
				return;
			}
			try
			{
				int num = 0;
				string[] bindStates = BindStates;
				foreach (string text in bindStates)
				{
					FsmState state = FsmUtil.GetState(__instance, text);
					if (state != null)
					{
						FsmUtil.InsertAction(state, 0, (FsmStateAction)(object)new AcquireBindInvulnerabilityAction());
						num++;
					}
				}
				if (num == 0)
				{
					WarnOnce(new InvalidOperationException("Spell Control bind states not found; bind invulnerability disabled."));
					return;
				}
				((Component)__instance).gameObject.AddComponent<CursedBindFsmMarker>();
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[CursedBind] bind-process invulnerability hooks installed ({num} states).");
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void Reset()
		{
			try
			{
				_lease?.Dispose();
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			_lease = null;
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[CursedBind] disabled: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class DashSignalPatch
	{
		public static Action? DashStarted { get; set; }

		public static void Postfix()
		{
			DashStarted?.Invoke();
		}
	}
	public static class GlacialSlowPatch
	{
		private sealed class EnemySlowDriver : MonoBehaviour
		{
			private sealed record WalkerEntry(Walker Walker, float Left, float Right);

			private sealed record WalkerV2Entry(WalkerV2 Walker, float Walk, float Run);

			private readonly List<WalkerEntry> _walkers = new List<WalkerEntry>();

			private readonly List<WalkerV2Entry> _walkersV2 = new List<WalkerV2Entry>();

			private Rigidbody2D[] _bodies = Array.Empty<Rigidbody2D>();

			private float _factor = 0.5f;

			private float _remaining = 10f;

			public void Initialize(float factor, float duration)
			{
				_factor = Mathf.Clamp(factor, 0.05f, 1f);
				_remaining = Mathf.Max(0.1f, duration);
				Capture();
			}

			public void Refresh(float factor, float duration)
			{
				_factor = Mathf.Clamp(factor, 0.05f, 1f);
				_remaining = Mathf.Max(0.1f, duration);
			}

			private void Capture()
			{
				Walker[] componentsInChildren = ((Component)this).GetComponentsInChildren<Walker>(true);
				foreach (Walker val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null))
					{
						_walkers.Add(new WalkerEntry(val, val.walkSpeedL, val.walkSpeedR));
						val.walkSpeedL *= _factor;
						val.walkSpeedR *= _factor;
					}
				}
				WalkerV2[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<WalkerV2>(true);
				foreach (WalkerV2 val2 in componentsInChildren2)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						_walkersV2.Add(new WalkerV2Entry(val2, val2.WalkSpeed, val2.RunSpeed));
						val2.WalkSpeed *= _factor;
						val2.RunSpeed *= _factor;
					}
				}
				_bodies = ((Component)this).GetComponentsInChildren<Rigidbody2D>(true);
			}

			private void Update()
			{
				_remaining -= Time.deltaTime;
				if (_remaining <= 0f)
				{
					Object.Destroy((Object)(object)this);
				}
			}

			private void FixedUpdate()
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				if (_factor >= 1f)
				{
					return;
				}
				Rigidbody2D[] bodies = _bodies;
				foreach (Rigidbody2D val in bodies)
				{
					if (!((Object)(object)val == (Object)null))
					{
						val.linearVelocity *= _factor;
						val.angularVelocity *= _factor;
					}
				}
			}

			private void OnDestroy()
			{
				foreach (WalkerEntry walker in _walkers)
				{
					if ((Object)(object)walker.Walker != (Object)null)
					{
						walker.Walker.walkSpeedL = walker.Left;
						walker.Walker.walkSpeedR = walker.Right;
					}
				}
				foreach (WalkerV2Entry item in _walkersV2)
				{
					if ((Object)(object)item.Walker != (Object)null)
					{
						item.Walker.WalkSpeed = item.Walk;
						item.Walker.RunSpeed = item.Run;
					}
				}
			}
		}

		public static double SlowDurationSeconds { get; set; } = 10.0;

		public static double SlowFactor { get; set; } = 0.5;

		public static void Prefix(HealthManager __instance, HitInstance hitInstance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).gameObject == (Object)null) && hitInstance.IsHeroDamage && CloaklessRuneBridge.TryConsumeGlacialAugment())
			{
				ApplySlow(((Component)__instance).gameObject);
			}
		}

		private static void ApplySlow(GameObject enemy)
		{
			if (!((Object)(object)enemy == (Object)null))
			{
				float factor = (float)SlowFactor;
				float duration = (float)SlowDurationSeconds;
				EnemySlowDriver component = enemy.GetComponent<EnemySlowDriver>();
				if ((Object)(object)component != (Object)null)
				{
					component.Refresh(factor, duration);
				}
				else
				{
					enemy.AddComponent<EnemySlowDriver>().Initialize(factor, duration);
				}
			}
		}
	}
	public static class HailOfBladesCritPatch
	{
		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (ReaperRuneBridge.IsHailOfBladesFullLayers() && hitInstance.IsHeroDamage && !hitInstance.CriticalHit && (int)hitInstance.AttackType == 0)
			{
				hitInstance.CriticalHit = true;
			}
		}
	}
	public static class HunterConquerorDamagePatch
	{
		public static Func<double>? Multiplier;

		public static Func<bool>? IsEnhanced;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			double multiplier = Multiplier?.Invoke() ?? 1.0;
			bool enhanced = IsEnhanced?.Invoke() ?? false;
			hitInstance.DamageDealt = ApplyMultiplier(hitInstance.DamageDealt, multiplier, enhanced, hitInstance.IsHeroDamage, hitInstance.AttackType);
		}

		public static int ApplyMultiplier(int damage, double multiplier, bool enhanced, bool isHeroDamage, AttackTypes attackType)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (multiplier <= 1.0)
			{
				return damage;
			}
			if (!enhanced || !isHeroDamage)
			{
				return damage;
			}
			if ((int)attackType == 2)
			{
				return damage;
			}
			return (int)Math.Round((double)damage * multiplier);
		}
	}
	public static class HunterVanillaComboPreserver
	{
		public static Func<int>? LayerCount { get; set; }

		public static bool Prefix()
		{
			return (LayerCount?.Invoke() ?? 0) <= 0;
		}
	}
	public static class NailAttackRangePatch
	{
		public static bool Enabled { get; set; } = true;

		public static float RangeMultiplier { get; set; } = 2f;

		public static void Postfix(NailAttackBase __instance)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled && !(RangeMultiplier <= 0f) && WandererRuneBridge.IsActive())
			{
				WandererEnhancementState current = WandererEnhancementState.Current;
				if (current != null && current.IsEnhanced)
				{
					Vector3 localScale = ((Component)__instance).transform.localScale;
					((Component)__instance).transform.localScale = new Vector3(localScale.x * RangeMultiplier, localScale.y, localScale.z);
				}
			}
		}
	}
	public static class ParrySignalPatch
	{
		public static Action? Parried;

		public static void Postfix()
		{
			Parried?.Invoke();
		}
	}
	public static class ReaperChargeSlashDamagePatch
	{
		public static double DamageMultiplier { get; set; } = 1.5;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			if (!(DamageMultiplier <= 1.0) && ReaperRuneBridge.IsChargeSlashEnhanced() && hitInstance.IsHeroDamage && (int)hitInstance.AttackType == 16)
			{
				hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * DamageMultiplier);
			}
		}
	}
	public static class ReaperChargeSlashScalePatch
	{
		private sealed class ChargeSlashScaleMarker : MonoBehaviour
		{
			public Vector3 Original;
		}

		public static Func<bool> IsChargeSlashEnhanced { get; set; } = () => false;

		public static float ScaleMultiplier { get; set; } = 1.5f;

		public static void Postfix(NailAttackBase __instance)
		{
			//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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)__instance).transform;
			if (!((Object)(object)transform == (Object)null) && ((Object)transform).name.IndexOf("Charge Slash", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				ChargeSlashScaleMarker chargeSlashScaleMarker = ((Component)transform).GetComponent<ChargeSlashScaleMarker>();
				if ((Object)(object)chargeSlashScaleMarker == (Object)null)
				{
					chargeSlashScaleMarker = ((Component)transform).gameObject.AddComponent<ChargeSlashScaleMarker>();
					chargeSlashScaleMarker.Original = transform.localScale;
				}
				transform.localScale = (Vector3)(IsChargeSlashEnhanced() ? new Vector3(chargeSlashScaleMarker.Original.x * ScaleMultiplier, chargeSlashScaleMarker.Original.y * ScaleMultiplier, chargeSlashScaleMarker.Original.z) : chargeSlashScaleMarker.Original);
			}
		}
	}
	public static class ReaperFireBladeDamagePatch
	{
		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			if (!ReaperFireBladeBridge.IsActive())
			{
				return;
			}
			double num = ReaperFireBladeBridge.DamageMultiplier();
			if (!(num <= 1.0) && hitInstance.IsHeroDamage)
			{
				AttackTypes attackType = hitInstance.AttackType;
				if ((int)attackType <= 1 || (int)attackType == 6 || (int)attackType == 16)
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * num);
				}
			}
		}
	}
	public static class ReaperSilkBundleAutoCollect
	{
		private sealed class SilkOrbMarker : MonoBehaviour
		{
			public PlayMakerFSM? Fsm;

			private void OnDestroy()
			{
				lock (_markers)
				{
					_markers.Remove(this);
				}
			}
		}

		private const string FsmName = "Control";

		private const string GetSilkState = "Get Silk";

		private const string CollectableState = "Collectable";

		private const string CollectState = "Collect";

		private const string DisappearEvent = "DISAPPEAR";

		private static readonly HashSet<SilkOrbMarker> _markers = new HashSet<SilkOrbMarker>();

		private static bool _failed;

		private static bool _warned;

		public static bool Enabled { get; set; }

		public static void Postfix(GameObject obj, GameObject prefab)
		{
			if (!Enabled || _failed || (Object)(object)obj == (Object)null || (Object)(object)prefab == (Object)null || ((Object)prefab).name != "Reaper Silk Bundle" || (Object)(object)obj.GetComponent<SilkOrbMarker>() != (Object)null)
			{
				return;
			}
			PlayMakerFSM val = ((IEnumerable<PlayMakerFSM>)obj.GetComponents<PlayMakerFSM>()).FirstOrDefault((Func<PlayMakerFSM, bool>)((PlayMakerFSM f) => (Object)(object)f != (Object)null && f.Fsm != null && f.Fsm.Name == "Control"));
			if ((Object)(object)val == (Object)null)
			{
				Fail("Control FSM not found on Reaper Silk Bundle");
				return;
			}
			try
			{
				Fsm fsm = val.Fsm;
				FsmState state = fsm.GetState("Get Silk");
				FsmState state2 = fsm.GetState("Collectable");
				FsmState state3 = fsm.GetState("Collect");
				if (state == null || state2 == null || state3 == null)
				{
					Fail("one of states Get Silk/Collectable/Collect missing");
					return;
				}
				DisableCameraShake(state);
				RetargetDisappear(state2, state3);
				SilkOrbMarker silkOrbMarker = obj.AddComponent<SilkOrbMarker>();
				silkOrbMarker.Fsm = val;
				lock (_markers)
				{
					_markers.Add(silkOrbMarker);
				}
			}
			catch (Exception ex)
			{
				Fail(ex.Message);
			}
		}

		public static void NotifyBindCompleted()
		{
			if (!Enabled || _failed)
			{
				return;
			}
			SilkOrbMarker[] array;
			lock (_markers)
			{
				array = _markers.ToArray();
			}
			SilkOrbMarker[] array2 = array;
			foreach (SilkOrbMarker silkOrbMarker in array2)
			{
				if (!((Object)(object)silkOrbMarker == (Object)null) && !((Object)(object)silkOrbMarker.Fsm == (Object)null) && !((Object)(object)((Component)silkOrbMarker).gameObject == (Object)null))
				{
					try
					{
						silkOrbMarker.Fsm.SetState("Collect");
					}
					catch (Exception ex)
					{
						WarnOnce(ex);
					}
				}
			}
		}

		private static void DisableCameraShake(FsmState getSilk)
		{
			FsmStateAction val = ((IEnumerable<FsmStateAction>)getSilk.Actions).FirstOrDefault((Func<FsmStateAction, bool>)((FsmStateAction a) => a != null && ((object)a).GetType().Name.IndexOf("Shake", StringComparison.OrdinalIgnoreCase) >= 0));
			if (val != null)
			{
				val.Enabled = false;
			}
			else if (getSilk.Actions.Length > 2)
			{
				getSilk.Actions[2].Enabled = false;
			}
		}

		private static void RetargetDisappear(FsmState collectable, FsmState collect)
		{
			FsmTransition val = ((IEnumerable<FsmTransition>)collectable.Transitions).FirstOrDefault((Func<FsmTransition, bool>)((FsmTransition t) => t != null && t.EventName == "DISAPPEAR"));
			if (val != null)
			{
				val.ToFsmState = collect;
			}
		}

		private static void Fail(string reason)
		{
			_failed = true;
			Enabled = false;
			WarnOnce(new InvalidOperationException(reason));
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				Debug.LogWarning((object)("[ReaperSilkBundle] " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
	public static class ReaperSilkDropProbabilityPatch
	{
		private static FieldInfo? _dropsField;

		private static FieldInfo? _probabilityField;

		private static bool _checked;

		private static bool _available;

		private static bool _warned;

		private static float[]? _saved;

		public static bool Enabled { get; set; }

		public static void Prefix(HeroController __instance)
		{
			if (!Enabled || !ReaperRuneBridge.IsDropRateWindowActive() || !EnsureAvailable())
			{
				return;
			}
			try
			{
				if (!(_dropsField.GetValue(__instance) is Array { Length: >=3 } array))
				{
					return;
				}
				_saved = new float[3];
				for (int i = 0; i < 3; i++)
				{
					object value = array.GetValue(i);
					if (value == null)
					{
						_saved = null;
						break;
					}
					_saved[i] = Convert.ToSingle(_probabilityField.GetValue(value));
					_probabilityField.SetValue(value, i switch
					{
						1 => 0.5f, 
						0 => 0.15f, 
						_ => 0.35f, 
					});
				}
			}
			catch (Exception ex)
			{
				_saved = null;
				WarnOnce(ex);
			}
		}

		public static void Restore()
		{
			if (_saved == null)
			{
				return;
			}
			try
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance == (Object)null || !(_dropsField.GetValue(instance) is Array { Length: >=3 } array))
				{
					return;
				}
				for (int i = 0; i < 3; i++)
				{
					object value = array.GetValue(i);
					if (value != null)
					{
						_probabilityField.SetValue(value, _saved[i]);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			finally
			{
				_saved = null;
			}
		}

		private static bool EnsureAvailable()
		{
			if (_checked)
			{
				return _available;
			}
			_checked = true;
			try
			{
				_dropsField = AccessTools.Field(typeof(HeroController), "reaperBundleDrops");
				if (_dropsField == null || _dropsField.FieldType == null || !_dropsField.FieldType.IsArray)
				{
					WarnOnce(new InvalidOperationException("reaperBundleDrops field not found or not an array"));
					return false;
				}
				_probabilityField = AccessTools.Field(_dropsField.FieldType.GetElementType(), "Probability");
				if (_probabilityField == null)
				{
					WarnOnce(new InvalidOperationException("Probability field not found on bundle drop element"));
					return false;
				}
				_available = true;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			return _available;
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				Debug.LogWarning((object)("[ReaperSilkDrop] " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
	public static class ReaperSubBladeAttackSpeedPatch
	{
		private static bool _probeLogged;

		public static double Bonus { get; set; } = 0.3;

		public static void Postfix(ref float __result)
		{
			if (ReaperRuneBridge.IsSubBladeCharged())
			{
				float num = __result;
				__result = (float)((double)__result * AttackCycleSpeed.TimeFactor(1, Bonus));
				if (!_probeLogged)
				{
					_probeLogged = true;
					Debug.LogWarning((object)($"[HailOfBlades][probe] attack-speed getter scaled {num} -> {__result} " + $"(bonus={Bonus}, charged={ReaperRuneBridge.SubBladeChargedAttacksRemaining()})."));
				}
			}
		}
	}
	public static class UnsealedSpellbookFreeBindPatch
	{
		private static bool _probeLogged;

		public static void Prefix(HeroController __instance, ref int amount, SilkTakeSource source)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (amount < 9 || (int)source != 0)
			{
				return;
			}
			HeroController val = (HeroController)(((Object)(object)__instance != (Object)null) ? ((object)__instance) : ((object)HeroController.instance));
			if (!((Object)(object)val == (Object)null) && val.cState != null && (val.cState.isBinding || val.cState.focusing) && CloaklessRuneBridge.TryConsumeFreeBind())
			{
				amount = 0;
				if (!_probeLogged)
				{
					_probeLogged = true;
					Debug.LogWarning((object)"[UnsealedSpellbook][probe] free bind consumed; silk cost set to 0.");
				}
			}
		}
	}
	public static class WandererAttackSpeedPatch
	{
		public static double PerLayer { get; set; } = 0.06;

		public static void Postfix(ref float __result)
		{
			if (WandererRuneBridge.IsActive())
			{
				int num = WandererRuneBridge.LayerCount();
				if (num > 0)
				{
					__result = (float)((double)__result * AttackCycleSpeed.TimeFactor(num, PerLayer));
				}
			}
		}
	}
	public static class WandererCritChancePatch
	{
		public static double CritBonus { get; set; } = 0.02;

		public static void Postfix(ref float __result)
		{
			if (!(CritBonus <= 0.0) && WandererRuneBridge.IsActive() && WandererRuneBridge.IsFullLayers())
			{
				__result += (float)CritBonus;
			}
		}
	}
	public static class WandererLuckyPatch
	{
		public static void Postfix(HeroController __instance, ref bool __result)
		{
			if (!__result && WandererRuneBridge.IsActive() && WandererRuneBridge.LayerCount() > 0 && !__instance.cState.isMaggoted && ((ToolBase)Gameplay.WandererCrest).IsEquipped)
			{
				__result = true;
			}
		}
	}
	public static class WandererParryCritPatch
	{
		public static void Postfix(HeroController __instance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			if (WandererRuneBridge.IsActive())
			{
				WandererCrestStateInfo wandererState = __instance.WandererState;
				if (!wandererState.QueuedNextHitCritical)
				{
					wandererState.QueuedNextHitCritical = true;
					__instance.WandererState = wandererState;
				}
			}
		}
	}
	public static class WitchAftershockDamagePatch
	{
		public const double DamageMultiplier = 1.5;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_003f: 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_004d: Invalid comparison between Unknown and I4
			if (WitchRuneBridge.AftershockLayers() <= 0 || !hitInstance.IsHeroDamage)
			{
				return;
			}
			if ((int)hitInstance.AttackType == 6)
			{
				hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * 1.5);
			}
			else if ((int)hitInstance.AttackType == 0 || (int)hitInstance.AttackType == 1)
			{
				string text = (((Object)(object)hitInstance.Source != (Object)null) ? ((Object)hitInstance.Source).name : string.Empty);
				if (text.IndexOf("Down", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("Slash", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Spike", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * 1.5);
				}
			}
		}
	}
	public static class WitchDashInvulnPatch
	{
		public static void Postfix()
		{
			if (WitchRuneBridge.AftershockLayers() > 0)
			{
				WitchRuneBridge.AcquireDashInvulnerability?.Invoke();
			}
		}
	}
	public static class WitchGraspAttackSpeedPatch
	{
		public static void Postfix(ref float __result)
		{
			if (WitchRuneBridge.IsGraspCharged())
			{
				__result = (float)((double)__result * AttackCycleSpeed.TimeFactor(1, 0.3));
			}
		}
	}
	public static class WitchGraspDamagePatch
	{
		public const double DamageMultiplier = 1.3;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			if (WitchRuneBridge.IsGraspCharged() && hitInstance.IsHeroDamage && ((int)hitInstance.AttackType == 0 || (int)hitInstance.AttackType == 1))
			{
				hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * 1.3);
			}
		}
	}
	public static class WitchGraspDownslashDamagePatch
	{
		public const double DamageMultiplier = 1.5;

		public static void Prefix(ref HitInstance hitInstance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			if (WitchRuneBridge.GraspLayers() > 0 && hitInstance.IsHeroDamage && ((int)hitInstance.AttackType == 0 || (int)hitInstance.AttackType == 1))
			{
				string text = (((Object)(object)hitInstance.Source != (Object)null) ? ((Object)hitInstance.Source).name : string.Empty);
				if (text.IndexOf("Down", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("Slash", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Spike", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * 1.5);
				}
			}
		}
	}
	public static class WitchGraspRangePatch
	{
		public const float RangeMultiplier = 1.3f;

		public static void Postfix(NailAttackBase __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			if (WitchRuneBridge.IsGraspCharged())
			{
				Vector3 localScale = ((Component)__instance).transform.localScale;
				((Component)__instance).transform.localScale = new Vector3(localScale.x * 1.3f, localScale.y, localScale.z);
			}
		}
	}
	public static class WitchTakeSilkCostPatch
	{
		public const int ReducedCost = 5;

		private static bool _probeLogged;

		public static void Prefix(ref int amount, SilkTakeSource source)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (WitchRuneBridge.IsBindChainActive() && WitchRuneBridge.IsGraspActive() && amount >= 9)
			{
				if (!_probeLogged)
				{
					_probeLogged = true;
					Debug.LogWarning((object)$"[WitchBind][probe] TakeSilk reduced 9 -> {5} while bind chain active (source={source}).");
				}
				amount = 5;
			}
		}
	}
}
namespace CrestsEvolve.Features
{
	public sealed class ArchitectCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "architect";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public FirstStrikeRune FirstStrike { get; }

		public ElectrocuteRune Electrocute { get; }

		public bool IsToolRepairActive => Gate.IsActive;

		public bool IsToolTransformActive => Gate.IsActive;

		public ArchitectCrest(bool enabled, FirstStrikeRune firstStrike, ElectrocuteRune electrocute)
		{
			_enabled = enabled;
			Gate = new CrestGate("architect", RuneCrestIds.Architect, enabled);
			FirstStrike = firstStrike ?? throw new ArgumentNullException("firstStrike");
			Electrocute = electrocute ?? throw new ArgumentNullException("electrocute");
			Runes = new IRuneEffect[2] { FirstStrike, Electrocute };
			RuneKeys = new string[2] { FirstStrike.Key, Electrocute.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				FirstStrike.Start(currentCrestId);
				Electrocute.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				FirstStrike.Tick(deltaSeconds);
				Electrocute.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			FirstStrike.Dispose();
			Electrocute.Dispose();
		}
	}
	public sealed class BeastCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "beast";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public DarkHarvestRune DarkHarvest { get; }

		public PredatorRune Predator { get; }

		public bool IsRedBloodTintActive => Gate.IsActive;

		public bool IsRageProtectionActive => Gate.IsActive;

		public bool IsBindNoPrepActive => Gate.IsActive;

		public BeastCrest(bool enabled, DarkHarvestRune darkHarvest, PredatorRune predator)
		{
			_enabled = enabled;
			Gate = new CrestGate("beast", RuneCrestIds.Beast, enabled);
			DarkHarvest = darkHarvest ?? throw new ArgumentNullException("darkHarvest");
			Predator = predator ?? throw new ArgumentNullException("predator");
			Runes = new IRuneEffect[2] { DarkHarvest, Predator };
			RuneKeys = new string[2] { DarkHarvest.Key, Predator.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				DarkHarvest.Start(currentCrestId);
				Predator.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				DarkHarvest.Tick(deltaSeconds);
				Predator.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			DarkHarvest.Dispose();
			Predator.Dispose();
		}
	}
	public enum BlueHealthTintKind
	{
		None,
		Red,
		Green
	}
	public static class BlueHealthTintResolver
	{
		public static BlueHealthTintKind Resolve(bool beastTintActive, bool witchTintActive, bool cursedTintActive, bool isPoison)
		{
			if (isPoison)
			{
				return BlueHealthTintKind.None;
			}
			if (beastTintActive)
			{
				return BlueHealthTintKind.Red;
			}
			if (witchTintActive || cursedTintActive)
			{
				return BlueHealthTintKind.Green;
			}
			return BlueHealthTintKind.None;
		}
	}
	public sealed class CloaklessCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		private readonly IRuneEffect? _extraRune;

		public string Key => "cloakless";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public GlacialAugmentRune GlacialAugment { get; }

		public UnsealedSpellbookRune UnsealedSpellbook { get; }

		public IRuneEffect? RandomPassive => _extraRune;

		public string? RandomPassiveKey => _extraRune?.Key;

		public CloaklessCrest(bool enabled, GlacialAugmentRune glacialAugment, UnsealedSpellbookRune unsealedSpellbook, bool randomPassiveEnabled, IReadOnlyList<IRuneEffect>? randomPool, Random? random = null, string? pinnedPassiveKey = null)
		{
			_enabled = enabled;
			Gate = new CrestGate("cloakless", RuneCrestIds.Cloakless, enabled);
			GlacialAugment = glacialAugment ?? throw new ArgumentNullException("glacialAugment");
			UnsealedSpellbook = unsealedSpellbook ?? throw new ArgumentNullException("unsealedSpellbook");
			List<IRuneEffect> list = new List<IRuneEffect> { GlacialAugment, UnsealedSpellbook };
			List<string> list2 = new List<string> { GlacialAugment.Key, UnsealedSpellbook.Key };
			if (randomPassiveEnabled && randomPool != null && randomPool.Count > 0)
			{
				List<IRuneEffect> list3 = new List<IRuneEffect>();
				foreach (IRuneEffect item in randomPool)
				{
					if (item != null && !string.Equals(item.Key, GlacialAugment.Key, StringComparison.Ordinal) && !string.Equals(item.Key, UnsealedSpellbook.Key, StringComparison.Ordinal))
					{
						list3.Add(item);
					}
				}
				if (list3.Count > 0)
				{
					_extraRune = (string.IsNullOrWhiteSpace(pinnedPassiveKey) ? null : list3.FirstOrDefault((IRuneEffect r) => string.Equals(r.Key, pinnedPassiveKey, StringComparison.OrdinalIgnoreCase))) ?? list3[(random ?? new Random()).Next(list3.Count)];
					list.Add(_extraRune);
					list2.Add(_extraRune.Key);
				}
			}
			Runes = list.ToArray();
			RuneKeys = list2.ToArray();
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				GlacialAugment.Start(currentCrestId);
				UnsealedSpellbook.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				GlacialAugment.Tick(deltaSeconds);
				UnsealedSpellbook.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			GlacialAugment.Dispose();
			UnsealedSpellbook.Dispose();
		}
	}
	public sealed class CursedCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "cursed";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public AftershockRune Aftershock { get; }

		public GuardianRune Guardian { get; }

		public bool IsBindInvulnerabilityActive => Gate.IsActive;

		public bool IsBindEnabled => Gate.IsActive;

		public bool IsGreenBloodTintActive => Gate.IsActive;

		public CursedCrest(bool enabled, AftershockRune aftershock, GuardianRune guardian)
		{
			_enabled = enabled;
			Gate = new CrestGate("cursed", RuneCrestIds.Cursed, enabled);
			Aftershock = aftershock ?? throw new ArgumentNullException("aftershock");
			Guardian = guardian ?? throw new ArgumentNullException("guardian");
			Runes = new IRuneEffect[2] { Aftershock, Guardian };
			RuneKeys = new string[2] { Aftershock.Key, Guardian.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				Aftershock.Start(currentCrestId);
				Guardian.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				Aftershock.Tick(deltaSeconds);
				Guardian.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			Aftershock.Dispose();
			Guardian.Dispose();
		}
	}
	public sealed class HunterCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "hunter";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public ConquerorRune Conqueror { get; }

		public int VanillaFocusProtectionLayers => Conqueror.LayerCount;

		public HunterCrest(bool enabled, ConquerorRune conqueror)
		{
			_enabled = enabled;
			Gate = new CrestGate("hunter", RuneCrestIds.Hunter, enabled);
			Conqueror = conqueror ?? throw new ArgumentNullException("conqueror");
			Runes = new IRuneEffect[1] { Conqueror };
			RuneKeys = new string[1] { Conqueror.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				Conqueror.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				Conqueror.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			Conqueror.Dispose();
		}
	}
	public sealed class ReaperCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "reaper";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public PressTheAttackRune PressTheAttack { get; }

		public HailOfBladesRune HailOfBlades { get; }

		public bool IsDropRateOverrideActive => PressTheAttack.IsDropRateOverrideActive;

		public bool IsAutoCollectEnabled => PressTheAttack.IsAutoCollectEnabled;

		public ReaperCrest(bool enabled, PressTheAttackRune pressTheAttack, HailOfBladesRune hailOfBlades)
		{
			_enabled = enabled;
			Gate = new CrestGate("reaper", RuneCrestIds.Reaper, enabled);
			PressTheAttack = pressTheAttack ?? throw new ArgumentNullException("pressTheAttack");
			HailOfBlades = hailOfBlades ?? throw new ArgumentNullException("hailOfBlades");
			Runes = new IRuneEffect[2] { PressTheAttack, HailOfBlades };
			RuneKeys = new string[2] { PressTheAttack.Key, HailOfBlades.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				PressTheAttack.Start(currentCrestId);
				HailOfBlades.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				PressTheAttack.Tick(deltaSeconds);
				HailOfBlades.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			PressTheAttack.Dispose();
			HailOfBlades.Dispose();
		}
	}
	public sealed class ShamanCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "shaman";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public ArcaneCometRune ArcaneComet { get; }

		public PhaseRushRune PhaseRush { get; }

		public ShamanCrest(bool enabled, ArcaneCometRune arcaneComet, PhaseRushRune phaseRush)
		{
			_enabled = enabled;
			Gate = new CrestGate("shaman", RuneCrestIds.Shaman, enabled);
			ArcaneComet = arcaneComet ?? throw new ArgumentNullException("arcaneComet");
			PhaseRush = phaseRush ?? throw new ArgumentNullException("phaseRush");
			Runes = new IRuneEffect[2] { ArcaneComet, PhaseRush };
			RuneKeys = new string[2] { ArcaneComet.Key, PhaseRush.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				ArcaneComet.Start(currentCrestId);
				PhaseRush.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				ArcaneComet.Tick(deltaSeconds);
				PhaseRush.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			ArcaneComet.Dispose();
			PhaseRush.Dispose();
		}
	}
	public sealed class WandererCrest : ICrestRuneSet, IDisposable
	{
		private readonly bool _enabled;

		public string Key => "wanderer";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public LethalTempoRune LethalTempo { get; }

		public double FullLayerCritBonus { get; }

		public bool IsFullLayers => LethalTempo.IsFullLayers;

		public WandererCrest(bool enabled, LethalTempoRune lethalTempo, double fullLayerCritBonus)
		{
			_enabled = enabled;
			Gate = new CrestGate("wanderer", RuneCrestIds.Wanderer, enabled);
			LethalTempo = lethalTempo ?? throw new ArgumentNullException("lethalTempo");
			FullLayerCritBonus = Math.Max(0.0, fullLayerCritBonus);
			Runes = new IRuneEffect[1] { LethalTempo };
			RuneKeys = new string[1] { LethalTempo.Key };
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				LethalTempo.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				LethalTempo.Tick(deltaSeconds);
			}
		}

		public void Dispose()
		{
			LethalTempo.Dispose();
		}
	}
	public sealed class WitchCrest : ICrestRuneSet, IDisposable
	{
		public sealed class WitchBindChain : IDisposable
		{
			public const double ChainDurationSeconds = 3.0;

			public const double RefundDelaySeconds = 0.8;

			public const int RefundSilk = 5;

			public const int ChainCostSilk = 5;

			private readonly ManualLogSource _log;

			private readonly GameEventHub _events;

			private readonly IClock _clock;

			private readonly Func<string, HealSourceKind> _classify;

			private readonly Action<int> _addSilk;

			private bool _started;

			private bool _active;

			private bool _chainActive;

			private double _chainExpiresAt;

			private double? _refundAt;

			private bool _bindHealSinceBind;

			public CrestGate Gate { get; }

			public bool IsChainActive
			{
				get
				{
					if (_started && _active)
					{
						return _chainActive;
					}
					return false;
				}
			}

			public WitchBindChain(ManualLogSource log, GameEventHub events, IClock clock, Func<string, HealSourceKind> classify, Action<int> addSilk, CrestGate gate)
			{
				_log = log;
				_events = events;
				_clock = clock;
				_classify = classify;
				_addSilk = addSilk;
				Gate = gate ?? throw new ArgumentNullException("gate");
				Gate.ActiveChanged += OnGateChanged;
			}

			public void Start(string currentCrestId)
			{
				if (!_started)
				{
					_started = true;
					_events.HealResolved += OnHealResolved;
					_events.BindCompleted += OnBindCompleted;
					_events.BenchRested += OnLifecycleReset;
					_events.PlayerDied += OnLifecycleReset;
					_events.SceneChanged += OnSceneChanged;
					OnGateChanged(Gate.IsActive);
				}
			}

			public void Tick()
			{
				if (!_started)
				{
					return;
				}
				if (_chainActive && _clock.Now >= _chainExpiresAt)
				{
					_chainActive = false;
					_log.LogDebug((object)"[WitchBind] bind chain expired.");
				}
				if (_refundAt.HasValue && _clock.Now >= _refundAt.Value && !_bindHealSinceBind)
				{
					_refundAt = null;
					if (_active)
					{
						_addSilk(5);
						_log.LogDebug((object)$"[WitchBind] bind missed; refunded {5} silk.");
					}
				}
			}

			public void Dispose()
			{
				_started = false;
				_events.HealResolved -= OnHealResolved;
				_events.BindCompleted -= OnBindCompleted;
				_events.BenchRested -= OnLifecycleReset;
				_events.PlayerDied -= OnLifecycleReset;
				_events.SceneChanged -= OnSceneChanged;
				Gate.ActiveChanged -= OnGateChanged;
				Reset();
			}

			private void OnHealResolved(HealEvent e)
			{
				if (_active && _classify(e.SourceTag) == HealSourceKind.Bind)
				{
					_bindHealSinceBind = true;
					_refundAt = null;
					_chainActive = true;
					_chainExpiresAt = _clock.Now + 3.0;
					_log.LogDebug((object)"[WitchBind] bind healed; chain active, next cost reduced to 5.");
				}
			}

			private void OnBindCompleted()
			{
				if (_active)
				{
					_bindHealSinceBind = false;
					_refundAt = _clock.Now + 0.8;
				}
			}

			private void OnGateChanged(bool active)
			{
				_active = active;
				if (!active)
				{
					Reset();
				}
			}

			private void OnSceneChanged(string scene)
			{
				OnLifecycleReset();
			}

			private void OnLifecycleReset()
			{
				Reset();
			}

			private void Reset()
			{
				_chainActive = false;
				_refundAt = null;
				_bindHealSinceBind = false;
			}
		}

		private readonly bool _enabled;

		public string Key => "witch";

		public CrestGate Gate { get; }

		public IReadOnlyList<IRuneEffect> Runes { get; }

		public IReadOnlyList<string> RuneKeys { get; }

		public GraspOfTheUndyingRune Grasp { get; }

		public FleetFootworkRune Swift { get; }

		public WitchBindChain BindChain { get; }

		public bool IsGreenBloodTintActive => Gate.IsActive;

		public bool IsGraspActive => Grasp.Layers > 0;

		public WitchCrest(bool enabled, ManualLogSource log, GameEventHub events, IClock clock, Func<string, HealSourceKind> classifyHeal, Action<int> addSilk, GraspOfTheUndyingRune grasp, FleetFootworkRune fleetFootwork)
		{
			_enabled = enabled;
			Gate = new CrestGate("witch", RuneCrestIds.Witch, enabled);
			Grasp = grasp ?? throw new ArgumentNullException("grasp");
			Swift = fleetFootwork ?? throw new ArgumentNullException("fleetFootwork");
			Runes = new IRuneEffect[2] { Grasp, Swift };
			RuneKeys = new string[2] { Grasp.Key, Swift.Key };
			BindChain = new WitchBindChain(log, events, clock, classifyHeal, addSilk, Gate);
		}

		public void Start(string currentCrestId)
		{
			if (_enabled)
			{
				Grasp.Start(currentCrestId);
				Swift.Start(currentCrestId);
				BindChain.Start(currentCrestId);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_enabled)
			{
				Grasp.Tick(deltaSeconds);
				Swift.Tick(deltaSeconds);
				BindChain.Tick();
			}
		}

		public void Dispose()
		{
			Grasp.Dispose();
			Swift.Dispose();
			BindChain.Dispose();
		}
	}
}
namespace CrestsEvolve.Features.StatusIcons
{
	public enum CycleClearOn
	{
		None,
		OnAttack,
		OnSkillHit,
		OnAnyDamage
	}
	public sealed class CrestCycleDriver : IDisposable
	{
		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly StatusIconTimer _timer;

		private readonly string _crestId;

		private readonly CycleClearOn _clearOn;

		public CrestCycleDriver(ManualLogSource log, GameEventHub events, StatusIconTimer timer, string crestId, CycleClearOn clearOn)
		{
			_log = log;
			_events = events;
			_crestId = crestId;
			_clearOn = clearOn;
			_timer = timer;
		}

		public void Start()
		{
			_events.AttackResolved += OnAttack;
		}

		public void Dispose()
		{
			_events.AttackResolved -= OnAttack;
		}

		public void Tick(double deltaSeconds)
		{
			if (RuneEffects.RunesActive)
			{
				_timer.Tick(deltaSeconds);
			}
		}

		private void OnAttack(AttackEvent e)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (RuneEffects.RunesActive && !e.IsAdditionalDamage && _clearOn switch
			{
				CycleClearOn.OnAttack => true, 
				CycleClearOn.OnSkillHit => (int)e.Kind == 4, 
				CycleClearOn.OnAnyDamage => true, 
				_ => false, 
			})
			{
				_timer.Consume();
				_log.LogDebug((object)("[StatusIcons] " + _crestId + " cycle cleared."));
			}
		}
	}
	public sealed class CrestRuneIconDriver : IDisposable
	{
		private readonly GameEventHub _events;

		private readonly StatusIconLedger _ledger;

		private readonly IReadOnlyDictionary<string, IReadOnlyList<(string Key, string Owner)>> _targets;

		private readonly Func<string> _currentCrestId;

		private readonly Func<bool> _isRuneToolEquipped;

		public CrestRuneIconDriver(GameEventHub events, StatusIconLedger ledger, IReadOnlyDictionary<string, IReadOnlyList<(string Key, string Owner)>> targets, Func<string> currentCrestId, Func<bool> isRuneToolEquipped)
		{
			_events = events;
			_ledger = ledger;
			_targets = targets;
			_currentCrestId = currentCrestId;
			_isRuneToolEquipped = isRuneToolEquipped ?? throw new ArgumentNullException("isRuneToolEquipped");
		}

		public void Start(string currentCrestId)
		{
			_events.CrestChanged += OnCrestChanged;
			_events.SceneChanged += OnSceneChanged;
			_events.ToolEquipsChanged += OnToolEquipsChanged;
			Apply(currentCrestId);
		}

		public void Dispose()
		{
			_events.CrestChanged -= OnCrestChanged;
			_events.SceneChanged -= OnSceneChanged;
			_events.ToolEquipsChanged -= OnToolEquipsChanged;
		}

		private void OnCrestChanged(CrestChangedEvent e)
		{
			Apply(e.Current);
		}

		private void OnSceneChanged(string scene)
		{
			Apply(_currentCrestId());
		}

		private void OnToolEquipsChanged()
		{
			Apply(_currentCrestId());
		}

		private void Apply(string crestId)
		{
			if (!_isRuneToolEquipped())
			{
				foreach (KeyValuePair<string, IReadOnlyList<(string, string)>> target in _targets)
				{
					foreach (var item in target.Value)
					{
						if (_ledger.IsRegistered(item.Item1))
						{
							_ledger.SetVisible(item.Item1, item.Item2, false);
						}
					}
				}
				return;
			}
			foreach (KeyValuePair<string, IReadOnlyList<(string, string)>> target2 in _targets)
			{
				foreach (var item2 in target2.Value)
				{
					if (_ledger.IsRegistered(item2.Item1))
					{
						bool flag = string.Equals(target2.Key, crestId, StringComparison.OrdinalIgnoreCase);
						_ledger.SetVisible(item2.Item1, item2.Item2, flag);
					}
				}
			}
		}
	}
	public sealed class FireBladeDriver : IDisposable
	{
		public const string IconKey = "reaper.fireblade";

		public const string IconOwner = "reaper-fireblade";

		private const int MaxLayers = 3;

		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly StatusIconLedger _ledger;

		private readonly RuneGate _gate;

		private readonly ReaperFireBladeOptions _options;

		private readonly Func<double, bool> _spawnExplosion;

		private readonly Action? _applyFireVisual;

		private readonly AttackSkillWindow _window;

		private int _layers;

		private bool _started;

		private bool _active;

		public int Layers => _layers;

		public RuneGate Gate => _gate;

		public double CurrentAttackMultiplier { get; private set; } = 1.0;

		public FireBladeDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, IClock clock, ReaperFireBladeOptions options, RuneGate gate, Func<double, bool> spawnExplosion, Action? applyFireVisual = null)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			_log = log;
			_events = events;
			_ledger = ledger;
			_gate = gate ?? throw new ArgumentNullException("gate");
			_options = options;
			_spawnExplosion = spawnExplosion;
			_applyFireVisual = applyFireVisual;
			_window = new AttackSkillWindow(clock, options.WindowEnd);
			_gate.ActiveChanged += OnGateChanged;
		}

		public void Start(string currentCrestId)
		{
			if (!_started)
			{
				_started = true;
				_events.AttackStarted += OnAttackStarted;
				_events.SkillUsed += OnSkillUsed;
				_events.AttackResolved += OnAttack;
				_events.Parried += OnParried;
				_events.BenchRested += OnLifecycleReset;
				_events.PlayerDied += OnLifecycleReset;
				_events.SceneChanged += OnSceneChanged;
				Reset("start");
				OnGateChanged(_gate.IsActive);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (_started && !Active())
			{
				Reset("inactive");
			}
		}

		public void Dispose()
		{
			_started = false;
			_events.AttackStarted -= OnAttackStarted;
			_events.SkillUsed -= OnSkillUsed;
			_events.AttackResolved -= OnAttack;
			_events.Parried -= OnParried;
			_events.BenchRested -= OnLifecycleReset;
			_events.PlayerDied -= OnLifecycleReset;
			_events.SceneChanged -= OnSceneChanged;
			_gate.ActiveChanged -= OnGateChanged;
			Reset("driver disposed");
		}

		private void OnAttackStarted()
		{
			if (!Active())
			{
				return;
			}
			_window.OnAttack();
			CurrentAttackMultiplier = ((_layers > 0) ? (1.0 + 2.0 * _options.FireBuffBonus) : 1.0);
			if (_layers <= 0)
			{
				return;
			}
			try
			{
				_applyFireVisual?.Invoke();
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[FireBlade] fire visual failed: " + ex.Message));
			}
		}

		private void OnSkillUsed(SkillUseEvent e)
		{
			if (Active())
			{
				if (_window.TryConsumeIn(_options.PreciseStart, _options.PreciseEnd))
				{
					AddLayers(3);
				}
				else if (_window.TryConsumeIn(_options.WindowStart, _options.WindowEnd))
				{
					AddLayers(1);
				}
				else
				{
					_window.Clear();
				}
			}
		}

		private void OnAttack(AttackEvent e)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Invalid comparison between Unknown and I4
			if (!Active() || e.IsAdditionalDamage)
			{
				return;
			}
			if ((int)e.Kind == 0)
			{
				if (_layers > 0)
				{
					_layers--;
					SetIcon();
					_log.LogDebug((object)$"[FireBlade] normal attack consumed 1 layer ({_layers} left), no explosion.");
				}
			}
			else if (((int)e.Kind == 1 || (int)e.Kind == 3) && _layers >= 3)
			{
				SpawnExplosionForAttack(e.BaseDamage);
			}
		}

		private void OnParried()
		{
			if (Active() && _layers >= 3)
			{
				SpawnExplosion(_options.ParryExplosionDamage);
			}
		}

		private void SpawnExplosionForAttack(double baseDamage)
		{
			SpawnExplosion(baseDamage * _options.ExplosionDamageMultiplier);
		}

		private void SpawnExplosion(double damage)
		{
			bool flag = false;
			try
			{
				flag = _spawnExplosion(damage);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[FireBlade] explosion spawn threw: " + ex.Message));
			}
			_log.LogDebug((object)$"[FireBlade] explosion consumed 3 layers: damage={damage}, spawned={flag}.");
			_layers = 0;
			SetIcon();
		}

		private void AddLayers(int amount)
		{
			_layers = Math.Min(3, _layers + amount);
			SetIcon();
			_log.LogDebug((object)$"[FireBlade] fire-blade window hit: +{amount} layer(s) ({_layers}/{3}).");
		}

		private void OnGateChanged(bool active)
		{
			_active = active;
			if (!active)
			{
				Reset("gate closed");
			}
		}

		private void OnSceneChanged(string scene)
		{
			OnLifecycleReset();
		}

		private void OnLifecycleReset()
		{
			Reset("lifecycle reset");
		}

		private void Reset(string reason)
		{
			bool num = _layers != 0 || CurrentAttackMultiplier != 1.0;
			_layers = 0;
			CurrentAttackMultiplier = 1.0;
			_window.Clear();
			SetIcon();
			if (num)
			{
				_log.LogDebug((object)("[FireBlade] reset (" + reason + ")."));
			}
		}

		private void SetIcon()
		{
			_ledger.Set("reaper.fireblade", "reaper-fireblade", _layers);
		}

		private bool Active()
		{
			if (_started && _active)
			{
				return _options.Enabled;
			}
			return false;
		}
	}
	public sealed record ReaperFireBladeOptions(bool Enabled, double WindowStart, double WindowEnd, double PreciseStart, double PreciseEnd, double FireBuffBonus, double ExplosionRadius, double ExplosionDamageMultiplier, double ParryExplosionDamage, bool FireVisualEnabled);
	public static class FireBladeBinder
	{
		public static ReaperFireBladeOptions Bind(ConfigFile config, ManualLogSource log)
		{
			bool value = config.Bind<bool>("Reaper.FireBlade", "Enabled", true, "Enable the Fire Blade passive (Flintslate second form; window stacking, damage, explosions).").Value;
			double value2 = config.Bind<double>("Reaper.FireBlade", "WindowStart", 0.2, "Fire-blade press window start after a nail swing.").Value;
			double value3 = config.Bind<double>("Reaper.FireBlade", "WindowEnd", 0.3, "Fire-blade press window end after a nail swing.").Value;
			double value4 = config.Bind<double>("Reaper.FireBlade", "PreciseStart", 0.27, "Precise fire-blade window start; grants +3 layers.").Value;
			double value5 = config.Bind<double>("Reaper.FireBlade", "PreciseEnd", 0.3, "Precise fire-blade window end; grants +3 layers.").Value;
			double value6 = config.Bind<double>("Reaper.FireBlade", "FireBuffBonus", 0.25, "Vanilla fire-buff damage bonus assumed by the passive (damage x (1 + 2 x bonus), [待实测]).").Value;
			double value7 = config.Bind<double>("Reaper.FireBlade", "ExplosionRadius", 3.0, "Fire-blade explosion radius in meters (REA-006/007, [待实测]).").Value;
			double value8 = config.Bind<double>("Reaper.FireBlade", "ExplosionDamageMultiplier", 3.0, "Fire-blade explosion damage over the triggering attack's base damage (REA-006/007, [待实测]).").Value;
			double value9 = config.Bind<double>("Reaper.FireBlade", "ParryExplosionDamage", 10.0, "Fire-blade explosion damage when triggered by parry (no base attack damage, [待实测]).").Value;
			ReaperFireBladeOptions reaperFireBladeOptions = new ReaperFireBladeOptions(FireVisualEnabled: config.Bind<bool>("Reaper.FireBlade", "FireVisualEnabled", true, "Apply vanilla fire-nail visual (HeroNailImbuement.SetElement) while layers > 0.").Value, Enabled: value, WindowStart: Math.Max(0.0, value2), WindowEnd: Math.Max(value2, value3), PreciseStart: Math.Max(value2, value4), PreciseEnd: Math.Max(value4, value5), FireBuffBonus: Math.Max(0.0, value6), ExplosionRadius: Math.Max(0.1, value7), ExplosionDamageMultiplier: Math.Max(0.0, value8), ParryExplosionDamage: Math.Max(0.0, value9));
			log.LogDebug((object)$"[FireBlade] config bound: {reaperFireBladeOptions}");
			return reaperFireBladeOptions;
		}
	}
	public sealed class WitchAftershockDriver : IDisposable
	{
		public const string IconKey = "witch.aftershock";

		public const string IconOwner = "witch-aftershock";

		private const int MaxLayers = 10;

		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly StatusIconLedger _ledger;

		private readonly RuneGate _gate;

		private readonly Func<string, HealSourceKind> _classify;

		private int _layers;

		private bool _started;

		private bool _active;

		public int Layers => _layers;

		public RuneGate Gate => _gate;

		public WitchAftershockDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, Func<string, HealSourceKind> classify, RuneGate gate)
		{
			_log = log;
			_events = events;
			_ledger = ledger;
			_classify = classify;
			_gate = gate ?? throw new ArgumentNullException("gate");
			_gate.ActiveChanged += OnGateChanged;
		}

		public void Start(string currentCrestId)
		{
			if (!_started)
			{
				_started = true;
				_events.HealResolved += OnHealResolved;
				_events.PlayerDamageAfter += OnPlayerDamage;
				_events.BenchRested += OnLifecycleReset;
				_events.PlayerDied += OnLifecycleReset;
				_events.SceneChanged += OnSceneChanged;
				Apply();
				OnGateChanged(_gate.IsActive);
			}
		}

		public void Dispose()
		{
			_started = false;
			_events.HealResolved -= OnHealResolved;
			_events.PlayerDamageAfter -= OnPlayerDamage;
			_events.BenchRested -= OnLifecycleReset;
			_events.PlayerDied -= OnLifecycleReset;
			_events.SceneChanged -= OnSceneChanged;
			_gate.ActiveChanged -= OnGateChanged;
			_layers = 0;
			Apply();
		}

		private void OnHealResolved(HealEvent e)
		{
			if (_started && _active && _classify(e.SourceTag) == HealSourceKind.Bind)
			{
				int num = ((e.Applied > 0) ? e.Applied : e.Requested);
				if (num > 0)
				{
					AddLayers(num);
				}
			}
		}

		private void OnPlayerDamage(PlayerDamageEvent e)
		{
			if (_started && _active && !e.Cancelled && _layers > 0)
			{
				ConsumeLayers(2);
			}
		}

		private void OnGateChanged(bool active)
		{
			_active = active;
			if (!active)
			{
				Reset("gate closed");
			}
		}

		private void OnSceneChanged(string scene)
		{
			OnLifecycleReset();
		}

		private void OnLifecycleReset()
		{
			Reset("lifecycle reset");
		}

		private void AddLayers(int amount)
		{
			_layers = Math.Min(10, _layers + amount);
			Apply();
			_log.LogDebug((object)$"[WitchAftershock] +{amount} layer(s) ({_layers}/{10}).");
		}

		private void ConsumeLayers(int amount)
		{
			_layers = Math.Max(0, _layers - amount);
			Apply();
			_log.LogDebug((object)$"[WitchAftershock] damaged: -{amount} layer(s) ({_layers} left).");
		}

		private void Reset(string reason)
		{
			if (_layers != 0)
			{
				_layers = 0;
				Apply();
				_log.LogDebug((object)("[WitchAftershock] reset (" + reason + ")."));
			}
		}

		private void Apply()
		{
			_ledger.Set("witch.aftershock", "witch-aftershock", _layers);
			_ledger.SetVisible("witch.aftershock", "witch-aftershock", _layers > 0);
		}
	}
}
namespace CrestsEvolve.Features.Runa
{
	public sealed class AftershockRune : IRuneEffect, IDisposable
	{
		public const string IconKey = "cursed.aftershock";

		public const string IconOwner = "cursed-aftershock";

		private readonly bool _enabled;

		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly StatusIconLedger _ledger;

		private readonly AftershockOptions _options;

		private readonly Action<int> _addBlueMasks;

		private bool _started;

		private bool _active;

		private bool _charged;

		private double _elapsed;

		public string Key => "aftershock";

		public RuneGate Gate { get; }

		public IReadOnlyList<(string Key, string Owner)> Icons => new(string, string)[1] { ("cursed.aftershock", "cursed-aftershock") };

		public bool IsCharged => _charged;

		public AftershockRune(bool enabled, ManualLogSource log, GameEventHub events, StatusIconLedger ledger, IClock clock, RuneGate gate, AftershockOptions options, Action<int> addBlueMasks)
		{
			_enabled = enabled;
			_log = log;
			_events = events;
			_ledger = ledger;
			Gate = gate ?? throw new ArgumentNullException("gate");
			_options = options ?? throw new ArgumentNullException("options");
			_addBlueMasks = addBlueMasks ?? throw new ArgumentNullException("addBlueMasks");
			Gate.ActiveChanged += OnGateChanged;
		}

		public void Start(string currentCrestId)
		{
			if (!_started)
			{
				_started = true;
				_events.BindCompleted += OnBindCompleted;
				_events.PlayerDied += OnLifecycleReset;
				SetIcon();
				OnGateChanged(Gate.IsActive);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (!_started)
			{
				return;
			}
			if (!_active)
			{
				Reset("gate closed");
			}
			else if (!_charged)
			{
				_elapsed += deltaSeconds;
				if (_elapsed >= _options.CycleSeconds)
				{
					_charged = true;
					_log.LogDebug((object)"[Aftershock] charged; next bind restores masks.");
				}
				SetIcon();
			}
		}

		public void Dispose()
		{
			_started = false;
			_events.BindCompleted -= OnBindCompleted;
			_events.PlayerDied -= OnLifecycleReset;
			Gate.ActiveChanged -= OnGateChanged;
			Reset("driver disposed");
		}

		private void OnBindCompleted()
		{
			if (_started && _active && _charged)
			{
				try
				{
					_addBlueMasks(_options.BlueMasksOnBind);
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("[Aftershock] blue-mask grant failed: " + ex.Message));
				}
				Reset("bind consumed");
				_log.LogDebug((object)$"[Aftershock] bind consumed charge; +{_options.BlueMasksOnBind} masks.");
			}
		}

		private void OnGateChanged(bool active)
		{
			_active = active;
			if (!active)
			{
				Reset("gate closed");
			}
		}

		private void OnLifecycleReset()
		{
			Reset("lifecycle reset");
		}

		private void Reset(string reason)
		{
			bool num = _charged || _elapsed != 0.0;
			_charged = false;
			_elapsed = 0.0;
			SetIcon();
			if (num)
			{
				_log.LogDebug((object)("[Aftershock] reset (" + reason + ")."));
			}
		}

		private void SetIcon()
		{
			int num = (int)Math.Round(_options.CycleSeconds);
			_ledger.SetMax("cursed.aftershock", "cursed-aftershock", num);
			_ledger.SetVisible("cursed.aftershock", "cursed-aftershock", _active);
			_ledger.Set("cursed.aftershock", "cursed-aftershock", _charged ? num : Math.Min(num, (int)Math.Floor(_elapsed)));
		}
	}
	public sealed record AftershockOptions(bool Enabled, double CycleSeconds, int BlueMasksOnBind);
	public static class AftershockBinder
	{
		public static AftershockOptions Bind(ConfigFile config, ManualLogSource log)
		{
			AftershockOptions aftershockOptions = new AftershockOptions(config.Bind<bool>("Cursed.Aftershock", "Enabled", true, "Enable the Cursed Aftershock rune (10s charge; bind restores 3 blue masks).").Value, Math.Max(0.1, config.Bind<double>("Cursed.Aftershock", "CycleSeconds", 10.0, "Seconds until the rune is fully charged.").Value), Math.Max(1, config.Bind<int>("Cursed.Aftershock", "BlueMasksOnBind", 3, "Blue masks restored when binding at full charge.").Value));
			log.LogDebug((object)$"[Aftershock] config bound: {aftershockOptions}");
			return aftershockOptions;
		}
	}
	public sealed class ArcaneCometRune : IRuneEffect, IDisposable
	{
		public const string IconKey = "shaman.cycle";

		public const string IconOwner = "shaman";

		private readonly bool _enabled;

		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly StatusIconLedger _ledger;

		private readonly ArcaneCometOptions _options;

		private readonly Action _spawnSpiritFlame;

		private bool _started;

		private bool _active;

		private bool _charged;

		private double _elapsed;

		public string Key => "arcane-comet";

		public RuneGate Gate { get; }

		public IReadOnlyList<(string Key, string Owner)> Icons => new(string, string)[1] { ("shaman.cycle", "shaman") };

		public bool IsCharged => _charged;

		public ArcaneCometRune(bool enabled, ManualLogSource log, GameEventHub events, StatusIconLedger ledger, IClock clock, RuneGate gate, ArcaneCometOptions options, Action spawnSpiritFlame)
		{
			_enabled = enabled;
			_log = log;
			_events = events;
			_ledger = ledger;
			Gate = gate ?? throw new ArgumentNullException("gate");
			_options = options ?? throw new ArgumentNullException("options");
			_spawnSpiritFlame = spawnSpiritFlame ?? throw new ArgumentNullException("spawnSpiritFlame");
			Gate.ActiveChanged += OnGateChanged;
		}

		public void Start(string currentCrestId)
		{
			if (!_started)
			{
				_started = true;
				_events.EnemyDamageResolved += OnEnemyDamage;
				_events.PlayerDied += OnLifecycleReset;
				SetIcon();
				OnGateChanged(Gate.IsActive);
			}
		}

		public void Tick(float deltaSeconds)
		{
			if (!_started)
			{
				return;
			}
			if (!_active)
			{
				Reset("gate closed");
			}
			else if (!_charged)
			{
				_elapsed += deltaSeconds;
				if (_elapsed >= _options.CycleSeconds)
				{
					_charged = true;
					_log.LogDebug((object)"[ArcaneComet] charged; next skill hit summons a spirit flame.");
				}
				SetIcon();
			}
		}

		public void Dispose()
		{
			_started = false;
			_events.EnemyDamageResolved -= OnEnemyDamage;
			_events.PlayerDied -= OnLifecycleReset;
			Gate.ActiveChanged -= OnGateChanged;
			Reset("driver disposed");
		}

		private void OnEnemyDamage(AttackEvent e)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			if (_started && _active && _charged && !e.IsAdditionalDamage && e.IsHeroDamage && (int)e.Kind == 4)
			{

CrestsEvolve.RageOfTheGoner/CrestsEvolve.RageOfTheGoner.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrestsEvolve.Core.Balance;
using CrestsEvolve.Core.Combat;
using CrestsEvolve.Core.Events;
using CrestsEvolve.Core.Rage;
using CrestsEvolve.Core.State;
using CrestsEvolve.Core.UI;
using CrestsEvolve.Features;
using CrestsEvolve.Features.Rage;
using CrestsEvolve.Features.StatusIcons;
using CrestsEvolve.GameInterop;
using CrestsEvolve.Rage1;
using CrestsEvolve.Rage2;
using CrestsEvolve.RageOfTheGoner.Bootstrap;
using GlobalEnums;
using GlobalSettings;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CrestsEvolve.RageOfTheGoner")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")]
[assembly: AssemblyProduct("CrestsEvolve.RageOfTheGoner")]
[assembly: AssemblyTitle("CrestsEvolve.RageOfTheGoner")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace CrestsEvolve.Rage2
{
	public static class ArchitectRage2
	{
		public const string CrestId = "toolmaster";

		public static bool IsToolHit(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (hit.IsHeroDamage)
			{
				return hit.RepresentingTool != null;
			}
			return false;
		}

		public static void SilkPostfix(HitInstance hitInstance)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!ArchitectRageBridge.IsSuperRageActive() || !IsToolHit(hitInstance))
			{
				return;
			}
			int num = ArchitectRageBridge.ToolSilkPerHit();
			if (num > 0)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(num, false, (SilkAddSource)0);
				}
			}
		}
	}
	public static class BeastRage2
	{
		public const string CrestId = "warrior";

		public static void DamagePrefix(ref HitInstance hitInstance)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (!BeastRageBridge.IsSuperRageActive() || !hitInstance.IsHeroDamage)
			{
				return;
			}
			AttackTypes attackType = hitInstance.AttackType;
			if ((int)attackType <= 1 || (int)attackType == 6 || (int)attackType == 16)
			{
				double num = BeastRageBridge.AttackDamageMultiplier();
				if (!(num <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * num);
				}
			}
		}

		public static void AttackSpeedPostfix(ref float __result)
		{
			if (BeastRageBridge.IsSuperRageActive())
			{
				double num = BeastRageBridge.AttackSpeedBonus();
				if (!(num <= 0.0))
				{
					__result = (float)((double)__result / (1.0 + num));
				}
			}
		}
	}
	public static class CloaklessRage2
	{
		public const string CrestId = "cloakless";

		public static Func<float> NextFloat { get; set; } = () => Random.Range(0f, 1f);

		public static bool ShouldCrit(double chance, float roll)
		{
			if (chance > 0.0)
			{
				return roll <= (float)chance;
			}
			return false;
		}

		public static void CritPrefix(ref HitInstance hitInstance)
		{
			if (CloaklessRageBridge.IsSuperRageActive() && hitInstance.IsHeroDamage && !hitInstance.CriticalHit && ShouldCrit(CloaklessRageBridge.CritChance(), NextFloat()))
			{
				hitInstance.CriticalHit = true;
			}
		}
	}
	public static class CursedRage2
	{
		public const string CrestId = "cursed";

		public static void NoCostPostfix(PlayerData __instance, ref int __result)
		{
			if (CursedRageBridge.IsSuperRageActive())
			{
				__result = 0;
			}
		}
	}
	public static class HunterRage2
	{
		public const string CrestId = "hunter";

		public static int ExtraSilk(int layers, int threshold, int silkPerHit)
		{
			if (layers <= threshold)
			{
				return 0;
			}
			return Math.Max(0, silkPerHit);
		}

		public static void SilkPostfix(HitInstance hitInstance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!HunterRageBridge.IsSuperRageActive() || !hitInstance.IsHeroDamage)
			{
				return;
			}
			int num = ExtraSilk(HunterRageBridge.ComboLayerCount(), HunterRageBridge.FocusThresholdSuperRage(), HunterRageBridge.SilkPerHit());
			if (num > 0)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(num, false, (SilkAddSource)0);
				}
			}
		}
	}
	public static class ReaperRage2
	{
		public const string CrestId = "reaper";

		public static int SilkPartsAmount(int amount, int multiplier)
		{
			return Math.Max(0, amount * multiplier);
		}

		public static void SilkPartsPrefix(HeroController __instance, ref int amount)
		{
			if (ReaperRageBridge.IsSuperRageActive())
			{
				amount = SilkPartsAmount(amount, ReaperRageBridge.SilkOrbPartsMultiplier());
			}
		}
	}
	public static class ShamanRage2
	{
		public const string CrestId = "spell";

		public static int ApplyCostReduction(int cost, int reduction)
		{
			return Math.Max(0, cost - reduction);
		}

		public static void SilkCostPostfix(PlayerData __instance, ref int __result)
		{
			if (ShamanRageBridge.IsSuperRageActive())
			{
				__result = ApplyCostReduction(__result, ShamanRageBridge.SkillCostReduction());
			}
		}
	}
	public static class WandererRage2
	{
		public const string CrestId = "wanderer";

		public static void CritMultiplierPostfix(ref float __result)
		{
			if (WandererRageBridge.IsSuperRageActive())
			{
				__result *= (float)WandererRageBridge.CritDamageMultiplier();
			}
		}

		public static void KnockbackMultiplierPostfix(ref float __result)
		{
			if (WandererRageBridge.IsSuperRageActive())
			{
				__result *= (float)WandererRageBridge.KnockbackMultiplier();
			}
		}
	}
	public static class WitchRage2
	{
		public const string CrestId = "witch";

		public static void DamagePrefix(ref HitInstance hitInstance)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (WitchRageBridge.IsSuperRageActive() && hitInstance.IsHeroDamage)
			{
				double num = 1.0;
				if (((hitInstance.Source != null) ? ((Object)hitInstance.Source).name : string.Empty).IndexOf("Bind", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					num = WitchRageBridge.BindDamageMultiplier();
				}
				else if (WitchRage1.IsMultiHitAttack(hitInstance))
				{
					num = WitchRageBridge.SuperRageMultiHitDamageMultiplier();
				}
				if (!(num <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * num);
				}
			}
		}
	}
	public sealed class WitchRage2BindRangeScaler : MonoBehaviour
	{
		private readonly Dictionary<Transform, Vector3> _originals = new Dictionary<Transform, Vector3>();

		private Transform? _witchBind;

		private bool _captured;

		private float _appliedMultiplier;

		private void LateUpdate()
		{
			if (!WitchRageBridge.IsSuperRageActive() || !WitchRageBridge.ScaleBindRange())
			{
				if (_captured)
				{
					RestoreAll();
				}
				return;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)_witchBind == (Object)null)
			{
				_captured = false;
				_originals.Clear();
				_witchBind = FindWitchBind(instance);
				if ((Object)(object)_witchBind == (Object)null)
				{
					return;
				}
			}
			float num = (float)WitchRageBridge.BindRangeMultiplier();
			if (num <= 0f)
			{
				return;
			}
			if (!_captured)
			{
				CaptureAndApply(num);
				_captured = true;
				_appliedMultiplier = num;
				return;
			}
			CaptureAndApply(num);
			if (!Mathf.Approximately(_appliedMultiplier, num))
			{
				ApplyMultiplier(num);
				_appliedMultiplier = num;
			}
		}

		private void CaptureAndApply(float multiplier)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_witchBind == (Object)null)
			{
				return;
			}
			foreach (Transform item in _witchBind)
			{
				Transform val = item;
				if (!((Object)(object)val == (Object)null))
				{
					string name = ((Object)val).name;
					if ((name.IndexOf("Damager", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Tendril", StringComparison.OrdinalIgnoreCase) >= 0) && !_originals.ContainsKey(val))
					{
						Vector3 localScale = val.localScale;
						_originals.Add(val, localScale);
						val.localScale = new Vector3(localScale.x * multiplier, localScale.y * multiplier, localScale.z * multiplier);
					}
				}
			}
		}

		private void ApplyMultiplier(float multiplier)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Transform, Vector3> original in _originals)
			{
				if (!((Object)(object)original.Key == (Object)null))
				{
					original.Key.localScale = new Vector3(original.Value.x * multiplier, original.Value.y * multiplier, original.Value.z * multiplier);
				}
			}
		}

		private static Transform? FindWitchBind(HeroController hero)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if ((Object)(object)hero != (Object)null)
			{
				foreach (Transform item in ((Component)hero).transform)
				{
					Transform val = item;
					if (string.Equals(((Object)val).name, "Witch Bind", StringComparison.OrdinalIgnoreCase))
					{
						return val;
					}
				}
			}
			GameObject val2 = GameObject.Find("Witch Bind");
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return val2.transform;
		}

		private void RestoreAll()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Transform, Vector3> original in _originals)
			{
				if (!((Object)(object)original.Key == (Object)null))
				{
					original.Key.localScale = original.Value;
				}
			}
			_originals.Clear();
			_captured = false;
			_appliedMultiplier = 0f;
		}

		private void OnDestroy()
		{
			if (_captured)
			{
				RestoreAll();
			}
		}
	}
}
namespace CrestsEvolve.Rage1
{
	public static class ArchitectRage1
	{
		public const string CrestId = "toolmaster";

		public static bool IsToolHit(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (hit.IsHeroDamage)
			{
				return hit.RepresentingTool != null;
			}
			return false;
		}

		public static int ScaleDamage(int damage, double multiplier)
		{
			return (int)Math.Round((double)damage * multiplier);
		}

		public static void DamagePrefix(ref HitInstance hitInstance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ArchitectRageBridge.IsActive() && IsToolHit(hitInstance))
			{
				double num = ArchitectRageBridge.ToolDamageMultiplier();
				if (!(num <= 1.0))
				{
					hitInstance.DamageDealt = ScaleDamage(hitInstance.DamageDealt, num);
				}
			}
		}
	}
	public static class BeastRage1
	{
		public const string CrestId = "warrior";

		public static void RangePostfix(NailAttackBase __instance)
		{
			//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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (BeastRageBridge.IsActive())
			{
				float num = (float)BeastRageBridge.AttackRangeMultiplier();
				if (!(num <= 0f))
				{
					Vector3 localScale = ((Component)__instance).transform.localScale;
					((Component)__instance).transform.localScale = new Vector3(localScale.x * num, localScale.y, localScale.z);
				}
			}
		}
	}
	public static class CloaklessRage1
	{
		public const string CrestId = "cloakless";

		private static ManualLogSource? _log;

		private static FieldInfo? _luckyDiceShieldedHits;

		private static bool _warned;

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_luckyDiceShieldedHits = AccessTools.Field(typeof(HeroController), "luckyDiceShieldedHits");
			if (_luckyDiceShieldedHits == null)
			{
				log.LogWarning((object)"[CloaklessRage] luckyDiceShieldedHits field not found; block disabled.");
			}
		}

		public static int BlockThreshold(int current, bool active, int blockChancePercent)
		{
			if (!active)
			{
				return current;
			}
			return blockChancePercent;
		}

		public static void LuckyDiceThresholdPostfix(int hits, ref int __result)
		{
			if (CloaklessRageBridge.IsActive())
			{
				__result = BlockThreshold(__result, active: true, CloaklessRageBridge.BlockChancePercent());
			}
		}

		public static void TakeDamagePrefix(HeroController __instance, HazardType hazardType)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if (!CloaklessRageBridge.IsActive() || (int)hazardType != 1 || (Object)(object)__instance == (Object)null || _luckyDiceShieldedHits == null)
			{
				return;
			}
			try
			{
				if ((int)(_luckyDiceShieldedHits.GetValue(__instance) ?? ((object)0)) < 1)
				{
					_luckyDiceShieldedHits.SetValue(__instance, 1);
				}
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogWarning((object)("[CloaklessRage] luckyDiceShieldedHits write failed: " + ex.Message));
					}
				}
			}
		}
	}
	public static class CursedRage1
	{
		public const string CrestId = "cursed";

		private static readonly string[] SkillSourceKeywords = new string[4] { "Wave", "Rune", "Charge Slash", "Bind" };

		public static bool IsSkillSourceName(string sourceName)
		{
			if (string.IsNullOrEmpty(sourceName))
			{
				return false;
			}
			string[] skillSourceKeywords = SkillSourceKeywords;
			foreach (string value in skillSourceKeywords)
			{
				if (sourceName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsSkillHit(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!hit.IsHeroDamage)
			{
				return false;
			}
			if ((int)hit.AttackType == 2 || (int)hit.AttackType == 16)
			{
				return true;
			}
			return IsSkillSourceName((hit.Source != null) ? ((Object)hit.Source).name : string.Empty);
		}

		public static int ScaleDamage(int damage, double multiplier)
		{
			return (int)Math.Round((double)damage * multiplier);
		}

		public static void SkillDamagePrefix(ref HitInstance hitInstance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (CursedRageBridge.IsActive() && IsSkillHit(hitInstance))
			{
				double num = CursedRageBridge.SkillDamageMultiplier();
				if (!(num <= 1.0))
				{
					hitInstance.DamageDealt = ScaleDamage(hitInstance.DamageDealt, num);
				}
			}
		}
	}
	public static class HunterRage1
	{
		public const string CrestId = "hunter";

		public static int ExtraSilk(int layers, int threshold, int silkPerHit)
		{
			if (layers <= threshold)
			{
				return 0;
			}
			return Math.Max(0, silkPerHit);
		}

		public static void SilkPostfix(HitInstance hitInstance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!HunterRageBridge.IsActive() || !hitInstance.IsHeroDamage)
			{
				return;
			}
			int num = ExtraSilk(HunterRageBridge.ComboLayerCount(), HunterRageBridge.FocusThresholdRage(), HunterRageBridge.SilkPerHit());
			if (num > 0)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(num, false, (SilkAddSource)0);
				}
			}
		}
	}
	public static class ReaperRage1
	{
		public const string CrestId = "reaper";

		public static void CritExplosionPostfix(HealthManager __instance, HitInstance hitInstance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (ReaperRageBridge.IsActive() && hitInstance.IsHeroDamage && hitInstance.CriticalHit && (int)hitInstance.AttackType != 11 && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).transform == (Object)null))
			{
				ReaperRageBridge.SpawnExplosionAt(((Component)__instance).transform.position);
			}
		}

		public static void BindCritPostfix(HeroController __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (ReaperRageBridge.IsActive() && !((Object)(object)__instance == (Object)null))
			{
				WandererCrestStateInfo wandererState = __instance.WandererState;
				if (!wandererState.QueuedNextHitCritical)
				{
					wandererState.QueuedNextHitCritical = true;
					__instance.WandererState = wandererState;
				}
			}
		}
	}
	public static class ShamanRage1
	{
		public const string CrestId = "spell";

		public static bool IsWaveHit(string? sourceName)
		{
			if (string.IsNullOrEmpty(sourceName))
			{
				return false;
			}
			if (sourceName.IndexOf("Wave", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return sourceName.IndexOf("Rune", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		public static void WaveSilkPrefix(ref HitInstance hitInstance)
		{
			if (!ShamanRageBridge.IsActive() || !hitInstance.IsHeroDamage || !IsWaveHit((hitInstance.Source != null) ? ((Object)hitInstance.Source).name : string.Empty))
			{
				return;
			}
			int num = ShamanRageBridge.WaveSilkPerHit();
			if (num > 0)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(num, false, (SilkAddSource)0);
				}
			}
		}
	}
	public static class WandererRage1
	{
		public const string CrestId = "wanderer";

		public static void DamagePrefix(ref HitInstance hitInstance)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (!WandererRageBridge.IsActive() || !hitInstance.IsHeroDamage)
			{
				return;
			}
			AttackTypes attackType = hitInstance.AttackType;
			if ((int)attackType <= 1 || (int)attackType == 6 || (int)attackType == 16)
			{
				double num = WandererRageBridge.DamageMultiplier();
				if (!(num <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * num);
				}
			}
		}
	}
	public static class WitchRage1
	{
		public const string CrestId = "witch";

		private static bool _dashInProgress;

		public static bool IsMultiHitSourceName(string? sourceName)
		{
			if (string.IsNullOrEmpty(sourceName))
			{
				return false;
			}
			if (sourceName.IndexOf("Charge Slash", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (sourceName.IndexOf("Down", StringComparison.OrdinalIgnoreCase) >= 0 && (sourceName.IndexOf("Slash", StringComparison.OrdinalIgnoreCase) >= 0 || sourceName.IndexOf("Spike", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				return true;
			}
			return false;
		}

		public static bool IsMultiHitAttack(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!hit.IsHeroDamage)
			{
				return false;
			}
			if (_dashInProgress)
			{
				return true;
			}
			if ((int)hit.AttackType == 16)
			{
				return true;
			}
			return IsMultiHitSourceName((hit.Source != null) ? ((Object)hit.Source).name : string.Empty);
		}

		public static void DashPostfix(HeroController __instance)
		{
			_dashInProgress = (Object)(object)__instance != (Object)null && __instance.cState != null && __instance.cState.dashing;
		}

		public static void SilkPrefix(ref HitInstance hitInstance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!WitchRageBridge.IsActive() || !IsMultiHitAttack(hitInstance))
			{
				return;
			}
			int num = WitchRageBridge.MultiHitSilkPerHit();
			if (num > 0)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(num, false, (SilkAddSource)0);
				}
			}
		}
	}
}
namespace CrestsEvolve.GameInterop
{
	public static class ArchitectRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> ToolDamageMultiplier { get; set; } = () => 1.75;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<int> ToolSilkPerHit { get; set; } = () => 0;
	}
	public static class BeastRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<double> AttackRangeMultiplier { get; set; } = () => 1.25;

		public static Func<double> AttackDamageMultiplier { get; set; } = () => 1.25;

		public static Func<double> AttackSpeedBonus { get; set; } = () => 0.18;

		public static Func<bool> IsHealBlocked { get; set; } = () => false;

		public static Action<bool> SetHealBlocked { get; set; } = delegate
		{
		};

		public static Action SetRageActive { get; set; } = delegate
		{
		};
	}
	public static class CloaklessRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<int> BlockChancePercent { get; set; } = () => 80;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<double> CritChance { get; set; } = () => 0.8;
	}
	public static class CursedRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> SkillDamageMultiplier { get; set; } = () => 1.75;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;
	}
	public static class HunterRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<int> ComboLayerCount { get; set; } = () => 0;

		public static Func<int> SilkPerHit { get; set; } = () => 1;

		public static Func<int> FocusThresholdRage { get; set; } = () => 6;

		public static Func<int> FocusThresholdSuperRage { get; set; } = () => 12;
	}
	public static class RageToolBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;
	}
	public static class ReaperRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<int> SilkOrbPartsMultiplier { get; set; } = () => 3;

		public static Func<Vector3, bool> SpawnExplosionAt { get; set; } = (Vector3 _) => false;
	}
	public static class ReaperSuperRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> ExplosionDamageMultiplier { get; set; } = () => 1.0;

		public static Func<float> ExplosionRadius { get; set; } = () => 3f;

		public static Func<double, float, Vector3, bool> SpawnExplosionAt { get; set; } = (double _, float _, Vector3 _) => false;
	}
	public static class ShamanRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> CritChance { get; set; } = () => 0.1;

		public static Func<int> WaveSilkPerHit { get; set; } = () => 1;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<int> SkillCostReduction { get; set; } = () => 1;
	}
	public static class WandererRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> DamageMultiplier { get; set; } = () => 1.0;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<double> CritDamageMultiplier { get; set; } = () => 2.0;

		public static Func<double> KnockbackMultiplier { get; set; } = () => 2.0;
	}
	public static class WandererSuperRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<int> BonusCount { get; set; } = () => 0;

		public static Func<double> CritPerBonus { get; set; } = () => 0.02;
	}
	public static class WitchRageBridge
	{
		public static Func<bool> IsActive { get; set; } = () => false;

		public static Func<double> DashDamageMultiplier { get; set; } = () => 1.0;

		public static Func<int> DashSilkPerHit { get; set; } = () => 0;

		public static Func<double> SawbladeCritChance { get; set; } = () => 0.0;

		public static Func<string> SawbladeToolId { get; set; } = () => "Brolly Spike";

		public static Func<double> BindDamageMultiplier { get; set; } = () => 1.5;

		public static Func<double> BindRangeMultiplier { get; set; } = () => 1.5;

		public static Func<bool> ScaleBindRange { get; set; } = () => true;

		public static Func<bool> IsSuperRageActive { get; set; } = () => false;

		public static Func<int> MultiHitSilkPerHit { get; set; } = () => 1;

		public static Func<double> SuperRageMultiHitDamageMultiplier { get; set; } = () => 2.0;
	}
}
namespace CrestsEvolve.Features.StatusIcons
{
	public sealed class RageStatusDriver : IDisposable
	{
		public sealed record RageIconState(bool Visible, int Value, string? ColorHex);

		public const string IconKey = "rage.fury";

		public const string IconOwner = "rage";

		private readonly RageFeature _rage;

		private readonly StatusIconLedger _ledger;

		private readonly GameEventHub _events;

		private readonly Func<bool> _isRageToolEquipped;

		private bool _started;

		public RageStatusDriver(RageFeature rage, StatusIconLedger ledger, GameEventHub events, Func<bool>? isRageToolEquipped = null)
		{
			_rage = rage ?? throw new ArgumentNullException("rage");
			_ledger = ledger ?? throw new ArgumentNullException("ledger");
			_events = events ?? throw new ArgumentNullException("events");
			_isRageToolEquipped = isRageToolEquipped ?? ((Func<bool>)(() => true));
		}

		public static RageIconState Resolve(bool toolEquipped, RageMode mode)
		{
			//IL_000c: 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_001e: Invalid comparison between Unknown and I4
			if (!toolEquipped)
			{
				return new RageIconState(Visible: false, 0, null);
			}
			if ((int)mode == 0)
			{
				return new RageIconState(Visible: true, 0, "#FFFFFF");
			}
			if ((int)mode == 2)
			{
				return new RageIconState(Visible: true, 1, null);
			}
			return new RageIconState(Visible: true, 0, null);
		}

		public void Start()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!_started)
			{
				_started = true;
				_rage.Changed += OnChanged;
				_events.ToolEquipsChanged += OnToolEquipsChanged;
				Refresh(_rage.Snapshot.Mode, _isRageToolEquipped());
			}
		}

		public void RefreshEquipped()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (_started)
			{
				Refresh(_rage.Snapshot.Mode, _isRageToolEquipped());
			}
		}

		public void Dispose()
		{
			if (_started)
			{
				_started = false;
				_rage.Changed -= OnChanged;
				_events.ToolEquipsChanged -= OnToolEquipsChanged;
				_ledger.Set("rage.fury", "rage", 0);
				_ledger.SetVisible("rage.fury", "rage", false);
				_ledger.SetColorOverride("rage.fury", "rage", (string)null);
			}
		}

		private void OnChanged(RageSnapshot snapshot)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Refresh(snapshot.Mode, _isRageToolEquipped());
		}

		private void OnToolEquipsChanged()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (_started)
			{
				Refresh(_rage.Snapshot.Mode, _isRageToolEquipped());
			}
		}

		private void Refresh(RageMode mode, bool toolEquipped)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			RageIconState rageIconState = Resolve(toolEquipped, mode);
			_ledger.SetVisible("rage.fury", "rage", rageIconState.Visible);
			_ledger.Set("rage.fury", "rage", rageIconState.Value);
			_ledger.SetColorOverride("rage.fury", "rage", rageIconState.ColorHex);
		}
	}
}
namespace CrestsEvolve.Features.Rage
{
	public sealed class ArchitectRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "toolmaster";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public ArchitectRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class BeastRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "warrior";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public BeastRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class CloaklessRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "cloakless";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public CloaklessRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class CursedRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "cursed";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public CursedRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public static class FuryWhiteSlotPolicy
	{
		public static bool ShouldProjectMaxHealth(bool rageEnabled, bool isFuryInWhiteSlot)
		{
			return rageEnabled && isFuryInWhiteSlot;
		}
	}
	public sealed class FuryWhiteSlotDriver : IDisposable
	{
		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly IGameApi _game;

		private readonly Func<bool> _isFuryInWhiteSlot;

		private readonly Func<bool> _isRageEnabled;

		private bool _projectedByWhiteSlot;

		private bool _started;

		public FuryWhiteSlotDriver(ManualLogSource log, GameEventHub events, IGameApi game, Func<bool> isFuryInWhiteSlot, Func<bool> isRageEnabled)
		{
			_log = log ?? throw new ArgumentNullException("log");
			_events = events ?? throw new ArgumentNullException("events");
			_game = game ?? throw new ArgumentNullException("game");
			_isFuryInWhiteSlot = isFuryInWhiteSlot ?? throw new ArgumentNullException("isFuryInWhiteSlot");
			_isRageEnabled = isRageEnabled ?? throw new ArgumentNullException("isRageEnabled");
		}

		public void Start()
		{
			if (!_started)
			{
				_started = true;
				_events.ToolEquipsChanged += OnChanged;
				_events.SceneChanged += OnSceneChanged;
				_events.CrestChanged += OnCrestChanged;
				Refresh();
			}
		}

		public void Dispose()
		{
			if (_started)
			{
				_started = false;
				_events.ToolEquipsChanged -= OnChanged;
				_events.SceneChanged -= OnSceneChanged;
				_events.CrestChanged -= OnCrestChanged;
				if (_projectedByWhiteSlot)
				{
					_game.SetTemporaryMaxHealth((int?)null);
					_projectedByWhiteSlot = false;
				}
			}
		}

		private void OnCrestChanged(CrestChangedEvent e)
		{
			Refresh();
		}

		private void OnSceneChanged(string scene)
		{
			Refresh();
		}

		private void OnChanged()
		{
			Refresh();
		}

		private void Refresh()
		{
			bool flag;
			try
			{
				flag = FuryWhiteSlotPolicy.ShouldProjectMaxHealth(_isRageEnabled(), _isFuryInWhiteSlot());
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[FuryWhiteSlot] gate query failed: " + ex.Message));
				return;
			}
			if (flag)
			{
				_game.SetTemporaryMaxHealth((int?)1);
				_projectedByWhiteSlot = true;
			}
			else if (_projectedByWhiteSlot)
			{
				_game.SetTemporaryMaxHealth((int?)null);
				_projectedByWhiteSlot = false;
			}
		}
	}
	public sealed class HunterRageBehavior : IRageBehavior
	{
		private readonly HunterBalanceOptions _balance;

		private readonly Func<bool> _gateActive;

		public string CrestId => "hunter";

		public double SuperRageDurationSeconds => _balance.SuperRageDurationSeconds;

		public int AttacksPerBonus => _balance.SuperRageHitsPerBonus;

		public HunterRageBehavior(HunterBalanceOptions balance, Func<bool>? gateActive = null)
		{
			_balance = balance ?? throw new ArgumentNullException("balance");
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.RefreshSuperRage;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed record RageToolOptions(string ToolName);
	public static class RageBinder
	{
		public static RageToolOptions BindTool(ConfigFile config)
		{
			return new RageToolOptions(config.Bind<string>("Rage", "ToolName", "Fury of the Fallen", "White tool that gates all rage effects (normal rage + super rage / rage plus).").Value);
		}
	}
	public sealed class RageFeature : IDisposable
	{
		private readonly ManualLogSource _log;

		private readonly GameEventHub _events;

		private readonly IGameApi _game;

		private readonly RageBehaviorRegistry _behaviors;

		private readonly RageBalanceOptions _options;

		private readonly Func<bool> _isRageToolEquipped;

		private readonly Func<HealEvent, bool> _healInterceptor;

		private RageStateMachine _machine;

		private RageSnapshot _lastSnapshot;

		private bool _started;

		private readonly bool _enabled;

		private int _lastMaxHealth = -1;

		private RageMode _lastMode;

		private bool _rageToolGateActive = true;

		public RageMode CurrentMode => _machine.Current;

		public RageSnapshot Snapshot => _machine.Snapshot;

		public event Action<RageSnapshot>? Changed;

		public RageFeature(ManualLogSource log, GameEventHub events, IGameApi game, RageBehaviorRegistry behaviors, RageBalanceOptions options, Func<bool>? isRageToolEquipped = null)
		{
			_log = log ?? throw new ArgumentNullException("log");
			_events = events ?? throw new ArgumentNullException("events");
			_game = game ?? throw new ArgumentNullException("game");
			_behaviors = behaviors ?? throw new ArgumentNullException("behaviors");
			_options = options ?? throw new ArgumentNullException("options");
			_enabled = options.Enabled;
			_isRageToolEquipped = isRageToolEquipped ?? ((Func<bool>)(() => true));
			_healInterceptor = OnHealIntercept;
			IRageBehavior behavior = behaviors.Get(game.CurrentCrestId) ?? new DefaultRageBehavior(options);
			_machine = new RageStateMachine(behavior, OnModeChanged);
			_lastSnapshot = _machine.Snapshot;
		}

		public void Start()
		{
			if (!_started)
			{
				if (!_enabled)
				{
					_log.LogInfo((object)"[Rage] disabled by configuration (Rage.Enabled=false).");
					return;
				}
				_started = true;
				_events.CrestChanged += OnCrestChanged;
				_events.PlayerDamageAfter += OnPlayerDamaged;
				_events.HealthChanged += OnHealthChanged;
				_events.EnemyDamageResolved += OnEnemyDamageResolved;
				_events.BenchRested += OnBenchRested;
				_events.PlayerDied += OnPlayerDied;
				_events.SceneChanged += OnSceneChanged;
				_events.ToolEquipsChanged += OnToolEquipsChanged;
				_events.HealInterceptor = _healInterceptor;
				_rageToolGateActive = SafeRageToolEquipped();
				Refresh();
			}
		}

		public void Tick(double deltaSeconds)
		{
			if (_enabled)
			{
				Refresh(deltaSeconds);
			}
		}

		public void Dispose()
		{
			if (_started)
			{
				_started = false;
				_events.CrestChanged -= OnCrestChanged;
				_events.PlayerDamageAfter -= OnPlayerDamaged;
				_events.HealthChanged -= OnHealthChanged;
				_events.EnemyDamageResolved -= OnEnemyDamageResolved;
				_events.BenchRested -= OnBenchRested;
				_events.PlayerDied -= OnPlayerDied;
				_events.SceneChanged -= OnSceneChanged;
				_events.ToolEquipsChanged -= OnToolEquipsChanged;
				if ((object)_events.HealInterceptor == _healInterceptor)
				{
					_events.HealInterceptor = null;
				}
				_machine.Reset((ResetReason)3);
				PublishIfChanged();
			}
		}

		private bool OnHealIntercept(HealEvent heal)
		{
			RageContext context = BuildContext();
			RageHealDecision rageHealDecision = _machine.HandleHealRequest(context, new RageHealRequest(heal.Requested, heal.SourceTag));
			switch (rageHealDecision)
			{
			case RageHealDecision.RefreshSuperRage:
				_log.LogDebug((object)$"[Rage] heal consumed to refresh super rage duration (amount={heal.Requested}).");
				break;
			case RageHealDecision.ExitSuperRage:
				_log.LogDebug((object)$"[Rage] heal consumed to exit super rage (amount={heal.Requested}).");
				break;
			}
			Refresh();
			return rageHealDecision != RageHealDecision.Allow;
		}

		private void OnCrestChanged(CrestChangedEvent e)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if ((int)_machine.Current == 2)
			{
				Refresh();
				return;
			}
			IRageBehavior rageBehavior = _behaviors.Get(e.Current) ?? new DefaultRageBehavior(_options);
			if (!string.Equals(rageBehavior.CrestId, _machine.BehaviorCrestId, StringComparison.OrdinalIgnoreCase))
			{
				_machine.Reset((ResetReason)0);
				_machine = new RageStateMachine(rageBehavior, OnModeChanged);
				_log.LogInfo((object)("[Rage] behavior switched to '" + rageBehavior.CrestId + "' for crest '" + e.Current + "'."));
			}
			Refresh();
		}

		private void OnPlayerDamaged(PlayerDamageEvent e)
		{
			if (!e.Cancelled)
			{
				_machine.HandlePlayerDamaged(BuildContext(), new RageDamageEvent(e.MaskDamage, e.SourceTag));
				Refresh();
			}
		}

		private void OnHealthChanged(HealthChangedEvent e)
		{
			Refresh();
		}

		private void OnEnemyDamageResolved(AttackEvent e)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			if (e.IsHeroDamage && !e.IsAdditionalDamage && (int)_machine.Current == 2)
			{
				_machine.OnAttackResolved(BuildContext());
				Refresh();
			}
		}

		private void OnBenchRested()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if ((int)_machine.Current != 2)
			{
				Reset((ResetReason)1);
			}
		}

		private void OnPlayerDied()
		{
			Reset((ResetReason)3);
		}

		private void OnSceneChanged(string scene)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if ((int)_machine.Current != 2)
			{
				Reset((ResetReason)5);
			}
		}

		private void OnToolEquipsChanged()
		{
			_rageToolGateActive = SafeRageToolEquipped();
			if (_rageToolGateActive)
			{
				Refresh();
			}
			else
			{
				Reset((ResetReason)8);
			}
		}

		private bool SafeRageToolEquipped()
		{
			try
			{
				return _isRageToolEquipped();
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[Rage] rage-tool gate query failed: " + ex.Message));
				return false;
			}
		}

		private void Reset(ResetReason reason)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			_machine.Reset(reason);
			Refresh();
		}

		private void Refresh(double deltaSeconds = 0.0)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			RageContext rageContext = BuildContext();
			RageMode current = _machine.Current;
			_machine.Update(rageContext, deltaSeconds);
			_lastMaxHealth = rageContext.MaxHealth;
			for (int i = 0; i < 3; i++)
			{
				if (_machine.Current == current)
				{
					break;
				}
				current = _machine.Current;
				_machine.Update(rageContext, 0.0);
			}
			PublishIfChanged();
		}

		private RageContext BuildContext()
		{
			int num = Math.Max(1, _game.MaxHealth);
			bool maxHealthChanged = num != _lastMaxHealth;
			return new RageContext(_game.CurrentHealth, num, 0, IsEnhancing: false, maxHealthChanged, _rageToolGateActive);
		}

		private void OnModeChanged(RageMode mode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)mode == 2 && (int)_lastMode != 2)
			{
				_game.ClearBlueHealth("rage.super-rage");
			}
			_lastMode = mode;
			_log.LogInfo((object)$"[Rage] mode changed: {mode} (crest={_machine.BehaviorCrestId})");
		}

		private void PublishIfChanged()
		{
			RageSnapshot snapshot = _machine.Snapshot;
			if (!(snapshot == _lastSnapshot))
			{
				_lastSnapshot = snapshot;
				this.Changed?.Invoke(snapshot);
			}
		}
	}
	public sealed class ReaperRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "reaper";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public ReaperRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class ShamanRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "spell";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public ShamanRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class WandererRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "wanderer";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public WandererRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.RefreshSuperRage;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class WitchRageBehavior : IRageBehavior
	{
		private readonly Func<bool> _gateActive;

		public string CrestId => "witch";

		public double SuperRageDurationSeconds => 10.0;

		public int AttacksPerBonus => 6;

		public WitchRageBehavior(Func<bool>? gateActive = null)
		{
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive())
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			return RageDamageResponse.Keep;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
}
namespace CrestsEvolve.Core.Rage
{
	public sealed record RageContext(int Health, int MaxHealth, int CurrentStacks, bool IsEnhancing, bool MaxHealthChanged = false, bool RageToolGateActive = true);
	public sealed record RageSnapshot(RageMode Mode, string BehaviorCrestId, double RemainingSeconds, int AttackCount, int BonusCount, long Revision)
	{
		[CompilerGenerated]
		public void Deconstruct(out RageMode Mode, out string BehaviorCrestId, out double RemainingSeconds, out int AttackCount, out int BonusCount, out long Revision)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected I4, but got Unknown
			Mode = (RageMode)(int)this.Mode;
			BehaviorCrestId = this.BehaviorCrestId;
			RemainingSeconds = this.RemainingSeconds;
			AttackCount = this.AttackCount;
			BonusCount = this.BonusCount;
			Revision = this.Revision;
		}
	}
	public enum RageHealDecision
	{
		Allow,
		RefreshSuperRage,
		ExitSuperRage,
		Consume
	}
	public enum RageDamageResponse
	{
		Keep,
		ResetProgress,
		Exit
	}
	public sealed record RageHealRequest(int Amount, string SourceTag);
	public sealed record RageDamageEvent(int MaskDamage, string SourceTag);
	public static class RageRules
	{
		public static bool IsOneMask(RageContext context)
		{
			if (context.Health > 0)
			{
				return context.Health <= 1;
			}
			return false;
		}

		public static bool IsMaxHealthOne(RageContext context)
		{
			return context.MaxHealth <= 1;
		}

		public static bool CanAutoSuperRage(RageContext context)
		{
			if (IsOneMask(context))
			{
				return IsMaxHealthOne(context);
			}
			return false;
		}
	}
	public interface IRageBehavior
	{
		string CrestId { get; }

		double SuperRageDurationSeconds { get; }

		int AttacksPerBonus { get; }

		bool CanEnterRage(RageContext context);

		bool CanEnterSuperRage(RageContext context);

		bool ShouldExit(RageContext context);

		bool ShouldResetOn(ResetReason reason);

		RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal);

		RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage);

		void OnEnterRage(RageContext context);

		void OnEnterSuperRage(RageContext context);

		void OnExit(RageMode previous, RageContext context);

		void Tick(double deltaSeconds, RageContext context);
	}
	public sealed class DefaultRageBehavior : IRageBehavior
	{
		private readonly bool _autoSuperRageEnabled;

		private readonly bool _resetBonusOnDamage;

		private readonly double _superRageDurationSeconds;

		private readonly int _attacksPerBonus;

		private readonly Func<bool> _gateActive;

		public string CrestId => "default";

		public double SuperRageDurationSeconds => _superRageDurationSeconds;

		public int AttacksPerBonus => _attacksPerBonus;

		public DefaultRageBehavior(bool autoSuperRageEnabled = true, bool resetBonusOnDamage = false, double superRageDurationSeconds = 10.0, int attacksPerBonus = 6, Func<bool>? gateActive = null)
		{
			if (superRageDurationSeconds <= 0.0)
			{
				throw new ArgumentOutOfRangeException("superRageDurationSeconds");
			}
			if (attacksPerBonus <= 0)
			{
				throw new ArgumentOutOfRangeException("attacksPerBonus");
			}
			_autoSuperRageEnabled = autoSuperRageEnabled;
			_resetBonusOnDamage = resetBonusOnDamage;
			_superRageDurationSeconds = superRageDurationSeconds;
			_attacksPerBonus = attacksPerBonus;
			_gateActive = gateActive ?? ((Func<bool>)(() => true));
		}

		public DefaultRageBehavior(RageBalanceOptions options, Func<bool>? gateActive = null)
			: this(options.AutoSuperRageEnabled, options.ResetBonusOnDamage, options.SuperRageDurationSeconds, options.AttacksPerBonus, gateActive)
		{
		}

		public bool CanEnterRage(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return _gateActive();
			}
			return false;
		}

		public bool CanEnterSuperRage(RageContext context)
		{
			if (_gateActive() && _autoSuperRageEnabled)
			{
				return RageRules.CanAutoSuperRage(context);
			}
			return false;
		}

		public bool ShouldExit(RageContext context)
		{
			if (RageRules.IsOneMask(context))
			{
				return !_gateActive();
			}
			return true;
		}

		public bool ShouldResetOn(ResetReason reason)
		{
			return true;
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			return RageHealDecision.Allow;
		}

		public RageDamageResponse OnPlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			if (!_resetBonusOnDamage)
			{
				return RageDamageResponse.Keep;
			}
			return RageDamageResponse.ResetProgress;
		}

		public void OnEnterRage(RageContext context)
		{
		}

		public void OnEnterSuperRage(RageContext context)
		{
		}

		public void OnExit(RageMode previous, RageContext context)
		{
		}

		public void Tick(double deltaSeconds, RageContext context)
		{
		}
	}
	public sealed class RageBehaviorRegistry
	{
		private readonly Dictionary<string, IRageBehavior> _behaviors = new Dictionary<string, IRageBehavior>(StringComparer.OrdinalIgnoreCase);

		public void Register(IRageBehavior behavior)
		{
			if (behavior == null)
			{
				throw new ArgumentNullException("behavior");
			}
			if (string.IsNullOrWhiteSpace(behavior.CrestId))
			{
				throw new ArgumentException("Rage behavior CrestId must not be empty.", "behavior");
			}
			if (!_behaviors.TryAdd(behavior.CrestId, behavior))
			{
				throw new InvalidOperationException("Rage behavior already registered: " + behavior.CrestId);
			}
		}

		public IRageBehavior? Get(string crestId)
		{
			if (string.IsNullOrWhiteSpace(crestId))
			{
				return null;
			}
			if (_behaviors.TryGetValue(crestId, out IRageBehavior value))
			{
				return value;
			}
			foreach (KeyValuePair<string, IRageBehavior> behavior in _behaviors)
			{
				if (crestId.StartsWith(behavior.Key + "_", StringComparison.OrdinalIgnoreCase))
				{
					return behavior.Value;
				}
			}
			return null;
		}
	}
	public sealed class RageStateMachine
	{
		private readonly IRageBehavior _behavior;

		private readonly Action<RageMode>? _onModeChanged;

		private RageContext _lastContext = new RageContext(0, 1, 0, IsEnhancing: false);

		private double _superRageRemaining;

		private int _attackCount;

		private int _bonusCount;

		private long _revision;

		private bool _suppressAutoReentry;

		public RageMode Current { get; private set; }

		public bool IsActive => (int)Current > 0;

		public string BehaviorCrestId => _behavior.CrestId;

		public double RemainingSeconds
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				if ((int)Current != 2)
				{
					return 0.0;
				}
				return Math.Max(0.0, _superRageRemaining);
			}
		}

		public int AttackCount => _attackCount;

		public int BonusCount => _bonusCount;

		public RageSnapshot Snapshot => new RageSnapshot(Current, BehaviorCrestId, RemainingSeconds, AttackCount, BonusCount, _revision);

		public event Action<int>? BonusReached;

		public RageStateMachine(IRageBehavior behavior, Action<RageMode>? onModeChanged = null)
		{
			_behavior = behavior ?? throw new ArgumentNullException("behavior");
			_onModeChanged = onModeChanged;
		}

		public void Update(RageContext context, double deltaSeconds)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected I4, but got Unknown
			if (deltaSeconds < 0.0)
			{
				throw new ArgumentOutOfRangeException("deltaSeconds");
			}
			bool flag = context.MaxHealthChanged || context.MaxHealth != _lastContext.MaxHealth;
			if (_suppressAutoReentry && (context.Health != _lastContext.Health || flag))
			{
				_suppressAutoReentry = false;
			}
			_lastContext = context;
			RageMode current = Current;
			switch ((int)current)
			{
			case 0:
				if (context.RageToolGateActive && _behavior.CanEnterRage(context))
				{
					EnterRage(context);
				}
				break;
			case 1:
				if (!context.RageToolGateActive)
				{
					Exit(context);
				}
				else if (_behavior.ShouldExit(context))
				{
					Exit(context);
				}
				else if (flag && _behavior.CanEnterSuperRage(context) && !_suppressAutoReentry)
				{
					EnterSuperRage(context);
				}
				else
				{
					_behavior.Tick(deltaSeconds, context);
				}
				break;
			case 2:
				if (!context.RageToolGateActive)
				{
					Exit(context);
				}
				else if (!RageRules.IsMaxHealthOne(context))
				{
					Exit(context);
				}
				else
				{
					_behavior.Tick(deltaSeconds, context);
				}
				break;
			}
		}

		public void OnAttackResolved(RageContext? context = null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Current == 2)
			{
				if (context != null)
				{
					_lastContext = context;
				}
				_attackCount++;
				if (_behavior.AttacksPerBonus > 0 && _attackCount % _behavior.AttacksPerBonus == 0)
				{
					_bonusCount++;
					_revision++;
					this.BonusReached?.Invoke(_bonusCount);
				}
			}
		}

		public RageHealDecision HandleHealRequest(RageContext context, RageHealRequest heal)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			_lastContext = context;
			if ((int)Current != 2)
			{
				return RageHealDecision.Allow;
			}
			RageHealDecision rageHealDecision = _behavior.HandleHealRequest(context, heal);
			switch (rageHealDecision)
			{
			case RageHealDecision.RefreshSuperRage:
				_superRageRemaining = _behavior.SuperRageDurationSeconds;
				_revision++;
				break;
			case RageHealDecision.ExitSuperRage:
				Exit(context);
				break;
			}
			return rageHealDecision;
		}

		public void HandlePlayerDamaged(RageContext context, RageDamageEvent damage)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Current != 0)
			{
				switch (_behavior.OnPlayerDamaged(context, damage))
				{
				case RageDamageResponse.ResetProgress:
					ResetProgress();
					break;
				case RageDamageResponse.Exit:
					Exit(context);
					break;
				}
			}
		}

		public void Reset(ResetReason reason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Current != 0 && _behavior.ShouldResetOn(reason))
			{
				_suppressAutoReentry = false;
				Exit(_lastContext);
			}
		}

		public void ResetProgress()
		{
			if (_attackCount != 0 || _bonusCount != 0)
			{
				_attackCount = 0;
				_bonusCount = 0;
				_revision++;
			}
		}

		private void EnterRage(RageContext context)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Current = (RageMode)1;
			_revision++;
			_behavior.OnEnterRage(context);
			_onModeChanged?.Invoke(Current);
		}

		private void EnterSuperRage(RageContext context)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			Current = (RageMode)2;
			_superRageRemaining = _behavior.SuperRageDurationSeconds;
			_attackCount = 0;
			_bonusCount = 0;
			_suppressAutoReentry = false;
			_revision++;
			_behavior.OnEnterSuperRage(context);
			_onModeChanged?.Invoke(Current);
		}

		private void Exit(RageContext context, bool expired = false)
		{
			//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_004a: 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)
			RageMode current = Current;
			Current = (RageMode)0;
			_superRageRemaining = 0.0;
			_attackCount = 0;
			_bonusCount = 0;
			if (expired)
			{
				_suppressAutoReentry = true;
			}
			_revision++;
			_behavior.OnExit(current, context);
			_onModeChanged?.Invoke(Current);
		}
	}
}
namespace CrestsEvolve.RageOfTheGoner
{
	[BepInPlugin("local.crestsevolve.rageofthegoner", "RAGE OF THE GONER", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "local.crestsevolve.rageofthegoner";

		public const string PluginName = "RAGE OF THE GONER";

		public const string PluginVersion = "0.1.0";

		private Harmony? _harmony;

		private RageBootstrap? _bootstrap;

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("local.crestsevolve.rageofthegoner");
			_bootstrap = new RageBootstrap(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config, _harmony);
			_bootstrap.Start();
		}

		private void OnDestroy()
		{
			_bootstrap?.Dispose();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace CrestsEvolve.RageOfTheGoner.Bootstrap
{
	public sealed class RageBootstrap : IDisposable
	{
		private sealed class RageIconDriver : IStatusIconDriver, IDisposable
		{
			private readonly RageFeature _rage;

			private readonly RageStatusDriver _driver;

			public RageIconDriver(RageFeature rage)
			{
				_rage = rage;
				_driver = new RageStatusDriver(rage, FoundationServices.Current.StatusLedger, FoundationServices.Current.Events, () => RageToolBridge.IsActive());
			}

			public void Start(string currentCrestId)
			{
				_driver.Start();
			}

			public void Dispose()
			{
				_driver.Dispose();
			}

			public void RefreshEquipped()
			{
				_driver.RefreshEquipped();
			}
		}

		private sealed class RageProjectionAdapter : IRageProjection, IDisposable
		{
			private readonly RageFeature _rage;

			public RageProjectionData? Current
			{
				get
				{
					//IL_000d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0013: Invalid comparison between Unknown and I4
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					//IL_001c: Invalid comparison between Unknown and I4
					//IL_0022: Unknown result type (might be due to invalid IL or missing references)
					//IL_0028: Invalid comparison between Unknown and I4
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Expected O, but got Unknown
					RageSnapshot snapshot = _rage.Snapshot;
					return new RageProjectionData((int)snapshot.Mode == 1 || (int)snapshot.Mode == 2, (int)snapshot.Mode == 2, snapshot.RemainingSeconds, snapshot.Revision);
				}
			}

			public event Action? Changed;

			public RageProjectionAdapter(RageFeature rage)
			{
				_rage = rage;
				_rage.Changed += OnChanged;
			}

			private void OnChanged(RageSnapshot snapshot)
			{
				this.Changed?.Invoke();
			}

			public void Dispose()
			{
				_rage.Changed -= OnChanged;
			}
		}

		private readonly ManualLogSource _log;

		private readonly ConfigFile _config;

		private readonly Harmony _harmony;

		private RageFeature? _rage;

		private RageProjectionAdapter? _projection;

		private FuryWhiteSlotDriver? _furyWhiteSlot;

		private GameObject? _witchRage2Go;

		private bool _disposed;

		public RageBootstrap(ManualLogSource log, ConfigFile config, Harmony harmony)
		{
			_log = log;
			_config = config;
			_harmony = harmony;
		}

		public void Start()
		{
			//IL_0750: Unknown result type (might be due to invalid IL or missing references)
			//IL_075a: Expected O, but got Unknown
			FoundationServices services = FoundationServices.Current;
			if (services == null)
			{
				_log.LogWarning((object)"[RageOfTheGoner] foundation not loaded; rage disabled.");
				return;
			}
			FoundationServices obj = services;
			BalanceOptions obj2 = services.Balance.<Clone>$();
			obj2.set_Hunter(BalanceBinder.BindHunter(_config));
			obj2.set_Rage(BalanceBinder.BindRage(_config));
			obj.Balance = obj2;
			RageToolOptions rageToolOptions = RageBinder.BindTool(_config);
			bool rageToolWarned = false;
			RageToolBridge.IsActive = delegate
			{
				try
				{
					return WhiteToolSystem.IsEquippedAnywhere(rageToolOptions.ToolName);
				}
				catch (Exception ex)
				{
					if (!rageToolWarned)
					{
						rageToolWarned = true;
						_log.LogWarning((object)("[Rage] rage tool gate query failed: " + ex.Message));
					}
					return false;
				}
			};
			RageBehaviorRegistry rageBehaviorRegistry = new RageBehaviorRegistry();
			rageBehaviorRegistry.Register(new DefaultRageBehavior(services.Balance.Rage.AutoSuperRageEnabled, services.Balance.Rage.ResetBonusOnDamage, services.Balance.Rage.SuperRageDurationSeconds, services.Balance.Rage.AttacksPerBonus, () => RageToolBridge.IsActive()));
			rageBehaviorRegistry.Register(new HunterRageBehavior(services.Balance.Hunter, rageGate(() => true)));
			rageBehaviorRegistry.Register(new ReaperRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new WandererRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new BeastRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new WitchRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new ArchitectRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new ShamanRageBehavior(rageGate(() => true)));
			rageBehaviorRegistry.Register(new CursedRageBehavior(rageGate(() => string.Equals(services.Game.CurrentCrestId, "Cursed", StringComparison.OrdinalIgnoreCase))));
			rageBehaviorRegistry.Register(new CloaklessRageBehavior(rageGate(() => string.Equals(services.Game.CurrentCrestId, "Cloakless", StringComparison.OrdinalIgnoreCase))));
			_rage = new RageFeature(_log, services.Events, services.Game, rageBehaviorRegistry, services.Balance.Rage, () => RageToolBridge.IsActive());
			WandererRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "wanderer", StringComparison.OrdinalIgnoreCase);
			WandererRageBridge.DamageMultiplier = () => services.Balance.Rage.WandererDamageMultiplier;
			BeastRageBridge.SetRageActive = delegate
			{
				services.BeastState.SetRageStateActive(true);
			};
			BeastRageBridge.SetHealBlocked = delegate(bool blocked)
			{
				services.BeastState.SetRageHealBlocked(blocked);
			};
			WitchRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "witch", StringComparison.OrdinalIgnoreCase);
			WitchRageBridge.DashDamageMultiplier = () => services.Balance.Rage.WitchDashDamageMultiplier;
			WitchRageBridge.DashSilkPerHit = () => (_rage != null && (int)_rage.CurrentMode == 2) ? services.Balance.Rage.WitchDashSilkPerHit : 0;
			WitchRageBridge.BindDamageMultiplier = () => (_rage == null || (int)_rage.CurrentMode != 2) ? 1.5 : services.Balance.Rage.WitchSuperRageBindDamageMultiplier;
			WitchRageBridge.BindRangeMultiplier = () => (_rage == null || (int)_rage.CurrentMode != 2) ? 1.5 : services.Balance.Rage.WitchSuperRageBindRangeMultiplier;
			WitchRageBridge.SawbladeCritChance = () => services.Balance.Rage.WitchSawbladeCritChance;
			WitchRageBridge.SawbladeToolId = () => services.Balance.Rage.WitchSawbladeToolId;
			WitchRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "witch", StringComparison.OrdinalIgnoreCase);
			ArchitectRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "toolmaster", StringComparison.OrdinalIgnoreCase);
			ArchitectRageBridge.ToolDamageMultiplier = () => services.Balance.Rage.ArchitectToolDamageMultiplier;
			ArchitectRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "toolmaster", StringComparison.OrdinalIgnoreCase);
			ArchitectRageBridge.ToolSilkPerHit = () => services.Balance.Rage.ArchitectToolSilkPerHit;
			ShamanRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "spell", StringComparison.OrdinalIgnoreCase);
			ShamanRageBridge.CritChance = () => services.Balance.Rage.ShamanCritChance;
			ShamanRageBridge.WaveSilkPerHit = () => services.Balance.Rage.ShamanWaveSilkPerHit;
			ShamanRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "spell", StringComparison.OrdinalIgnoreCase);
			ShamanRageBridge.SkillCostReduction = () => services.Balance.Rage.ShamanSkillCostReduction;
			CursedRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "cursed", StringComparison.OrdinalIgnoreCase);
			CursedRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "cursed", StringComparison.OrdinalIgnoreCase);
			CursedRageBridge.SkillDamageMultiplier = () => services.Balance.Rage.CursedSkillDamageMultiplier;
			CloaklessRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "cloakless", StringComparison.OrdinalIgnoreCase);
			CloaklessRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "cloakless", StringComparison.OrdinalIgnoreCase);
			CloaklessRageBridge.BlockChancePercent = () => (int)Math.Round(services.Balance.Rage.CloaklessBlockChance * 100.0);
			CloaklessRageBridge.CritChance = () => services.Balance.Rage.CloaklessCritChance;
			HunterRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "hunter", StringComparison.OrdinalIgnoreCase);
			HunterRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "hunter", StringComparison.OrdinalIgnoreCase);
			HunterRageBridge.ComboLayerCount = () => services.HunterState.CurrentMeterHits();
			HunterRageBridge.SilkPerHit = () => services.Balance.Rage.HunterSilkPerHit;
			HunterRageBridge.FocusThresholdRage = () => services.Balance.Rage.HunterFocusThresholdRage;
			HunterRageBridge.FocusThresholdSuperRage = () => services.Balance.Rage.HunterFocusThresholdSuperRage;
			ReaperRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "reaper", StringComparison.OrdinalIgnoreCase);
			ReaperRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "reaper", StringComparison.OrdinalIgnoreCase);
			ReaperRageBridge.SilkOrbPartsMultiplier = () => services.Balance.Rage.ReaperSilkOrbPartsMultiplier;
			ReaperRageBridge.SpawnExplosionAt = (Vector3 position) => services.Game.SpawnNativeExplosionAt(position);
			BeastRageBridge.IsActive = () => _rage != null && ((int)_rage.CurrentMode == 1 || (int)_rage.CurrentMode == 2) && string.Equals(_rage.Snapshot.BehaviorCrestId, "warrior", StringComparison.OrdinalIgnoreCase);
			BeastRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "warrior", StringComparison.OrdinalIgnoreCase);
			BeastRageBridge.AttackRangeMultiplier = () => services.Balance.Rage.BeastAttackRangeMultiplier;
			BeastRageBridge.AttackDamageMultiplier = () => services.Balance.Rage.BeastAttackDamageMultiplier;
			BeastRageBridge.AttackSpeedBonus = () => services.Balance.Rage.BeastAttackSpeedBonus;
			WandererRageBridge.IsSuperRageActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "wanderer", StringComparison.OrdinalIgnoreCase);
			WandererRageBridge.CritDamageMultiplier = () => services.Balance.Rage.WandererCritDamageMultiplier;
			WandererRageBridge.KnockbackMultiplier = () => services.Balance.Rage.WandererKnockbackMultiplier;
			WitchRageBridge.MultiHitSilkPerHit = () => services.Balance.Rage.WitchMultiHitSilkPerHit;
			WitchRageBridge.SuperRageMultiHitDamageMultiplier = () => services.Balance.Rage.WitchSuperRageMultiHitDamageMultiplier;
			WandererSuperRageBridge.IsActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "wanderer", StringComparison.OrdinalIgnoreCase);
			WandererSuperRageBridge.BonusCount = () => (_rage != null) ? _rage.Snapshot.BonusCount : 0;
			WandererSuperRageBridge.CritPerBonus = () => services.Balance.Rage.WandererSuperRageCritPerBonus;
			ReaperSuperRageBridge.IsActive = () => _rage != null && (int)_rage.CurrentMode == 2 && string.Equals(_rage.Snapshot.BehaviorCrestId, "reaper", StringComparison.OrdinalIgnoreCase);
			RegisterIcons(services);
			RageIconDriver rageIconDriver = new RageIconDriver(_rage);
			services.StatusIcons.RegisterDriver((IStatusIconDriver)(object)rageIconDriver);
			services.StatusIcons.AddTick((Action<float>)delegate(float delta)
			{
				_rage.Tick(delta);
			});
			services.StatusIcons.AddTick((Action<float>)delegate
			{
				rageIconDriver.RefreshEquipped();
			});
			if (StatusIconFeature.ShouldStart(services.StatusOptions))
			{
				_rage.Start();
			}
			else
			{
				_log.LogInfo((object)"[Rage] status-icon master switch disabled; rage not started (vanilla behavior).");
			}
			_projection = new RageProjectionAdapter(_rage);
			services.Runtime.AttachRage((IRageProjection)(object)_projection);
			RegisterRageProbe();
			InstallPatches(services);
			_witchRage2Go = new GameObject("CrestsEvolveWitchRage2");
			Object.DontDestroyOnLoad((Object)(object)_witchRage2Go);
			_witchRage2Go.AddComponent<WitchRage2BindRangeScaler>();
			services.StatusIcons.Start(services.Game.CurrentCrestId);
			_furyWhiteSlot = new FuryWhiteSlotDriver(_log, services.Events, services.Game, () => WhiteToolSystem.IsEquippedInWhiteSlot(rageToolOptions.ToolName), () => services.Balance.Rage.Enabled && StatusIconFeature.ShouldStart(services.StatusOptions));
			_furyWhiteSlot.Start();
			_log.LogInfo((object)"[RageOfTheGoner] rage wired.");
			static Func<bool> rageGate(Func<bool> gate)
			{
				return () => gate() && RageToolBridge.IsActive();
			}
		}

		private void RegisterIcons(FoundationServices services)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			Dictionary<string, StatusIconEntryOptions> dictionary = new Dictionary<string, StatusIconEntryOptions>(StringComparer.Ordinal);
			string[] array = new string[3] { "rage.fury", "hunter.super-rage", "wanderer.super-rage" };
			foreach (string key in array)
			{
				IconDefault val = StatusIconDefaults.All.First((IconDefault d) => d.Key == key);
				StatusIconEntryOptions val2 = StatusIconBinder.BindIcon(_config, "UI.StatusIcons." + key, key, new StatusIconEntryOptions(true, val.Max, val.ColorHex, val.Texture ?? "placeholder", val.IconColorHex));
				dictionary[key] = val2;
				services.StatusIcons.RegisterIcon(new StatusIconDefinition(key, "rage", val2.Max));
			}
			services.StatusOptions.RegisterIconOptions((IEnumerable<KeyValuePair<string, StatusIconEntryOptions>>)dictionary);
		}

		private void RegisterRageProbe()
		{
			if (_rage != null)
			{
				_rage.Changed += delegate(RageSnapshot snapshot)
				{
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0037: Unknown result type (might be due to invalid IL or missing references)
					//IL_003d: Invalid comparison between Unknown and I4
					_log.LogInfo((object)($"[Rage][probe] snapshot mode={snapshot.Mode} bonus={snapshot.BonusCount} " + $"remaining={snapshot.RemainingSeconds:0.0} (rage.fury current={(((int)snapshot.Mode == 2) ? 1 : 0)}/1)"));
				};
			}
		}

		private void InstallPatches(FoundationServices services)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Expected O, but got Unknown
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Expected O, but got Unknown
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Expected O, but got Unknown
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Expected O, but got Unknown
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Expected O, but got Unknown
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0448: Expected O, but got Unknown
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0517: Expected O, but got Unknown
			//IL_056c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0579: Expected O, but got Unknown
			//IL_05fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0608: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(HealthManager), "Hit", new Type[1] { typeof(HitInstance) }, (Type[])null);
			if (methodInfo != null)
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ArchitectRage1), "DamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ShamanRage1), "WaveSilkPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CursedRage1), "SkillDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CloaklessRage2), "CritPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(WandererRage1), "DamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BeastRage2), "DamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(WitchRage1), "SilkPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(WitchRage2), "DamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ArchitectRage2), "SilkPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HunterRage1), "SilkPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HunterRage2), "SilkPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ReaperRage1), "CritExplosionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				_log.LogWarning((object)"[Rage] HealthManager.Hit not found; architect/shaman/cursed/cloakless hit effects disabled.");
			}
			MethodInfo methodInfo2 = AccessTools.PropertyGetter(typeof(PlayerData), "SilkSkillCost");
			if (methodInfo2 != null)
			{
				_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ShamanRage2), "SilkCostPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(CursedRage2), "NoCostPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				_log.LogWarning((object)"[Rage] PlayerData.SilkSkillCost not found; shaman/cursed cost effects disabled.");
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(HeroController), "BindCompleted", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(ReaperRage1), "BindCritPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo4 = AccessTools.Method(typeof(HeroController), "AddSilkParts", new Type[1] { typeof(int) }, (Type[])null);
			if (methodInfo4 != null)
			{
				_harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(ReaperRage2), "SilkPartsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo5 = AccessTools.Method(typeof(HeroController), "Dash", (Type[])null, (Type[])null);
			if (methodInfo5 != null)
			{
				_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(WitchRage1), "DashPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo6 = AccessTools.PropertyGetter(typeof(Gameplay), "WandererCritMultiplier");
			if (methodInfo6 != null)
			{
				_harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, new HarmonyMethod(typeof(WandererRage2), "CritMultiplierPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo7 = AccessTools.PropertyGetter(typeof(Gameplay), "WeightedAnkletDmgKnockbackMult");
			if (methodInfo7 != null)
			{
				_harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(typeof(WandererRage2), "KnockbackMultiplierPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo8 = AccessTools.Method(typeof(NailAttackBase), "OnSlashStarting", (Type[])null, (Type[])null);
			if (methodInfo8 != null)
			{
				_harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(typeof(BeastRage1), "RangePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo[] array = new MethodInfo[6]
			{
				AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackDuration"),
				AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackRecoveryTime"),
				AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackCooldownTime"),
				AccessTools.PropertyGetter(typeof(HeroControllerConfig), "QuickAttackCooldownTime"),
				AccessTools.PropertyGetter(typeof(HeroController), "CurrentNailChargeTime"),
				AccessTools.PropertyGetter(typeof(HeroController), "CurrentNailChargeBeginTime")
			};
			foreach (MethodInfo methodInfo9 in array)
			{
				if (!(methodInfo9 == null))
				{
					_harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(typeof(BeastRage2), "AttackSpeedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			CloaklessRage1.Configure(_log);
			MethodInfo methodInfo10 = AccessTools.Method(typeof(HeroController), "GetLuckyDiceShieldThreshold", (Type[])null, (Type[])null);
			if (methodInfo10 != null)
			{
				_harmony.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, new HarmonyMethod(typeof(CloaklessRage1), "LuckyDiceThresholdPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo11 = AccessTools.Method(typeof(HeroController), "TakeDamage", new Type[5]
			{
				typeof(GameObject),
				typeof(CollisionSide),
				typeof(int),
				typeof(HazardType),
				typeof(DamagePropertyFlags)
			}, (Type[])null);
			if (methodInfo11 != null)
			{
				_harmony.Patch((MethodBase)methodInfo11, new HarmonyMethod(typeof(CloaklessRage1), "TakeDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				_log.LogWarning((object)"[Rage] HeroController.TakeDamage not found; cloakless block disabled.");
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				FoundationServices current = FoundationServices.Current;
				if (current != null)
				{
					current.Runtime.AttachRage((IRageProjection)null);
				}
				if ((Object)(object)_witchRage2Go != (Object)null)
				{
					Object.Destroy((Object)(object)_witchRage2Go);
				}
				_furyWhiteSlot?.Dispose();
				_rage?.Dispose();
				_projection?.Dispose();
				RageToolBridge.IsActive = () => false;
				_harmony.UnpatchSelf();
			}
		}
	}
}

CrestsEvolve.ToolsAscension/CrestsEvolve.ToolsAscension.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrestsEvolve.Core.Balance;
using CrestsEvolve.Core.Events;
using CrestsEvolve.Core.State;
using CrestsEvolve.Core.Tools;
using CrestsEvolve.Core.UI;
using CrestsEvolve.Features;
using CrestsEvolve.Features.StatusIcons;
using CrestsEvolve.Features.Tools;
using CrestsEvolve.Features.Tools.Blue;
using CrestsEvolve.Features.Tools.Yellow;
using CrestsEvolve.GameInterop;
using CrestsEvolve.GameInterop.Patches;
using CrestsEvolve.ToolsAscension.Bootstrap;
using CrestsEvolve.ToolsAscension.Features.Tools;
using GlobalEnums;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using Microsoft.CodeAnalysis;
using Silksong.FsmUtil;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CrestsEvolve.ToolsAscension")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")]
[assembly: AssemblyProduct("CrestsEvolve.ToolsAscension")]
[assembly: AssemblyTitle("CrestsEvolve.ToolsAscension")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace CrestsEvolve.GameInterop
{
	public sealed class CogflyAutoReleaseRunner : MonoBehaviour
	{
		private const float Interval = 1f;

		private float _timer;

		private void Update()
		{
			_timer += Time.deltaTime;
			if (!(_timer < 1f))
			{
				_timer = 0f;
				CogflyAutoReleasePatch.Tick();
			}
		}
	}
	public sealed class CogflySpawner
	{
		public const string PrefabName = "Clockwork Hatchling";

		public const string ToolName = "Cogwork Flier";

		public const string AltToolName = "Cogfly";

		private readonly ManualLogSource _log;

		private GameObject? _prefab;

		private AssetBundle? _bundle;

		private FieldInfo? _toolSourceField;

		private bool _warnedResolve;

		private bool _warnedSpawn;

		private bool _warnedToolSource;

		private bool _warnedCount;

		private bool _bundleLoadFailed;

		private bool _loggedSpawn;

		public CogflySpawner(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
			_toolSourceField = AccessTools.Field(typeof(ClockworkHatchling), "toolSource");
		}

		public void OnSceneChanged()
		{
			if ((Object)(object)_bundle == (Object)null)
			{
				_prefab = null;
			}
		}

		public void Tick()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ToolItem val = ToolItemManager.GetToolByName("Cogwork Flier") ?? ToolItemManager.GetToolByName("Cogfly");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int toolStorageAmount = ToolItemManager.GetToolStorageAmount(val);
			int num = CountActive();
			if (!CogflyAutoReleaseRules.ShouldRelease(num, toolStorageAmount))
			{
				return;
			}
			GameObject val2 = ResolvePrefab(val);
			if ((Object)(object)val2 == (Object)null)
			{
				if (!_warnedResolve)
				{
					_warnedResolve = true;
					_log.LogWarning((object)"[CogflySpawner] 'Clockwork Hatchling' prefab not resolved; auto-release disabled.");
				}
				return;
			}
			try
			{
				Vector3 val3 = ((Component)instance).transform.position + new Vector3(1.5f, 1f, 0f);
				GameObject val4 = ObjectPoolExtensions.Spawn(val2, val3, Quaternion.identity);
				if (!((Object)(object)val4 == (Object)null))
				{
					val4.SetActive(true);
					ClockworkHatchling component = val4.GetComponent<ClockworkHatchling>();
					if ((Object)(object)component != (Object)null && _toolSourceField != null)
					{
						_toolSourceField.SetValue(component, val);
					}
					else if (!_warnedToolSource)
					{
						_warnedToolSource = true;
						_log.LogWarning((object)"[CogflySpawner] hatchling prefab missing ClockworkHatchling/toolSource; tool association skipped.");
					}
					if (!_loggedSpawn)
					{
						_loggedSpawn = true;
						_log.LogInfo((object)$"[CogflySpawner] spawned '{((Object)val4).name}' (active {num + 1}/{toolStorageAmount}).");
					}
				}
			}
			catch (Exception ex)
			{
				if (!_warnedSpawn)
				{
					_warnedSpawn = true;
					_log.LogWarning((object)("[CogflySpawner] spawn failed: " + ex.Message));
				}
			}
		}

		private int CountActive()
		{
			try
			{
				return Object.FindObjectsByType<ClockworkHatchling>((FindObjectsSortMode)0).Count((ClockworkHatchling h) => (Object)(object)h != (Object)null && (IsCogflyHatchling(h) || _toolSourceField == null));
			}
			catch (Exception ex)
			{
				if (!_warnedCount)
				{
					_warnedCount = true;
					_log.LogWarning((object)("[CogflySpawner] hatchling count failed: " + ex.Message));
				}
				return 0;
			}
		}

		private bool IsCogflyHatchling(ClockworkHatchling hatchling)
		{
			if (_toolSourceField == null)
			{
				return true;
			}
			try
			{
				object? value = _toolSourceField.GetValue(hatchling);
				ToolItem val = (ToolItem)((value is ToolItem) ? value : null);
				return (Object)(object)val != (Object)null && (string.Equals(val.name, "Cogwork Flier", StringComparison.Ordinal) || string.Equals(val.name, "Cogfly", StringComparison.Ordinal));
			}
			catch
			{
				return true;
			}
		}

		private GameObject? ResolvePrefab(ToolItem tool)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_prefab != (Object)null)
			{
				return _prefab;
			}
			_prefab = tool.Usage.ThrowPrefab;
			if ((Object)(object)_prefab != (Object)null)
			{
				return _prefab;
			}
			_prefab = LoadViaAddressables();
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = LoadViaLoadedBundles();
			}
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = LoadViaBundleFile();
			}
			return _prefab;
		}

		private GameObject? LoadViaAddressables()
		{
			try
			{
				Type type = (from a in AppDomain.CurrentDomain.GetAssemblies()
					select a.GetType("UnityEngine.AddressableAssets.Addressables", throwOnError: false)).FirstOrDefault((Type t) => t != null);
				if (type == null)
				{
					return null;
				}
				MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
					where m.Name == "LoadAssetAsync" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string)
					select m).Take(2).ToArray();
				if (array.Length != 1)
				{
					return null;
				}
				object obj = array[0].MakeGenericMethod(typeof(GameObject)).Invoke(null, new object[1] { "Clockwork Hatchling" });
				if (obj == null)
				{
					return null;
				}
				object? obj2 = obj.GetType().GetMethod("WaitForCompletion", Type.EmptyTypes)?.Invoke(obj, null);
				return (GameObject?)((obj2 is GameObject) ? obj2 : null);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[CogflySpawner] Addressables load failed: " + ex.Message));
				return null;
			}
		}

		private GameObject? LoadViaLoadedBundles()
		{
			try
			{
				foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
				{
					if (!((Object)(object)allLoadedAssetBundle == (Object)null))
					{
						GameObject val = allLoadedAssetBundle.LoadAsset<GameObject>("Clockwork Hatchling");
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[CogflySpawner] loaded-bundle search failed: " + ex.Message));
			}
			return null;
		}

		private GameObject? LoadViaBundleFile()
		{
			if (_bundleLoadFailed)
			{
				return null;
			}
			try
			{
				string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "herodynamic_assets_all.bundle");
				if (!File.Exists(text))
				{
					return null;
				}
				if ((Object)(object)_bundle == (Object)null)
				{
					_bundle = AssetBundle.LoadFromFile(text);
				}
				AssetBundle? bundle = _bundle;
				return (bundle != null) ? bundle.LoadAsset<GameObject>("Clockwork Hatchling") : null;
			}
			catch (Exception ex)
			{
				_bundleLoadFailed = true;
				_log.LogWarning((object)("[CogflySpawner] bundle load failed: " + ex.Message));
				return null;
			}
		}
	}
	public static class ReserveBindBridge
	{
		public static Func<bool>? IsEquipped { get; set; } = () => false;

		public static Func<bool>? TryRestore { get; set; } = () => false;

		public static Func<bool>? TryRepairTool { get; set; }
	}
	public sealed class RevengeCrystalSpawner
	{
		public const string PrefabName = "Revenge Crystal Hornet";

		public const string PrefabPath = "Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab";

		public const string SpawnQueueGroupPath = "Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset";

		private const int MaxSpawnPerCall = 3;

		private const int SpawnQueueGroupLimit = 3;

		private const float SecondsBetweenStatueSpawns = 0.1f;

		private readonly ManualLogSource _log;

		private GameObject? _prefab;

		private AssetBundle? _prefabBundle;

		private AssetBundle? _spawnQueueGroupBundle;

		private bool _groupLimitRaised;

		private bool _disabled;

		private bool _warnedResolve;

		private bool _warnedSpawn;

		private bool _warnedBundleSearch;

		private bool _prefabBundleLoadFailed;

		private bool _spawnQueueGroupLoadFailed;

		public RevengeCrystalSpawner(ManualLogSource log)
		{
			_log = log ?? throw new ArgumentNullException("log");
		}

		public void OnSceneChanged()
		{
			if ((Object)(object)_prefabBundle == (Object)null && (Object)(object)_spawnQueueGroupBundle == (Object)null)
			{
				_prefab = null;
			}
			_groupLimitRaised = false;
			_disabled = false;
		}

		public void Spawn(int count)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (count <= 0 || _disabled)
			{
				return;
			}
			EnsureGroupLimit();
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				_log.LogDebug((object)"[RevengeCrystalSpawner] spawn skipped: HeroController.instance is null.");
				return;
			}
			GameObject val = ResolvePrefab();
			if ((Object)(object)val == (Object)null)
			{
				if (!_warnedResolve)
				{
					_warnedResolve = true;
					_log.LogWarning((object)"[RevengeCrystalSpawner] Revenge Crystal Hornet prefab not resolved; Revenge Crystal white/L2-L3 spawn disabled.");
				}
				return;
			}
			Vector3 position = ((Component)instance).transform.position;
			int num = Math.Min(count, 3);
			_log.LogInfo((object)$"[RevengeCrystalSpawner] spawning {num} statue(s) from '{((Object)val).name}'.");
			for (int i = 0; i < num; i++)
			{
				try
				{
					GameObject val2 = ObjectPoolExtensions.Spawn(val, position, Quaternion.identity);
					if ((Object)(object)val2 != (Object)null)
					{
						val2.SetActive(true);
						BindHero(val2, ((Component)instance).gameObject);
						ResetStatueFsm(val2);
					}
				}
				catch (Exception ex)
				{
					if (!_warnedSpawn)
					{
						_warnedSpawn = true;
						_log.LogWarning((object)("[RevengeCrystalSpawner] spawn failed: " + ex.Message));
					}
				}
			}
		}

		public void SpawnStaggered(int count)
		{
			if (count <= 0 || _disabled)
			{
				return;
			}
			EnsureGroupLimit();
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				_log.LogDebug((object)"[RevengeCrystalSpawner] staggered spawn skipped: HeroController.instance is null.");
				return;
			}
			GameObject val = ResolvePrefab();
			if ((Object)(object)val == (Object)null)
			{
				if (!_warnedResolve)
				{
					_warnedResolve = true;
					_log.LogWarning((object)"[RevengeCrystalSpawner] Revenge Crystal Hornet prefab not resolved; staggered spawn disabled.");
				}
			}
			else
			{
				int num = Math.Min(count, 3);
				_log.LogInfo((object)$"[RevengeCrystalSpawner] spawning {num} staggered statue(s) from '{((Object)val).name}'.");
				((MonoBehaviour)instance).StartCoroutine(SpawnStaggeredRoutine(instance, val, num));
			}
		}

		private IEnumerator SpawnStaggeredRoutine(HeroController hero, GameObject prefab, int amount)
		{
			Vector3 offset = default(Vector3);
			for (int i = 0; i < amount; i++)
			{
				if (i > 0)
				{
					yield return (object)new WaitForSeconds(0.1f);
				}
				try
				{
					GameObject val = ObjectPoolExtensions.Spawn(prefab, ((Component)hero).transform.position, Quaternion.identity);
					if ((Object)(object)val != (Object)null)
					{
						val.SetActive(true);
						BindHero(val, ((Component)hero).gameObject);
						ResetStatueFsm(val);
						((Vector3)(ref offset))..ctor((float)(i + 1) * 0.6f, (i % 2 == 0) ? 0.5f : (-0.5f), 0f);
						val.AddComponent<RevengeCrystalStatueOffsetter>().Init(((Component)hero).transform, offset);
					}
				}
				catch (Exception ex)
				{
					if (!_warnedSpawn)
					{
						_warnedSpawn = true;
						_log.LogWarning((object)("[RevengeCrystalSpawner] staggered spawn failed: " + ex.Message));
					}
				}
			}
		}

		private GameObject? ResolvePrefab()
		{
			if ((Object)(object)_prefab != (Object)null)
			{
				return _prefab;
			}
			if (_disabled)
			{
				return null;
			}
			_prefab = LoadViaAddressables();
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = FindUniqueRuntimeObject();
			}
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = LoadViaAssetBundle();
			}
			if ((Object)(object)_prefab != (Object)null)
			{
				_log.LogInfo((object)("[RevengeCrystalSpawner] prefab resolved: " + ((Object)_prefab).name));
			}
			return _prefab;
		}

		private GameObject? LoadViaAddressables()
		{
			try
			{
				string[] array = new string[2] { "Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab", "Revenge Crystal Hornet" };
				foreach (string key in array)
				{
					object? obj = LoadAddressableObject(typeof(GameObject), key);
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if ((Object)(object)val != (Object)null && LooksLikeStatuePrefab(val))
					{
						return val;
					}
				}
				return null;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[RevengeCrystalSpawner] Addressables load failed for 'Revenge Crystal Hornet': " + ex.Message));
				return null;
			}
		}

		private object? LoadAddressableObject(Type assetType, string key)
		{
			try
			{
				Type type = (from a in AppDomain.CurrentDomain.GetAssemblies()
					select a.GetType("UnityEngine.AddressableAssets.Addressables", throwOnError: false)).FirstOrDefault((Type t) => t != null);
				if (type == null)
				{
					return null;
				}
				MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
					where m.Name == "LoadAssetAsync" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string)
					select m).Take(2).ToArray();
				if (array.Length != 1)
				{
					return null;
				}
				object obj = array[0].MakeGenericMethod(assetType).Invoke(null, new object[1] { key });
				if (obj == null)
				{
					return null;
				}
				MethodInfo method = obj.GetType().GetMethod("WaitForCompletion", Type.EmptyTypes);
				if (method == null)
				{
					return null;
				}
				return method.Invoke(obj, null);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[RevengeCrystalSpawner] Addressables load failed for '" + key + "': " + ex.Message));
				return null;
			}
		}

		private void EnsureGroupLimit()
		{
			if (_groupLimitRaised)
			{
				return;
			}
			try
			{
				List<SpawnQueueGroup> list = ResolveSpawnQueueGroups();
				if (list.Count == 0)
				{
					return;
				}
				FieldInfo field = typeof(SpawnQueueGroup).GetField("groupLimit", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field == null)
				{
					_log.LogWarning((object)"[RevengeCrystalSpawner] SpawnQueueGroup.groupLimit field not found.");
					return;
				}
				foreach (SpawnQueueGroup item in list)
				{
					field.SetValue(item, 3);
				}
				_groupLimitRaised = true;
				_log.LogInfo((object)($"[RevengeCrystalSpawner] SpawnQueueGroup.groupLimit raised to {3} " + $"({list.Count} instance(s))."));
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[RevengeCrystalSpawner] failed to raise SpawnQueueGroup.groupLimit: " + ex.Message));
			}
		}

		private List<SpawnQueueGroup> ResolveSpawnQueueGroups()
		{
			List<SpawnQueueGroup> list = new List<SpawnQueueGroup>();
			try
			{
				SpawnQueueGroup[] array = Resources.FindObjectsOfTypeAll<SpawnQueueGroup>();
				foreach (SpawnQueueGroup val in array)
				{
					if ((Object)(object)val != (Object)null && ((Object)val).name == "Revenge Crystal Hornet")
					{
						list.Add(val);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_warnedBundleSearch)
				{
					_warnedBundleSearch = true;
					_log.LogWarning((object)("[RevengeCrystalSpawner] runtime SpawnQueueGroup search failed: " + ex.Message));
				}
			}
			if (list.Count > 0)
			{
				return list;
			}
			try
			{
				foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
				{
					if (!((Object)(object)allLoadedAssetBundle == (Object)null))
					{
						SpawnQueueGroup val2 = allLoadedAssetBundle.LoadAsset<SpawnQueueGroup>("Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset");
						if ((Object)(object)val2 == (Object)null)
						{
							val2 = allLoadedAssetBundle.LoadAsset<SpawnQueueGroup>("Revenge Crystal Hornet");
						}
						if ((Object)(object)val2 != (Object)null)
						{
							list.Add(val2);
							break;
						}
					}
				}
			}
			catch (Exception ex2)
			{
				if (!_warnedBundleSearch)
				{
					_warnedBundleSearch = true;
					_log.LogWarning((object)("[RevengeCrystalSpawner] loaded-bundle SpawnQueueGroup search failed: " + ex2.Message));
				}
			}
			if (list.Count > 0)
			{
				return list;
			}
			object? obj = LoadAddressableObject(typeof(SpawnQueueGroup), "Revenge Crystal Hornet");
			SpawnQueueGroup val3 = (SpawnQueueGroup)((obj is SpawnQueueGroup) ? obj : null);
			if (val3 != null)
			{
				list.Add(val3);
				return list;
			}
			if (_spawnQueueGroupLoadFailed)
			{
				return list;
			}
			try
			{
				string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "dataassets_assets_assets", "dataassets", "spawnqueuegroups.bundle");
				if (!File.Exists(text))
				{
					return list;
				}
				AssetBundle val4 = _spawnQueueGroupBundle;
				if ((Object)(object)val4 == (Object)null)
				{
					val4 = FindLoadedBundle(Path.GetFileName(text));
					if ((Object)(object)val4 == (Object)null)
					{
						val4 = AssetBundle.LoadFromFile(text);
					}
					_spawnQueueGroupBundle = val4;
				}
				if ((Object)(object)val4 == (Object)null)
				{
					_spawnQueueGroupLoadFailed = true;
					return list;
				}
				SpawnQueueGroup val5 = val4.LoadAsset<SpawnQueueGroup>("Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset");
				if ((Object)(object)val5 != (Object)null)
				{
					list.Add(val5);
				}
			}
			catch (Exception ex3)
			{
				_spawnQueueGroupLoadFailed = true;
				_log.LogWarning((object)("[RevengeCrystalSpawner] SpawnQueueGroup bundle load failed: " + ex3.Message));
			}
			return list;
		}

		private GameObject? LoadViaAssetBundle()
		{
			if (_prefabBundleLoadFailed)
			{
				return null;
			}
			try
			{
				string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "localpoolprefabs_assets_shared.bundle");
				if (!File.Exists(text))
				{
					return null;
				}
				AssetBundle val = _prefabBundle;
				if ((Object)(object)val == (Object)null)
				{
					val = FindLoadedBundle(Path.GetFileName(text));
					if ((Object)(object)val == (Object)null)
					{
						val = AssetBundle.LoadFromFile(text);
					}
					_prefabBundle = val;
				}
				if ((Object)(object)val == (Object)null)
				{
					_prefabBundleLoadFailed = true;
					return null;
				}
				GameObject val2 = val.LoadAsset<GameObject>("Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab");
				return ((Object)(object)val2 != (Object)null && LooksLikeStatuePrefab(val2)) ? val2 : null;
			}
			catch (Exception ex)
			{
				_prefabBundleLoadFailed = true;
				_log.LogWarning((object)("[RevengeCrystalSpawner] AssetBundle load failed: " + ex.Message));
				return null;
			}
		}

		private AssetBundle? FindLoadedBundle(string fileName)
		{
			try
			{
				foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
				{
					if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, fileName, StringComparison.OrdinalIgnoreCase))
					{
						return allLoadedAssetBundle;
					}
				}
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
				foreach (AssetBundle allLoadedAssetBundle2 in AssetBundle.GetAllLoadedAssetBundles())
				{
					if ((Object)(object)allLoadedAssetBundle2 != (Object)null && ((Object)allLoadedAssetBundle2).name.IndexOf(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return allLoadedAssetBundle2;
					}
				}
			}
			catch (Exception ex)
			{
				if (!_warnedBundleSearch)
				{
					_warnedBundleSearch = true;
					_log.LogWarning((object)("[RevengeCrystalSpawner] loaded-bundle search failed: " + ex.Message));
				}
			}
			return null;
		}

		private static bool LooksLikeStatuePrefab(GameObject candidate)
		{
			if ((Object)(object)candidate == (Object)null)
			{
				return false;
			}
			PlayMakerFSM component = candidate.GetComponent<PlayMakerFSM>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if (!string.Equals(component.FsmName, "FSM", StringComparison.Ordinal))
			{
				return false;
			}
			if (component.FsmVariables.FindFsmGameObject("Form Antic Pt") == null)
			{
				return component.FsmVariables.FindFsmGameObject("Enemy Damager") != null;
			}
			return true;
		}

		private GameObject? FindUniqueRuntimeObject()
		{
			try
			{
				GameObject[] array = (from g in Resources.FindObjectsOfTypeAll<GameObject>()
					where (Object)(object)g != (Object)null && ((Object)g).name == "Revenge Crystal Hornet"
					select g).Take(2).ToArray();
				if (array.Length == 1)
				{
					return array[0];
				}
				if (array.Length > 1)
				{
					_disabled = true;
					_log.LogWarning((object)"[RevengeCrystalSpawner] multiple 'Revenge Crystal Hornet' objects found; spawn disabled (ambiguous).");
				}
				return null;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[RevengeCrystalSpawner] runtime object search failed: " + ex.Message));
				return null;
			}
		}

		private static void BindHero(GameObject spawned, GameObject hero)
		{
			if ((Object)(object)spawned == (Object)null || (Object)(object)hero == (Object)null)
			{
				return;
			}
			PlayMakerFSM component = spawned.GetComponent<PlayMakerFSM>();
			if (!((Object)(object)component == (Object)null))
			{
				FsmGameObject val = component.FsmVariables.FindFsmGameObject("Hero") ?? FsmVariables.GlobalVariables.FindFsmGameObject("Hero");
				if (val != null)
				{
					val.Value = hero;
				}
			}
		}

		private static void ResetStatueFsm(GameObject statue)
		{
			if ((Object)(object)statue == (Object)null)
			{
				return;
			}
			PlayMakerFSM component = statue.GetComponent<PlayMakerFSM>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			try
			{
				((object)component).GetType().GetMethod("SetState", new Type[1] { typeof(string) })?.Invoke(component, new object[1] { "Init Wait" });
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[RevengeCrystalSpawner] FSM reset failed: " + ex.Message));
			}
		}
	}
	public sealed class RevengeCrystalStatueOffsetter : MonoBehaviour
	{
		private Transform? _hero;

		private Vector3 _offset;

		public void Init(Transform hero, Vector3 offset)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			_hero = hero;
			_offset = offset;
			((MonoBehaviour)this).StartCoroutine(ApplyOffsetAfterAppear());
		}

		private IEnumerator ApplyOffsetAfterAppear()
		{
			yield return (object)new WaitForSeconds(1.3f);
			if ((Object)(object)_hero != (Object)null)
			{
				((Component)this).transform.position = _hero.position + _offset;
			}
		}
	}
	public sealed class ShellSatchelRepairRunner : MonoBehaviour
	{
		private sealed class Entry
		{
			public ToolItem? Tool;

			public float ReadyTime;
		}

		private const float RepairDelaySeconds = 2f;

		private static readonly List<Entry> Pending = new List<Entry>();

		private static bool _warned;

		public static void Schedule(ToolItem tool)
		{
			if ((Object)(object)tool == (Object)null)
			{
				return;
			}
			foreach (Entry item in Pending)
			{
				if ((Object)(object)item.Tool == (Object)(object)tool)
				{
					item.ReadyTime = Time.time + 2f;
					return;
				}
			}
			Pending.Add(new Entry
			{
				Tool = tool,
				ReadyTime = Time.time + 2f
			});
		}

		public static void CancelAll()
		{
			Pending.Clear();
		}

		private void Update()
		{
			for (int num = Pending.Count - 1; num >= 0; num--)
			{
				Entry entry = Pending[num];
				if ((Object)(object)entry.Tool == (Object)null)
				{
					Pending.RemoveAt(num);
				}
				else if (!(Time.time < entry.ReadyTime))
				{
					Pending.RemoveAt(num);
					TryRepair(entry.Tool);
				}
			}
		}

		private static void TryRepair(ToolItem tool)
		{
			//IL_0020: 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)
			try
			{
				if (ShellSatchelAutoRepairPatch.IsLevelActive(ShellSatchelAutoRepairPatch.GetLevel?.Invoke("Shell Satchel") ?? 0) && (int)tool.Type == 0 && tool.SavedData.AmountLeft <= 0)
				{
					tool.CollectFree(ToolItemManager.GetToolStorageAmount(tool));
					ToolItemStatesLiquid val = (ToolItemStatesLiquid)(object)((tool is ToolItemStatesLiquid) ? tool : null);
					if (val != null)
					{
						val.RefillRefills(false);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					Debug.LogWarning((object)("[ShellSatchelRepair] repair failed: " + ex.Message));
				}
			}
		}
	}
	public sealed class ToolEquipRefreshBridge : MonoBehaviour
	{
		private GameEventHub? _events;

		private ToolEquipIconDriver? _driver;

		public void Initialize(GameEventHub events, ToolEquipIconDriver driver)
		{
			_events = events;
			_driver = driver;
			events.CrestChanged += OnCrestChanged;
			events.SceneChanged += OnSceneChanged;
		}

		private void OnDestroy()
		{
			if (_events != null)
			{
				_events.CrestChanged -= OnCrestChanged;
				_events.SceneChanged -= OnSceneChanged;
			}
		}

		private void OnCrestChanged(CrestChangedEvent e)
		{
			((MonoBehaviour)this).StartCoroutine(RefreshNextFrame());
		}

		private void OnSceneChanged(string scene)
		{
			((MonoBehaviour)this).StartCoroutine(RefreshNextFrame());
		}

		private IEnumerator RefreshNextFrame()
		{
			yield return null;
			_driver?.Refresh();
		}
	}
}
namespace CrestsEvolve.GameInterop.Patches
{
	public static class BellBindSkillShieldPatch
	{
		private sealed class ActionCache
		{
			public bool Stored;

			public bool OriginalEnabled;
		}

		private sealed class SkillShieldMarker : MonoBehaviour
		{
		}

		private sealed class BindBellGateMarker : MonoBehaviour
		{
		}

		private sealed class EndBellBindShieldAction : FsmStateAction
		{
			public override void OnEnter()
			{
				try
				{
					EndShield();
				}
				catch (Exception ex)
				{
					WarnOnce(ex);
				}
				((FsmStateAction)this).Finish();
			}
		}

		public static readonly string[] SkillShieldEvents = new string[4] { "NEEDLE THROW", "THREAD SPHERE", "PARRY", "SILK BOMB" };

		private static readonly string[] EndStates = new string[4] { "N Throw Recover", "Special End", "Cancel All", "Cancel Frame" };

		public static Func<string, bool>? IsEquippedInWhiteSlot;

		private static ManualLogSource? _log;

		private static bool _warned;

		private static FieldInfo? _bellBindFsmField;

		private static readonly List<PlayMakerFSM> _patchedSpecials = new List<PlayMakerFSM>();

		private static readonly List<PlayMakerFSM> _patchedBind = new List<PlayMakerFSM>();

		private static readonly ConditionalWeakTable<ActivateGameObject, ActionCache> _bindBellCache = new ConditionalWeakTable<ActivateGameObject, ActionCache>();

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
			_bellBindFsmField = AccessTools.Field(typeof(HeroController), "bellBindFSM");
			_patchedSpecials.Clear();
			_patchedBind.Clear();
		}

		public static bool ShouldTriggerSkillShield(string? eventName)
		{
			if (eventName != null)
			{
				return Array.IndexOf<string>(SkillShieldEvents, eventName) >= 0;
			}
			return false;
		}

		public static void OnSkillEvent(PlayMakerFSM __instance, string eventName)
		{
			try
			{
				if (ShouldTriggerSkillShield(eventName) && !((Object)(object)__instance == (Object)null) && !(__instance.FsmName != "Silk Specials"))
				{
					Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
					if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Bell Bind"))
					{
						ActivateShield();
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void OnFsmStart(PlayMakerFSM __instance)
		{
			if ((Object)(object)__instance == (Object)null || __instance.Fsm == null || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal))
			{
				return;
			}
			try
			{
				if (__instance.FsmName == "Silk Specials")
				{
					InstallSkillEndActions(__instance);
				}
				else if (__instance.FsmName == "Spell Control")
				{
					InstallBindBellGate(__instance);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void RefreshAll()
		{
			for (int num = _patchedBind.Count - 1; num >= 0; num--)
			{
				PlayMakerFSM val = _patchedBind[num];
				if ((Object)(object)val == (Object)null)
				{
					_patchedBind.RemoveAt(num);
				}
				else
				{
					ApplyBindBellGate(val);
				}
			}
		}

		public static void RestoreAll()
		{
			foreach (PlayMakerFSM item in _patchedBind)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ApplyBindBellGate(item, forceInactive: true);
				}
			}
			_patchedBind.Clear();
			_patchedSpecials.Clear();
		}

		private static void ActivateShield()
		{
			PlayMakerFSM val = ResolveBellBindFsm();
			if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
			{
				((Component)val).gameObject.SetActive(true);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogDebug((object)"[BellBindSkillShield] white-slot skill shield activated.");
				}
			}
		}

		private static void EndShield()
		{
			PlayMakerFSM val = ResolveBellBindFsm();
			if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeSelf)
			{
				val.SendEvent("DISAPPEAR");
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogDebug((object)"[BellBindSkillShield] white-slot skill shield ended (DISAPPEAR).");
				}
			}
		}

		private static PlayMakerFSM? ResolveBellBindFsm()
		{
			if (_bellBindFsmField == null)
			{
				return null;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			object? value = _bellBindFsmField.GetValue(instance);
			return (PlayMakerFSM?)((value is PlayMakerFSM) ? value : null);
		}

		private static void InstallSkillEndActions(PlayMakerFSM fsm)
		{
			if ((Object)(object)((Component)fsm).GetComponent<SkillShieldMarker>() != (Object)null)
			{
				return;
			}
			int num = 0;
			string[] endStates = EndStates;
			foreach (string text in endStates)
			{
				FsmState state = FsmUtil.GetState(fsm, text);
				if (state != null)
				{
					FsmUtil.InsertAction(state, state.Actions.Length, (FsmStateAction)(object)new EndBellBindShieldAction());
					num++;
				}
			}
			if (num == 0)
			{
				WarnOnce(new InvalidOperationException("Silk Specials FSM end states not found (N Throw Recover/Special End/Cancel All/Cancel Frame); skill shield end disabled."));
				return;
			}
			((Component)fsm).gameObject.AddComponent<SkillShieldMarker>();
			_patchedSpecials.Add(fsm);
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[BellBindSkillShield] Silk Specials FSM hook installed ({num} end state(s)).");
			}
		}

		private static void InstallBindBellGate(PlayMakerFSM fsm)
		{
			if ((Object)(object)((Component)fsm).GetComponent<BindBellGateMarker>() != (Object)null)
			{
				ApplyBindBellGate(fsm);
				return;
			}
			if (!FindBindBellActivation(fsm))
			{
				WarnOnce(new InvalidOperationException("Spell Control | Bind Bell? ActivateGameObject(Bind Bell, true) not found; bind-release gate disabled."));
				return;
			}
			((Component)fsm).gameObject.AddComponent<BindBellGateMarker>();
			_patchedBind.Add(fsm);
			ApplyBindBellGate(fsm);
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)"[BellBindSkillShield] Spell Control | Bind Bell? gate installed (white-slot bind no shield).");
			}
		}

		private static bool FindBindBellActivation(PlayMakerFSM fsm)
		{
			FsmState[] fsmStates = fsm.FsmStates;
			foreach (FsmState val in fsmStates)
			{
				if (val.Name != "Bind Bell?")
				{
					continue;
				}
				FsmStateAction[] actions = val.Actions;
				for (int j = 0; j < actions.Length; j++)
				{
					if (IsBindBellActivation(actions[j]))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsBindBellActivation(FsmStateAction action)
		{
			ActivateGameObject val = (ActivateGameObject)(object)((action is ActivateGameObject) ? action : null);
			if (val != null && val.activate != null && val.activate.Value && val.gameObject != null && val.gameObject.GameObject != null)
			{
				return string.Equals(((NamedVariable)val.gameObject.GameObject).Name, "Bind Bell", StringComparison.Ordinal);
			}
			return false;
		}

		private static void ApplyBindBellGate(PlayMakerFSM fsm, bool forceInactive = false)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			try
			{
				bool flag = !forceInactive && IsEquippedInWhiteSlot != null && IsEquippedInWhiteSlot("Bell Bind");
				FsmState[] fsmStates = fsm.FsmStates;
				foreach (FsmState val in fsmStates)
				{
					if (val.Name != "Bind Bell?")
					{
						continue;
					}
					FsmStateAction[] actions = val.Actions;
					foreach (FsmStateAction val2 in actions)
					{
						if (IsBindBellActivation(val2))
						{
							ActionCache orCreateValue = _bindBellCache.GetOrCreateValue((ActivateGameObject)val2);
							if (!orCreateValue.Stored)
							{
								orCreateValue.Stored = true;
								orCreateValue.OriginalEnabled = val2.Enabled;
							}
							val2.Enabled = !flag && orCreateValue.OriginalEnabled;
						}
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[BellBindSkillShield] disabled: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class BlueToolEffectPatches
	{
		private sealed class WispCooldownCache
		{
			public float Min;

			public float Max;
		}

		private sealed class SlashScaleCache
		{
			public Vector3 Original;
		}

		private const int SilkMaxCapacity = 36;

		public static Func<string, int>? GetLevel;

		public static Func<string, bool>? IsEquippedInWhiteSlot;

		public static Action<int>? SpawnRevengeCrystals;

		public static Action<int>? AddExtraBlueHealth;

		private static ManualLogSource? _log;

		private static bool _warned;

		private static FieldInfo? _moss1Hits;

		private static FieldInfo? _moss2Hits;

		private static FieldInfo? _lavaCooldown;

		private static FieldInfo? _taggedDamage;

		private static FieldInfo? _wispCooldownField;

		private static FieldInfo? _minMaxStartField;

		private static FieldInfo? _minMaxEndField;

		private static FieldInfo? _queuedAutoThrowTool;

		private static FieldInfo? _willThrowTool;

		private static MethodInfo? _resetMaggotCharm;

		private static FieldInfo? _heroCState;

		private static FieldInfo? _whipLashing;

		private static FieldInfo? _luckyDiceShieldedHits;

		private static object? _zeroMinMaxFloat;

		private static double _pendingPoisonMultiplier = 1.0;

		private static double _pendingSilkMultiplier = 1.0;

		private static int _quickSlingRemaining;

		private static int _revengeHealthBefore = -1;

		private static int _lastLoggedCompassCap = -1;

		private static ToolItem? _quickSlingTool;

		private static FieldInfo? _quickeningTimeLeft;

		private static FieldInfo? _imbuementTimeLeft;

		private static FieldInfo? _nailAttackBaseScale;

		private static string? _pendingWhiteSlotTool;

		private static double _pendingWhiteSlotMultiplier = 1.0;

		private static readonly ConditionalWeakTable<HeroWispLantern, WispCooldownCache> _wispCooldownCache = new ConditionalWeakTable<HeroWispLantern, WispCooldownCache>();

		private static readonly ConditionalWeakTable<NailAttackBase, SlashScaleCache> _slashScales = new ConditionalWeakTable<NailAttackBase, SlashScaleCache>();

		public static bool IsDiceCritWindow { get; private set; }

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_moss1Hits = AccessTools.Field(typeof(HeroController), "mossCreep1Hits");
			_moss2Hits = AccessTools.Field(typeof(HeroController), "mossCreep2Hits");
			_lavaCooldown = AccessTools.Field(typeof(HeroController), "lavaBellCooldownTimeLeft");
			_taggedDamage = AccessTools.Field(typeof(TagDamageTaker), "taggedDamage");
			_wispCooldownField = AccessTools.Field(typeof(HeroWispLantern), "wispSpawnCooldown");
			Type type = Type.GetType("TeamCherry.SharedUtils.MinMaxFloat, TeamCherry.SharedUtils");
			if (type != null)
			{
				_minMaxStartField = AccessTools.Field(type, "Start");
				_minMaxEndField = AccessTools.Field(type, "End");
				try
				{
					_zeroMinMaxFloat = Activator.CreateInstance(type);
					if (_zeroMinMaxFloat != null && _minMaxStartField != null && _minMaxEndField != null)
					{
						_minMaxStartField.SetValue(_zeroMinMaxFloat, 0f);
						_minMaxEndField.SetValue(_zeroMinMaxFloat, 0f);
					}
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("[BlueToolEffects] MinMaxFloat zero instance creation failed: " + ex.Message));
				}
			}
			_queuedAutoThrowTool = AccessTools.Field(typeof(HeroController), "queuedAutoThrowTool");
			_willThrowTool = AccessTools.Field(typeof(HeroController), "willThrowTool");
			_quickeningTimeLeft = AccessTools.Field(typeof(HeroController), "quickeningTimeLeft");
			_imbuementTimeLeft = AccessTools.Field(typeof(HeroNailImbuement), "imbuementTimeLeft");
			_nailAttackBaseScale = AccessTools.Field(typeof(NailAttackBase), "scale");
			_resetMaggotCharm = AccessTools.Method(typeof(HeroController), "ResetMaggotCharm", (Type[])null, (Type[])null);
			_heroCState = AccessTools.Field(typeof(HeroController), "cState");
			_whipLashing = ((_heroCState == null) ? null : AccessTools.Field(_heroCState.FieldType, "whipLashing"));
			_luckyDiceShieldedHits = AccessTools.Field(typeof(HeroController), "luckyDiceShieldedHits");
			ClearQuickSling();
			ClearPendingWhiteSlot();
			_revengeHealthBefore = -1;
		}

		public static double GetDamageMultiplier(string toolName)
		{
			return EffectsFor(toolName).DamageMultiplier;
		}

		public static bool ShouldApplyEffectDamagePrefix(bool hasRepresentingTool)
		{
			return !hasRepresentingTool;
		}

		public static bool IsShellSatchelWhiteFixedCostActive()
		{
			return ShouldApplyShellSatchelWhiteFixedCost(IsEquippedInWhiteSlot?.Invoke("Shell Satchel") ?? false, EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost);
		}

		public static bool IsCompassEquippedAnywhere()
		{
			if (!Gameplay.CompassTool.Status.IsEquipped)
			{
				return IsEquippedInWhiteSlot?.Invoke("Compass") ?? false;
			}
			return true;
		}

		public static bool IsCompassAbsoluteStorageActive(ToolItem tool)
		{
			if ((Object)(object)tool != (Object)null)
			{
				return ShouldApplyCompassAbsoluteStorage(IsCompassEquippedAnywhere(), GetLevel?.Invoke("Compass") ?? 0, tool.name);
			}
			return false;
		}

		public static bool IsCogworkStorageTool(string toolName)
		{
			if (!string.Equals(toolName, "Cogwork Flier", StringComparison.Ordinal))
			{
				return string.Equals(toolName, "Cogfly", StringComparison.Ordinal);
			}
			return true;
		}

		public static bool ShouldApplyShellSatchelWhiteFixedCost(bool inWhiteSlot, bool effectEnabled)
		{
			return inWhiteSlot && effectEnabled;
		}

		public static bool ShouldApplyCompassAbsoluteStorage(bool compassEquipped, int level, string toolName)
		{
			if (compassEquipped && level >= 2)
			{
				return IsCogworkStorageTool(toolName);
			}
			return false;
		}

		public static bool ShouldForceDiceLucky(bool diceEquipped, int level, bool inCritWindow)
		{
			return diceEquipped && level >= 2 && inCritWindow;
		}

		public static void LongneedleSlashPrefix(NailAttackBase __instance)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (((ToolBase)Gameplay.LongNeedleTool).IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Longneedle");
				if (!(toolEffectSpec.NailLengthMultiplier <= 1.0) || !(toolEffectSpec.NailWidthMultiplier <= 1.0) || !(toolEffectSpec.NailWhiteLengthMultiplier <= 1.0))
				{
					_slashScales.Remove(__instance);
					Vector3 original = (Vector3)((_nailAttackBaseScale != null) ? ((Vector3)(_nailAttackBaseScale.GetValue(__instance) ?? ((object)Vector3.one))) : ((Component)__instance).transform.localScale);
					_slashScales.Add(__instance, new SlashScaleCache
					{
						Original = original
					});
				}
			}
		}

		public static void LongneedleSlashPostfix(NailAttackBase __instance)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if (!((ToolBase)Gameplay.LongNeedleTool).IsEquipped)
			{
				return;
			}
			ToolEffectSpec toolEffectSpec = EffectsFor("Longneedle");
			if ((!(toolEffectSpec.NailLengthMultiplier <= 1.0) || !(toolEffectSpec.NailWidthMultiplier <= 1.0) || !(toolEffectSpec.NailWhiteLengthMultiplier <= 1.0)) && _slashScales.TryGetValue(__instance, out SlashScaleCache value))
			{
				_slashScales.Remove(__instance);
				double num = toolEffectSpec.NailLengthMultiplier;
				double num2 = toolEffectSpec.NailWidthMultiplier;
				if (IsWitchCrest())
				{
					num += toolEffectSpec.WitchNailLengthBonus;
					num2 += toolEffectSpec.WitchNailWidthBonus;
				}
				num *= toolEffectSpec.NailWhiteLengthMultiplier;
				((Component)__instance).transform.localScale = new Vector3(value.Original.x * (float)num, value.Original.y * (float)num2, value.Original.z);
			}
		}

		public static void WispLanternEquipsChangedPostfix(HeroWispLantern __instance)
		{
			ToolEffectSpec toolEffectSpec = EffectsFor("Wisp Lantern");
			if (!Gameplay.WispLanternTool.Status.IsEquipped || toolEffectSpec.WispSpawnIntervalSeconds <= 0f)
			{
				RestoreWispCooldown(__instance);
			}
			else
			{
				SetWispCooldown(__instance, toolEffectSpec.WispSpawnIntervalSeconds);
			}
		}

		public static bool TakeSilkWispPrefix(int amount, SilkTakeSource source)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)source == 1)
			{
				return !EffectsFor("Wisp Lantern").WispNoSilkCost;
			}
			return true;
		}

		public static void SilkSkillCostPostfix(PlayerData __instance, ref int __result)
		{
			if (Gameplay.FleaCharmTool.IsEquippedHud)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Flea Charm");
				if (toolEffectSpec.SilkSkillCost > 0 && (toolEffectSpec.SilkSkillCostNoHealthGate || __instance.health >= __instance.CurrentMaxHealth))
				{
					__result = toolEffectSpec.SilkSkillCost;
				}
			}
		}

		public static void NailChargeTimePostfix(HeroController __instance, ref float __result)
		{
			ApplyNailChargeFactor(__instance, ref __result, __instance.NAIL_CHARGE_TIME);
		}

		public static void NailChargeBeginTimePostfix(HeroController __instance, ref float __result)
		{
			ApplyNailChargeFactor(__instance, ref __result, __instance.NAIL_CHARGE_BEGIN_TIME);
		}

		public static void SilkGainPrefix(HeroController __instance, HitInstance hitInstance)
		{
			//IL_0029: 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_0031: Invalid comparison between Unknown and I4
			if (ToolItemManager.IsToolEquipped("Pinstress Tool"))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Pinstress Tool");
				if (toolEffectSpec.ChargeSilkMultiplier > 1.0 && (int)hitInstance.AttackType == 16)
				{
					_pendingSilkMultiplier = toolEffectSpec.ChargeSilkMultiplier;
				}
			}
		}

		public static void AddSilkPrefix(ref int amount)
		{
			if (!(_pendingSilkMultiplier <= 1.0))
			{
				amount = (int)Math.Round((double)amount * _pendingSilkMultiplier);
				_pendingSilkMultiplier = 1.0;
			}
		}

		public static void WandererCritMultiplierPostfix(ref float __result)
		{
			if (Gameplay.CompassTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Compass");
				if (toolEffectSpec.CritMultiplierBonus > 0.0)
				{
					__result += (float)toolEffectSpec.CritMultiplierBonus;
				}
			}
		}

		public static void ZapDamageMultPostfix(ref float __result)
		{
			if (Gameplay.ZapImbuementTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Zap Imbuement");
				double num = toolEffectSpec.SilkSkillDamageBonus;
				if (toolEffectSpec.SilkSkillDamageWhiteBonus)
				{
					num += 0.25;
				}
				if (num > 0.0)
				{
					__result += (float)num;
				}
			}
		}

		public static void SilkRegenMaxPostfix(PlayerData __instance, ref int __result)
		{
			if (Gameplay.WhiteRingTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("White Ring");
				int num = ((toolEffectSpec.SilkRegenCapBonus <= 0) ? 1 : toolEffectSpec.SilkRegenCapBonus);
				__result += num - 1;
			}
		}

		public static void WhiteRingSpeedMultiplierPostfix(ref float __result)
		{
			if (Gameplay.WhiteRingTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("White Ring");
				double num = ((toolEffectSpec.SilkRegenSpeedFactor > 0.0) ? toolEffectSpec.SilkRegenSpeedFactor : 1.35);
				__result *= (float)(1.35 / num);
			}
		}

		public static bool SilkSpoolSetRegenPrefix(SilkSpool __instance, int amount, bool isUpgraded)
		{
			if (amount != 0)
			{
				return true;
			}
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("White Ring"))
			{
				return true;
			}
			return !EffectsFor("White Ring").SilkRegenNoResetOnChange;
		}

		public static void SilkMaxPostfix(PlayerData __instance, ref int __result)
		{
			if (Gameplay.SpoolExtenderTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Spool Extender");
				int num = ((toolEffectSpec.SilkCapBonus > 0) ? toolEffectSpec.SilkCapBonus : 3);
				if (toolEffectSpec.SilkCapWhiteDouble)
				{
					num *= 2;
				}
				__result = Math.Min(__instance.CurrentSilkMaxBasic + num, 36);
			}
		}

		public static void DrawSpoolPrefix(ref int maxOffset)
		{
			try
			{
				PlayerData instance = PlayerData.instance;
				if (instance != null)
				{
					int num = instance.CurrentSilkMax - instance.CurrentSilkMaxBasic;
					if (num > 0)
					{
						maxOffset += num;
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void BrollyHitPrefix(ref HitInstance hitInstance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (IsBrollyHit(hitInstance) && Gameplay.BrollySpikeTool.Status.IsEquipped && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Brolly Spike");
				if (!(toolEffectSpec.DamageMultiplier <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier);
				}
			}
		}

		public static void BrollyHitPostfix(HitInstance hitInstance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (!IsBrollyHit(hitInstance))
			{
				return;
			}
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Brolly Spike") && EffectsFor("Brolly Spike").BrollyWhiteSilk)
			{
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.AddSilk(1, false, (SilkAddSource)0);
				}
			}
		}

		public static void DazzleHitPrefix(ref HitInstance hitInstance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (!IsDazzleHit(hitInstance))
			{
				return;
			}
			ToolDefinition toolDefinition = FindDazzleDefinition();
			if (!(toolDefinition == null) && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor(toolDefinition.Name);
				if (!(toolEffectSpec.DamageMultiplier <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier);
				}
			}
		}

		public static void DazzleWhiteTakeDamagePostfix(HeroController __instance)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			ToolDefinition toolDefinition = FindDazzleDefinition();
			if (toolDefinition == null)
			{
				return;
			}
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot(toolDefinition.Name) || !EffectsFor(toolDefinition.Name).DazzleWhiteOnHit)
			{
				return;
			}
			try
			{
				GameObject val = ReadDazzleFlashPrefab((PlayMakerFSM?)(((Object)(object)__instance.spellControl != (Object)null) ? ((object)__instance.spellControl) : ((object)((IEnumerable<PlayMakerFSM>)((Component)__instance).GetComponents<PlayMakerFSM>()).FirstOrDefault((Func<PlayMakerFSM, bool>)((PlayMakerFSM f) => (Object)(object)f != (Object)null && (f.FsmName == "Bind" || f.FsmName == "Spell Control"))))), toolDefinition.Name == "Dazzle Bind Upgraded");
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = ((Component)__instance).transform.position + new Vector3(0f, 0f, -0.21f);
					ObjectPoolExtensions.Spawn(val, val2, Quaternion.identity);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void RevengeCrystalTakeDamagePrefix(HeroController __instance)
		{
			_revengeHealthBefore = -1;
			if (!((Object)(object)__instance == (Object)null))
			{
				PlayerData playerData = __instance.playerData;
				if (playerData != null)
				{
					_revengeHealthBefore = playerData.health + playerData.healthBlue;
				}
			}
		}

		public static void RevengeCrystalTakeDamagePostfix(HeroController __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				PlayerData playerData = __instance.playerData;
				if (playerData == null)
				{
					return;
				}
				int revengeHealthBefore = _revengeHealthBefore;
				_revengeHealthBefore = -1;
				if (revengeHealthBefore >= 0 && playerData.health + playerData.healthBlue < revengeHealthBefore)
				{
					string text = "Revenge Crystal";
					ToolEffectSpec toolEffectSpec = EffectsFor(text);
					bool equipped = ToolItemManager.IsToolEquipped(text);
					bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(text) ?? false;
					int effectiveLevel = GetLevel?.Invoke(text) ?? 0;
					int revengeCrystalCount = toolEffectSpec.RevengeCrystalCount;
					bool num = RevengeCrystalRules.ShouldSpawnExtras(equipped, inWhiteSlot, effectiveLevel, revengeCrystalCount);
					int num2 = RevengeCrystalRules.ExtraCount(revengeCrystalCount);
					if (num && num2 > 0)
					{
						SpawnRevengeCrystals?.Invoke(num2);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void RevengeCrystalSpecialDamagePostfix(HeroController __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				string text = "Revenge Crystal";
				ToolEffectSpec toolEffectSpec = EffectsFor(text);
				bool equipped = ToolItemManager.IsToolEquipped(text);
				bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(text) ?? false;
				int effectiveLevel = GetLevel?.Invoke(text) ?? 0;
				int revengeCrystalCount = toolEffectSpec.RevengeCrystalCount;
				bool num = RevengeCrystalRules.ShouldSpawnExtras(equipped, inWhiteSlot, effectiveLevel, revengeCrystalCount);
				int num2 = RevengeCrystalRules.ExtraCount(revengeCrystalCount);
				if (num && num2 > 0)
				{
					SpawnRevengeCrystals?.Invoke(num2);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void ShardsAddPrefix(PlayerData __instance, ref int amount)
		{
			if (amount > 0 && ToolItemManager.IsToolEquipped("Bone Necklace"))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Bone Necklace");
				if (!(toolEffectSpec.ShardValueMultiplier <= 1.0))
				{
					amount = (int)Math.Round((double)amount * toolEffectSpec.ShardValueMultiplier);
				}
			}
		}

		public static void GeoAddPrefix(HeroController __instance, ref int amount)
		{
			if (amount > 0 && ToolItemManager.IsToolEquipped("Rosary Magnet"))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Rosary Magnet");
				if (!(toolEffectSpec.GeoValueMultiplier <= 1.0))
				{
					amount = (int)Math.Round((double)amount * toolEffectSpec.GeoValueMultiplier);
				}
			}
		}

		public static void MaxFallVelocityPostfix(HeroController __instance, ref float __result)
		{
			if (Gameplay.WeightedAnkletTool.Status.IsEquipped)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Weighted Anklet");
				if (!(toolEffectSpec.FallSpeedBonusPercent <= 0.0))
				{
					__result = __instance.MAX_FALL_VELOCITY * (float)(1.0 + toolEffectSpec.FallSpeedBonusPercent);
				}
			}
		}

		public static void WeightedKnockbackMultPostfix(ref float __result)
		{
			if (Gameplay.WeightedAnkletTool.Status.IsEquipped && (GetLevel?.Invoke("Weighted Anklet") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Weighted Anklet").KnockbackMultiplier;
			}
		}

		public static void WeightedInvulnMultPostfix(ref float __result)
		{
			if (Gameplay.WeightedAnkletTool.Status.IsEquipped && (GetLevel?.Invoke("Weighted Anklet") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Weighted Anklet").InvulnMultiplier;
			}
		}

		public static void BarbedWireDealtMultPostfix(ref float __result)
		{
			if (Gameplay.BarbedWireTool.Status.IsEquipped && (GetLevel?.Invoke("Barbed Wire") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Barbed Wire").BarbedWireDamageDealtMultiplier;
			}
		}

		public static void BarbedWireTakenMultPostfix(ref float __result)
		{
			if (Gameplay.BarbedWireTool.Status.IsEquipped)
			{
				Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
				if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Barbed Wire") && EffectsFor("Barbed Wire").BarbedWireWhiteNoDamageTakenMultiplier)
				{
					__result = 1f;
				}
				else if ((GetLevel?.Invoke("Barbed Wire") ?? 0) >= 2)
				{
					__result = (float)EffectsFor("Barbed Wire").BarbedWireDamageTakenMultiplier;
				}
			}
		}

		public static void DeadPurseHoldPercentPostfix(ref float __result)
		{
			if (Gameplay.DeadPurseTool.Status.IsEquipped && (GetLevel?.Invoke("Dead Mans Purse") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Dead Mans Purse").DeadPurseHoldPercent;
			}
		}

		public static void CocoonBrokenMinOneCocoonPrefix(HeroController __instance)
		{
			try
			{
				if (Gameplay.DeadPurseTool.Status.IsEquipped && (GetLevel?.Invoke("Dead Mans Purse") ?? 0) >= 3 && EffectsFor("Dead Mans Purse").DeadPurseMinOneCocoon)
				{
					PlayerData val = __instance.playerData ?? PlayerData.instance;
					if (val != null && val.HeroCorpseMoneyPool == 0 && val.geo > 0)
					{
						val.geo--;
						val.HeroCorpseMoneyPool = 1;
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void CompassStoragePostfix(ToolItem __instance, ref int __result)
		{
			if ((Object)(object)__instance == (Object)null || !IsCompassEquippedAnywhere())
			{
				return;
			}
			int num = GetLevel?.Invoke("Compass") ?? 0;
			if (num < 2 || !IsCogworkStorageTool(__instance.name))
			{
				return;
			}
			__result = ((num >= 3) ? 12 : 8);
			if (__result != _lastLoggedCompassCap)
			{
				_lastLoggedCompassCap = __result;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[CompassStorage] cogfly capacity -> {__result} (level {num}).");
				}
			}
		}

		public static void ToolReplenishCostPostfix(ref int __result)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Shell Satchel") && EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost)
			{
				__result = 1;
			}
		}

		public static void ReplenishUsageMultiplierPostfix(ref float __result)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Shell Satchel") && EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost)
			{
				__result = 1f;
			}
		}

		public static void LuckyDiceThresholdPostfix(int hits, ref int __result)
		{
			if (Gameplay.LuckyDiceTool.Status.IsEquipped)
			{
				int num = GetLevel?.Invoke("Magnetite Dice") ?? 0;
				if (num >= 2)
				{
					int num2 = ((num >= 3) ? 8 : 4);
					__result = Math.Min(hits * num2, num2 * 5);
				}
			}
		}

		public static void LuckyDiceTakeDamagePrefix(HeroController __instance, ref int __state)
		{
			__state = ((_luckyDiceShieldedHits != null && (Object)(object)__instance != (Object)null) ? ((int)(_luckyDiceShieldedHits.GetValue(__instance) ?? ((object)0))) : 0);
		}

		public static void LuckyDiceTakeDamagePostfix(HeroController __instance, HazardType hazardType, int __state)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if ((Object)(object)__instance == (Object)null || __state <= 0 || (int)hazardType != 1)
			{
				return;
			}
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Magnetite Dice") || !EffectsFor("Magnetite Dice").LuckyDiceWhiteNoReset || _luckyDiceShieldedHits == null)
			{
				return;
			}
			try
			{
				if ((int)(_luckyDiceShieldedHits.GetValue(__instance) ?? ((object)0)) == 0)
				{
					_luckyDiceShieldedHits.SetValue(__instance, __state);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void IsWandererLuckyDicePostfix(HeroController __instance, ref bool __result)
		{
			if (!__result && !((Object)(object)__instance == (Object)null) && !__instance.cState.isMaggoted && ShouldForceDiceLucky(Gameplay.LuckyDiceTool.Status.IsEquipped, GetLevel?.Invoke("Magnetite Dice") ?? 0, IsDiceCritWindow))
			{
				__result = true;
			}
		}

		public static void DoDamagePrefix(GameObject target, bool isFirstHit)
		{
			if (ShouldForceDiceLucky(Gameplay.LuckyDiceTool.Status.IsEquipped, GetLevel?.Invoke("Magnetite Dice") ?? 0, inCritWindow: true))
			{
				IsDiceCritWindow = true;
			}
		}

		public static void DoDamagePostfix(GameObject target, bool isFirstHit)
		{
			IsDiceCritWindow = false;
		}

		public static void DoDamageFinalizer(GameObject target, bool isFirstHit, Exception __exception)
		{
			IsDiceCritWindow = false;
		}

		public static void WandererCritChanceDicePostfix(ref float __result)
		{
			if (Gameplay.LuckyDiceTool.Status.IsEquipped && (GetLevel?.Invoke("Magnetite Dice") ?? 0) >= 2)
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Magnetite Dice");
				double num = toolEffectSpec.LuckyDiceCritChance;
				HeroController instance = HeroController.instance;
				if ((Object)(object)instance != (Object)null && ((ToolBase)Gameplay.WandererCrest).IsEquipped && instance.playerData != null && instance.playerData.silk >= 9)
				{
					num += toolEffectSpec.LuckyDiceWandererCritBonus;
				}
				__result = (float)num;
			}
		}

		public static void GetLuckModifierDicePostfix(ref float __result)
		{
			if (Gameplay.LuckyDiceTool.Status.IsEquipped && (GetLevel?.Invoke("Magnetite Dice") ?? 0) >= 2)
			{
				__result = 1f;
			}
		}

		public static void MusicianRangeMultPostfix(ref float __result)
		{
			if (Gameplay.MusicianCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Musician Charm") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Musician Charm").MusicianRangeMultiplier;
			}
		}

		public static void MusicianDrainTimeMultPostfix(ref float __result)
		{
			if (Gameplay.MusicianCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Musician Charm") ?? 0) >= 2)
			{
				__result = (float)EffectsFor("Musician Charm").MusicianSongTimeMultiplier;
			}
		}

		public static void SilkDrainDisabledPostfix(ref bool __result)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Sprintmaster") && EffectsFor("Sprintmaster").SprintmasterWhiteNoSilkCost)
			{
				__result = true;
			}
		}

		public static void ThiefSmallGeoIncreasePostfix(ref float __result)
		{
			ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefSmallGeoIncrease);
		}

		public static void ThiefMedGeoIncreasePostfix(ref float __result)
		{
			ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefMedGeoIncrease);
		}

		public static void ThiefLargeGeoIncreasePostfix(ref float __result)
		{
			ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefLargeGeoIncrease);
		}

		public static void ThiefGeoLossPostfix(ref object __result)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Thief Charm") && EffectsFor("Thief Charm").ThiefWhiteNoLoss && _zeroMinMaxFloat != null)
			{
				__result = _zeroMinMaxFloat;
			}
		}

		public static void ThiefGeoLossLooseChancePostfix(ref float __result)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Thief Charm") && EffectsFor("Thief Charm").ThiefWhiteNoLoss)
			{
				__result = 0f;
			}
		}

		public static bool TakeSilkClawlinePrefix(HeroController __instance, int amount, SilkTakeSource source)
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Thief Claw"))
			{
				return true;
			}
			if (!EffectsFor("Thief Claw").ClawlineNoSilkCost)
			{
				return true;
			}
			try
			{
				object obj = _heroCState?.GetValue(__instance);
				if (obj != null && _whipLashing != null && (bool)(_whipLashing.GetValue(obj) ?? ((object)false)))
				{
					return false;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			return true;
		}

		public static void ThrowToolPrefix(HeroController __instance, bool isAutoThrow)
		{
			try
			{
				if (!Gameplay.QuickSlingTool.Status.IsEquipped)
				{
					Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
					if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Quick Sling"))
					{
						goto IL_0033;
					}
				}
				if (!ToolItemManager.IsCustomToolOverride)
				{
					object? obj = _willThrowTool?.GetValue(__instance);
					ToolItem val = (ToolItem)((obj is ToolItem) ? obj : null);
					if ((Object)(object)val == (Object)null)
					{
						_quickSlingRemaining = 0;
						_quickSlingTool = null;
						return;
					}
					ToolEffectSpec toolEffectSpec = EffectsFor("Quick Sling");
					int num = ((toolEffectSpec.QuickSlingThrowCount > 0) ? toolEffectSpec.QuickSlingThrowCount : 2);
					if (QuickSlingWhiteSlotRules.ShouldApplyWhiteSlotModifier(toolEffectSpec, IsEquippedInWhiteSlot?.Invoke("Quick Sling") ?? false, val.name))
					{
						_quickSlingRemaining = 0;
						_quickSlingTool = null;
						if (!isAutoThrow)
						{
							_pendingWhiteSlotTool = val.name;
							_pendingWhiteSlotMultiplier = (string.Equals(val.name, "Lifeblood Syringe", StringComparison.Ordinal) ? ((double)QuickSlingWhiteSlotRules.SyringeBlueHealth(toolEffectSpec)) : QuickSlingWhiteSlotRules.DurationMultiplier(toolEffectSpec));
						}
					}
					else if (QuickSlingWhiteSlotRules.ShouldStartThrowChain(isWhiteSlotModifiedTool: false, num))
					{
						_quickSlingTool = val;
						if (!isAutoThrow)
						{
							_quickSlingRemaining = num - 1;
						}
					}
					else
					{
						_quickSlingRemaining = 0;
						_quickSlingTool = null;
					}
					return;
				}
				goto IL_0033;
				IL_0033:
				_quickSlingRemaining = 0;
				_quickSlingTool = null;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void ThrowToolPostfix(HeroController __instance, bool isAutoThrow)
		{
			try
			{
				if (_quickSlingRemaining <= 0)
				{
					return;
				}
				if (!Gameplay.QuickSlingTool.Status.IsEquipped)
				{
					Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
					if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Quick Sling"))
					{
						goto IL_0040;
					}
				}
				if (!ToolItemManager.IsCustomToolOverride)
				{
					if (isAutoThrow)
					{
						object? obj = _willThrowTool?.GetValue(__instance);
						if ((Object)((obj is ToolItem) ? obj : null) != (Object)null)
						{
							_quickSlingRemaining = 0;
							_quickSlingTool = null;
							_queuedAutoThrowTool?.SetValue(__instance, false);
						}
						else if (_quickSlingRemaining > 1 && (Object)(object)_quickSlingTool != (Object)null)
						{
							_quickSlingRemaining--;
							_willThrowTool?.SetValue(__instance, _quickSlingTool);
							_queuedAutoThrowTool?.SetValue(__instance, true);
						}
						else
						{
							_quickSlingRemaining = 0;
							_quickSlingTool = null;
						}
					}
					return;
				}
				goto IL_0040;
				IL_0040:
				_quickSlingRemaining = 0;
				_quickSlingTool = null;
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void ThrowToolEndPostfix(HeroController __instance)
		{
			if (_quickSlingRemaining <= 0)
			{
				_quickSlingTool = null;
			}
		}

		public static void ActivateQuickeningPostfix(HeroController __instance)
		{
			if (_pendingWhiteSlotTool != "Flea Brew" || _quickeningTimeLeft == null)
			{
				return;
			}
			try
			{
				if (!(_pendingWhiteSlotMultiplier <= 1.0))
				{
					float num = (float)(_quickeningTimeLeft.GetValue(__instance) ?? ((object)0f));
					_quickeningTimeLeft.SetValue(__instance, num * (float)_pendingWhiteSlotMultiplier);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			finally
			{
				ClearPendingWhiteSlot();
			}
		}

		public static void NailImbuementSetElementPostfix(HeroNailImbuement __instance)
		{
			if (_pendingWhiteSlotTool != "Flintstone" || _imbuementTimeLeft == null)
			{
				return;
			}
			try
			{
				if (!(_pendingWhiteSlotMultiplier <= 1.0))
				{
					float num = (float)(_imbuementTimeLeft.GetValue(__instance) ?? ((object)0f));
					_imbuementTimeLeft.SetValue(__instance, num * (float)_pendingWhiteSlotMultiplier);
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			finally
			{
				ClearPendingWhiteSlot();
			}
		}

		public static void OnToolUsed(ToolUsedEvent toolUsed)
		{
			if (!(_pendingWhiteSlotTool != "Lifeblood Syringe") && string.Equals(toolUsed.ToolName, "Lifeblood Syringe", StringComparison.Ordinal))
			{
				int num = Math.Max(1, (int)Math.Round(_pendingWhiteSlotMultiplier));
				int num2 = Math.Max(0, num - 1);
				if (num2 > 0)
				{
					AddExtraBlueHealth?.Invoke(num2);
				}
				ClearPendingWhiteSlot();
			}
		}

		private static void ClearPendingWhiteSlot()
		{
			_pendingWhiteSlotTool = null;
			_pendingWhiteSlotMultiplier = 1.0;
		}

		private static void ClearQuickSling(HeroController? hero = null)
		{
			bool flag = _quickSlingRemaining > 0 || (Object)(object)_quickSlingTool != (Object)null;
			_quickSlingRemaining = 0;
			_quickSlingTool = null;
			if ((Object)(object)hero == (Object)null || !flag)
			{
				return;
			}
			try
			{
				_queuedAutoThrowTool?.SetValue(hero, false);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static bool AddToMaggotCharmTimerPrefix()
		{
			return !MaggotImmuneActive();
		}

		public static bool DidMaggotCharmHitPrefix()
		{
			return !MaggotImmuneActive();
		}

		public static bool IsMaggotRepairOnHealActive()
		{
			if (ToolItemManager.IsToolEquipped("Maggot Charm"))
			{
				return EffectsFor("Maggot Charm").MaggotRepairOnHeal;
			}
			return false;
		}

		public static bool IsMaggotRepairOnKillActive()
		{
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Maggot Charm"))
			{
				return EffectsFor("Maggot Charm").MaggotRepairOnKill;
			}
			return false;
		}

		public static void ResetMaggotCharmNow()
		{
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null || _resetMaggotCharm == null)
			{
				return;
			}
			try
			{
				_resetMaggotCharm.Invoke(instance, null);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static bool DoMossToolHitPrefix(HeroController __instance)
		{
			try
			{
				PlayerData instance = PlayerData.instance;
				if (instance == null || instance.health <= 0 || instance.silk >= instance.CurrentSilkMax)
				{
					return true;
				}
				if (HandleMossTool(__instance, Gameplay.MossCreep1Tool, _moss1Hits, 1))
				{
					return false;
				}
				if (HandleMossTool(__instance, Gameplay.MossCreep2Tool, _moss2Hits, 2))
				{
					return false;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			return true;
		}

		public static bool HeroTakeDamagePrefix(HeroController __instance, ref int damageAmount, HazardType hazardType, DamagePropertyFlags damagePropertyFlags)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (HealUninterruptibleActive(__instance))
				{
					return false;
				}
				ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm");
				if (toolDefinition != null && ((int)hazardType == 4 || (damagePropertyFlags & 4) != 0))
				{
					int level = GetLevel?.Invoke("Lava Charm") ?? 0;
					bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false;
					if (toolDefinition.ResolveEffects(level, inWhiteSlot).LavaDamageImmune)
					{
						damageAmount = 0;
					}
				}
				ToolDefinition toolDefinition2 = ToolCatalog.Find("Weighted Anklet");
				if (toolDefinition2 != null)
				{
					int level2 = GetLevel?.Invoke("Weighted Anklet") ?? 0;
					bool inWhiteSlot2 = IsEquippedInWhiteSlot?.Invoke("Weighted Anklet") ?? false;
					if (toolDefinition2.ResolveEffects(level2, inWhiteSlot2).TwoDamageToOne && damageAmount == 2)
					{
						damageAmount = 1;
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
			return true;
		}

		public static bool CanBeGrabbedPrefix(HeroController __instance, bool ignoreParryState, ref bool __result)
		{
			if (HealUninterruptibleActive(__instance))
			{
				__result = false;
				return false;
			}
			return true;
		}

		public static bool CanBeBarnacleGrabbedPrefix(HeroController __instance, ref bool __result)
		{
			if (HealUninterruptibleActive(__instance))
			{
				__result = false;
				return false;
			}
			return true;
		}

		private static bool HealUninterruptibleActive(HeroController hero)
		{
			if ((Object)(object)hero == (Object)null || hero.cState == null)
			{
				return false;
			}
			if (!hero.cState.focusing && !hero.cState.isBinding)
			{
				return false;
			}
			Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
			if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Bone Necklace"))
			{
				return false;
			}
			return EffectsFor("Bone Necklace").HealUninterruptible;
		}

		public static void UseLavaBellPostfix(HeroController __instance)
		{
			try
			{
				ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm");
				if (!(toolDefinition == null))
				{
					int level = GetLevel?.Invoke("Lava Charm") ?? 0;
					bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false;
					int lavaCooldownSeconds = toolDefinition.ResolveEffects(level, inWhiteSlot).LavaCooldownSeconds;
					if (lavaCooldownSeconds > 0)
					{
						_lavaCooldown?.SetValue(__instance, (float)lavaCooldownSeconds);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static bool TakeFrostDamagePrefix()
		{
			return !ColdDebuffImmune();
		}

		public static bool AddFrostPrefix()
		{
			return !ColdDebuffImmune();
		}

		public static bool SetFrostAmountPrefix()
		{
			return !ColdDebuffImmune();
		}

		public static void DamageTagOnHitPrefix(DamageTag __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Gameplay.PoisonPouchDamageTag)
			{
				_pendingPoisonMultiplier = (GetLevel?.Invoke("Poison Pouch") ?? 0) switch
				{
					2 => 2.0, 
					3 => 3.0, 
					_ => 1.0, 
				};
			}
		}

		public static void HealthManagerApplyTagDamagePrefix(ref DamageTagInstance damageTagInstance)
		{
			if (_pendingPoisonMultiplier > 1.0)
			{
				damageTagInstance.amount = (int)Math.Round((double)damageTagInstance.amount * _pendingPoisonMultiplier);
				_pendingPoisonMultiplier = 1.0;
			}
		}

		public static void TagDamageTakerAddDamageTagToStackPostfix(TagDamageTaker __instance, DamageTag damageTag, int hitAmountOverride)
		{
			if (hitAmountOverride <= 0 || (Object)(object)damageTag != (Object)(object)Gameplay.PoisonPouchDamageTag)
			{
				return;
			}
			ToolDefinition toolDefinition = ToolCatalog.Find("Poison Pouch");
			if (toolDefinition == null)
			{
				return;
			}
			int level = GetLevel?.Invoke("Poison Pouch") ?? 0;
			bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Poison Pouch") ?? false;
			if (!toolDefinition.ResolveEffects(level, inWhiteSlot).PoisonStacking)
			{
				return;
			}
			try
			{
				if (_taggedDamage?.GetValue(__instance) is Dictionary<DamageTag, DamageTagInfo> dictionary && dictionary.TryGetValue(damageTag, out var value))
				{
					DamageTagInfo obj = value;
					obj.HitsLeft += hitAmountOverride;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static bool HandleMossTool(HeroController hero, ToolItem tool, FieldInfo? hitsField, int silk)
		{
			if ((Object)(object)tool == (Object)null)
			{
				return false;
			}
			string name = tool.name;
			if (!WhiteToolSystem.IsEquippedAnywhere(name))
			{
				return false;
			}
			int num = GetLevel?.Invoke(name) ?? 0;
			bool flag = IsEquippedInWhiteSlot?.Invoke(name) ?? false;
			ToolEffectSpec toolEffectSpec = ToolCatalog.Find(name)?.ResolveEffects(num, flag) ?? ToolEffectSpec.None;
			if (num == 0 && !flag)
			{
				return false;
			}
			int num2 = MossRules.PerHitSpools(toolEffectSpec.MossSpoolsPerHit, silk);
			if (toolEffectSpec.MossSilkPerWhiteHit > 0)
			{
				hero.AddSilk(toolEffectSpec.MossSilkPerWhiteHit, false, (SilkAddSource)1);
				hitsField?.SetValue(hero, 0);
				GameCameras.instance.silkSpool.SetMossState(0, 1);
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=white-direct silk={toolEffectSpec.MossSilkPerWhiteHit}"));
				}
				return true;
			}
			int num3 = (int)(hitsField?.GetValue(hero) ?? ((object)0)) + 1;
			if (num3 >= 2)
			{
				hitsField?.SetValue(hero, 0);
				hero.AddSilk(num2, false, (SilkAddSource)1);
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=convert silk={num2}"));
				}
			}
			else
			{
				hitsField?.SetValue(hero, num3);
				GameCameras.instance.silkSpool.SetMossState(1, num2);
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=spools count={num2}"));
				}
			}
			return true;
		}

		private static bool ColdDebuffImmune()
		{
			ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm");
			if (toolDefinition == null)
			{
				return false;
			}
			int level = GetLevel?.Invoke("Lava Charm") ?? 0;
			bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false;
			return toolDefinition.ResolveEffects(level, inWhiteSlot).ColdDebuffImmune;
		}

		public static ToolEffectSpec EffectsFor(string toolName)
		{
			ToolDefinition toolDefinition = ToolCatalog.Find(toolName);
			if (toolDefinition == null)
			{
				return ToolEffectSpec.None;
			}
			int level = GetLevel?.Invoke(toolName) ?? 0;
			bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(toolName) ?? false;
			return toolDefinition.ResolveEffects(level, inWhiteSlot);
		}

		private static bool IsWitchCrest()
		{
			return string.Equals(HeroController.instance?.playerData?.CurrentCrestID, "Witch", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsBrollyHit(HitInstance hit)
		{
			//IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hit.RepresentingTool != (Object)null && string.Equals(hit.RepresentingTool.name, "Brolly Spike", StringComparison.Ordinal))
			{
				return true;
			}
			if ((Object)(object)hit.Source != (Object)null)
			{
				return ((Object)hit.Source).name.IndexOf("Brolly", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool IsDazzleHit(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hit.RepresentingTool != (Object)null && (string.Equals(hit.RepresentingTool.name, "Dazzle Bind", StringComparison.Ordinal) || string.Equals(hit.RepresentingTool.name, "Dazzle Bind Upgraded", StringComparison.Ordinal)))
			{
				return true;
			}
			if ((Object)(object)hit.Source != (Object)null)
			{
				return ((Object)hit.Source).name.IndexOf("dazzle", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		public static bool IsBellBindSource(string? toolName, string? sourceName)
		{
			if (!string.IsNullOrEmpty(toolName) && string.Equals(toolName, "Bell Bind", StringComparison.Ordinal))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(sourceName))
			{
				if (sourceName.IndexOf("bell", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return sourceName.IndexOf("shield", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool IsBellBindHit(HitInstance hit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ToolItem representingTool = hit.RepresentingTool;
			string toolName = ((representingTool != null) ? representingTool.name : null);
			GameObject source = hit.Source;
			return IsBellBindSource(toolName, (source != null) ? ((Object)source).name : null);
		}

		public static void BellBindHitPrefix(ref HitInstance hitInstance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (IsBellBindHit(hitInstance) && ToolItemManager.IsToolEquipped("Bell Bind") && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Bell Bind");
				if (!(toolEffectSpec.DamageMultiplier <= 1.0))
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier);
				}
			}
		}

		private static ToolDefinition? FindDazzleDefinition()
		{
			string text = DazzleWhiteRules.SelectDefinitionName(WhiteToolSystem.IsEquippedAnywhere("Dazzle Bind Upgraded"), WhiteToolSystem.IsEquippedAnywhere("Dazzle Bind"));
			if (text != null)
			{
				return ToolCatalog.Find(text);
			}
			return null;
		}

		private static GameObject? ReadDazzleFlashPrefab(PlayMakerFSM? bindFsm, bool isUpgraded)
		{
			if ((Object)(object)bindFsm == (Object)null)
			{
				return null;
			}
			FsmState state = FsmUtil.GetState(bindFsm, "Dazzle?");
			if (state == null)
			{
				return null;
			}
			string text = (isUpgraded ? "Dazzle Flash Upgraded" : "Dazzle Flash");
			FsmStateAction[] actions = state.Actions;
			foreach (FsmStateAction obj in actions)
			{
				SetGameObject val = (SetGameObject)(object)((obj is SetGameObject) ? obj : null);
				if (val != null && val.variable != null && ((NamedVariable)val.variable).Name == text && val.gameObject != null)
				{
					return val.gameObject.Value;
				}
			}
			return null;
		}

		private static bool MaggotImmuneActive()
		{
			if (ToolItemManager.IsToolEquipped("Maggot Charm"))
			{
				return EffectsFor("Maggot Charm").MaggotImmune;
			}
			return false;
		}

		private static void ApplyNailChargeFactor(HeroController hero, ref float result, float baseValue)
		{
			if (ToolItemManager.IsToolEquipped("Pinstress Tool"))
			{
				ToolEffectSpec toolEffectSpec = EffectsFor("Pinstress Tool");
				if (!(toolEffectSpec.NailChargeTimeFactor <= 0.0) && !(toolEffectSpec.NailChargeTimeFactor >= 1.0))
				{
					result = (float)((double)baseValue * toolEffectSpec.NailChargeTimeFactor);
				}
			}
		}

		private static void SetWispCooldown(HeroWispLantern instance, float seconds)
		{
			if (_wispCooldownField == null || _minMaxStartField == null || _minMaxEndField == null)
			{
				return;
			}
			try
			{
				if (!_wispCooldownCache.TryGetValue(instance, out WispCooldownCache value))
				{
					object value2 = _wispCooldownField.GetValue(instance);
					value = new WispCooldownCache
					{
						Min = (float)_minMaxStartField.GetValue(value2),
						Max = (float)_minMaxEndField.GetValue(value2)
					};
					_wispCooldownCache.Add(instance, value);
				}
				object value3 = _wispCooldownField.GetValue(instance);
				_minMaxStartField.SetValue(value3, seconds);
				_minMaxEndField.SetValue(value3, seconds);
				_wispCooldownField.SetValue(instance, value3);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void RestoreWispCooldown(HeroWispLantern instance)
		{
			if (_wispCooldownField == null || _minMaxStartField == null || _minMaxEndField == null || !_wispCooldownCache.TryGetValue(instance, out WispCooldownCache value))
			{
				return;
			}
			try
			{
				object value2 = _wispCooldownField.GetValue(instance);
				_minMaxStartField.SetValue(value2, value.Min);
				_minMaxEndField.SetValue(value2, value.Max);
				_wispCooldownField.SetValue(instance, value2);
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		private static void ApplyThiefGeoIncrease(ref float result, Func<ToolEffectSpec, double> selector)
		{
			if (Gameplay.ThiefCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Thief Charm") ?? 0) >= 2)
			{
				double num = selector(EffectsFor("Thief Charm"));
				if (num > 0.0)
				{
					result = (float)num;
				}
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[BlueToolEffects] patch failed: " + ex.Message));
				}
			}
		}
	}
	public static class CogflyAutoReleasePatch
	{
		public static Func<bool>? IsEnabled;

		public static CogflySpawner? Spawner;

		public static void Tick()
		{
			Func<bool>? isEnabled = IsEnabled;
			if (isEnabled != null && isEnabled() && Spawner != null)
			{
				Spawner.Tick();
			}
		}

		public static void OnSceneChanged()
		{
			Spawner?.OnSceneChanged();
		}
	}
	public static class FlintBrewStackBridge
	{
		public static Func<bool>? IsActive;

		public static FlintBrewStackState FlintState { get; } = new FlintBrewStackState();

		public static FlintBrewStackState BrewState { get; } = new FlintBrewStackState();

		public static bool IsEnabled => IsActive?.Invoke() ?? false;
	}
	public static class FlintBrewStackPatch
	{
		private static FieldRef<HeroNailImbuement, float>? _imbuementTimeLeftRef;

		private static FieldRef<HeroController, float>? _quickeningTimeLeftRef;

		private static bool _warned;

		public static void Configure(ManualLogSource log)
		{
			_warned = false;
			_imbuementTimeLeftRef = AccessTools.FieldRefAccess<HeroNailImbuement, float>("imbuementTimeLeft");
			_quickeningTimeLeftRef = AccessTools.FieldRefAccess<HeroController, float>("quickeningTimeLeft");
		}

		public static void SetElementPrefix(HeroNailImbuement __instance, ref float __state)
		{
			__state = ((_imbuementTimeLeftRef != null) ? _imbuementTimeLeftRef.Invoke(__instance) : 0f);
		}

		public static void SetElementPostfix(HeroNailImbuement __instance, NailElements element, float __state)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if (!FlintBrewStackBridge.IsEnabled)
			{
				return;
			}
			if ((int)element == 0)
			{
				FlintBrewStackBridge.FlintState.Reset();
			}
			else
			{
				if ((int)element != 1)
				{
					return;
				}
				try
				{
					float num = FlintBrewStackBridge.FlintState.AddUse();
					if (num > 0f && _imbuementTimeLeftRef != null)
					{
						_imbuementTimeLeftRef.Invoke(__instance) = __state + num;
					}
				}
				catch (Exception ex)
				{
					WarnOnce(ex);
				}
			}
		}

		public static void ActivateQuickeningPrefix(HeroController __instance, ref float __state)
		{
			__state = ((_quickeningTimeLeftRef != null) ? _quickeningTimeLeftRef.Invoke(__instance) : 0f);
		}

		public static void ActivateQuickeningPostfix(HeroController __instance, float __state)
		{
			if (!FlintBrewStackBridge.IsEnabled)
			{
				return;
			}
			try
			{
				float num = FlintBrewStackBridge.BrewState.AddUse();
				if (num > 0f && _quickeningTimeLeftRef != null)
				{
					_quickeningTimeLeftRef.Invoke(__instance) = __state + num;
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void StopQuickeningPostfix(HeroController __instance)
		{
			if (FlintBrewStackBridge.IsEnabled)
			{
				FlintBrewStackBridge.BrewState.Reset();
			}
		}

		public static void QuickAttackSpeedMultPostfix(HeroControllerConfig __instance, ref float __result)
		{
			if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.BrewState.Stacks > 1)
			{
				HeroController instance = HeroController.instance;
				if (!((Object)(object)instance == (Object)null) && instance.Config == __instance && instance.IsUsingQuickening)
				{
					__result *= FlintBrewStackBridge.BrewState.Stacks;
				}
			}
		}

		public static void QuickAttackCooldownTimePostfix(HeroControllerConfig __instance, ref float __result)
		{
			if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.BrewState.Stacks > 1)
			{
				HeroController instance = HeroController.instance;
				if (!((Object)(object)instance == (Object)null) && instance.Config == __instance && instance.IsUsingQuickening && __result > 0f)
				{
					__result /= FlintBrewStackBridge.BrewState.Stacks;
				}
			}
		}

		public static void HitPrefix(ref HitInstance hitInstance)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.FlintState.Stacks > 1 && !((Object)(object)hitInstance.NailImbuement == (Object)null))
			{
				HeroController instance = HeroController.instance;
				if (!((Object)(object)((instance != null) ? instance.NailImbuement : null) == (Object)null) && (int)instance.NailImbuement.CurrentElement == 1 && hitInstance.NailImbuement == instance.NailImbuement.CurrentImbuement)
				{
					hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * (double)FlintBrewStackBridge.FlintState.Stacks);
				}
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				Debug.LogWarning((object)("[FlintBrewStack] patch failed: " + ex.Message));
			}
		}
	}
	public static class FracturedMaskBreakPatch
	{
		public static void Prefix(PlayerData __instance, ref int __state)
		{
			__state = ReadAmountLeft();
		}

		public static void Postfix(PlayerData __instance, int __state)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (__state <= 0 || ReadAmountLeft() != 0)
			{
				return;
			}
			Func<bool> isEquipped = FracturedMaskBridge.IsEquipped;
			if (isEquipped == null || !isEquipped())
			{
				return;
			}
			Func<bool> tryRepair = FracturedMaskBridge.TryRepair;
			if (tryRepair == null || !tryRepair())
			{
				return;
			}
			ToolItem fracturedMaskTool = Gameplay.FracturedMaskTool;
			if (!((Object)(object)fracturedMaskTool == (Object)null))
			{
				Data savedData = fracturedMaskTool.SavedData;
				savedData.AmountLeft = ToolItemManager.GetToolStorageAmount(fracturedMaskTool);
				if (savedData.AmountLeft <= 0)
				{
					savedData.AmountLeft = 1;
				}
				fracturedMaskTool.SavedData = savedData;
				EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null);
			}
		}

		private static int ReadAmountLeft()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ToolItem fracturedMaskTool = Gameplay.FracturedMaskTool;
				return ((Object)(object)fracturedMaskTool != (Object)null) ? fracturedMaskTool.SavedData.AmountLeft : 0;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[FracturedMask] AmountLeft read failed: " + ex.Message));
				return -1;
			}
		}
	}
	public static class MagnetiteDiceMagnetPatch
	{
		private sealed class MagnetDelayCache
		{
			public bool Stored;

			public float StartDelayMin;

			public float StartDelayMax;

			public float AttractDelayMin;

			public float AttractDelayMax;

			public float StartMoveDuration;
		}

		public static Func<string, int>? GetLevel;

		public static Func<string, bool>? IsEquippedInWhiteSlot;

		private static ManualLogSource? _log;

		private static bool _warned;

		private static FieldInfo? _startDelayField;

		private static FieldInfo? _attractDelayField;

		private static FieldInfo? _startMoveDurationField;

		private static FieldInfo? _minMaxStartField;

		private static FieldInfo? _minMaxEndField;

		private static readonly ConditionalWeakTable<CurrencyObjectBase, MagnetDelayCache> _cache = new ConditionalWeakTable<CurrencyObjectBase, MagnetDelayCache>();

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
			_startDelayField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetStartDelay");
			_attractDelayField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetAttractDelay");
			_startMoveDurationField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetStartMoveDuration");
			Type type = Type.GetType("TeamCherry.SharedUtils.MinMaxFloat, TeamCherry.SharedUtils");
			if (type != null)
			{
				_minMaxStartField = AccessTools.Field(type, "Start");
				_minMaxEndField = AccessTools.Field(type, "End");
			}
		}

		public static void OnToolEquipsUpdatedPrefix(CurrencyObjectBase __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				int num = GetLevel?.Invoke("Magnetite Dice") ?? 0;
				bool num2 = num >= 2 && Gameplay.LuckyDiceTool.Status.IsEquipped;
				ToolEffectSpec toolEffectSpec = ToolCatalog.Find("Magnetite Dice")?.ResolveEffects(num, inWhiteSlot: false) ?? ToolEffectSpec.None;
				MagnetDelayCache orCreateValue = _cache.GetOrCreateValue(__instance);
				if (!orCreateValue.Stored)
				{
					orCreateValue.Stored = true;
					orCreateValue.StartDelayMin = ReadMin(_startDelayField, __instance);
					orCreateValue.StartDelayMax = ReadMax(_startDelayField, __instance);
					orCreateValue.AttractDelayMin = ReadMin(_attractDelayField, __instance);
					orCreateValue.AttractDelayMax = ReadMax(_attractDelayField, __instance);
					orCreateValue.StartMoveDuration = ((_startMoveDurationField != null) ? ((float)(_startMoveDurationField.GetValue(__instance) ?? ((object)0f))) : 0f);
				}
				if (!num2)
				{
					Restore(__instance, orCreateValue);
				}
				else if (toolEffectSpec.LuckyDiceMagnetInstant)
				{
					WriteMinMax(_startDelayField, __instance, 0f, 0f);
					WriteMinMax(_attractDelayField, __instance, 0f, 0f);
					if (_startMoveDurationField != null)
					{
						_startMoveDurationField.SetValue(__instance, 0f);
					}
				}
				else
				{
					double luckyDiceMagnetDelayFactor = toolEffectSpec.LuckyDiceMagnetDelayFactor;
					if (luckyDiceMagnetDelayFactor > 0.0 && luckyDiceMagnetDelayFactor < 1.0)
					{
						WriteMinMax(_startDelayField, __instance, orCreateValue.StartDelayMin * (float)luckyDiceMagnetDelayFactor, orCreateValue.StartDelayMax * (float)luckyDiceMagnetDelayFactor);
						WriteMinMax(_attractDelayField, __instance, orCreateValue.AttractDelayMin * (float)luckyDiceMagnetDelayFactor, orCreateValue.AttractDelayMax * (float)luckyDiceMagnetDelayFactor);
					}
				}
			}
			catch (Exception ex)
			{
				WarnOnce(ex);
			}
		}

		public static void MagnetToolIsEquippedPostfix(CurrencyObjectBase __instance, ref bool __result)
		{
			if (!__result && __instance is ShellShard)
			{
				Func<string, bool>? isEquippedInWhiteSlot = IsEquippedInWhiteSlot;
				if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Rosary Magnet"))
				{
					__result = true;
				}
			}
		}

		private static void Restore(CurrencyObjectBase instance, MagnetDelayCache cache)
		{
			WriteMinMax(_startDelayField, instance, cache.StartDelayMin, cache.StartDelayMax);
			WriteMinMax(_attractDelayField, instance, cache.AttractDelayMin, cache.AttractDelayMax);
			if (_startMoveDurationField != null)
			{
				_startMoveDurationField.SetValue(instance, cache.StartMoveDuration);
			}
		}

		private static float ReadMin(FieldInfo? field, CurrencyObjectBase instance)
		{
			if (field == null || _minMaxStartField == null)
			{
				return 0f;
			}
			object value = field.GetValue(instance);
			if (value != null)
			{
				return (float)(_minMaxStartField.GetValue(value) ?? ((object)0f));
			}
			return 0f;
		}

		private static float ReadMax(FieldInfo? field, CurrencyObjectBase instance)
		{
			if (field == null || _minMaxEndField == null)
			{
				return 0f;
			}
			object value = field.GetValue(instance);
			if (value != null)
			{
				return (float)(_minMaxEndField.GetValue(value) ?? ((object)0f));
			}
			return 0f;
		}

		private static void WriteMinMax(FieldInfo? field, CurrencyObjectBase instance, float min, float max)
		{
			if (!(field == null) && !(_minMaxStartField == null) && !(_minMaxEndField == null))
			{
				object value = field.GetValue(instance);
				if (value != null)
				{
					_minMaxStartField.SetValue(value, min);
					_minMaxEndField.SetValue(value, max);
				}
			}
		}

		private static void WarnOnce(Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[MagnetiteDice] magnet patch disabled: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	public static class MultibindFsmPatch
	{
		private sealed class ActionValueCache
		{
			public bool Stored;

			public bool IsInt;

			public bool IsFloat;

			public int OriginalInt;

			public float OriginalFloat;
		}

		private sealed class MultibindFsmMarker : MonoBehaviour
		{
		}

		public static Func<string, int>? GetLevel;

		public static Func<string, bool>? IsEquippedInWhiteSlot;

		public static Func<string, bool>? IsEquipped;

		private static ManualLogSource? _log;

		private static bool _warned;

		private static readonly List<PlayMakerFSM> _patched = new List<PlayMakerFSM>();

		private static readonly ConditionalWeakTable<FsmStateAction, ActionValueCache> _cache = new ConditionalWeakTable<FsmStateAction, ActionValueCache>();

		public static void Configure(ManualLogSource log)
		{
			_log = log;
			_warned = false;
		}

		public static void OnFsmStart(PlayMakerFSM __instance)
		{
			if ((Object)(object)__instance == (Object)null || __instance.Fsm == null)
			{
				return;
			}
			string fsmName = __instance.FsmName;
			if ((fsmName != "Bind" && fsmName != "Spell Control") || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal))
			{