Decompiled source of Loop The Gungeon v1.1.2

LoopTheGungeon.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Alexandria.CharacterAPI;
using Alexandria.DungeonAPI;
using Alexandria.ItemAPI;
using Alexandria.Misc;
using Alexandria.NPCAPI;
using BepInEx;
using BepInEx.Logging;
using Brave.BulletScript;
using Dungeonator;
using Gunfiguration;
using HarmonyLib;
using HutongGames.PlayMaker;
using InControl;
using LoopTheGungeon.Config;
using LoopTheGungeon.Console;
using LoopTheGungeon.Content;
using LoopTheGungeon.Core;
using LoopTheGungeon.Patches;
using LoopTheGungeon.Util;
using LoopTheGungeon.Visuals;
using Microsoft.CodeAnalysis;
using Pathfinding;
using SGUI;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LoopTheGungeon")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LoopTheGungeon")]
[assembly: AssemblyCopyright("Copyright ©  2020")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d6d7a494-722e-4763-959b-c2d6b6a42b01")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
public static class HellRage
{
	public class HellRageOnCombat : MonoBehaviour
	{
		private float RAGE_DURATION = 6f;

		private float _currentDamageMultiplier = 1.5f;

		private Color _currentFlatColor = new Color(0.5f, 0f, 0f, 0.75f);

		private PlayerController _owner;

		private Action _enteredCombatHandler;

		private Coroutine _activationCo;

		private Coroutine _rageCo;

		private StatModifier _damageMod;

		private float _rageTimeLeft;

		private bool _buffActive;

		public void Init(PlayerController owner)
		{
			_owner = owner;
			if (_enteredCombatHandler == null)
			{
				_enteredCombatHandler = OnEnteredCombat;
			}
			if ((Object)(object)_owner != (Object)null)
			{
				PlayerController owner2 = _owner;
				owner2.OnEnteredCombat = (Action)Delegate.Remove(owner2.OnEnteredCombat, _enteredCombatHandler);
				PlayerController owner3 = _owner;
				owner3.OnEnteredCombat = (Action)Delegate.Combine(owner3.OnEnteredCombat, _enteredCombatHandler);
			}
		}

		private void OnDestroy()
		{
			CleanupSubscriptions();
			CleanupBuff(_owner);
		}

		private void CleanupSubscriptions()
		{
			if ((Object)(object)_owner != (Object)null && _enteredCombatHandler != null)
			{
				PlayerController owner = _owner;
				owner.OnEnteredCombat = (Action)Delegate.Remove(owner.OnEnteredCombat, _enteredCombatHandler);
			}
			_enteredCombatHandler = null;
			_owner = null;
		}

		private void OnEnteredCombat()
		{
			//IL_006e: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_owner == (Object)null)
			{
				return;
			}
			int rageStacks = GetRageStacks(_owner);
			if (rageStacks > 0)
			{
				_currentDamageMultiplier = 1f + 0.5f * (float)rageStacks;
				if (rageStacks > 3)
				{
					_currentFlatColor = new Color(0.388f, 0.067f, 0.729f, 0.75f);
				}
				else
				{
					_currentFlatColor = new Color(0.5f, 0f, 0f, 0.75f);
				}
				_rageTimeLeft = RAGE_DURATION;
				if (_rageCo == null)
				{
					_rageCo = ((MonoBehaviour)_owner).StartCoroutine(RageCR(_owner));
				}
			}
		}

		private IEnumerator RageCR(PlayerController player)
		{
			yield return (object)new WaitForSeconds(0.5f);
			if (!_buffActive)
			{
				_buffActive = true;
				_damageMod = new StatModifier
				{
					amount = _currentDamageMultiplier,
					modifyType = (ModifyMethod)1,
					statToBoost = (StatType)5
				};
				player.ownerlessStatModifiers.Add(_damageMod);
				player.stats.RecalculateStats(player, false, false);
				if ((Object)(object)((GameActor)player).CurrentGun != (Object)null)
				{
					((GameActor)player).CurrentGun.ForceImmediateReload(false);
				}
			}
			float particleCounter = 0f;
			while (_rageTimeLeft > 0f)
			{
				_rageTimeLeft -= BraveTime.DeltaTime;
				float num = ((_rageTimeLeft <= 1f) ? (1f - _rageTimeLeft) : 0f);
				player.baseFlatColorOverride = Vector3Extensions.WithAlpha(_currentFlatColor, Mathf.Lerp(_currentFlatColor.a, 0f, num));
				if ((int)GameManager.Options.ShaderQuality != 0 && (int)GameManager.Options.ShaderQuality != 3 && Object.op_Implicit((Object)(object)player) && player.IsVisible && !((GameActor)player).IsFalling)
				{
					particleCounter += BraveTime.DeltaTime * 40f;
					if (particleCounter > 1f)
					{
						int num2 = Mathf.FloorToInt(particleCounter);
						particleCounter %= 1f;
						GlobalSparksDoer.DoRandomParticleBurst(num2, Vector2Extensions.ToVector3ZisY(((BraveBehaviour)player).sprite.WorldBottomLeft, 0f), Vector2Extensions.ToVector3ZisY(((BraveBehaviour)player).sprite.WorldTopRight, 0f), Vector3.up, 90f, 0.5f, (float?)null, (float?)null, (Color?)null, (SparksType)1);
					}
				}
				yield return null;
				if ((Object)(object)player == (Object)null)
				{
					break;
				}
			}
			CleanupBuff(player);
			_rageCo = null;
		}

		public void PlayActivationFx(float seconds = 3f, int burstCount = 40)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_owner == (Object)null))
			{
				if (GetRageStacks(_owner) > 3)
				{
					_currentFlatColor = new Color(0.388f, 0.067f, 0.729f, 0.75f);
				}
				else
				{
					_currentFlatColor = new Color(0.5f, 0f, 0f, 0.75f);
				}
				if (_activationCo != null)
				{
					((MonoBehaviour)_owner).StopCoroutine(_activationCo);
				}
				_activationCo = ((MonoBehaviour)_owner).StartCoroutine(ActivationFxCR(_owner, seconds, burstCount));
			}
		}

		private IEnumerator ActivationFxCR(PlayerController player, float seconds, int burstCount)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				yield break;
			}
			try
			{
				if ((int)GameManager.Options.ShaderQuality != 0 && (int)GameManager.Options.ShaderQuality != 3 && player.IsVisible && !((GameActor)player).IsFalling && (Object)(object)((BraveBehaviour)player).sprite != (Object)null)
				{
					GlobalSparksDoer.DoRandomParticleBurst(Mathf.Max(1, burstCount), Vector2Extensions.ToVector3ZisY(((BraveBehaviour)player).sprite.WorldBottomLeft, 0f), Vector2Extensions.ToVector3ZisY(((BraveBehaviour)player).sprite.WorldTopRight, 0f), Vector3.up, 90f, 0.6f, (float?)null, (float?)null, (Color?)null, (SparksType)1);
				}
			}
			catch
			{
			}
			float t = 0f;
			float dur = Mathf.Max(0.05f, seconds);
			while (t < dur && Object.op_Implicit((Object)(object)player) && _rageCo == null)
			{
				t += BraveTime.DeltaTime;
				float num = 1f - Mathf.Clamp01(t / dur);
				player.baseFlatColorOverride = Vector3Extensions.WithAlpha(_currentFlatColor, _currentFlatColor.a * num);
				yield return null;
			}
			if (Object.op_Implicit((Object)(object)player))
			{
				player.baseFlatColorOverride = Color.clear;
			}
			_activationCo = null;
		}

		private void CleanupBuff(PlayerController player)
		{
			//IL_000a: 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 ((Object)(object)player != (Object)null)
			{
				player.baseFlatColorOverride = Color.clear;
				if (_buffActive && _damageMod != null)
				{
					player.ownerlessStatModifiers.Remove(_damageMod);
					player.stats.RecalculateStats(player, false, false);
				}
			}
			_damageMod = null;
			_buffActive = false;
			_rageTimeLeft = 0f;
		}
	}

	public static int GetRageStacks(PlayerController p)
	{
		if (!Object.op_Implicit((Object)(object)p))
		{
			return 0;
		}
		MasteryShrineInteractable.ShrineRageMarker component = ((Component)p).GetComponent<MasteryShrineInteractable.ShrineRageMarker>();
		if (!Object.op_Implicit((Object)(object)component))
		{
			return 0;
		}
		return Mathf.Max(0, component.Stacks);
	}

	public static void ResetRageStacksForAllPlayers()
	{
		GameManager instance = GameManager.Instance;
		PlayerController[] array = ((instance != null) ? instance.AllPlayers : null);
		if (array == null)
		{
			return;
		}
		foreach (PlayerController val in array)
		{
			if (!Object.op_Implicit((Object)(object)val))
			{
				continue;
			}
			try
			{
				MasteryShrineInteractable.ShrineRageMarker component = ((Component)val).GetComponent<MasteryShrineInteractable.ShrineRageMarker>();
				if ((Object)(object)component != (Object)null)
				{
					component.Stacks = 0;
				}
			}
			catch
			{
			}
			try
			{
				HellRageOnCombat component2 = ((Component)val).GetComponent<HellRageOnCombat>();
				if ((Object)(object)component2 != (Object)null)
				{
					Object.Destroy((Object)(object)component2);
				}
			}
			catch
			{
			}
		}
	}
}
namespace Mod.Patches
{
	[HarmonyPatch(typeof(InfinilichDeathController), "HandleClockhair")]
	public static class Patch_InfinilichDeathController_HandleClockhair
	{
		private static bool _loopShotTriggeredThisClockhair;

		private static Vector2 _camVel;

		private const float MAX_CAM_DRIFT_FROM_LICH = 25f;

		private const float EDGE_UV = 0.1f;

		private const float PAN_SPEED_MAX = 6f;

		private const float PAN_ACCEL = 10f;

		[HarmonyPrefix]
		private static bool Prefix(InfinilichDeathController __instance, PlayerController interactor, ref IEnumerator __result)
		{
			__result = CustomHandleClockhair(__instance, interactor);
			return false;
		}

		private static IEnumerator CustomHandleClockhair(InfinilichDeathController self, PlayerController interactor)
		{
			_loopShotTriggeredThisClockhair = false;
			_camVel = Vector2.zero;
			try
			{
				GameManager.Instance.PrimaryPlayer.SetInputOverride("past");
				if ((int)GameManager.Instance.CurrentGameType == 1 && Object.op_Implicit((Object)(object)GameManager.Instance.SecondaryPlayer))
				{
					GameManager.Instance.SecondaryPlayer.SetInputOverride("past");
				}
				GameUIRoot.Instance.ToggleLowerPanels(false, false, string.Empty);
				GameUIRoot.Instance.HideCoreUI(string.Empty);
				CameraController camera = GameManager.Instance.MainCameraController;
				Vector2 val = Vector2.op_Implicit(camera.OverridePosition);
				Vector2 desiredCamCenter = ((BraveBehaviour)((BraveBehaviour)self).aiAnimator).sprite.WorldCenter;
				camera.SetManualControl(true, true);
				_camVel = Vector2.zero;
				if (Vector2.Distance(val, desiredCamCenter) > 2.5f)
				{
					camera.OverridePosition = Vector2.op_Implicit(desiredCamCenter);
				}
				Transform clockhairTransform = ((GameObject)Object.Instantiate(BraveResources.Load("Clockhair", ".prefab"))).transform;
				ClockhairController clockhair = ((Component)clockhairTransform).GetComponent<ClockhairController>();
				float elapsed = 0f;
				float duration = clockhair.ClockhairInDuration;
				Vector3 clockhairTargetPosition = Vector2.op_Implicit(((GameActor)GameManager.Instance.PrimaryPlayer).CenterPosition);
				Vector3 clockhairStartPosition = clockhairTargetPosition + new Vector3(-20f, 5f, 0f);
				((BraveBehaviour)clockhair).renderer.enabled = true;
				((BraveBehaviour)clockhair).spriteAnimator.alwaysUpdateOffscreen = true;
				((BraveBehaviour)clockhair).spriteAnimator.Play("clockhair_intro");
				clockhair.hourAnimator.Play("hour_hand_intro");
				clockhair.minuteAnimator.Play("minute_hand_intro");
				clockhair.secondAnimator.Play("second_hand_intro");
				while (elapsed < duration)
				{
					if (GameManager.INVARIANT_DELTA_TIME == 0f)
					{
						elapsed += 0.05f;
					}
					elapsed += GameManager.INVARIANT_DELTA_TIME;
					float num = elapsed / duration;
					float num2 = Mathf.SmoothStep(0f, 1f, num);
					clockhairTargetPosition = Vector2.op_Implicit(GetTargetClockhairPosition(self, Vector3Extensions.XY(clockhairTargetPosition)));
					Vector3 val2 = Vector3.Slerp(clockhairStartPosition, clockhairTargetPosition, num2);
					clockhairTransform.position = Vector3Extensions.WithZ(val2, 0f);
					UpdateCameraDuringLichClockhair(camera, desiredCamCenter);
					UpdateEyes(self, Vector3Extensions.XY(clockhairTransform.position), isInDanger: false);
					if (num > 0.5f)
					{
						((BraveBehaviour)clockhair).renderer.enabled = true;
					}
					if (num > 0.75f)
					{
						((Component)clockhair.hourAnimator).GetComponent<Renderer>().enabled = true;
						((Component)clockhair.minuteAnimator).GetComponent<Renderer>().enabled = true;
						((Component)clockhair.secondAnimator).GetComponent<Renderer>().enabled = true;
					}
					((BraveBehaviour)clockhair).sprite.UpdateZDepth();
					yield return null;
				}
				clockhair.SetMotionType(1f);
				BraveInput currentInput = BraveInput.GetInstanceForPlayer(GameManager.Instance.PrimaryPlayer.PlayerIDX);
				float shotTargetTime = 0f;
				float holdDuration = 3f;
				Vector3 lastScreenShakeAmount = Vector3.zero;
				Vector3 lastJitterAmount = Vector3.zero;
				bool targetingPlayer;
				PlayerController targetedPlayer;
				while (true)
				{
					Transform transform = ((BraveBehaviour)clockhair).transform;
					transform.position -= lastJitterAmount;
					((BraveBehaviour)clockhair).transform.position = Vector2.op_Implicit(GetTargetClockhairPosition(self, Vector3Extensions.XY(((BraveBehaviour)clockhair).transform.position)));
					((BraveBehaviour)clockhair).sprite.UpdateZDepth();
					bool num3 = CheckLichTarget(self, clockhairTransform);
					targetingPlayer = false;
					targetedPlayer = null;
					if (Object.op_Implicit((Object)(object)GameManager.Instance.PrimaryPlayer) && Object.op_Implicit((Object)(object)((BraveBehaviour)GameManager.Instance.PrimaryPlayer).healthHaver) && ((BraveBehaviour)GameManager.Instance.PrimaryPlayer).healthHaver.IsAlive && CheckPlayerTarget(GameManager.Instance.PrimaryPlayer, clockhairTransform))
					{
						targetingPlayer = true;
						targetedPlayer = GameManager.Instance.PrimaryPlayer;
					}
					if (!targetingPlayer && (int)GameManager.Instance.CurrentGameType == 1 && Object.op_Implicit((Object)(object)GameManager.Instance.SecondaryPlayer) && Object.op_Implicit((Object)(object)((BraveBehaviour)GameManager.Instance.SecondaryPlayer).healthHaver) && ((BraveBehaviour)GameManager.Instance.SecondaryPlayer).healthHaver.IsAlive && CheckPlayerTarget(GameManager.Instance.SecondaryPlayer, clockhairTransform))
					{
						targetingPlayer = true;
						targetedPlayer = GameManager.Instance.SecondaryPlayer;
					}
					bool flag = num3 || targetingPlayer;
					clockhair.SetMotionType(flag ? (-10f) : 1f);
					bool flag2 = ((OneAxisInputControl)currentInput.ActiveActions.ShootAction).IsPressed || ((OneAxisInputControl)currentInput.ActiveActions.InteractAction).IsPressed;
					shotTargetTime = ((flag2 && flag) ? (shotTargetTime + BraveTime.DeltaTime) : Mathf.Max(0f, shotTargetTime - BraveTime.DeltaTime * 3f));
					UpdateCameraDuringLichClockhair(camera, desiredCamCenter);
					UpdateEyes(self, Vector3Extensions.XY(((BraveBehaviour)clockhair).transform.position), flag2);
					if ((((OneAxisInputControl)currentInput.ActiveActions.ShootAction).WasReleased || ((OneAxisInputControl)currentInput.ActiveActions.InteractAction).WasReleased) && flag && shotTargetTime > holdDuration && !GameManager.Instance.IsPaused)
					{
						break;
					}
					if (shotTargetTime > 0f)
					{
						lastScreenShakeAmount = camera.DoFrameScreenShake(Mathf.Lerp(0f, 0.5f, shotTargetTime / holdDuration), Mathf.Lerp(3f, 8f, shotTargetTime / holdDuration), Vector2.op_Implicit(Vector3.right), lastScreenShakeAmount, Time.realtimeSinceStartup);
						float num4 = Mathf.Lerp(0f, 0.35f, shotTargetTime / holdDuration);
						float num5 = 0.5f;
						float num6 = Mathf.Lerp(4f, 7f, shotTargetTime / holdDuration);
						clockhair.UpdateDistortion(num4, num5, num6);
						float num7 = Mathf.Lerp(2f, 0.25f, shotTargetTime / holdDuration);
						clockhair.UpdateDesat(true, num7);
						shotTargetTime = Mathf.Min(holdDuration + 0.25f, shotTargetTime + BraveTime.DeltaTime);
						float num8 = Mathf.Lerp(0f, 0.5f, (shotTargetTime - 1f) / (holdDuration - 1f));
						Vector3 val3 = Vector2Extensions.ToVector3ZUp(Random.insideUnitCircle * num8, 0f);
						BraveInput.DoSustainedScreenShakeVibration(shotTargetTime / holdDuration * 0.8f);
						Transform transform2 = ((BraveBehaviour)clockhair).transform;
						transform2.position += val3;
						lastJitterAmount = val3;
						clockhair.SetMotionType(Mathf.Lerp(-10f, -2400f, shotTargetTime / holdDuration));
					}
					else
					{
						lastJitterAmount = Vector3.zero;
						camera.ClearFrameScreenShake(lastScreenShakeAmount);
						lastScreenShakeAmount = Vector3.zero;
						clockhair.UpdateDistortion(0f, 0f, 0f);
						clockhair.UpdateDesat(false, 0f);
						shotTargetTime = 0f;
						BraveInput.DoSustainedScreenShakeVibration(0f);
					}
					yield return null;
				}
				camera.ClearFrameScreenShake(lastScreenShakeAmount);
				BraveInput.DoSustainedScreenShakeVibration(0f);
				BraveInput.DoVibrationForAllPlayers((Time)10, (Strength)30);
				((MonoBehaviour)clockhair).StartCoroutine(clockhair.WipeoutDistortionAndFade(0.5f));
				GameObjectExtensions.SetLayerRecursively(((Component)clockhair).gameObject, LayerMask.NameToLayer("Unoccluded"));
				Pixelator.Instance.FadeToBlack(0.2f, true, 0.2f);
				Pixelator.Instance.DoRenderGBuffer = false;
				Pixelator.Instance.LerpToLetterbox(0.45f, 0.45f);
				((BraveBehaviour)clockhair).spriteAnimator.PlayAndDisableRenderer("clockhair_fire");
				((Component)clockhair.hourAnimator).GetComponent<Renderer>().enabled = false;
				((Component)clockhair.minuteAnimator).GetComponent<Renderer>().enabled = false;
				((Component)clockhair.secondAnimator).GetComponent<Renderer>().enabled = false;
				yield return null;
				if (!targetingPlayer || !((Object)(object)targetedPlayer != (Object)null) || _loopShotTriggeredThisClockhair)
				{
					yield break;
				}
				_loopShotTriggeredThisClockhair = true;
				LoopManager.PendingLichRewards = true;
				try
				{
					clockhair.UpdateDesat(false, 0f);
				}
				catch
				{
				}
				try
				{
					clockhair.UpdateDistortion(0f, 0f, 0f);
				}
				catch
				{
				}
				try
				{
					GameManager.Instance.PrimaryPlayer.ClearInputOverride("past");
				}
				catch
				{
				}
				try
				{
					if (Object.op_Implicit((Object)(object)GameManager.Instance.SecondaryPlayer))
					{
						GameManager.Instance.SecondaryPlayer.ClearInputOverride("past");
					}
				}
				catch
				{
				}
				try
				{
					((MonoBehaviour)GameManager.Instance).StopAllCoroutines();
				}
				catch
				{
				}
				try
				{
					LoopManager.LoadingScreenState.UseCustomLoadScreenOnce = true;
				}
				catch
				{
				}
				try
				{
					TimeTubeTransition.StartLoopTimeTubeThenLoop((MonoBehaviour)(object)GameManager.Instance);
				}
				catch
				{
				}
			}
			finally
			{
				_camVel = Vector2.zero;
			}
		}

		private static void UpdateCameraDuringLichClockhair(CameraController cam, Vector2 lichAnchor)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)cam == (Object)null) && !((Object)(object)cam.Camera == (Object)null))
			{
				Vector3 val = cam.Camera.ScreenToViewportPoint(Input.mousePosition);
				float num = 0f;
				if (val.x < 0.1f)
				{
					num = (val.x - 0.1f) / 0.1f;
				}
				else if (val.x > 0.9f)
				{
					num = (val.x - 0.9f) / 0.1f;
				}
				float num2 = 0f;
				if (val.y < 0.1f)
				{
					num2 = (val.y - 0.1f) / 0.1f;
				}
				else if (val.y > 0.9f)
				{
					num2 = (val.y - 0.9f) / 0.1f;
				}
				Vector2 val2 = new Vector2(num, num2) * 6f;
				_camVel = Vector2.MoveTowards(_camVel, val2, BraveTime.DeltaTime * 10f);
				Vector2 val3 = Vector2.op_Implicit(cam.OverridePosition) + _camVel * BraveTime.DeltaTime;
				float num3 = Vector2.Distance(val3, lichAnchor);
				if (num3 > 25f && num3 > 0.001f)
				{
					val3 = lichAnchor + (val3 - lichAnchor) * (25f / num3);
				}
				cam.OverridePosition = Vector2.op_Implicit(val3);
			}
		}

		private static bool CheckPlayerTarget(PlayerController target, Transform clockhairTransform)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			return Vector2.Distance(Vector3Extensions.XY(clockhairTransform.position) + new Vector2(-0.375f, 0.25f), ((GameActor)target).CenterPosition) < 0.625f;
		}

		private static bool CheckLichTarget(InfinilichDeathController self, Transform clockhairTransform)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Vector2.Distance(Vector3Extensions.XY(clockhairTransform.position) + new Vector2(-0.375f, 0.25f), ((GameActor)((BraveBehaviour)self).aiActor).CenterPosition + new Vector2(0f, -1.25f)) < 0.875f;
			}
			catch
			{
				return false;
			}
		}

		private static Vector2 GetTargetClockhairPosition(InfinilichDeathController self, Vector2 currentClockhairPosition)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00a2: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_001e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0058: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//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_006f: Unknown result type (might be due to invalid IL or missing references)
			BraveInput instanceForPlayer = BraveInput.GetInstanceForPlayer(GameManager.Instance.PrimaryPlayer.PlayerIDX);
			if (!instanceForPlayer.IsKeyboardAndMouse(false))
			{
				Vector2 val = currentClockhairPosition + ((TwoAxisInputControl)instanceForPlayer.ActiveActions.Aim).Vector * 6f * BraveTime.DeltaTime;
				val = Vector2.Max(GameManager.Instance.MainCameraController.MinVisiblePoint, val);
				return Vector2.Min(GameManager.Instance.MainCameraController.MaxVisiblePoint, val);
			}
			Vector2 val2 = Vector3Extensions.XY(GameManager.Instance.MainCameraController.Camera.ScreenToWorldPoint(Input.mousePosition)) + new Vector2(0.375f, -0.25f);
			val2 = Vector2.Max(GameManager.Instance.MainCameraController.MinVisiblePoint, val2);
			return Vector2.Min(GameManager.Instance.MainCameraController.MaxVisiblePoint, val2);
		}

		private static void UpdateEyes(InfinilichDeathController self, Vector2 clockhairPosition, bool isInDanger)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AccessTools.Method(typeof(InfinilichDeathController), "UpdateEyes", (Type[])null, (Type[])null)?.Invoke(self, new object[2] { clockhairPosition, isInDanger });
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(LichIntroDoer), "PlayerWalkedIn")]
	public static class Patch_Lich_Start_TrackFlawless
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static OnDamagedEvent <>9__0_0;

			internal void <Postfix>b__0_0(float resultValue, float maxValue, CoreDamageTypes damageTypes, DamageCategory damageCategory, Vector2 damageDirection)
			{
				try
				{
					LoopManager.LastLichWasFlawless = false;
				}
				catch
				{
				}
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			try
			{
				LoopManager.LastLichWasFlawless = true;
				GameManager instance = GameManager.Instance;
				if (((instance != null) ? instance.AllPlayers : null) == null)
				{
					return;
				}
				for (int i = 0; i < instance.AllPlayers.Length; i++)
				{
					PlayerController val = instance.AllPlayers[i];
					if (!Object.op_Implicit((Object)(object)val) || (Object)(object)((BraveBehaviour)val).healthHaver == (Object)null)
					{
						continue;
					}
					HealthHaver healthHaver = ((BraveBehaviour)val).healthHaver;
					object obj = <>c.<>9__0_0;
					if (obj == null)
					{
						OnDamagedEvent val2 = delegate
						{
							try
							{
								LoopManager.LastLichWasFlawless = false;
							}
							catch
							{
							}
						};
						<>c.<>9__0_0 = val2;
						obj = (object)val2;
					}
					healthHaver.OnDamaged += (OnDamagedEvent)obj;
				}
			}
			catch
			{
			}
		}
	}
}
namespace LoopTheGungeon
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("milz.etg.loopthegungeon", "Loop The Gungeon", "1.1.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "milz.etg.loopthegungeon";

		public const string NAME = "Loop The Gungeon";

		public const string VERSION = "1.1.2";

		public static Plugin Instance;

		public static Harmony HarmonyInstance;

		public static int GlobalLoopOffset = -1;

		private static bool _commandsRegistered;

		private bool _patched;

		private bool _hooksInstalled;

		private SceneHandler _sceneHandler;

		private SaveHandler _saveHandler;

		private void Awake()
		{
			GlobalLoopOffset = -1;
			Instance = this;
			_saveHandler = new SaveHandler();
			_sceneHandler = new SceneHandler(_saveHandler);
			try
			{
				InstallHooksOnce();
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Hook install failed: {1}", "Loop The Gungeon", arg));
			}
			try
			{
				DataStorage.Init();
				_saveHandler.TryRestorePendingResumeFromDisk();
			}
			catch (Exception arg2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Config init failed: {1}", "Loop The Gungeon", arg2));
			}
			try
			{
				TryApplyHarmonyPatches();
			}
			catch (Exception arg3)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Harmony patching failed: {1}", "Loop The Gungeon", arg3));
			}
		}

		private void InstallHooksOnce()
		{
			if (_hooksInstalled)
			{
				return;
			}
			_hooksInstalled = true;
			try
			{
				SceneManager.sceneLoaded += _sceneHandler.OnSceneLoaded;
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] sceneLoaded hook failed: {1}", "Loop The Gungeon", arg));
			}
			try
			{
				DungeonHooks.OnPostDungeonGeneration += LoopManager.OnPostDungeonGeneration;
			}
			catch (Exception arg2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] OnPostDungeonGeneration LoopManager hook failed: {1}", "Loop The Gungeon", arg2));
			}
			try
			{
				DungeonHooks.OnPostDungeonGeneration += ForgeHandler.OnPostDungeonGeneration;
			}
			catch (Exception arg3)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] OnPostDungeonGeneration ForgeHandler hook failed: {1}", "Loop The Gungeon", arg3));
			}
			try
			{
				DungeonHooks.OnPostDungeonGeneration += MasteryShrine.OnPostDungeonGeneration;
			}
			catch (Exception arg4)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] OnPostDungeonGeneration MasteryShrine hook failed: {1}", "Loop The Gungeon", arg4));
			}
		}

		public void Start()
		{
			ETGModMainBehaviour.WaitForGameManagerStart((Action<GameManager>)GMStart);
		}

		private void GMStart(GameManager g)
		{
			if ((Object)(object)g == (Object)null)
			{
				return;
			}
			try
			{
				GunfigManager.Init();
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Gunfig init failed: {1}", "Loop The Gungeon", arg));
			}
			try
			{
				MasterRoundHell.Init();
			}
			catch (Exception arg2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] MasterRoundHell.Init failed: {1}", "Loop The Gungeon", arg2));
			}
			IntroWave.LogIntro("Loop The Gungeon started LOoOoping!");
			if (!LoopManager.IsResumeFlow())
			{
				LoopManager.ResetNoticeEmitted = false;
			}
			if (_commandsRegistered)
			{
				return;
			}
			_commandsRegistered = true;
			try
			{
				ConsoleCommands.RegisterCommands();
			}
			catch (Exception arg3)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] RegisterDebugCommands failed: {1}", "Loop The Gungeon", arg3));
			}
			try
			{
				ETGModConsole.Commands.AddGroup("loop", (Action<string[]>)delegate
				{
				});
			}
			catch (Exception arg4)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] AddGroup(loop) failed: {1}", "Loop The Gungeon", arg4));
			}
		}

		private void TryApplyHarmonyPatches()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			if (_patched)
			{
				return;
			}
			try
			{
				HarmonyInstance = new Harmony("milz.etg.loopthegungeon");
				Harmony harmonyInstance = HarmonyInstance;
				MethodInfo method = typeof(GameManager).GetMethod("DelayedLoadCharacterSelect", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)method == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"[Loop The Gungeon] Patch FAIL: GameManager.DelayedLoadCharacterSelect not found.");
				}
				else
				{
					harmonyInstance.Patch((MethodBase)method, new HarmonyMethod(typeof(LoopManager), "SaveAndQuitBoundary", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				harmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Harmony patching OK.");
				_patched = true;
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Harmony patching FAILED: {1}", "Loop The Gungeon", arg));
			}
		}

		private void OnDestroy()
		{
			try
			{
				_saveHandler?.StopCoroutines();
			}
			catch
			{
			}
			try
			{
				_sceneHandler?.StopCoroutines();
			}
			catch
			{
			}
			if (_hooksInstalled)
			{
				_hooksInstalled = false;
				if (_sceneHandler != null)
				{
					SceneManager.sceneLoaded -= _sceneHandler.OnSceneLoaded;
				}
				DungeonHooks.OnPostDungeonGeneration -= LoopManager.OnPostDungeonGeneration;
				DungeonHooks.OnPostDungeonGeneration -= MasteryShrine.OnPostDungeonGeneration;
			}
			if (Instance == this)
			{
				Instance = null;
			}
			try
			{
				ProjectileSpeedScaler.RestoreBaselineNow();
			}
			catch
			{
			}
			try
			{
				ButtonSpritesOverride.ClearRuntimeCaches(destroyUnityObjects: true);
			}
			catch
			{
			}
			try
			{
				LoopManager.ResetMasteryShrineRuntime();
				ShrineSpritesOverride.TryResetMasteryShrineVisuals();
				ShrineSpritesOverride.ClearRuntimeCaches(destroyUnityObjects: true);
			}
			catch
			{
			}
		}

		internal static void StopAndNull(ref Coroutine c)
		{
			if (c != null && (Object)(object)Instance != (Object)null)
			{
				try
				{
					((MonoBehaviour)Instance).StopCoroutine(c);
				}
				catch
				{
				}
				c = null;
			}
		}

		internal static Coroutine StartGlobalCoroutine(IEnumerator e)
		{
			if ((Object)(object)Instance == (Object)null)
			{
				return null;
			}
			try
			{
				return ((MonoBehaviour)Instance).StartCoroutine(e);
			}
			catch
			{
				return null;
			}
		}

		internal void ClearResumeAnnouncement()
		{
			try
			{
				_saveHandler?.ClearResumeAnnouncement();
			}
			catch
			{
			}
		}

		internal void ArmResumeAnnouncementIfNeeded()
		{
			try
			{
				_saveHandler?.ArmResumeAnnouncementIfNeeded();
			}
			catch
			{
			}
		}

		public static bool ShouldSuppressResumeArming()
		{
			try
			{
				return SaveHandler.ShouldSuppressResumeArming();
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class GunfigManager
	{
		private class ScalingPresetDefinition
		{
			internal readonly string Name;

			internal readonly string Hp;

			internal readonly string AtkSpeed;

			internal readonly string MoveSpeed;

			internal readonly string ProjSpeed;

			internal readonly string Enemies;

			internal ScalingPresetDefinition(string name, string hp, string atkSpeed, string moveSpeed, string projSpeed, string enemies)
			{
				Name = name;
				Hp = hp;
				AtkSpeed = atkSpeed;
				MoveSpeed = moveSpeed;
				ProjSpeed = projSpeed;
				Enemies = enemies;
			}
		}

		internal static Gunfig gunfig = null;

		internal static bool _initialized;

		private static readonly Color Header = new Color(0f, 1f, 0.702f);

		private const string ObsoleteConfigFileName = "milz.loopthegungeon.cfg";

		private static readonly List<string> DefaultEnabled = new List<string> { "Yeah", "Nah" };

		private static readonly List<string> DefaultDisabled = new List<string> { "Nah", "Yeah" };

		internal const string ScalingPreset = "Scaling Preset";

		private const string CustomScalingPreset = "Custom";

		private const string GameBreakingScalingPreset = "Game Breaking";

		private static bool _applyingScalingPreset;

		internal const string DPS = "Break DPS cap";

		internal const string LOTJ = "Banish Lord of the Jammed";

		internal const string TAX = "Pay Loop tax";

		internal const string HpPerLoop = "Health";

		internal const string AtkSpeedPerLoop = "Attack Speed";

		internal const string MoveSpeedPerLoop = "Movement Speed";

		internal const string ProjSpeedPerLoop = "Projectile Speed";

		internal const string EnemiesPerLoop = "Room Wave Enemies";

		internal const string ShopPricingPerLoop = "Shop Pricing";

		internal const string SpecialPricingPerLoop = "Special NPC Pricing";

		private static readonly List<string> PercentageOptions = new List<string>
		{
			"+0%", "+5%", "+10%", "+15%", "+20%", "+25%", "+30%", "+35%", "+40%", "+45%",
			"+50%", "+55%", "+60%", "+65%", "+70%", "+75%", "+80%", "+85%", "+90%", "+95%",
			"+100%", "+150%", "+200%", "+250%", "+300%"
		};

		private static readonly List<string> NumberOptions = new List<string>
		{
			"+0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9",
			"+10", "+15", "+20", "+30"
		};

		private static readonly List<ScalingPresetDefinition> ScalingPresetDefinitions = new List<ScalingPresetDefinition>
		{
			new ScalingPresetDefinition("Off", "+0%", "+0%", "+0%", "+0%", "+0"),
			new ScalingPresetDefinition("Easy", "+10%", "+5%", "+5%", "+5%", "+1"),
			new ScalingPresetDefinition("Normal", "+20%", "+15%", "+10%", "+10%", "+2"),
			new ScalingPresetDefinition("Hard", "+40%", "+30%", "+20%", "+20%", "+3"),
			new ScalingPresetDefinition("Brutal", "+70%", "+50%", "+30%", "+30%", "+5"),
			new ScalingPresetDefinition("Impossible", "+100%", "+75%", "+50%", "+50%", "+10")
		};

		private static readonly List<string> ScalingPresets = ScalingPresetDefinitions.Select((ScalingPresetDefinition preset) => preset.Name).Concat(new string[2] { "Custom", "Game Breaking" }).ToList();

		internal static void Init()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized)
			{
				_initialized = true;
				RemoveObsoleteConfig();
				gunfig = Gunfig.Get(GunfigHelpers.WithColor("Loop The Gungeon", Header));
				BuildMenu();
			}
		}

		private static void RemoveObsoleteConfig()
		{
			try
			{
				string path = Path.Combine(Paths.ConfigPath, "milz.loopthegungeon.cfg");
				if (File.Exists(path))
				{
					File.Delete(path);
					Debug.Log((object)"[Loop The Gungeon] Removed obsolete configuration file: milz.loopthegungeon.cfg");
				}
			}
			catch (Exception arg)
			{
				Debug.LogWarning((object)("[Loop The Gungeon] Could not remove obsolete configuration file. " + $"It can be safely deleted manually. Error: {arg}"));
			}
		}

		internal static void BuildMenu()
		{
			BuildGameplayMenu();
			BuildEnemyMenu();
			BuildEconomyMenu();
			gunfig.AddLabel(GunfigHelpers.Gray("                         .           .                   .              *"));
			gunfig.AddLabel(GunfigHelpers.Gray("       *          .                       .       *                 ."));
			gunfig.AddLabel(GunfigHelpers.Gray("              .          *       .       *                  .             ."));
			gunfig.AddLabel(GunfigHelpers.Gray("    .                         .       .             .                      ."));
			gunfig.AddLabel(GunfigHelpers.Gray(".                 *                       .              .       *"));
			gunfig.AddLabel(GunfigHelpers.Gray("*    hi!          .       .      *             .     ."));
			gunfig.AddLabel(GunfigHelpers.Gray("r    _-_                \\|/"));
			gunfig.AddLabel(GunfigHelpers.Gray("(°°)  (°o°)   (^^)(°°)  \\(°o°)/"));
		}

		private static void BuildGameplayMenu()
		{
			Gunfig obj = gunfig.AddSubMenu("Gameplay");
			obj.ToggleDPS("Break DPS cap", "Removes the DPS cap, so your build can really shine.");
			obj.ToggleLOTJ("Banish Lord of the Jammed", "Removes the Lord of the Jammed, embraces the curse.");
			obj.ToggleTAX("Pay Loop tax", "Removes all casings every loop, for \"balance\".");
		}

		private static void BuildEnemyMenu()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			Gunfig scaling = gunfig.AddSubMenu("Enemy Scaling");
			scaling.AddScrollBox("Scaling Preset", GunfigHelpers.WithDefault(ScalingPresets, "Normal"), (string)null, (Action<string, string>)null, Enumerable.Repeat("Applies a preset to all enemy scaling modifiers.", ScalingPresets.Count).ToList(), (Update)1);
			scaling.SetSelectableValues("Scaling Preset", ScalingPresetDefinitions.Select((ScalingPresetDefinition preset) => preset.Name).ToList());
			Gunfig obj = gunfig;
			obj.OnPendingValueChanged = (Action<string, string>)Delegate.Combine(obj.OnPendingValueChanged, (Action<string, string>)delegate(string key, string value)
			{
				if (key == "Scaling Preset")
				{
					ApplyScalingPreset(scaling, value);
				}
				else
				{
					UpdateScalingPreset(scaling);
				}
			});
			scaling.EnemyPercentageList("Health", "Enemy health growth per loop (compounded).", Color.green, "+20%");
			scaling.EnemyPercentageList("Attack Speed", "Enemy attack speed increase per loop (additive).", Color.red, "+20%");
			scaling.EnemyPercentageList("Movement Speed", "Enemy movement speed increase per loop (additive).", Color.yellow, "+20%");
			scaling.EnemyPercentageList("Projectile Speed", "Enemy projectile increase per loop (additive).", Color.cyan, "+20%");
			scaling.NumberList("Room Wave Enemies", "Extra enemies added to room waves per loop.", "+2");
		}

		private static void BuildEconomyMenu()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Gunfig obj = gunfig.AddSubMenu("Economy Scaling");
			obj.EconomyPercentageList("Shop Pricing", "Shop price and payout increase per loop (additive).", Color.green, "20%");
			obj.AddLabel(GunfigHelpers.Gray(""));
			obj.AddLabel(GunfigHelpers.Gray("Affects all shops using coins as currency."));
			obj.AddLabel(GunfigHelpers.Gray("Also boosts Sell Creep payout for balance"));
			obj.AddLabel(GunfigHelpers.Gray(""));
			obj.EconomyPercentageList("Special NPC Pricing", "Special NPC price and payout increase per loop (additive)", Color.magenta, "20%");
			obj.AddLabel(GunfigHelpers.Gray(""));
			obj.AddLabel(GunfigHelpers.Gray("Special NPCs include Gunsling King,"));
			obj.AddLabel(GunfigHelpers.Gray("Synergrace, Vampire, and Winchester"));
			obj.AddLabel(GunfigHelpers.Gray(""));
		}

		private static void ApplyScalingPreset(Gunfig scaling, string preset)
		{
			ScalingPresetDefinition scalingPresetDefinition = ScalingPresetDefinitions.FirstOrDefault((ScalingPresetDefinition p) => p.Name == preset);
			if (scalingPresetDefinition == null)
			{
				return;
			}
			_applyingScalingPreset = true;
			try
			{
				scaling.SetPendingValue("Health", scalingPresetDefinition.Hp);
				scaling.SetPendingValue("Attack Speed", scalingPresetDefinition.AtkSpeed);
				scaling.SetPendingValue("Movement Speed", scalingPresetDefinition.MoveSpeed);
				scaling.SetPendingValue("Projectile Speed", scalingPresetDefinition.ProjSpeed);
				scaling.SetPendingValue("Room Wave Enemies", scalingPresetDefinition.Enemies);
			}
			finally
			{
				_applyingScalingPreset = false;
			}
		}

		private static string GetMatchingScalingPreset(Gunfig scaling)
		{
			string pendingValue = scaling.GetPendingValue("Health");
			string pendingValue2 = scaling.GetPendingValue("Attack Speed");
			string pendingValue3 = scaling.GetPendingValue("Movement Speed");
			string pendingValue4 = scaling.GetPendingValue("Projectile Speed");
			string pendingValue5 = scaling.GetPendingValue("Room Wave Enemies");
			foreach (ScalingPresetDefinition scalingPresetDefinition in ScalingPresetDefinitions)
			{
				if (pendingValue == scalingPresetDefinition.Hp && pendingValue2 == scalingPresetDefinition.AtkSpeed && pendingValue3 == scalingPresetDefinition.MoveSpeed && pendingValue4 == scalingPresetDefinition.ProjSpeed && pendingValue5 == scalingPresetDefinition.Enemies)
				{
					return scalingPresetDefinition.Name;
				}
			}
			bool num = pendingValue == PercentageOptions[PercentageOptions.Count - 1] && pendingValue2 == PercentageOptions[PercentageOptions.Count - 1] && pendingValue3 == PercentageOptions[PercentageOptions.Count - 1] && pendingValue4 == PercentageOptions[PercentageOptions.Count - 1];
			bool flag = pendingValue5 == NumberOptions[NumberOptions.Count - 1];
			if (num && flag)
			{
				return "Game Breaking";
			}
			return "Custom";
		}

		private static void UpdateScalingPreset(Gunfig scaling)
		{
			if (!_applyingScalingPreset)
			{
				string matchingScalingPreset = GetMatchingScalingPreset(scaling);
				scaling.SetPendingValue("Scaling Preset", matchingScalingPreset);
			}
		}

		private static void ApplyGunfigScaling()
		{
			try
			{
				ProjectileSpeedScaler.ApplyFromCurrentScaling();
			}
			catch
			{
			}
		}

		internal static float GetHpPerLoop()
		{
			return ParsePercentage(gunfig.Value("Health"));
		}

		internal static float GetAtkSpeedPerLoop()
		{
			return ParsePercentage(gunfig.Value("Attack Speed"));
		}

		internal static float GetMoveSpeedPerLoop()
		{
			return ParsePercentage(gunfig.Value("Movement Speed"));
		}

		internal static float GetProjSpeedPerLoop()
		{
			return ParsePercentage(gunfig.Value("Projectile Speed"));
		}

		internal static float GetShopPricingPerLoop()
		{
			return ParsePercentage(gunfig.Value("Shop Pricing"));
		}

		internal static float GetSpecialPricingPerLoop()
		{
			return ParsePercentage(gunfig.Value("Special NPC Pricing"));
		}

		internal static int GetExtraEnemiesPerLoop()
		{
			if (int.TryParse(gunfig.Value("Room Wave Enemies"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0;
		}

		private static float ParsePercentage(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return 0f;
			}
			value = value.Replace("%", "").Trim();
			if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return 0f;
			}
			return result / 100f;
		}

		private static void ToggleDPS(this Gunfig gunfig, string toggleName, string toggleDesc)
		{
			string item = GunfigHelpers.Red(toggleDesc);
			gunfig.AddScrollBox(toggleName, DefaultDisabled, (string)null, (Action<string, string>)delegate(string _, string value)
			{
				try
				{
					BossDpsCapPatch.ApplyBossDpsCapSettingToExistingBosses(value == "Yeah");
				}
				catch
				{
				}
			}, new List<string> { item, item }, (Update)1);
		}

		private static void ToggleLOTJ(this Gunfig gunfig, string toggleName, string toggleDesc)
		{
			string item = GunfigHelpers.Magenta(toggleDesc);
			gunfig.AddScrollBox(toggleName, DefaultDisabled, (string)null, (Action<string, string>)delegate
			{
				try
				{
					LordOfTheJammedPatch.ApplyLive();
				}
				catch
				{
				}
			}, new List<string> { item, item }, (Update)1);
		}

		private static void ToggleTAX(this Gunfig gunfig, string toggleName, string toggleDesc)
		{
			string item = GunfigHelpers.Green(toggleDesc);
			gunfig.AddScrollBox(toggleName, DefaultEnabled, (string)null, (Action<string, string>)null, new List<string> { item, item }, (Update)1);
		}

		private static void EnemyPercentageList(this Gunfig gunfig, string toggleName, string toggleDesc, Color color, string defaultValue)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			string element = GunfigHelpers.WithColor(toggleDesc, color);
			gunfig.AddScrollBox(toggleName, GunfigHelpers.WithDefault(PercentageOptions, defaultValue), (string)null, (Action<string, string>)delegate
			{
				ApplyGunfigScaling();
			}, Enumerable.Repeat(element, PercentageOptions.Count).ToList(), (Update)1);
		}

		private static void EconomyPercentageList(this Gunfig gunfig, string toggleName, string toggleDesc, Color color, string defaultValue)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			string element = GunfigHelpers.WithColor(toggleDesc, color);
			gunfig.AddScrollBox(toggleName, GunfigHelpers.WithDefault(PercentageOptions, defaultValue), (string)null, (Action<string, string>)null, Enumerable.Repeat(element, PercentageOptions.Count).ToList(), (Update)1);
		}

		private static void NumberList(this Gunfig gunfig, string toggleName, string toggleDesc, string defaultValue)
		{
			string element = GunfigHelpers.Magenta(toggleDesc);
			gunfig.AddScrollBox(toggleName, GunfigHelpers.WithDefault(NumberOptions, defaultValue), (string)null, (Action<string, string>)delegate
			{
				ApplyGunfigScaling();
			}, Enumerable.Repeat(element, NumberOptions.Count).ToList(), (Update)1);
		}
	}
}
namespace LoopTheGungeon.Config
{
	public static class DataStorage
	{
		[Serializable]
		public class Data
		{
			public bool DebugMode;

			public int SavedLoopOffset;

			public bool ResumePending;

			public string ResumeRunGuid = string.Empty;

			public string ResumeOfferedMasteries = string.Empty;

			public string ResumeRunSummary = string.Empty;
		}

		private static readonly string DataPath = Path.Combine(ETGMod.ResourcesDirectory, "data.loopthegungeon.json");

		private static readonly string TempPath = DataPath + ".tmp";

		private static readonly object _ioLock = new object();

		public static Data DataStore = new Data();

		private static bool _debugMode;

		public static bool DebugMode
		{
			get
			{
				try
				{
					return _debugMode;
				}
				catch
				{
					return false;
				}
			}
		}

		public static void Init()
		{
			Load();
		}

		public static void Load()
		{
			bool flag = false;
			try
			{
				lock (_ioLock)
				{
					if (!File.Exists(DataPath))
					{
						DataStore = new Data();
						flag = true;
					}
					else
					{
						string text = File.ReadAllText(DataPath);
						if (string.IsNullOrEmpty(text) || text.Trim().Length == 0)
						{
							DataStore = new Data();
							flag = true;
						}
						else
						{
							DataStore = JsonUtility.FromJson<Data>(text) ?? new Data();
						}
					}
					Normalize();
					_debugMode = DataStore.DebugMode;
				}
				if (flag)
				{
					Save();
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)string.Format("[{0}] Failed to load persistent data: {1}", "Loop The Gungeon", arg));
				DataStore = new Data();
				Normalize();
				_debugMode = DataStore.DebugMode;
			}
		}

		public static void ReloadDebugMode()
		{
			try
			{
				if (!File.Exists(DataPath))
				{
					return;
				}
				string text = File.ReadAllText(DataPath);
				if (!string.IsNullOrEmpty(text) && text.Trim().Length != 0)
				{
					Data data = JsonUtility.FromJson<Data>(text);
					if (data != null)
					{
						_debugMode = data.DebugMode;
					}
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)string.Format("[{0}] Failed to reload debug mode: {1}", "Loop The Gungeon", arg));
			}
		}

		public static void Save()
		{
			try
			{
				lock (_ioLock)
				{
					if (DataStore == null)
					{
						DataStore = new Data();
					}
					Normalize();
					DataStore.DebugMode = _debugMode;
					string contents = JsonUtility.ToJson((object)DataStore, true);
					File.WriteAllText(TempPath, contents);
					ReplaceAtomic(TempPath, DataPath);
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)string.Format("[{0}] Failed to save persistent data: {1}", "Loop The Gungeon", arg));
				try
				{
					if (File.Exists(TempPath))
					{
						File.Delete(TempPath);
					}
				}
				catch
				{
				}
			}
		}

		public static void ClearResume()
		{
			try
			{
				if (DataStore == null)
				{
					DataStore = new Data();
				}
				DataStore.ResumePending = false;
				DataStore.SavedLoopOffset = 0;
				DataStore.ResumeRunGuid = string.Empty;
				DataStore.ResumeOfferedMasteries = string.Empty;
				DataStore.ResumeRunSummary = string.Empty;
				Save();
			}
			catch (Exception arg)
			{
				Debug.LogError((object)string.Format("[{0}] Failed to clear resume data: {1}", "Loop The Gungeon", arg));
			}
		}

		private static void Normalize()
		{
			if (DataStore == null)
			{
				DataStore = new Data();
			}
			if (DataStore.ResumeRunGuid == null)
			{
				DataStore.ResumeRunGuid = string.Empty;
			}
			if (DataStore.ResumeOfferedMasteries == null)
			{
				DataStore.ResumeOfferedMasteries = string.Empty;
			}
			if (DataStore.ResumeRunSummary == null)
			{
				DataStore.ResumeRunSummary = string.Empty;
			}
		}

		private static void ReplaceAtomic(string tempPath, string destinationPath)
		{
			if (File.Exists(destinationPath))
			{
				try
				{
					File.Replace(tempPath, destinationPath, null);
					return;
				}
				catch
				{
				}
			}
			if (File.Exists(destinationPath))
			{
				File.Delete(destinationPath);
			}
			File.Move(tempPath, destinationPath);
		}
	}
}
namespace LoopTheGungeon.Visuals
{
	public static class ShrineSpritesOverride
	{
		private readonly struct CreatedKey : IEquatable<CreatedKey>
		{
			public readonly string CollectionStable;

			public readonly string Name;

			public CreatedKey(tk2dSpriteCollectionData c, string name)
			{
				CollectionStable = GetCollectionStableId(c);
				Name = name ?? string.Empty;
			}

			public bool Equals(CreatedKey other)
			{
				if (string.Equals(CollectionStable, other.CollectionStable, StringComparison.Ordinal))
				{
					return string.Equals(Name, other.Name, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CreatedKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (17 * 31 + StringComparer.Ordinal.GetHashCode(CollectionStable ?? "")) * 31 + StringComparer.Ordinal.GetHashCode(Name ?? "");
			}
		}

		private readonly struct MatKey : IEquatable<MatKey>
		{
			public readonly int BaseMatId;

			public readonly int TexId;

			public MatKey(Material baseMat, Texture2D tex)
			{
				BaseMatId = (Object.op_Implicit((Object)(object)baseMat) ? ((Object)baseMat).GetInstanceID() : 0);
				TexId = (Object.op_Implicit((Object)(object)tex) ? ((Object)tex).GetInstanceID() : 0);
			}

			public bool Equals(MatKey other)
			{
				if (BaseMatId == other.BaseMatId)
				{
					return TexId == other.TexId;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is MatKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (BaseMatId * 397) ^ TexId;
			}
		}

		private sealed class LruCache<TKey, TValue>
		{
			private struct Entry
			{
				public TKey Key;

				public TValue Value;
			}

			private readonly int _cap;

			private readonly Dictionary<TKey, LinkedListNode<Entry>> _map;

			private readonly LinkedList<Entry> _lru;

			private readonly Action<TValue> _onEvict;

			public int Count => _map.Count;

			public LruCache(int capacity, Action<TValue> onEvict)
			{
				_cap = Mathf.Max(1, capacity);
				_map = new Dictionary<TKey, LinkedListNode<Entry>>(_cap);
				_lru = new LinkedList<Entry>();
				_onEvict = onEvict;
			}

			public bool TryGetValue(TKey key, out TValue value)
			{
				if (_map.TryGetValue(key, out var value2))
				{
					_lru.Remove(value2);
					_lru.AddFirst(value2);
					value = value2.Value.Value;
					return true;
				}
				value = default(TValue);
				return false;
			}

			public void Set(TKey key, TValue value)
			{
				if (_map.TryGetValue(key, out var value2))
				{
					value2.Value = new Entry
					{
						Key = key,
						Value = value
					};
					_lru.Remove(value2);
					_lru.AddFirst(value2);
					return;
				}
				while (_map.Count >= _cap)
				{
					EvictOne();
				}
				LinkedListNode<Entry> linkedListNode = new LinkedListNode<Entry>(new Entry
				{
					Key = key,
					Value = value
				});
				_lru.AddFirst(linkedListNode);
				_map[key] = linkedListNode;
			}

			private void EvictOne()
			{
				LinkedListNode<Entry> last = _lru.Last;
				if (last == null)
				{
					return;
				}
				_lru.RemoveLast();
				_map.Remove(last.Value.Key);
				if (_onEvict == null)
				{
					return;
				}
				try
				{
					_onEvict(last.Value.Value);
				}
				catch
				{
				}
			}

			public void Clear(bool destroyValues)
			{
				if (destroyValues && _onEvict != null)
				{
					foreach (Entry item in _lru)
					{
						try
						{
							_onEvict(item.Value);
						}
						catch
						{
						}
					}
				}
				_map.Clear();
				_lru.Clear();
			}
		}

		private const int MaxCachedMaterials = 64;

		private const int MaxCreatedIdMap = 128;

		private const int LEAD_LEGEND_TIER = 25;

		private const string INTERNAL_STATUE_PRE = "LOOP_STATUE_PRE";

		private const string INTERNAL_STATUE_SPENT = "LOOP_STATUE_SPENT";

		private const string INTERNAL_STATUE_LEGEND_PRE = "LOOP_STATUE_LEGEND_PRE";

		private const string INTERNAL_STATUE_LEGEND_SPENT = "LOOP_STATUE_LEGEND_SPENT";

		private const string INTERNAL_PEDESTAL_NORMAL = "LOOP_PEDESTAL_NORMAL";

		private const string INTERNAL_PEDESTAL_LEGEND = "LOOP_PEDESTAL_LEGEND";

		private static readonly LruCache<MatKey, Material> _matCache = new LruCache<MatKey, Material>(64, DestroyMaterial);

		private static readonly LruCache<CreatedKey, int> _createdIds = new LruCache<CreatedKey, int>(128, null);

		private static bool _tabletIconsInstalled;

		private static bool _portraitAtlasIconsInstalled;

		public static void ClearIds()
		{
			_createdIds.Clear(destroyValues: false);
		}

		public static void ClearRuntimeCaches(bool destroyUnityObjects)
		{
			_createdIds.Clear(destroyValues: false);
			_matCache.Clear(destroyUnityObjects);
		}

		public static void TryResetMasteryShrineVisuals()
		{
			try
			{
				bool spent = !MasteryShrineInteractable.AnyAlivePlayerCanUseShrine();
				MasteryShrineInteractable masteryShrineInteractable = Object.FindObjectOfType<MasteryShrineInteractable>();
				if ((Object)(object)masteryShrineInteractable != (Object)null)
				{
					Apply(((Component)masteryShrineInteractable).gameObject, spent);
				}
			}
			catch
			{
			}
		}

		private static bool IsLeadLegendUnlocked()
		{
			try
			{
				return RunSummary.HasMasteryTitleReached(25);
			}
			catch
			{
				return false;
			}
		}

		private static string GetCollectionStableId(tk2dSpriteCollectionData c)
		{
			if (!Object.op_Implicit((Object)(object)c))
			{
				return "null";
			}
			if (!string.IsNullOrEmpty(c.spriteCollectionName))
			{
				return c.spriteCollectionName;
			}
			return ((Object)c).name ?? "null";
		}

		private static void DestroySafe(Object o)
		{
			try
			{
				if (o != (Object)null)
				{
					Object.Destroy(o);
				}
			}
			catch
			{
			}
		}

		private static void DestroyMaterial(Material m)
		{
			DestroySafe((Object)(object)m);
		}

		private static Material GetOrCreateMaterial(Material baseMat, Texture2D tex)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)baseMat) || !Object.op_Implicit((Object)(object)tex))
			{
				return null;
			}
			MatKey key = new MatKey(baseMat, tex);
			if (_matCache.TryGetValue(key, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			Material val = new Material(baseMat);
			val.mainTexture = (Texture)(object)tex;
			((Object)val).hideFlags = (HideFlags)20;
			_matCache.Set(key, val);
			return val;
		}

		public static bool Apply(GameObject shrineRoot, bool spent)
		{
			try
			{
				if (!Object.op_Implicit((Object)(object)shrineRoot))
				{
					return false;
				}
				bool flag = false;
				bool flag2 = IsLeadLegendUnlocked();
				tk2dBaseSprite val = FindSpriteOnChild(shrineRoot.transform, "ShrineStatue");
				if (Object.op_Implicit((Object)(object)val))
				{
					Texture2D val2 = null;
					string text = null;
					if (flag2)
					{
						if (spent)
						{
							val2 = ModTextures.MasteryShrine.StatueLegendSpentTex;
							text = "LOOP_STATUE_LEGEND_SPENT";
						}
						else
						{
							val2 = ModTextures.MasteryShrine.StatueLegendPreTex;
							text = "LOOP_STATUE_LEGEND_PRE";
						}
					}
					else if (spent)
					{
						val2 = ModTextures.MasteryShrine.StatueSpentTex;
						text = "LOOP_STATUE_SPENT";
					}
					else
					{
						val2 = ModTextures.MasteryShrine.StatuePreTex;
						text = "LOOP_STATUE_PRE";
					}
					flag |= SwapSpriteSingle(val, val2, text);
				}
				tk2dBaseSprite val3 = FindSpriteOnChild(shrineRoot.transform, "shrine_Base");
				if (Object.op_Implicit((Object)(object)val3))
				{
					Texture2D tex = (flag2 ? ModTextures.MasteryShrine.PedestalLegendTex : ModTextures.MasteryShrine.PedestalNormalTex);
					string internalName = (flag2 ? "LOOP_PEDESTAL_LEGEND" : "LOOP_PEDESTAL_NORMAL");
					flag |= SwapSpriteSingle(val3, tex, internalName);
				}
				return flag;
			}
			catch
			{
				return false;
			}
		}

		private static tk2dBaseSprite FindSpriteOnChild(Transform root, string childName)
		{
			try
			{
				if (!Object.op_Implicit((Object)(object)root))
				{
					return null;
				}
				Transform val = root.Find(childName);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return null;
				}
				return ((Component)val).GetComponent<tk2dBaseSprite>();
			}
			catch
			{
				return null;
			}
		}

		private static bool SwapSpriteSingle(tk2dBaseSprite spr, Texture2D tex, string internalName)
		{
			try
			{
				if (!Object.op_Implicit((Object)(object)spr) || !Object.op_Implicit((Object)(object)tex))
				{
					return false;
				}
				tk2dSpriteCollectionData collection = spr.Collection;
				if (!Object.op_Implicit((Object)(object)collection) || collection.spriteDefinitions == null)
				{
					return false;
				}
				int num = spr.spriteId;
				if (num < 0 || num >= collection.spriteDefinitions.Length)
				{
					num = 0;
				}
				int num2 = AddTexAsSpriteDef(collection, num, tex, internalName);
				if (num2 < 0)
				{
					return false;
				}
				spr.SetSprite(collection, num2);
				spr.ForceBuild();
				ModTextures.Tk2dUpdateMaterialSafe(spr);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static int AddTexAsSpriteDef(tk2dSpriteCollectionData collection, int templateSpriteId, Texture2D tex, string name, float worldHeight = -1f)
		{
			CreatedKey key = new CreatedKey(collection, name);
			if (_createdIds.TryGetValue(key, out var value) && value >= 0)
			{
				return value;
			}
			try
			{
				if (!Object.op_Implicit((Object)(object)collection) || !Object.op_Implicit((Object)(object)tex))
				{
					return -1;
				}
				tk2dSpriteDefinition[] array = collection.spriteDefinitions;
				if (array == null || array.Length == 0)
				{
					return -1;
				}
				try
				{
					tk2dSpriteDefinition[] spriteDefinitions = collection.spriteDefinitions;
					if (spriteDefinitions != null)
					{
						for (int i = 0; i < spriteDefinitions.Length; i++)
						{
							tk2dSpriteDefinition val = spriteDefinitions[i];
							if (val != null && string.Equals(val.name, name, StringComparison.Ordinal))
							{
								_createdIds.Set(new CreatedKey(collection, name), i);
								return i;
							}
						}
					}
				}
				catch
				{
				}
				tk2dSpriteDefinition val2 = array[Mathf.Clamp(templateSpriteId, 0, array.Length - 1)];
				if (val2 == null)
				{
					return -1;
				}
				tk2dSpriteDefinition val3 = CloneDefinition(val2, tex, name);
				ResizeDefByPixelRatio(val3, val2, tex);
				if (worldHeight > 0f)
				{
					ResizeDefinitionToWorldHeight(val3, tex, worldHeight);
				}
				int num = array.Length;
				Array.Resize(ref array, num + 1);
				array[num] = val3;
				collection.spriteDefinitions = array;
				_createdIds.Set(key, num);
				return num;
			}
			catch
			{
				return -1;
			}
		}

		public static int AddBadgeSpriteDef(tk2dSpriteCollectionData collection, Material baseMat, Texture2D tex, string name, float pixelsPerUnit = 16f)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: 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_01b8: 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)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)collection) || !Object.op_Implicit((Object)(object)tex) || !Object.op_Implicit((Object)(object)baseMat))
			{
				return -1;
			}
			int num = Mathf.RoundToInt(pixelsPerUnit * 1000f);
			string text = $"{name}__ppu{num}";
			CreatedKey key = new CreatedKey(collection, text);
			if (_createdIds.TryGetValue(key, out var value) && value >= 0)
			{
				return value;
			}
			tk2dSpriteDefinition[] spriteDefinitions = collection.spriteDefinitions;
			if (spriteDefinitions != null)
			{
				for (int i = 0; i < spriteDefinitions.Length; i++)
				{
					tk2dSpriteDefinition val = spriteDefinitions[i];
					if (val != null && string.Equals(val.name, text, StringComparison.Ordinal))
					{
						_createdIds.Set(key, i);
						return i;
					}
				}
			}
			try
			{
				tk2dSpriteDefinition val2 = new tk2dSpriteDefinition();
				val2.name = text;
				val2.materialInst = GetOrCreateMaterial(baseMat, tex);
				val2.uvs = (Vector2[])(object)new Vector2[4];
				val2.uvs[0] = new Vector2(0f, 0f);
				val2.uvs[1] = new Vector2(1f, 0f);
				val2.uvs[2] = new Vector2(0f, 1f);
				val2.uvs[3] = new Vector2(1f, 1f);
				float num2 = ((pixelsPerUnit <= 0.0001f) ? 0.0625f : (1f / pixelsPerUnit));
				float num3 = (float)((Texture)tex).width * num2;
				float num4 = (float)((Texture)tex).height * num2;
				float num5 = num3 * 0.5f;
				float num6 = num4 * 0.5f;
				val2.position0 = new Vector3(0f - num5, 0f - num6, 0f);
				val2.position1 = new Vector3(num5, 0f - num6, 0f);
				val2.position2 = new Vector3(0f - num5, num6, 0f);
				val2.position3 = new Vector3(num5, num6, 0f);
				val2.texelSize = new Vector2(num2, num2);
				int num7 = collection.spriteDefinitions.Length;
				Array.Resize(ref collection.spriteDefinitions, num7 + 1);
				collection.spriteDefinitions[num7] = val2;
				_createdIds.Set(key, num7);
				return num7;
			}
			catch
			{
				return -1;
			}
		}

		private static tk2dSpriteDefinition CloneDefinition(tk2dSpriteDefinition template, Texture2D newTex, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			tk2dSpriteDefinition val = new tk2dSpriteDefinition();
			CopyAllInstanceFields(template, val);
			val.name = name;
			if ((Object)(object)val.materialInst != (Object)null)
			{
				val.materialInst = GetOrCreateMaterial(val.materialInst, newTex);
			}
			SetFullUvsIfPresent(val);
			return val;
		}

		private static void CopyAllInstanceFields(object src, object dst)
		{
			if (src == null || dst == null)
			{
				return;
			}
			Type type = src.GetType();
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo[] fields = type.GetFields(bindingAttr);
			foreach (FieldInfo fieldInfo in fields)
			{
				try
				{
					if (!fieldInfo.IsInitOnly)
					{
						object obj = fieldInfo.GetValue(src);
						if (obj != null && obj.GetType().IsArray)
						{
							obj = ((Array)obj).Clone();
						}
						fieldInfo.SetValue(dst, obj);
					}
				}
				catch
				{
				}
			}
		}

		private static void SetFullUvsIfPresent(tk2dSpriteDefinition def)
		{
			//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_0043: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if (def != null && def.uvs != null && def.uvs.Length >= 4)
			{
				def.uvs[0] = new Vector2(0f, 0f);
				def.uvs[1] = new Vector2(1f, 0f);
				def.uvs[2] = new Vector2(0f, 1f);
				def.uvs[3] = new Vector2(1f, 1f);
			}
		}

		private static void ResizeDefinitionToWorldHeight(tk2dSpriteDefinition def, Texture2D tex, float worldHeight)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (def != null && !((Object)(object)tex == (Object)null) && ((Texture)tex).width > 0 && ((Texture)tex).height > 0)
			{
				float num = (float)((Texture)tex).width / (float)((Texture)tex).height;
				float num2 = worldHeight * num * 0.5f;
				float num3 = worldHeight * 0.5f;
				Vector3 position = default(Vector3);
				((Vector3)(ref position))..ctor(0f - num2, 0f - num3, 0f);
				Vector3 position2 = default(Vector3);
				((Vector3)(ref position2))..ctor(num2, 0f - num3, 0f);
				Vector3 position3 = default(Vector3);
				((Vector3)(ref position3))..ctor(0f - num2, num3, 0f);
				Vector3 position4 = default(Vector3);
				((Vector3)(ref position4))..ctor(num2, num3, 0f);
				def.position0 = position;
				def.position1 = position2;
				def.position2 = position3;
				def.position3 = position4;
			}
		}

		private static void ResizeDefByPixelRatio(tk2dSpriteDefinition def, tk2dSpriteDefinition template, Texture2D newTex)
		{
			//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_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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0040: 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)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00a5: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			if (def == null || template == null || (Object)(object)newTex == (Object)null || ((Texture)newTex).width <= 0 || ((Texture)newTex).height <= 0)
			{
				return;
			}
			Vector3 position = template.position0;
			Vector3 position2 = template.position1;
			Vector3 position3 = template.position2;
			_ = template.position3;
			Vector3 val = position2 - position;
			Vector3 val2 = position3 - position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float magnitude2 = ((Vector3)(ref val2)).magnitude;
			if (magnitude <= 0.0001f || magnitude2 <= 0.0001f)
			{
				return;
			}
			Vector2 texelSize = template.texelSize;
			if (!(texelSize.x <= 1E-06f) && !(texelSize.y <= 1E-06f))
			{
				float num = magnitude / texelSize.x;
				float num2 = magnitude2 / texelSize.y;
				if (!(num <= 1f) && !(num2 <= 1f))
				{
					float num3 = (float)((Texture)newTex).width / num;
					float num4 = (float)((Texture)newTex).height / num2;
					Vector3 val3 = val * num3;
					Vector3 val4 = val2 * num4;
					Vector3 val5 = (position + position2) * 0.5f;
					def.position0 = val5 - 0.5f * val3;
					def.position1 = val5 + 0.5f * val3;
					def.position2 = def.position0 + val4;
					def.position3 = def.position1 + val4;
				}
			}
		}

		internal static void TryInstallUiIcons()
		{
			TryInstallTabletIcons();
			TryInstallConversationAtlasIcons();
		}

		internal static void TryInstallTabletIcons()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (_tabletIconsInstalled)
			{
				return;
			}
			try
			{
				GameObject val = (GameObject)ResourceCache.Acquire("ControllerButtonSprite");
				tk2dBaseSprite val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<tk2dBaseSprite>() : null);
				tk2dSpriteCollectionData val3 = (Object.op_Implicit((Object)(object)val2) ? val2.Collection : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					EnsureSpriteInCollection(val3, ModTextures.UI.HellRoundTex, "loop_hell_round");
					EnsureSpriteInCollection(val3, ModTextures.UI.CoolnessTex, "loop_coolness");
					EnsureSpriteInCollection(val3, ModTextures.UI.CurseTex, "loop_curse");
					EnsureSpriteInCollection(val3, ModTextures.UI.GlassTex, "loop_glass");
					EnsureSpriteInCollection(val3, ModTextures.UI.RageTex, "loop_rage");
					_tabletIconsInstalled = true;
				}
			}
			catch
			{
			}
		}

		internal static void TryInstallConversationAtlasIcons()
		{
			if (_portraitAtlasIconsInstalled)
			{
				return;
			}
			try
			{
				GameUIRoot instance = GameUIRoot.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.ConversationBar == (Object)null))
				{
					dfSprite portraitSprite = instance.ConversationBar.portraitSprite;
					if (!((Object)(object)portraitSprite == (Object)null) && !((Object)(object)portraitSprite.Atlas == (Object)null))
					{
						EnsureSpriteInAtlas(portraitSprite.Atlas, ModTextures.UI.HellRoundBoxTex, "loop_hell_round_box");
						_portraitAtlasIconsInstalled = true;
					}
				}
			}
			catch
			{
			}
		}

		private static void EnsureSpriteInCollection(tk2dSpriteCollectionData col, Texture2D tex, string name)
		{
			if ((Object)(object)col == (Object)null || (Object)(object)tex == (Object)null || string.IsNullOrEmpty(name))
			{
				return;
			}
			tk2dSpriteDefinition[] spriteDefinitions = col.spriteDefinitions;
			if (spriteDefinitions != null)
			{
				for (int i = 0; i < spriteDefinitions.Length; i++)
				{
					if (spriteDefinitions[i] != null && spriteDefinitions[i].name == name)
					{
						return;
					}
				}
			}
			SpriteBuilder.AddSpriteToCollection(tex, col, name);
		}

		private static void EnsureSpriteInAtlas(dfAtlas atlas, Texture2D tex, string name)
		{
			if ((Object)(object)atlas == (Object)null || (Object)(object)tex == (Object)null || string.IsNullOrEmpty(name))
			{
				return;
			}
			try
			{
				if (atlas[name] != (ItemInfo)null)
				{
					return;
				}
			}
			catch
			{
			}
			try
			{
				ToolsCharApi.AddNewItemToAtlas(atlas, tex, name);
			}
			catch
			{
			}
		}
	}
	internal static class ModTextures
	{
		internal static class MasteryShrine
		{
			public static Texture2D StatuePreTex => LoadPng("Resources/MasteryShrine", "statue_pre.png", (FilterMode)0);

			public static Texture2D StatueSpentTex => LoadPng("Resources/MasteryShrine", "statue_spent.png", (FilterMode)0);

			public static Texture2D StatueLegendPreTex => LoadPng("Resources/MasteryShrine", "statue_legend_pre.png", (FilterMode)0);

			public static Texture2D StatueLegendSpentTex => LoadPng("Resources/MasteryShrine", "statue_legend_spent.png", (FilterMode)0);

			public static Texture2D PedestalNormalTex => LoadPng("Resources/MasteryShrine", "pedestal_normal.png", (FilterMode)0);

			public static Texture2D PedestalLegendTex => LoadPng("Resources/MasteryShrine", "pedestal_legend.png", (FilterMode)0);

			public static Texture2D Mr1LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_1.png", (FilterMode)0);

			public static Texture2D Mr2LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_2.png", (FilterMode)0);

			public static Texture2D Mr3LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_3.png", (FilterMode)0);

			public static Texture2D Mr4LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_4.png", (FilterMode)0);

			public static Texture2D Mr5LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_5.png", (FilterMode)0);

			public static Texture2D Mr6LitTex => LoadPng("Resources/MasteryShrine", "mastery_badge_6.png", (FilterMode)0);

			public static Texture2D Mr6LitLegendTex => LoadPng("Resources/MasteryShrine", "mastery_badge_6_legend.png", (FilterMode)0);
		}

		internal static class LoopButton
		{
			public static Texture2D Talk1Tex => LoadPng("Resources/LoopButton", "loop_button_talk_1.png", (FilterMode)0);

			public static Texture2D Talk2Tex => LoadPng("Resources/LoopButton", "loop_button_talk_2.png", (FilterMode)0);

			public static Texture2D Talk3Tex => LoadPng("Resources/LoopButton", "loop_button_talk_3.png", (FilterMode)0);
		}

		internal static class TitleScreen
		{
			public static Texture2D Looper1Tex => LoadPng("Resources/TitleScreen", "looper_1.png", (FilterMode)0);

			public static Texture2D Looper2Tex => LoadPng("Resources/TitleScreen", "looper_2.png", (FilterMode)0);

			public static Texture2D Looper3Tex => LoadPng("Resources/TitleScreen", "looper_3.png", (FilterMode)0);

			public static Texture2D Looper4Tex => LoadPng("Resources/TitleScreen", "looper_4.png", (FilterMode)0);

			public static Texture2D Looper5Tex => LoadPng("Resources/TitleScreen", "looper_5.png", (FilterMode)0);

			public static Texture2D Looper6Tex => LoadPng("Resources/TitleScreen", "looper_6.png", (FilterMode)0);

			public static Texture2D Looper7Tex => LoadPng("Resources/TitleScreen", "looper_7.png", (FilterMode)0);

			public static Texture2D Looper8Tex => LoadPng("Resources/TitleScreen", "looper_8.png", (FilterMode)0);
		}

		internal static class UI
		{
			public static Texture2D CoolnessTex => LoadPng("Resources/UI", "coolness_icon.png", (FilterMode)0);

			public static Texture2D GlassTex => LoadPng("Resources/UI", "glass_icon.png", (FilterMode)0);

			public static Texture2D CurseTex => LoadPng("Resources/UI", "curse_icon.png", (FilterMode)0);

			public static Texture2D RageTex => LoadPng("Resources/UI", "rage_icon.png", (FilterMode)0);

			public static Texture2D HellRoundTex => LoadPng("Resources/UI", "hell_round_icon.png", (FilterMode)0);

			public static Texture2D HellRoundBoxTex => LoadPng("Resources/UI", "hell_round_box_icon.png", (FilterMode)0);
		}

		private sealed class CacheEntry
		{
			public Texture2D Tex;

			public long LooseLastWriteUtcTicks;
		}

		public static bool PreferLooseFiles = false;

		private static readonly string PluginDir = ResolvePluginDir();

		private static readonly Dictionary<string, CacheEntry> _cache = new Dictionary<string, CacheEntry>(StringComparer.OrdinalIgnoreCase);

		private static Action<tk2dBaseSprite> _tk2dUpdateMaterial;

		private static string ResolvePluginDir()
		{
			try
			{
				string text = null;
				try
				{
					Plugin instance = Plugin.Instance;
					object obj;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						PluginInfo info = ((BaseUnityPlugin)instance).Info;
						obj = ((info != null) ? info.Location : null);
					}
					text = (string)obj;
				}
				catch
				{
				}
				if (string.IsNullOrEmpty(text))
				{
					text = Assembly.GetExecutingAssembly().Location;
				}
				return string.IsNullOrEmpty(text) ? string.Empty : Path.GetDirectoryName(text);
			}
			catch
			{
				return string.Empty;
			}
		}

		private static Texture2D LoadPng(string folderUnderPluginDir, string fileName, FilterMode filter)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(fileName))
			{
				return null;
			}
			string cacheKey = folderUnderPluginDir + "/" + fileName + "|f=" + (int)filter;
			if (PreferLooseFiles && !string.IsNullOrEmpty(PluginDir))
			{
				string fullPath = Path.Combine(Path.Combine(PluginDir, folderUnderPluginDir.Replace('/', Path.DirectorySeparatorChar)), fileName);
				Texture2D val = TryLoadLoosePngCached(cacheKey, fullPath, filter);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return TryLoadEmbeddedPngCached(cacheKey, folderUnderPluginDir, fileName, filter);
		}

		private static Texture2D TryLoadLoosePngCached(string cacheKey, string fullPath, FilterMode filter)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (string.IsNullOrEmpty(fullPath) || !File.Exists(fullPath))
				{
					return null;
				}
				long ticks = File.GetLastWriteTimeUtc(fullPath).Ticks;
				if (_cache.TryGetValue(cacheKey, out var value) && value != null && (Object)(object)value.Tex != (Object)null && value.LooseLastWriteUtcTicks == ticks)
				{
					return value.Tex;
				}
				byte[] array = File.ReadAllBytes(fullPath);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false);
				if (!ImageConversion.LoadImage(val, array))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Texture)val).filterMode = filter;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Object)val).hideFlags = (HideFlags)20;
				if (value != null && (Object)(object)value.Tex != (Object)null)
				{
					Object.Destroy((Object)(object)value.Tex);
				}
				_cache[cacheKey] = new CacheEntry
				{
					Tex = val,
					LooseLastWriteUtcTicks = ticks
				};
				return val;
			}
			catch
			{
				return null;
			}
		}

		private static Texture2D TryLoadEmbeddedPngCached(string cacheKey, string folderUnderRoot, string fileName, FilterMode filter)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_cache.TryGetValue(cacheKey, out var value) && value != null && (Object)(object)value.Tex != (Object)null && value.LooseLastWriteUtcTicks == 0L)
				{
					return value.Tex;
				}
				string text = folderUnderRoot.Replace('/', '.').Replace('\\', '.');
				string name = "LoopTheGungeon." + text + "." + fileName;
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				using Stream stream = executingAssembly.GetManifestResourceStream(name);
				if (stream == null)
				{
					string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
					for (int i = 0; i < manifestResourceNames.Length; i++)
					{
						ETGModConsole.Log((object)manifestResourceNames[i], false);
					}
					return null;
				}
				byte[] array = new byte[stream.Length];
				stream.Read(array, 0, array.Length);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false);
				if (!ImageConversion.LoadImage(val, array))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Texture)val).filterMode = filter;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Object)val).hideFlags = (HideFlags)20;
				if (value != null && (Object)(object)value.Tex != (Object)null)
				{
					Object.Destroy((Object)(object)value.Tex);
				}
				_cache[cacheKey] = new CacheEntry
				{
					Tex = val,
					LooseLastWriteUtcTicks = 0L
				};
				return val;
			}
			catch
			{
				return null;
			}
		}

		public static void ClearAllCachedTextures(bool destroyUnityObjects)
		{
			if (destroyUnityObjects)
			{
				foreach (KeyValuePair<string, CacheEntry> item in _cache)
				{
					try
					{
						if ((Object)(object)item.Value?.Tex != (Object)null)
						{
							Object.Destroy((Object)(object)item.Value.Tex);
						}
					}
					catch
					{
					}
				}
			}
			_cache.Clear();
		}

		public static void Tk2dUpdateMaterialSafe(tk2dBaseSprite spr)
		{
			if ((Object)(object)spr == (Object)null)
			{
				return;
			}
			try
			{
				if (_tk2dUpdateMaterial == null)
				{
					MethodInfo method = typeof(tk2dBaseSprite).GetMethod("UpdateMaterial", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if ((object)method == null)
					{
						return;
					}
					_tk2dUpdateMaterial = (Action<tk2dBaseSprite>)Delegate.CreateDelegate(typeof(Action<tk2dBaseSprite>), null, method);
				}
				_tk2dUpdateMaterial(spr);
			}
			catch
			{
			}
		}
	}
	public static class ButtonSpritesOverride
	{
		private sealed class InstancedTk2dMarker : MonoBehaviour
		{
		}

		public class ButtonSpriteSetup : MonoBehaviour
		{
			public bool Applied;
		}

		private sealed class RuntimeAtlas
		{
			public Texture2D AtlasTex;

			public Material Mat;
		}

		private readonly struct CreatedKey : IEquatable<CreatedKey>
		{
			public readonly string CollectionStable;

			public readonly string Name;

			public CreatedKey(tk2dSpriteCollectionData c, string name)
			{
				CollectionStable = GetCollectionStableId(c);
				Name = name ?? string.Empty;
			}

			public bool Equals(CreatedKey other)
			{
				if (string.Equals(CollectionStable, other.CollectionStable, StringComparison.Ordinal))
				{
					return string.Equals(Name, other.Name, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CreatedKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (17 * 31 + StringComparer.Ordinal.GetHashCode(CollectionStable ?? "")) * 31 + StringComparer.Ordinal.GetHashCode(Name ?? "");
			}
		}

		private readonly struct AtlasKey : IEquatable<AtlasKey>
		{
			public readonly string ShaderName;

			public readonly string BaseAtlasName;

			public readonly int BaseW;

			public readonly int BaseH;

			public AtlasKey(Material templateMat)
			{
				Texture2D val = (Texture2D)(((Object)(object)templateMat != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
				ShaderName = ((Object.op_Implicit((Object)(object)templateMat) && Object.op_Implicit((Object)(object)templateMat.shader)) ? (((Object)templateMat.shader).name ?? "") : "");
				BaseAtlasName = (Object.op_Implicit((Object)(object)val) ? (((Object)val).name ?? "") : "");
				BaseW = (Object.op_Implicit((Object)(object)val) ? ((Texture)val).width : 0);
				BaseH = (Object.op_Implicit((Object)(object)val) ? ((Texture)val).height : 0);
			}

			public bool Equals(AtlasKey other)
			{
				if (BaseW == other.BaseW && BaseH == other.BaseH && string.Equals(ShaderName, other.ShaderName, StringComparison.Ordinal))
				{
					return string.Equals(BaseAtlasName, other.BaseAtlasName, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is AtlasKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((17 * 31 + BaseW) * 31 + BaseH) * 31 + StringComparer.Ordinal.GetHashCode(ShaderName ?? "")) * 31 + StringComparer.Ordinal.GetHashCode(BaseAtlasName ?? "");
			}
		}

		private readonly struct MatKey : IEquatable<MatKey>
		{
			public readonly string ShaderName;

			public readonly string BaseMatName;

			public readonly string TexName;

			public readonly int TexW;

			public readonly int TexH;

			public MatKey(Material baseMat, Texture2D tex)
			{
				ShaderName = ((Object.op_Implicit((Object)(object)baseMat) && Object.op_Implicit((Object)(object)baseMat.shader)) ? (((Object)baseMat.shader).name ?? "") : "");
				BaseMatName = (Object.op_Implicit((Object)(object)baseMat) ? (((Object)baseMat).name ?? "") : "");
				TexName = (Object.op_Implicit((Object)(object)tex) ? (((Object)tex).name ?? "") : "");
				TexW = (Object.op_Implicit((Object)(object)tex) ? ((Texture)tex).width : 0);
				TexH = (Object.op_Implicit((Object)(object)tex) ? ((Texture)tex).height : 0);
			}

			public bool Equals(MatKey other)
			{
				if (TexW == other.TexW && TexH == other.TexH && string.Equals(ShaderName, other.ShaderName, StringComparison.Ordinal) && string.Equals(BaseMatName, other.BaseMatName, StringComparison.Ordinal))
				{
					return string.Equals(TexName, other.TexName, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is MatKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((((17 * 31 + TexW) * 31 + TexH) * 31 + StringComparer.Ordinal.GetHashCode(ShaderName ?? "")) * 31 + StringComparer.Ordinal.GetHashCode(BaseMatName ?? "")) * 31 + StringComparer.Ordinal.GetHashCode(TexName ?? "");
			}
		}

		private sealed class LruCache<TKey, TValue>
		{
			private struct Entry
			{
				public TKey Key;

				public TValue Value;
			}

			private readonly int _cap;

			private readonly Dictionary<TKey, LinkedListNode<Entry>> _map;

			private readonly LinkedList<Entry> _lru;

			private readonly Action<TValue> _onEvict;

			public int Count => _map.Count;

			public LruCache(int capacity, Action<TValue> onEvict)
			{
				_cap = Mathf.Max(1, capacity);
				_map = new Dictionary<TKey, LinkedListNode<Entry>>(_cap);
				_lru = new LinkedList<Entry>();
				_onEvict = onEvict;
			}

			public bool TryGetValue(TKey key, out TValue value)
			{
				if (_map.TryGetValue(key, out var value2))
				{
					_lru.Remove(value2);
					_lru.AddFirst(value2);
					value = value2.Value.Value;
					return true;
				}
				value = default(TValue);
				return false;
			}

			public void Set(TKey key, TValue value)
			{
				if (_map.TryGetValue(key, out var value2))
				{
					value2.Value = new Entry
					{
						Key = key,
						Value = value
					};
					_lru.Remove(value2);
					_lru.AddFirst(value2);
					return;
				}
				while (_map.Count >= _cap)
				{
					EvictOne();
				}
				LinkedListNode<Entry> linkedListNode = new LinkedListNode<Entry>(new Entry
				{
					Key = key,
					Value = value
				});
				_lru.AddFirst(linkedListNode);
				_map[key] = linkedListNode;
			}

			private void EvictOne()
			{
				LinkedListNode<Entry> last = _lru.Last;
				if (last == null)
				{
					return;
				}
				_lru.RemoveLast();
				_map.Remove(last.Value.Key);
				if (_onEvict == null)
				{
					return;
				}
				try
				{
					_onEvict(last.Value.Value);
				}
				catch
				{
				}
			}

			public void Clear(bool destroyValues)
			{
				if (destroyValues && _onEvict != null)
				{
					foreach (Entry item in _lru)
					{
						try
						{
							_onEvict(item.Value);
						}
						catch
						{
						}
					}
				}
				_map.Clear();
				_lru.Clear();
			}
		}

		private readonly struct Key : IEquatable<Key>
		{
			public readonly tk2dSpriteCollectionData Col;

			public readonly int SpriteId;

			public Key(tk2dSpriteCollectionData col, int id)
			{
				Col = col;
				SpriteId = id;
			}

			public bool Equals(Key other)
			{
				if (Col == other.Col)
				{
					return SpriteId == other.SpriteId;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is Key other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (17 * 31 + (Object.op_Implicit((Object)(object)Col) ? ((Object)Col).GetInstanceID() : 0)) * 31 + SpriteId;
			}
		}

		private const int MaxCachedMaterials = 128;

		private const int MaxCachedAtlases = 16;

		private const int MaxCreatedIdMap = 512;

		private static readonly LruCache<MatKey, Material> _matCache = new LruCache<MatKey, Material>(128, DestroyMaterial);

		private static readonly LruCache<AtlasKey, RuntimeAtlas> _atlasCache = new LruCache<AtlasKey, RuntimeAtlas>(16, DestroyRuntimeAtlas);

		private static readonly LruCache<CreatedKey, int> _createdIds = new LruCache<CreatedKey, int>(512, null);

		private static string GetCollectionStableId(tk2dSpriteCollectionData c)
		{
			if (!Object.op_Implicit((Object)(object)c))
			{
				return "null";
			}
			try
			{
				PropertyInfo property = ((object)c).GetType().GetProperty("spriteCollectionName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)property != null)
				{
					string text = property.GetValue(c, null) as string;
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
			catch
			{
			}
			return ((Object)c).name ?? "null";
		}

		private static void DestroyMaterial(Material m)
		{
			try
			{
				if (Object.op_Implicit((Object)(object)m))
				{
					Object.Destroy((Object)(object)m);
				}
			}
			catch
			{
			}
		}

		private static void DestroyRuntimeAtlas(RuntimeAtlas ra)
		{
			if (ra == null)
			{
				return;
			}
			try
			{
				if (Object.op_Implicit((Object)(object)ra.AtlasTex))
				{
					Object.Destroy((Object)(object)ra.AtlasTex);
				}
			}
			catch
			{
			}
			try
			{
				if (Object.op_Implicit((Object)(object)ra.Mat))
				{
					Object.Destroy((Object)(object)ra.Mat);
				}
			}
			catch
			{
			}
		}

		public static void ClearRuntimeCaches(bool destroyUnityObjects)
		{
			_createdIds.Clear(destroyValues: false);
			_matCache.Clear(destroyUnityObjects);
			_atlasCache.Clear(destroyUnityObjects);
		}

		private static Material GetOrCreateMaterial(Material baseMat, Texture2D tex)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)baseMat) || !Object.op_Implicit((Object)(object)tex))
			{
				return null;
			}
			MatKey key = new MatKey(baseMat, tex);
			if (_matCache.TryGetValue(key, out var val