Decompiled source of UsefulUtilities v1.4.7

UsefulUtilities.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BTD_Mod_Helper;
using BTD_Mod_Helper.Api;
using BTD_Mod_Helper.Api.Audio;
using BTD_Mod_Helper.Api.Components;
using BTD_Mod_Helper.Api.Data;
using BTD_Mod_Helper.Api.Enums;
using BTD_Mod_Helper.Api.Helpers;
using BTD_Mod_Helper.Api.Internal;
using BTD_Mod_Helper.Api.ModOptions;
using BTD_Mod_Helper.Api.Towers;
using BTD_Mod_Helper.Api.UI;
using BTD_Mod_Helper.Extensions;
using HarmonyLib;
using Il2Cpp;
using Il2CppAssets;
using Il2CppAssets.Scripts;
using Il2CppAssets.Scripts.Data;
using Il2CppAssets.Scripts.Data.Boss;
using Il2CppAssets.Scripts.Data.Cosmetics;
using Il2CppAssets.Scripts.Data.Cosmetics.TowerAssetChanges;
using Il2CppAssets.Scripts.Data.Legends;
using Il2CppAssets.Scripts.Data.MapSets;
using Il2CppAssets.Scripts.Data.ParagonData;
using Il2CppAssets.Scripts.Data.Quests;
using Il2CppAssets.Scripts.Data.Skins;
using Il2CppAssets.Scripts.Data.TrophyStore;
using Il2CppAssets.Scripts.Models;
using Il2CppAssets.Scripts.Models.Bloons;
using Il2CppAssets.Scripts.Models.Entities;
using Il2CppAssets.Scripts.Models.Powers;
using Il2CppAssets.Scripts.Models.Profile;
using Il2CppAssets.Scripts.Models.Rounds;
using Il2CppAssets.Scripts.Models.ServerEvents;
using Il2CppAssets.Scripts.Models.TowerSets;
using Il2CppAssets.Scripts.Models.Towers;
using Il2CppAssets.Scripts.Models.Towers.Behaviors;
using Il2CppAssets.Scripts.Models.Towers.Upgrades;
using Il2CppAssets.Scripts.Simulation;
using Il2CppAssets.Scripts.Simulation.Bloons;
using Il2CppAssets.Scripts.Simulation.Input;
using Il2CppAssets.Scripts.Simulation.Objects;
using Il2CppAssets.Scripts.Simulation.SMath;
using Il2CppAssets.Scripts.Simulation.SimulationBehaviors;
using Il2CppAssets.Scripts.Simulation.Towers;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors;
using Il2CppAssets.Scripts.Simulation.Track;
using Il2CppAssets.Scripts.Unity;
using Il2CppAssets.Scripts.Unity.Analytics;
using Il2CppAssets.Scripts.Unity.Bridge;
using Il2CppAssets.Scripts.Unity.Display;
using Il2CppAssets.Scripts.Unity.Menu;
using Il2CppAssets.Scripts.Unity.Player;
using Il2CppAssets.Scripts.Unity.UI_New;
using Il2CppAssets.Scripts.Unity.UI_New.ChallengeEditor;
using Il2CppAssets.Scripts.Unity.UI_New.Coop;
using Il2CppAssets.Scripts.Unity.UI_New.DailyChallenge;
using Il2CppAssets.Scripts.Unity.UI_New.GameOver;
using Il2CppAssets.Scripts.Unity.UI_New.HeroInGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.AbilitiesMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.ActionMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.BloonMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.EditorMenus;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.RightMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.RightMenu.Powers;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.Stats;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.StoreMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu.TowerSelectionMenuThemes;
using Il2CppAssets.Scripts.Unity.UI_New.Legends;
using Il2CppAssets.Scripts.Unity.UI_New.Main.HeroSelect;
using Il2CppAssets.Scripts.Unity.UI_New.Main.Home;
using Il2CppAssets.Scripts.Unity.UI_New.Main.MapSelect;
using Il2CppAssets.Scripts.Unity.UI_New.Main.PowersSelect;
using Il2CppAssets.Scripts.Unity.UI_New.Popups;
using Il2CppAssets.Scripts.Unity.UI_New.Quests;
using Il2CppAssets.Scripts.Unity.UI_New.Settings;
using Il2CppAssets.Scripts.Unity.UI_New.Upgrade;
using Il2CppAssets.Scripts.Unity.UI_New.Utils;
using Il2CppAssets.Scripts.Utils.Messaging;
using Il2CppGeom;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNinjaKiwi.Common;
using Il2CppNinjaKiwi.Common.ResourceUtils;
using Il2CppNinjaKiwi.GUTS.Models.ContentBrowser;
using Il2CppNinjaKiwi.LiNK.Client;
using Il2CppNinjaKiwi.Localization;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.IO;
using Il2CppSystem.Linq;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using NAudio.Wave;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using UsefulUtilities;
using UsefulUtilities.Utilities;
using UsefulUtilities.Utilities.InGameCharts;
using UsefulUtilities.Utilities.InGameCharts.GroupTypes;
using UsefulUtilities.Utilities.InGameCharts.StatTypes;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(UsefulUtilitiesMod), "Useful Utilities", "1.4.7", "doombubbles", null)]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6")]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6-Epic")]
[assembly: HarmonyDontPatchAll]
[assembly: MelonOptionalDependencies(new string[] { "NAudio", "PathsPlusPlus" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("UsefulUtilities")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+12322fc1dd373dade4d99da92dc89b61e8a7b6b3")]
[assembly: AssemblyProduct("UsefulUtilities")]
[assembly: AssemblyTitle("UsefulUtilities")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			return !_moveNextCalled && (_moveNextCalled = true);
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object? IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => 1;

	T IReadOnlyList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
	}

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object? value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object? value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object? value)
	{
		return (!EqualityComparer<T>.Default.Equals(_item, (T)value)) ? (-1) : 0;
	}

	void IList.Insert(int index, object? value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object? value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return (!EqualityComparer<T>.Default.Equals(_item, item)) ? (-1) : 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		private readonly string <Name>k__BackingField;

		public string Name => <Name>k__BackingField;

		public ExtensionMarkerAttribute(string name)
		{
			<Name>k__BackingField = name;
		}
	}
}
namespace UsefulUtilities
{
	public static class ModHelperData
	{
		public const string WorksOnVersion = "55.0";

		public const string Version = "1.4.7";

		public const string Name = "Useful Utilities";

		public const string Description = "Adds an assortment of minor utilities to BTD6.\r\n\r\nNew: Upgrade Queueing, In Game Charts (Damage Meters and Incoming Bloons), Ability Cooldown Seconds Display, Jukebox Folder, Quick Sell, Multi Place, UI Transparency, Hotkey Display, Wiki Links, Clear Alerts, Full Screen Hotkey, Tower Selection Hotkeys, Cursor Size Hotkeys, Keep Default Upgrade Sounds\r\nPlus: Auto Nudge, Better Auto Start, Copy/Paste Towers, In-Game Hero Switch, Sacrfice Helper\r\nFrom Helpful Additions: Sandbox Clear Projectiles Button, Showing Blons in Challenge Editor, Single Player Co-Op";

		public const string RepoOwner = "doombubbles";

		public const string PrevRepoName = "useful-utilities";

		public const string RepoName = "UsefulUtilities";
	}
	public abstract class ToggleableUtility : UsefulUtility
	{
		private ModSettingBool setting = null;

		protected abstract bool DefaultEnabled { get; }

		public bool Enabled => ModSettingBool.op_Implicit(setting);

		public abstract override string Description { get; }

		protected virtual ModSettingCategory Category => null;

		public override void OnLoad()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_005c: Expected O, but got Unknown
			Dictionary<string, ModSetting> modSettings = ((ModContent)this).mod.ModSettings;
			string name = ((ModContent)this).Name;
			ModSettingBool val = new ModSettingBool(DefaultEnabled)
			{
				displayName = ((NamedModContent)this).DisplayName,
				icon = Icon,
				category = Category,
				description = ((NamedModContent)this).Description,
				source = (IModSettings)(object)this
			};
			ModSettingBool value = val;
			setting = val;
			modSettings[name] = (ModSetting)(object)value;
		}
	}
	public class UsefulUtilitiesMod : BloonsTD6Mod
	{
		public static readonly Dictionary<string, UsefulUtility> UsefulUtilities = new Dictionary<string, UsefulUtility>();

		public static readonly ModSettingCategory Jukebox = new ModSettingCategory("Jukebox")
		{
			icon = "MainMenuUiAtlas[JukeboxIcon]",
			order = 2
		};

		public static readonly ModSettingCategory Sandbox = new ModSettingCategory("Sandbox")
		{
			icon = "1bf486871cae1224ca90cf52c1965462",
			order = 3
		};

		public static readonly ModSettingCategory TrophyStore = new ModSettingCategory("Trophy Store")
		{
			icon = "MainMenuUiAtlas[TrophyStoreBtn]",
			order = 4
		};

		public static MelonPreferences_Category Preferences { get; private set; } = null;

		public override void OnApplicationStart()
		{
			Preferences = MelonPreferences.CreateCategory("5a1367fa308893747a4294d7d7958802");
			CollectionExtensions.Do<Type>(from type in AccessTools.GetTypesFromAssembly(((MelonBase)this).MelonAssembly.Assembly)
				where !type.IsNested
				select type, (Action<Type>)((BloonsMod)this).ApplyHarmonyPatches);
		}

		public override void OnSaveSettings(JObject settings)
		{
			foreach (UsefulUtility value in UsefulUtilities.Values)
			{
				value.OnSaveSettings();
			}
		}

		public override void OnUpdate()
		{
			foreach (UsefulUtility value in UsefulUtilities.Values)
			{
				value.OnUpdate();
			}
		}

		public override void OnRoundStart()
		{
			Meters.GetRoundData();
		}

		public override void OnMatchStart()
		{
			Meters.ClearData();
			UpgradeQueueing.QueuedUpgrades.Clear();
		}

		public override void OnGameObjectsReset()
		{
			Meters.ClearData();
			UpgradeQueueing.QueuedUpgrades.Clear();
		}

		public override void OnTitleScreen()
		{
			foreach (UsefulUtility value in UsefulUtilities.Values)
			{
				value.OnTitleScreen();
			}
		}

		public override void OnMainMenu()
		{
			foreach (UsefulUtility value in UsefulUtilities.Values)
			{
				value.OnMainMenu();
			}
		}
	}
	public abstract class UsefulUtility : NamedModContent, IModSettings, IModContent
	{
		protected virtual bool CreateCategory => false;

		protected virtual string Icon => ((ModContent)this).TextureExists(((ModContent)this).Name) ? ((ModContent)this).GetTextureGUID(((ModContent)this).Name) : null;

		protected virtual string DisableIfModPresent => ((ModContent)this).Name;

		protected static Instance MelonLogger => ((MelonBase)ModContent.GetInstance<UsefulUtilitiesMod>()).LoggerInstance;

		public override IEnumerable<ModContent> Load()
		{
			if (!ModHelper.HasMod(DisableIfModPresent))
			{
				Type[] nestedTypes = ((object)this).GetType().GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
				foreach (Type nestedType in nestedTypes)
				{
					((ModContent)this).mod.ApplyHarmonyPatches(nestedType);
				}
				OnLoad();
				yield return (ModContent)(object)this;
			}
		}

		public override void Register()
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			UsefulUtilitiesMod.UsefulUtilities[((ModContent)this).Name] = this;
			if (CreateCategory)
			{
				ModSettingCategory category = new ModSettingCategory(((NamedModContent)this).DisplayName)
				{
					icon = Icon,
					collapsed = true
				};
				foreach (ModSetting item in ((ModContent)this).mod.ModSettings.Values.Where((ModSetting setting) => (object)setting.source == this))
				{
					item.category = category;
				}
			}
			OnRegister();
		}

		public virtual void OnLoad()
		{
		}

		public virtual void OnRegister()
		{
		}

		public virtual void OnSaveSettings()
		{
		}

		public virtual void OnUpdate()
		{
		}

		public virtual void OnTitleScreen()
		{
		}

		public virtual void OnMainMenu()
		{
		}
	}
}
namespace UsefulUtilities.Utilities
{
	public class AbilitySeconds : UsefulUtility
	{
		[HarmonyPatch(typeof(AbilityMenu), "Update")]
		internal static class AbilityMenu_Update
		{
			[HarmonyPrefix]
			internal static void Prefix(AbilityMenu __instance)
			{
				Enumerator<StackedAbilityButton> enumerator = __instance.GetAbilitiesButtons().GetEnumerator();
				while (enumerator.MoveNext())
				{
					StackedAbilityButton current = enumerator.Current;
					AbilityToSimulation ability = ((IEnumerable<AbilityToSimulation>)current.abilities.ToArray()).OrderBy((AbilityToSimulation x) => x.CooldownRemaining).First();
					ApplyCooldownText(ability, (AbilityButton)(object)current);
				}
			}
		}

		[HarmonyPatch(typeof(TowerSelectionMenu), "OnUpdate")]
		internal static class TowerSelectionMenu_OnUpdate
		{
			[HarmonyPrefix]
			internal static void Prefix(TowerSelectionMenu __instance)
			{
				foreach (AbilityButton item in (Il2CppArrayBase<AbilityButton>)(object)__instance.abilityButtons)
				{
					ApplyCooldownText(item.ability, item);
				}
			}
		}

		public static readonly ModSettingDouble AbilityTextOpacity;

		public static readonly ModSettingInt DecimalPlaces;

		public static readonly ModSettingBool EnableTextColor;

		public static readonly ModSettingBool EnableDefaultCooldownCircle;

		public static readonly ModSettingBool EnableTrailingS;

		protected override bool CreateCategory => true;

		public override string Description => "Makes Ability buttons display their cooldown in seconds";

		private static void ApplyCooldownText(AbilityToSimulation? ability, AbilityButton abilityButton)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			if (ability == null)
			{
				return;
			}
			Transform val = ((Component)abilityButton).transform.Find("AbilitySecondsTextPanel");
			Image cooldownFade = abilityButton.cooldownFade;
			if (cooldownFade != null)
			{
				((Component)cooldownFade).gameObject.SetActive(ModSettingBool.op_Implicit(EnableDefaultCooldownCircle) || ModSettingDouble.op_Implicit(AbilityTextOpacity) == 0f);
			}
			if (ability.IsReady || ability.CurrentAdditionalCharges > 0)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					GameObjectExt.Destroy(((Component)val).gameObject);
				}
				return;
			}
			float num = ability.CooldownRemaining / (1f + ability.model.CooldownSpeedScale);
			ModHelperPanel val2;
			if ((Object)(object)val == (Object)null)
			{
				RectTransform component = ((Component)abilityButton).GetComponent<RectTransform>();
				GameObject gameObject = ((Component)abilityButton).gameObject;
				Rect rect = component.rect;
				float width = ((Rect)(ref rect)).width;
				rect = component.rect;
				val2 = GameObjectExt.AddModHelperPanel(gameObject, new Info("AbilitySecondsTextPanel", 0f, 0f, width, ((Rect)(ref rect)).height), (string)null, (Axis?)null, 50f, 0);
				ModHelperPanel obj = val2;
				rect = component.rect;
				float num2 = ((Rect)(ref rect)).width + 25f;
				rect = component.rect;
				ModHelperText val3 = ((ModHelperComponent)obj).AddText(new Info("AbilitySecondsText", 0f, 0f, num2, ((Rect)(ref rect)).height - 30f), "", 68f, (TextAlignmentOptions)1026);
				NK_TextMeshProUGUI text = val3.Text;
				((TMP_Text)text).fontStyle = (FontStyles)(((TMP_Text)text).fontStyle | 0x20);
				((Component)val3).transform.SetParent(((Component)val2).transform);
			}
			else
			{
				val2 = ((Component)val).GetComponent<ModHelperPanel>();
			}
			ModHelperText component2 = ((Component)((Component)val2).transform.Find("AbilitySecondsText")).GetComponent<ModHelperText>();
			if (ModSettingBool.op_Implicit(EnableTextColor))
			{
				float num3 = ability.CooldownRemaining / ability.CooldownTotal;
				((Graphic)component2.Text).color = new Color(1f, 1f - num3, 1f - num3, ModSettingDouble.op_Implicit(AbilityTextOpacity));
			}
			else
			{
				((Graphic)component2.Text).color = new Color(1f, 1f, 1f, ModSettingDouble.op_Implicit(AbilityTextOpacity));
			}
			string text2 = string.Format("{0:F" + ((ModSetting)DecimalPlaces).GetValue()?.ToString() + "}", num) + (ModSettingBool.op_Implicit(EnableTrailingS) ? "s" : "");
			component2.SetText(text2);
		}

		static AbilitySeconds()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_009e: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_00c0: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			ModSettingDouble val = new ModSettingDouble(1.0)
			{
				icon = "b313b6873bb06924c8d4133960338f6d",
				description = "Ability Timer Text Opacity. 0.0 = text disabled"
			};
			((ModSettingNumber<double>)val).min = 0.0;
			((ModSettingNumber<double>)val).max = 1.0;
			((ModSettingNumber<double>)val).slider = true;
			val.stepSize = 0.01f;
			AbilityTextOpacity = val;
			ModSettingInt val2 = new ModSettingInt(1)
			{
				icon = "MainMenuUiAtlas[EnterCodeIcon]"
			};
			((ModSettingNumber<long>)val2).min = 0L;
			((ModSettingNumber<long>)val2).max = 2L;
			((ModSetting)val2).description = "Amount of decimal places to display.";
			((ModSettingNumber<long>)val2).slider = true;
			DecimalPlaces = val2;
			EnableTextColor = new ModSettingBool(true)
			{
				icon = "UiEmoteIcons[Rainbow]",
				description = "Enable a red hue for abilities. The more time on a cooldown, the deeper the red."
			};
			EnableDefaultCooldownCircle = new ModSettingBool(false)
			{
				icon = "IngameUi[CooldownClockBg]",
				description = "Enable the default cooldown circle."
			};
			EnableTrailingS = new ModSettingBool(true)
			{
				description = "Enable to have \"s\" appended to timers (i.e. 6.9s opposed to 6.9)."
			};
		}
	}
	public class AutoNudge : UsefulUtility
	{
		private static readonly ModSettingHotkey NudgeToClosest = new ModSettingHotkey((KeyCode)9, (HotkeyModifier)0)
		{
			description = "HotKey that will automatically nudge towers to the closest valid spot while placing them.",
			icon = ModContent.GetTextureGUID<UsefulUtilitiesMod>("AutoNudge")
		};

		private static readonly ModSettingHotkey NudgeLeft = new ModSettingHotkey((KeyCode)276, (HotkeyModifier)0)
		{
			icon = "Gamepad[PS4_Dpad_Left]"
		};

		private static readonly ModSettingHotkey NudgeRight = new ModSettingHotkey((KeyCode)275, (HotkeyModifier)0)
		{
			icon = "Gamepad[PS4_Dpad_Right]"
		};

		private static readonly ModSettingHotkey NudgeUp = new ModSettingHotkey((KeyCode)273, (HotkeyModifier)0)
		{
			icon = "Gamepad[PS4_Dpad_Up]"
		};

		private static readonly ModSettingHotkey NudgeDown = new ModSettingHotkey((KeyCode)274, (HotkeyModifier)0)
		{
			icon = "Gamepad[PS4_Dpad_Down]"
		};

		private static readonly ModSettingHotkey ConfirmPlacement = new ModSettingHotkey((KeyCode)13, (HotkeyModifier)0)
		{
			icon = "Ui[SelectedTick]"
		};

		protected override bool CreateCategory => true;

		public override void OnUpdate()
		{
			Update();
		}

		public static void Update()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)InGame.instance) || InGame.Bridge == null || InGame.instance.ReviewMapMode || InGame.Bridge.IsSpectatorMode)
			{
				return;
			}
			InputManager inputManager = InGameExt[InGame.instance];
			if (!inputManager.IsInPlacementMode)
			{
				return;
			}
			if (NudgeToClosest.JustPressed())
			{
				NudgeClosest();
				if (ConfirmPlacement.IsPressed())
				{
					TaskScheduler.ScheduleTask((Action)delegate
					{
						inputManager.TryPlace();
					}, (Func<bool>)null);
				}
			}
			else
			{
				Vector2 val = Vector2.zero;
				if (NudgeLeft.IsPressed())
				{
					val += new Vector2(-1f, 0f);
				}
				if (NudgeRight.IsPressed())
				{
					val += new Vector2(1f, 0f);
				}
				if (NudgeUp.IsPressed())
				{
					val += new Vector2(0f, 1f);
				}
				if (NudgeDown.IsPressed())
				{
					val += new Vector2(0f, -1f);
				}
				if (val != Vector2.zero)
				{
					NudgeDirection(val);
				}
			}
			if (ConfirmPlacement.JustPressed())
			{
				inputManager.TryPlace();
			}
		}

		private static void NudgeClosest()
		{
			//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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = InputSystemController.MousePosition;
			int num = 0;
			while (!CanPlace(val))
			{
				val = InputSystemController.MousePosition + GeomExtensions.Rotate(Vector2.up, (float)(num * 10)) * (float)num / 10f;
				((Vector2)(ref val))..ctor((float)(int)val.x, (float)(int)val.y);
				if (num++ > 20000)
				{
					UsefulUtility.MelonLogger.Msg("No spot found");
					return;
				}
			}
			Mouse.current.WarpCursorPosition(val);
		}

		private static bool CanPlace(Vector2 realCursorPos)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			InputManager val = InGameExt[InGame.instance];
			UnityToSimulation bridge = InGame.instance.bridge;
			Vector2 worldFromPointer = InGame.instance.GetWorldFromPointer(realCursorPos);
			return bridge.CanPlaceTowerAt(worldFromPointer, val.placementModel, bridge.MyPlayerNumber, val.placementEntityId);
		}

		private static void NudgeDirection(Vector2 dir)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			int width = Screen.width;
			float num = (float)width / 1000f;
			if (Input.GetKey((KeyCode)306))
			{
				num *= 5f;
			}
			int num2 = ((Random.Shared.NextSingle() < num - (float)(int)num) ? 1 : 0);
			int num3 = (int)num + num2;
			Vector2 mousePosition = InputSystemController.MousePosition;
			Mouse.current.WarpCursorPosition(mousePosition + dir * (float)num3);
		}
	}
	public class BetterAutoStart : ToggleableUtility
	{
		[HarmonyPatch(typeof(Button), "OnPointerClick")]
		internal class Button_OnPointerClick
		{
			[HarmonyPostfix]
			internal static void Postfix(Button __instance, PointerEventData eventData)
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Invalid comparison between Unknown and I4
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Invalid comparison between Unknown and I4
				if ((Object)(object)InGame.instance == (Object)null || ((Object)__instance).name != "FastFoward-Go" || !IsEnabled)
				{
					return;
				}
				InputButton button = eventData.button;
				InputButton val = button;
				if ((int)val != 1)
				{
					if ((int)val == 2)
					{
						GameExt.GetPlayerProfile(Game.instance).inGameSettings.autoPlay = true;
						InGame.instance.bridge.SetAutoPlay(true);
						PopupScreen.instance.ShowSetValuePopup("Disable Auto Start on Round", "Auto Start will automatically disable just before the given round starts.", Action<int>.op_Implicit((Action<int>)delegate(int r)
						{
							turnOffOnRound = r - 1;
						}), InGame.Bridge.GetEndRound() + 1);
					}
				}
				else
				{
					bool autoPlay = !InGame.instance.bridge.simulation.autoPlay;
					GameExt.GetPlayerProfile(Game.instance).inGameSettings.autoPlay = autoPlay;
					InGame.instance.bridge.SetAutoPlay(autoPlay);
				}
			}
		}

		[HarmonyPatch(typeof(GoFastForwardToggle), "OnEnable")]
		internal static class GoFastForwardToggle_OnEnable
		{
			[HarmonyPostfix]
			private static void Postfix(GoFastForwardToggle __instance)
			{
				if (IsEnabled)
				{
					UpdateTextures(__instance, GameExt.GetPlayerProfile(Game.instance).inGameSettings.autoPlay);
				}
			}
		}

		[HarmonyPatch(typeof(UnityToSimulation), "SetAutoPlay")]
		internal static class UnityToSimulation_ToggleAutoPlay
		{
			[HarmonyPostfix]
			private static void Postfix(bool on)
			{
				if ((Object)(object)ShopMenuExt.instance != (Object)null && (Object)(object)ShopMenuExt.instance.goFFToggle != (Object)null && IsEnabled)
				{
					UpdateTextures(ShopMenuExt.instance.goFFToggle, on);
				}
			}
		}

		[HarmonyPatch(typeof(Simulation), "RoundEnd")]
		internal static class Simulation_RoundEnd
		{
			[HarmonyPrefix]
			internal static void Prefix(Simulation __instance, int round)
			{
				if (round + 1 == turnOffOnRound)
				{
					__instance.pauseAutoPlay = true;
					turnOffOnRound = -1;
				}
			}
		}

		[HarmonyPatch(typeof(InGame), "Quit")]
		internal static class InGame_Quit
		{
			[HarmonyPostfix]
			internal static void Postfix()
			{
				turnOffOnRound = -1;
			}
		}

		private static int turnOffOnRound = -1;

		protected override bool DefaultEnabled => true;

		public override string Description => "Makes the Auto Start setting visible on the Play button, and causes right clicking the play button to toggle Auto Start. Middle clicking the button will let you set an upcoming round to automatically disable auto start before.";

		private static bool IsEnabled => ModContent.GetInstance<BetterAutoStart>().Enabled;

		private static Sprite GetSprite(string name)
		{
			return ModContent.GetSprite<UsefulUtilitiesMod>(name, 10f);
		}

		private static void UpdateTextures(GoFastForwardToggle toggle, bool enabled)
		{
			if (enabled)
			{
				ImageExt.SetSprite(toggle.goImage.GetComponent<Image>(), GetSprite("GoBtn"));
				ImageExt.SetSprite(toggle.fastForwardOffImage.GetComponent<Image>(), GetSprite("FastForwardBtn"));
				ImageExt.SetSprite(toggle.fastForwardOnImage.GetComponent<Image>(), GetSprite("FastForwardGlowBtn"));
			}
			else
			{
				ImageExt.SetSprite(toggle.goImage.GetComponent<Image>(), "IngameUi[GoBtn]");
				ImageExt.SetSprite(toggle.fastForwardOffImage.GetComponent<Image>(), "IngameUi[FastForwardBtn]");
				ImageExt.SetSprite(toggle.fastForwardOnImage.GetComponent<Image>(), "IngameUi[FastForwardGlowBtn]");
			}
		}
	}
	public class BossChallengeBadges : ToggleableUtility
	{
		[HarmonyPatch(typeof(MapSelectScreen), "Open")]
		internal static class MapSelectScreen_Open
		{
			[HarmonyPostfix]
			internal static void Postfix(MapSelectScreen __instance, Object? data)
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				if (ModContent.GetInstance<BossChallengeBadges>().Enabled && (data == null || !((Il2CppObjectBase)data).Unbox<bool>()))
				{
					ModHelperButton val = ModHelperButton.Create(new Info("BossChallengeBadges", 180f), "Ui[BlueBtnSquare]", Action.op_Implicit((Action)delegate
					{
						SinglePlayerCoop.Active = false;
						Active = !Active;
						__instance.mapSelectTransition.UpdateMaps(2, true);
						AudioClipExtensions.Play(MenuManager.instance.buttonClick3Sound, "ClickSounds", 1f);
					}));
					((ModHelperComponent)val).AddImage(new Info("Icon", 150f), ModContent.GetTextureGUID<UsefulUtilitiesMod>("Boss"));
					((ModHelperComponent)val).SetParent(((Component)__instance).transform);
					MatchLocalPosition val2 = ((ModHelperComponent)val).AddComponent<MatchLocalPosition>();
					val2.transformToCopy = GameObjectExt.GetComponentInChildrenByName<Transform>(((Component)__instance).gameObject, "SearchBtnObject");
					val2.offset = new Vector3(15f, -256f, 0f);
				}
			}
		}

		[HarmonyPatch(typeof(MapButton), "Init")]
		internal static class MapButton_Init
		{
			[HarmonyPrefix]
			internal static void Prefix(MapButton __instance)
			{
				__instance.medals.SetActive(true);
				((Behaviour)__instance.button).enabled = true;
			}

			[HarmonyPostfix]
			internal unsafe static void Postfix(MapButton __instance)
			{
				//IL_0260: Unknown result type (might be due to invalid IL or missing references)
				//IL_0277: Unknown result type (might be due to invalid IL or missing references)
				//IL_0282: Unknown result type (might be due to invalid IL or missing references)
				//IL_0473: Unknown result type (might be due to invalid IL or missing references)
				//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_02db: Unknown result type (might be due to invalid IL or missing references)
				//IL_032a: Unknown result type (might be due to invalid IL or missing references)
				//IL_036f: Unknown result type (might be due to invalid IL or missing references)
				//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_041c: Unknown result type (might be due to invalid IL or missing references)
				ModHelperPanel val = GameObjectExt.GetComponentInChildrenByName<ModHelperPanel>(((Component)__instance).gameObject, "BossBadges");
				__instance.medals.SetActive(!Active);
				if (val != null)
				{
					((Component)val).gameObject.SetActive(Active);
				}
				if (!Active || InGameData.Editable.selectedCoopMode)
				{
					return;
				}
				BossType[] values = Enum.GetValues<BossType>();
				Dictionary<string, Dictionary<string, BossScoreComponents>> bossChallenges = ((Player<ProfileModel>)(object)Game.Player).Data.bossChallengeScores ?? new Dictionary<string, Dictionary<string, BossScoreComponents>>();
				SpriteReference val2 = __instance.basicBackground;
				__instance.chimpsGoldSparkles.SetActive(false);
				__instance.chimpsHematiteSparkles.SetActive(false);
				Dictionary<string, BossScoreComponents> val9 = default(Dictionary<string, BossScoreComponents>);
				if (values.All((BossType boss) => bossChallenges.TryGetValue(((object)(*(BossType*)(&boss))/*cast due to .constrained prefix*/).ToString() + "Elite", ref val9) && val9.ContainsKey(__instance.mapId)))
				{
					val2 = __instance.blackBackground;
					__instance.chimpsHematiteSparkles.SetActive(true);
				}
				else if (Il2CppSystemDictionaryExt.Entries<string, Dictionary<string, BossScoreComponents>>(bossChallenges).Any<(string, Dictionary<string, BossScoreComponents>)>(((string key, Dictionary<string, BossScoreComponents> value) tuple) => tuple.key.Contains("Elite") && tuple.value.ContainsKey(__instance.mapId)))
				{
					val2 = __instance.goldBackground;
					__instance.chimpsGoldSparkles.SetActive(true);
				}
				else if (values.All((BossType boss) => bossChallenges.TryGetValue(((object)(*(BossType*)(&boss))/*cast due to .constrained prefix*/).ToString(), ref val9) && val9.ContainsKey(__instance.mapId)))
				{
					val2 = __instance.silverBackground;
				}
				else if (Il2CppSystemDictionaryExt.Values<string, Dictionary<string, BossScoreComponents>>(bossChallenges).Any((Dictionary<string, BossScoreComponents> scores) => scores.ContainsKey(__instance.mapId)))
				{
					val2 = __instance.bronzeBackground;
				}
				ImageExt.SetSprite(__instance.mapBackground, val2);
				((Component)__instance.friendPanel).gameObject.SetActive(false);
				((Component)__instance.monkeyTeamsVisual).gameObject.SetActive(false);
				__instance.goldenBloonVisual.gameObject.SetActive(false);
				__instance.continueIcon.SetActive(Il2CppSystemDictionaryExt.Entries<string, MapSaveDataModel>(((Player<ProfileModel>)(object)Game.Player).Data.savedMaps).Any<(string, MapSaveDataModel)>(((string key, MapSaveDataModel value) tuple) => tuple.key.StartsWith("BC") && tuple.value.mapName == __instance.mapId));
				if ((Object)(object)val == (Object)null)
				{
					GameObject gameObject = ((Component)__instance).gameObject;
					Info val3 = default(Info);
					((Info)(ref val3))..ctor("BossBadges");
					((Info)(ref val3)).set_Position(new Vector2(0f, -250f));
					((Info)(ref val3)).set_SizeDelta(new Vector2(850f, 140f));
					val = GameObjectExt.AddModHelperPanel(gameObject, val3, (string)null, (Axis?)(Axis)0, 0f, 0);
					((LayoutGroup)((ModHelperComponent)val).LayoutGroup).childAlignment = (TextAnchor)4;
					for (int num = 0; num < values.Length; num++)
					{
						BossType bossType = values[num];
						ModHelperButton val4 = ((ModHelperComponent)val).AddButton(new Info(((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString(), (InfoPreset)1), (string)null, Action.op_Implicit((Action)delegate
						{
							//IL_001d: Unknown result type (might be due to invalid IL or missing references)
							((Player<ProfileModel>)(object)Game.Player).Data.isBossEliteSelected = true;
							((Player<ProfileModel>)(object)Game.Player).Data.selectedChallengeBoss = bossType;
							((Player<ProfileModel>)(object)Game.Player).Data.selectedChallengeBossMap = __instance.mapId;
							MenuManager.instance.OpenMenu(SceneNames.BossEventUI, (Object)(object)new Tuple<BossEvent, bool>((BossEvent)null, false), false);
						}));
						((Info)(ref val3))..ctor(((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString(), 150f);
						((Info)(ref val3)).set_Y((float)(num % 2 * 50));
						ModHelperImage val5 = ((ModHelperComponent)val4).AddImage(val3, VanillaSprites.ByName[((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString() + "Badge"]);
						((Graphic)val5.Image).color = new Color(0.5f, 0.5f, 0.5f);
						((Info)(ref val3))..ctor(((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString() + "Badge", 150f);
						((Info)(ref val3)).set_Y((float)(num % 2 * 50));
						((ModHelperComponent)val4).AddImage(val3, VanillaSprites.ByName[((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString() + "Badge"]);
						((Info)(ref val3))..ctor(((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString() + "EliteBadge", 150f);
						((Info)(ref val3)).set_Y((float)(num % 2 * 50));
						((ModHelperComponent)val4).AddImage(val3, VanillaSprites.ByName[((object)Unsafe.As<BossType, BossType>(ref bossType)/*cast due to .constrained prefix*/).ToString() + "EliteBadge"]);
					}
				}
				BossType[] array = values;
				Dictionary<string, BossScoreComponents> val7 = default(Dictionary<string, BossScoreComponents>);
				Dictionary<string, BossScoreComponents> val8 = default(Dictionary<string, BossScoreComponents>);
				for (int num2 = 0; num2 < array.Length; num2++)
				{
					BossType val6 = array[num2];
					Transform componentInChildrenByName = GameObjectExt.GetComponentInChildrenByName<Transform>(((Component)val).gameObject, ((object)(*(BossType*)(&val6))/*cast due to .constrained prefix*/).ToString() + "Badge");
					Transform componentInChildrenByName2 = GameObjectExt.GetComponentInChildrenByName<Transform>(((Component)val).gameObject, ((object)(*(BossType*)(&val6))/*cast due to .constrained prefix*/).ToString() + "EliteBadge");
					((Component)componentInChildrenByName).gameObject.SetActive(bossChallenges.TryGetValue(((object)(*(BossType*)(&val6))/*cast due to .constrained prefix*/).ToString(), ref val7) && val7 != null && val7.ContainsKey(__instance.mapId));
					((Component)componentInChildrenByName2).gameObject.SetActive(bossChallenges.TryGetValue(((object)(*(BossType*)(&val6))/*cast due to .constrained prefix*/).ToString() + "Elite", ref val8) && val8 != null && val8.ContainsKey(__instance.mapId));
				}
			}
		}

		[HarmonyPatch(typeof(MapButton), "OnClick")]
		internal static class MapButton_OnClick
		{
			[HarmonyPrefix]
			internal static bool Prefix(MapButton __instance)
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				if (!Active)
				{
					return true;
				}
				((Player<ProfileModel>)(object)Game.Player).Data.isBossEliteSelected = true;
				((Player<ProfileModel>)(object)Game.Player).Data.selectedChallengeBossMap = __instance.mapId;
				Enumerator<string, MapSaveDataModel> enumerator = ((Player<ProfileModel>)(object)Game.Player).Data.savedMaps.GetEnumerator();
				string text = default(string);
				MapSaveDataModel val = default(MapSaveDataModel);
				while (enumerator.MoveNext())
				{
					enumerator.Current.Deconstruct(ref text, ref val);
					string text2 = text;
					MapSaveDataModel val2 = val;
					if (text2.StartsWith("BC") && val2.mapName == __instance.mapId && Enum.TryParse<BossType>(text2.Replace("BC", ""), out BossType result))
					{
						((Player<ProfileModel>)(object)Game.Player).Data.selectedChallengeBoss = result;
						break;
					}
				}
				MenuManager.instance.OpenMenu(SceneNames.BossEventUI, (Object)(object)new Tuple<BossEvent, bool>((BossEvent)null, false), false);
				return false;
			}
		}

		public static bool Active { get; set; }

		protected override bool DefaultEnabled => true;

		public override string Description => "Shows a button in the map selection screen for showing Boss Challenge completions";

		protected override string Icon => ((ModContent)this).GetTextureGUID("Boss");

		public override void OnMainMenu()
		{
			Active = false;
		}
	}
	public class ClearAlerts : ToggleableUtility
	{
		[HarmonyPatch(typeof(Button), "OnPointerClick")]
		internal class Button_OnPointerClick
		{
			[HarmonyPostfix]
			internal static void Postfix(Button __instance, PointerEventData eventData)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Invalid comparison between Unknown and I4
				//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0604: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((int)eventData.button != 1 || Game.Player == null)
					{
						return;
					}
					ProfileModel data = ((Player<ProfileModel>)(object)Game.Player).Data;
					bool flag = false;
					bool flag2 = false;
					string text = default(string);
					List<InstaTowerModel> val3 = default(List<InstaTowerModel>);
					if (((Object)((Component)__instance).transform.parent).name == "PowersAnim")
					{
						Enumerator<string, PowerData> enumerator = data.powersData.GetEnumerator();
						PowerData val = default(PowerData);
						while (enumerator.MoveNext())
						{
							enumerator.Current.Deconstruct(ref text, ref val);
							PowerData val2 = val;
							if (val2.isNew)
							{
								val2.isNew = false;
								flag = true;
							}
						}
						Enumerator<string, List<InstaTowerModel>> enumerator2 = data.instaTowers.GetEnumerator();
						while (enumerator2.MoveNext())
						{
							enumerator2.Current.Deconstruct(ref text, ref val3);
							List<InstaTowerModel> val4 = val3;
							Enumerator<InstaTowerModel> enumerator3 = val4.GetEnumerator();
							while (enumerator3.MoveNext())
							{
								InstaTowerModel current = enumerator3.Current;
								if (current.isNew)
								{
									flag = true;
									current.isNew = false;
								}
							}
						}
						if (flag)
						{
							((Component)__instance).GetComponentInParent<PipEventChecker>().CheckEvent((Object)null);
						}
					}
					InstaTowerTypeDisplay val5 = default(InstaTowerTypeDisplay);
					if (GameObjectExt.HasComponent<InstaTowerTypeDisplay>(((Component)__instance).gameObject, ref val5))
					{
						List<InstaTowerModel> val6 = data.instaTowers[val5.baseTowerID];
						Enumerator<InstaTowerModel> enumerator4 = val6.GetEnumerator();
						while (enumerator4.MoveNext())
						{
							InstaTowerModel current2 = enumerator4.Current;
							if (current2.isNew)
							{
								flag = true;
								current2.isNew = false;
							}
						}
						if (flag)
						{
							((Component)((Component)__instance).transform.FindChild("Notify")).gameObject.SetActive(false);
						}
					}
					if (((Object)__instance).name == "InstaTowerMenuBtn")
					{
						Enumerator<string, List<InstaTowerModel>> enumerator5 = data.instaTowers.GetEnumerator();
						while (enumerator5.MoveNext())
						{
							enumerator5.Current.Deconstruct(ref text, ref val3);
							List<InstaTowerModel> val7 = val3;
							Enumerator<InstaTowerModel> enumerator6 = val7.GetEnumerator();
							while (enumerator6.MoveNext())
							{
								InstaTowerModel current3 = enumerator6.Current;
								if (current3.isNew)
								{
									flag = true;
									current3.isNew = false;
								}
							}
						}
						if (flag)
						{
							((Component)((Component)__instance).transform.FindChild("Notify")).gameObject.SetActive(false);
						}
					}
					if (((Object)((Component)__instance).transform.parent).name == "CoopAnim" || ((Object)__instance).name == "ContestedTerritoryButton")
					{
						CtEvent nextAvailableCtEventCached = CtEventExtensions.GetNextAvailableCtEventCached();
						if (nextAvailableCtEventCached != null && data.seenUpcomingCtEventId != ((BaseServerEvent)nextAvailableCtEventCached).id)
						{
							data.seenUpcomingCtEventId = ((BaseServerEvent)nextAvailableCtEventCached).id;
							flag = true;
							PipEventChecker componentInParent = ((Component)__instance).GetComponentInParent<PipEventChecker>();
							if (componentInParent != null)
							{
								componentInParent.CheckEvent((Object)null);
							}
						}
					}
					HeroButton val8 = default(HeroButton);
					if (GameObjectExt.HasComponent<HeroButton>(((Component)__instance).gameObject, ref val8))
					{
						if (data.seenNewHeroNotification.Add(val8.HeroId))
						{
							flag = true;
						}
						foreach (SkinData item in (Il2CppArrayBase<SkinData>)(object)GameData.Instance.skinsData.SkinList.items)
						{
							if (item.baseTowerName == val8.HeroId && data.seenNewTowerSkinNotification.Add(((Object)item).name))
							{
								flag = true;
							}
						}
						QuestDetails val9 = default(QuestDetails);
						if (QuestTrackerManager.instance.TryGetTowerTrialQuest(val8.HeroId, ref val9))
						{
							Enumerator<QuestSaveData> enumerator8 = data.questsSaveData.GetEnumerator();
							while (enumerator8.MoveNext())
							{
								QuestSaveData current5 = enumerator8.Current;
								if (!current5.hasSeenQuest && current5.questId == val9.id)
								{
									current5.hasSeenQuest = true;
									flag = true;
								}
							}
						}
						if (flag)
						{
							((Component)((Component)__instance).transform.FindChild("PipNotification")).gameObject.SetActive(false);
							if (val8.screen.DisplayedHeroId == val8.HeroId)
							{
								val8.screen.questPip.SetActive(false);
								foreach (HeroSkinButton componentsInChild in ((Component)val8.screen).GetComponentsInChildren<HeroSkinButton>())
								{
									componentsInChild.UpdateVisuals();
								}
							}
						}
					}
					NewHeroScreenNotification val10 = default(NewHeroScreenNotification);
					if (GameObjectExt.HasComponent<NewHeroScreenNotification>(((Component)__instance).gameObject, ref val10))
					{
						foreach (TowerDetailsModel item2 in (Il2CppArrayBase<TowerDetailsModel>)(object)Game.instance.model.heroSet)
						{
							if (data.seenNewHeroNotification.Add(item2.towerId))
							{
								flag = true;
							}
						}
						foreach (SkinData item3 in (Il2CppArrayBase<SkinData>)(object)GameData.Instance.skinsData.SkinList.items)
						{
							if (data.seenNewTowerSkinNotification.Add(((Object)item3).name))
							{
								flag = true;
							}
						}
						if (flag)
						{
							val10.newBanner.SetActive(false);
						}
					}
					Dictionary<string, QuestCategory> dictionary = new Dictionary<string, QuestCategory>
					{
						{
							"TalesTab",
							(QuestCategory)0
						},
						{
							"ChallengesTab",
							(QuestCategory)1
						},
						{
							"TutorialTab",
							(QuestCategory)2
						},
						{
							"ExperimentsTab",
							(QuestCategory)3
						}
					};
					if (dictionary.TryGetValue(((Object)__instance).name, out var value))
					{
						Enumerator<QuestSaveData> enumerator12 = data.questsSaveData.GetEnumerator();
						QuestDetails val11 = default(QuestDetails);
						while (enumerator12.MoveNext())
						{
							QuestSaveData current9 = enumerator12.Current;
							if (!current9.hasSeenQuest && GameData.Instance.questData.TryGetQuestData(current9.questId, ref val11) && val11.questCategory == value)
							{
								current9.hasSeenQuest = true;
								flag = true;
							}
						}
						if (flag)
						{
							((Component)((Component)__instance).transform.FindChild("NewPip")).gameObject.SetActive(false);
							Enumerator<QuestPanel> enumerator13 = ((Component)__instance).GetComponentInParent<QuestBrowserScreen>().questPanelList.GetEnumerator();
							while (enumerator13.MoveNext())
							{
								QuestPanel current10 = enumerator13.Current;
								current10.newQuestPanel.SetActive(false);
							}
						}
					}
					PipEventChecker val12 = default(PipEventChecker);
					if (Il2CppSystemObjectExt.Is<PipEventChecker>(((Component)__instance).GetComponentInParent<PipEventChecker>(), ref val12) && val12.IsPipVisible && ((Object)val12).name == "CommunityBtn")
					{
						OnlineProfileModel onlineProfileModel = Game.Player.onlineProfileModel;
						ContentTypeSaveData val13 = default(ContentTypeSaveData);
						if (onlineProfileModel != null && onlineProfileModel.contentBrowserData?.TryGetValue((ContentType)2, ref val13) == true)
						{
							foreach (string item4 in Enumerable.ToArray<string>(((Il2CppObjectBase)SkuSettings.instance.GetFeaturedContentIds((ContentType)2)).Cast<IEnumerable<string>>()))
							{
								if (!val13.seenFeaturedIds.Contains(item4))
								{
									val13.seenFeaturedIds.Add(item4);
									flag = true;
									flag2 = true;
								}
							}
							val12.CheckEvent((Object)null);
							foreach (GameObject item5 in (Il2CppArrayBase<GameObject>)(object)((Component)__instance).GetComponentInParent<MapSelectScreen>().communityButtonPipObjects)
							{
								item5.SetActive(false);
							}
						}
					}
					if (flag)
					{
						AudioClipExtensions.Play(MenuManager.instance.buttonClickSound, "FX", 1f);
						Game.Player.SaveNow();
					}
					if (flag2)
					{
						Game.Player.SyncOnlineProfile();
					}
				}
				catch (Exception ex)
				{
					ModHelper.Error<UsefulUtilitiesMod>((object)ex);
				}
			}
		}

		[HarmonyPatch(typeof(Toggle), "OnPointerClick")]
		internal class Toggle_OnPointerClick
		{
			[HarmonyPostfix]
			internal static void Postfix(Toggle __instance, PointerEventData eventData)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Invalid comparison between Unknown and I4
				try
				{
					if ((int)eventData.button != 1)
					{
						return;
					}
					ProfileModel data = ((Player<ProfileModel>)(object)Game.Player).Data;
					bool flag = false;
					PowerSelectButton val = default(PowerSelectButton);
					if (GameObjectExt.HasComponent<PowerSelectButton>(((Component)__instance).gameObject, ref val))
					{
						PowerData val2 = data.powersData[((Model)val.powerModel).name];
						if (val2.isNew)
						{
							val2.isNew = false;
							flag = true;
						}
						val.UpdatePowerDisplay(false);
					}
					if (flag)
					{
						AudioClipExtensions.Play(MenuManager.instance.buttonClickSound, "FX", 1f);
						Game.Player.SaveNow();
					}
				}
				catch (Exception ex)
				{
					ModHelper.Error<UsefulUtilitiesMod>((object)ex);
				}
			}
		}

		[HarmonyPatch(typeof(Btd6Player), "HasNewBossRushEvent")]
		internal static class Btd6Player_HasNewBossRushEvent
		{
			[HarmonyPrefix]
			internal static bool Prefix(Btd6Player __instance, ref bool __result)
			{
				if (__instance.IsFlagged)
				{
					__result = false;
					return false;
				}
				return true;
			}
		}

		protected override bool DefaultEnabled => true;

		public override string Description => "Right click on various red alert popups to clear them automatically. Includes powers, instas, heroes, skins, quests, CT.";

		protected override string Icon => "Ui[NoticeBtn]";

		public static void OnPointerClick()
		{
		}
	}
	public class CopyPasteTowers : UsefulUtility
	{
		[HarmonyPatch(typeof(Tower), "OnPlace")]
		private static class Tower_OnPlace
		{
			[HarmonyPrefix]
			private static void Prefix(Tower __instance)
			{
				//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				overrideNonPower = false;
				bool flag = false;
				flag = nextPlaceIsQueued;
				nextPlaceIsQueued = false;
				if (!nextPlaceIsPaste)
				{
					return;
				}
				nextPlaceIsPaste = false;
				foreach (BloonsMod mod in ModHelper.Mods)
				{
					mod.Call("OnTowerPasted", new object[2] { __instance, flag });
				}
				__instance.worth = CalculateCost(__instance);
				InGameExt.AddCash(InGame.instance, (double)(0f - __instance.worth + __instance.towerModel.cost));
				if (flag)
				{
					foreach (UpgradeModel item in from model in TowerModelExt.GetAppliedUpgrades(clipboard)
						orderby model.tier, model.path
						select model)
					{
						UpgradeQueueing.EnqueueUpgrade(new UpgradeQueueing.QueuedUpgrade(((RootObject)__instance).Id, item.path, item.tier + 1, ((Model)item).name));
					}
				}
				justPastedTower = true;
				if (lastCopyWasCut)
				{
					TowerToSimulation towerToSim = TowerExt.GetTowerToSim(__instance);
					TowerSelectionMenuExt.instance.SelectTower(towerToSim);
				}
				if (targetType != null)
				{
					__instance.SetTargetType(targetType);
				}
				if (__instance.towerModel.isParagon && lastDegree.HasValue)
				{
					ParagonTower behavior = ((RootBehavior)__instance).entity.GetBehavior<ParagonTower>();
					behavior.investmentInfo = lastDegree.Value;
					behavior.UpdateDegree();
					behavior.PlayParagonUpgradeSound();
					behavior.Finish();
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		internal static class TowerModel_isPowerTower
		{
			[HarmonyPostfix]
			internal static void Postfix(TowerModel __instance)
			{
				if (overrideNonPower)
				{
					lastCheckedPower = __instance;
				}
			}
		}

		[HarmonyPatch(typeof(GameModel), "GetPowerWithId")]
		internal static class GameModel_GetPowerWithId
		{
			[HarmonyPostfix]
			internal static void Postfix(ref PowerModel __result)
			{
				if (overrideNonPower && lastCheckedPower != null)
				{
					__result = ModelExt.Duplicate<PowerModel>(__result);
					__result.tower = lastCheckedPower;
					overrideNonPower = false;
					lastCheckedPower = null;
				}
			}
		}

		[HarmonyPatch(typeof(TimeManager), "ResetNow")]
		internal static class TimeManager_ResetNow
		{
			[HarmonyPostfix]
			internal static void Postfix()
			{
				clipboard = null;
				rootClipboard = null;
				foreach (BloonsMod mod in ModHelper.Mods)
				{
					mod.Call("OnClipboardCleared", Array.Empty<object>());
				}
			}
		}

		private static readonly ModSettingHotkey CopyTower = new ModSettingHotkey((KeyCode)99, (HotkeyModifier)3);

		private static readonly ModSettingHotkey PasteTower = new ModSettingHotkey((KeyCode)118, (HotkeyModifier)3);

		private static readonly ModSettingHotkey CutTower = new ModSettingHotkey((KeyCode)120, (HotkeyModifier)3);

		private static bool nextPlaceIsQueued;

		private static TowerModel? clipboard;

		private static TowerModel? rootClipboard;

		private static double baseCost;

		private static double cost;

		private static bool nextPlaceIsPaste;

		private static bool justPastedTower;

		private static bool lastCopyWasCut;

		private static TargetType? targetType;

		private static InvestmentInfo? lastDegree;

		private static bool overrideNonPower;

		private static TowerModel? lastCheckedPower;

		protected override bool CreateCategory => true;

		public override void OnUpdate()
		{
			Update();
		}

		public static void Update()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			if (!Object.op_Implicit((Object)(object)InGame.instance) || InGame.Bridge == null || InGame.instance.ReviewMapMode || InGame.Bridge.IsSpectatorMode || (int)InGame.instance.GameType == 13)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)TowerSelectionMenuExt.instance))
			{
				TowerToSimulation selectedTower = TowerSelectionMenuExt.instance.selectedTower;
				TowerModel val = ((selectedTower != null) ? selectedTower.Def : null);
				if (val != null && !val.isSubTower && (ModHelper.HasMod("Unlimited5thTiers") || (!val.IsHero() && !val.isParagon)) && ((Model)val).name.StartsWith(((EntityModel)val).baseId))
				{
					lastCopyWasCut = CutTower.JustPressed();
					if (CutTower.JustPressed() || CopyTower.JustPressed())
					{
						Copy(selectedTower.tower);
						if (CutTower.JustPressed())
						{
							QuickSell.blockQuickSell = true;
							TowerSelectionMenuExt.instance.Sell();
							lastCopyWasCut = true;
							QuickSell.blockQuickSell = false;
						}
						else
						{
							lastCopyWasCut = false;
						}
					}
				}
			}
			if (PasteTower.JustPressed() || (justPastedTower && (PasteTower.IsPressed() || MultiPlace.MultiPlaceModifier.IsPressed())))
			{
				Paste();
			}
			justPastedTower = false;
		}

		private static void Copy(Tower tower)
		{
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			cost = CalculateCost(tower.towerModel) + (double)ModifyClipboardCost(tower);
			clipboard = tower.towerModel;
			rootClipboard = ((Il2CppObjectBase)((Mutable)tower).rootModel).Cast<TowerModel>();
			TowerModel tower2 = InGameExt.GetGameModel(InGame.instance).GetTower(((EntityModel)clipboard).baseId, 0, 0, 0);
			baseCost = tower2.cost + (float)ModifyClipboardCost(tower);
			foreach (BloonsMod mod in ModHelper.Mods)
			{
				mod.Call("OnTowerCopied", new object[1] { tower });
			}
			string text = LocalizationManager.Instance.GetText(((Model)tower.towerModel).name);
			string text2 = $"Copied {text}\n\nTotal Cost is ${(int)cost}";
			if (!UpgradeQueueing.Off)
			{
				text2 += $" $({(int)baseCost} for queued)";
			}
			GameExt.ShowMessage(Game.instance, text2, (string)null);
			targetType = ((CommonBehaviorProxy<ITowerBehavior>)(object)tower).TargetType;
			InvestmentInfo? obj;
			if (!tower.towerModel.isParagon)
			{
				obj = null;
			}
			else
			{
				ParagonTower behavior = ((RootBehavior)tower).entity.GetBehavior<ParagonTower>();
				obj = ((behavior != null) ? new InvestmentInfo?(behavior.investmentInfo) : ((InvestmentInfo?)null));
			}
			lastDegree = obj;
		}

		private static void Paste()
		{
			//IL_0112: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			InputManager inputManager = InGameExt[InGame.instance];
			if (clipboard == null || rootClipboard == null || inputManager.IsInPlacementMode)
			{
				return;
			}
			if (InGameExt.GetCash(InGame.instance) < cost)
			{
				if (UpgradeQueueing.Off || InGameExt.GetCash(InGame.instance) < baseCost)
				{
					return;
				}
				TowerModel tower = InGame.Bridge.Model.GetTower(((EntityModel)clipboard).baseId, 0, 0, 0);
				inputManager.EnterPlacementMode(tower, PositionDelegate.op_Implicit((Action<Vector2>)delegate(Vector2 pos)
				{
					//IL_0023: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						nextPlaceIsPaste = true;
						nextPlaceIsQueued = true;
						overrideNonPower = clipboard.isPowerProTower;
						inputManager.CreatePlacementTower(pos);
					}
					catch (Exception ex)
					{
						overrideNonPower = false;
						UsefulUtility.MelonLogger.Error((object)ex);
					}
				}), new ObjectId
				{
					data = (uint)InGame.instance.bridge.GetInputId()
				}, false, 0);
				return;
			}
			inputManager.EnterPlacementMode(InGameExt.GetGameModel(InGame.instance).GetTowerWithName(((Model)rootClipboard).name), PositionDelegate.op_Implicit((Action<Vector2>)delegate(Vector2 pos)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					nextPlaceIsPaste = true;
					overrideNonPower = clipboard.isPowerProTower;
					inputManager.CreatePlacementTower(pos);
				}
				catch (Exception ex)
				{
					overrideNonPower = false;
					UsefulUtility.MelonLogger.Error((object)ex);
				}
			}), new ObjectId
			{
				data = (uint)InGame.instance.bridge.GetInputId()
			}, false, 0);
		}

		private static int ModifyClipboardCost(Tower tower)
		{
			return ModHelper.Mods.Aggregate(0, (int i, BloonsMod mod) => i + Convert.ToInt32(mod.Call("ModifyClipboardCost", new object[1] { tower }) ?? ((object)0)));
		}

		private static int BaseUpgradeCost(string name)
		{
			return Math.RoundToNearestInt((float)InGameExt.GetGameModel(InGame.instance).GetUpgrade(name).cost, 5);
		}

		private static double CalculateCost(TowerModel tower)
		{
			return ((IEnumerable<string>)tower.appliedUpgrades).Aggregate(tower.cost, (float i, string upgrade) => i + (float)BaseUpgradeCost(upgrade));
		}

		private static int CalculateCost(Tower tower)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			Simulation sim = ((RootObject)tower).Sim;
			TowerManager towerManager = sim.towerManager;
			TowerInventory towerInventory = sim.GetTowerInventory(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).PlayerOwnerId);
			float num = 0f;
			float num2 = 0f;
			towerInventory.GetTowerDiscount(tower.towerModel, ref num, ref num2, false);
			float areaDiscount = towerManager.GetAreaDiscount(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).Position.ToVector2());
			Dictionary<string, List<DiscountZone>> zoneDiscount = towerManager.GetZoneDiscount(tower.towerModel, Vector3Boxed.op_Implicit(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).Position), -1, 0, tower.owner, "");
			float discountMultiplier = towerManager.GetDiscountMultiplier(zoneDiscount);
			int num3 = Math.RoundToNearestInt((1f - (areaDiscount + discountMultiplier + num)) * (tower.towerModel.cost - num2), 5);
			num3 += CalculateUpgradeCosts(tower);
			return num3 + ModifyClipboardCost(tower);
		}

		private static int CalculateUpgradeCosts(Tower tower)
		{
			return ((IEnumerable<string>)tower.towerModel.appliedUpgrades).Sum((string u) => CalculateCost(tower, ((RootObject)tower).Sim.model.GetUpgrade(u)));
		}

		private static int CalculateCost(Tower tower, UpgradeModel upgrade)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Simulation sim = ((RootObject)tower).Sim;
			TowerManager towerManager = sim.towerManager;
			int path = upgrade.path;
			int num = upgrade.tier + 1;
			if (towerManager.GetFreeUpgrade(Vector3Boxed.op_Implicit(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).Position), tower, path, num))
			{
				return 0;
			}
			float areaDiscount = towerManager.GetAreaDiscount(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).Position.ToVector2());
			Dictionary<string, List<DiscountZone>> zoneDiscount = towerManager.GetZoneDiscount(tower.towerModel, Vector3Boxed.op_Implicit(((CommonBehaviorProxy<ITowerBehavior>)(object)tower).Position), path, num + 1, tower.owner, "");
			float discountMultiplier = towerManager.GetDiscountMultiplier(zoneDiscount);
			float simulationBehaviorDiscount = sim.GetSimulationBehaviorDiscount(tower, path, num, areaDiscount + discountMultiplier);
			return Math.RoundToNearestInt((float)upgrade.cost * (1f - simulationBehaviorDiscount), 5);
		}
	}
	public class CursorSizeHotkey : UsefulUtility
	{
		private static readonly ModSettingHotkey CycleCursorSize = new ModSettingHotkey();

		private static readonly ModSettingHotkey CursorSizeNormal = new ModSettingHotkey();

		private static readonly ModSettingHotkey CursorSizeLarge = new ModSettingHotkey();

		private static readonly ModSettingHotkey CursorSizeXLarge = new ModSettingHotkey();

		protected override bool CreateCategory => true;

		protected override string Icon => "UiEmoteIcons[Hand]";

		public override void OnUpdate()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			CursorConfig config = Cursor.instance.Config;
			CursorConfig val = config;
			if (CursorSizeNormal.JustPressed())
			{
				val = (CursorConfig)0;
			}
			if (CursorSizeLarge.JustPressed())
			{
				val = (CursorConfig)1;
			}
			if (CursorSizeXLarge.JustPressed())
			{
				val = (CursorConfig)2;
			}
			if (CycleCursorSize.JustPressed())
			{
				val = (CursorConfig)(val + 1);
				if ((int)val >= Enum.GetValues<CursorConfig>().Length)
				{
					val = (CursorConfig)0;
				}
			}
			if (config != val)
			{
				HotkeysScreen val2 = default(HotkeysScreen);
				if ((Object)(object)MenuManager.instance != (Object)null && Il2CppSystemObjectExt.Is<HotkeysScreen>((Il2CppObjectBase)(object)MenuManager.instance.GetCurrentMenu(), ref val2))
				{
					val2.SetCursorConfig(val);
				}
				else
				{
					Cursor.instance.Config = val;
				}
			}
		}
	}
	public class FullscreenHotkey : UsefulUtility
	{
		private static readonly ModSettingHotkey ToggleFullscreen = new ModSettingHotkey((KeyCode)292, (HotkeyModifier)0)
		{
			icon = ModContent.GetTextureGUID<UsefulUtilitiesMod>("Fullscreen"),
			description = "Toggles Fullscreen mode. Will remember your previous preferred resolution when switching back and forth."
		};

		private static MelonPreferences_Entry<int> lastWindowedWidth = null;

		private static MelonPreferences_Entry<int> lastWindowedHeight = null;

		private static MelonPreferences_Entry<int> lastFullscreenWidth = null;

		private static MelonPreferences_Entry<int> lastFullscreenHeight = null;

		public override void OnRegister()
		{
			lastWindowedWidth = UsefulUtilitiesMod.Preferences.CreateEntry<int>("lastWindowedWidth", 1600, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			lastWindowedHeight = UsefulUtilitiesMod.Preferences.CreateEntry<int>("lastWindowedHeight", 900, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			lastFullscreenWidth = UsefulUtilitiesMod.Preferences.CreateEntry<int>("lastFullscreenWidth", Display.main.systemWidth, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			lastFullscreenHeight = UsefulUtilitiesMod.Preferences.CreateEntry<int>("lastFullscreenHeight", Display.main.systemHeight, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		public override void OnUpdate()
		{
			if (!ToggleFullscreen.JustPressed())
			{
				return;
			}
			bool fullScreen = Screen.fullScreen;
			bool flag = !fullScreen;
			int newWidth;
			int value;
			if (fullScreen)
			{
				lastFullscreenWidth.Value = Screen.width;
				lastFullscreenHeight.Value = Screen.height;
				newWidth = lastWindowedWidth.Value;
				value = lastWindowedHeight.Value;
			}
			else
			{
				lastWindowedWidth.Value = Screen.width;
				lastWindowedHeight.Value = Screen.height;
				newWidth = lastFullscreenWidth.Value;
				value = lastFullscreenHeight.Value;
			}
			AnalyticsManager.Instance.ScreenResolution(newWidth, value, flag);
			Screen.SetResolution(newWidth, value, flag, Application.targetFrameRate);
			UsefulUtilitiesMod.Preferences.SaveToFile(false);
			TaskScheduler.ScheduleTask((Action)delegate
			{
				SettingsScreen val = default(SettingsScreen);
				if ((Object)(object)MenuManager.instance != (Object)null && Il2CppSystemObjectExt.Is<SettingsScreen>((Il2CppObjectBase)(object)MenuManager.instance.GetCurrentMenu(), ref val))
				{
					val.screenSizeDropDown.Populate();
				}
			}, (Func<bool>)(() => Screen.width == newWidth));
		}
	}
	public class HideFriendScores : ToggleableUtility
	{
		[HarmonyPatch(typeof(MapButton), "Init")]
		internal static class MapButton_Init
		{
			[HarmonyPostfix]
			internal static void Postfix(MapButton __instance)
			{
				if (ModContent.GetInstance<HideFriendScores>().Enabled && (Object)(object)__instance.friendPanel != (Object)null)
				{
					((Component)__instance.friendPanel).gameObject.SetActiveRecursively(false);
				}
			}
		}

		protected override bool DefaultEnabled => false;

		public override string Description => "Hides the indicators on the Map Select Screen of the highest round completed amongst you and your friends.";

		protected override string Icon => "MainMenuUiAtlas[FriendsIcon]";
	}
	public class HotkeyDisplay : ToggleableUtility
	{
		[HarmonyPatch(typeof(Hotkeys), "Setup")]
		internal static class Hotkeys_Setup
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Hotkeys __instance)
			{
				if (!ModContent.GetInstance<HotkeyDisplay>().Enabled)
				{
					return;
				}
				TowerPurchaseButton button = default(TowerPurchaseButton);
				if (Il2CppSystemObjectExt.Is<TowerPurchaseButton>((Il2CppObjectBase)(object)__instance.HeroButton, ref button))
				{
					UpdateHotkeyDisplay(button, __instance.heroHotkey);
				}
				Enumerator<TowerHotkeyInfo> enumerator = __instance.towerHotkeys.GetEnumerator();
				while (enumerator.MoveNext())
				{
					TowerHotkeyInfo current = enumerator.Current;
					if (Il2CppSystemObjectExt.Is<TowerPurchaseButton>((Il2CppObjectBase)(object)current.towerPurchaseButton, ref button))
					{
						UpdateHotkeyDisplay(button, current.hotkeyButton);
					}
				}
			}
		}

		private static readonly ModSettingBool ShortenModifiers = new ModSettingBool(false)
		{
			description = "Shortens modifier keys.\nControl becomes ^\nShift becomes +\nAlt becomes !"
		};

		private static readonly ModSettingDouble TextOpacity;

		protected override bool CreateCategory => true;

		protected override bool DefaultEnabled => true;

		public override string Description => "Shows the hotkeys used to place towers within the Tower Shop Menu";

		protected override string Icon => "Ui[HotkeysIcon]";

		private static void UpdateHotkeyDisplay(TowerPurchaseButton button, HotkeyButton? hotkeyButton)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Expected I4, but got Unknown
			if (hotkeyButton == null || (Object)(object)button == (Object)null)
			{
				return;
			}
			HotKey hotkey = hotkeyButton.hotkey;
			GameObject gameObject = ((Component)button).gameObject;
			ModHelperText val = gameObject.GetComponentInChildren<ModHelperText>(true);
			if ((Object)(object)val == (Object)null)
			{
				Info val2 = default(Info);
				((Info)(ref val2))..ctor("Hotkey");
				((Info)(ref val2)).set_Width(-50f);
				((Info)(ref val2)).set_Height(75f);
				((Info)(ref val2)).set_AnchorMin(new Vector2(0f, 1f));
				((Info)(ref val2)).set_AnchorMax(new Vector2(1f, 1f));
				((Info)(ref val2)).set_Pivot(new Vector2(0.5f, 1f));
				val = GameObjectExt.AddModHelperComponent<ModHelperText>(gameObject, ModHelperText.Create(val2, "", 48f, (TextAlignmentOptions)516));
				((Component)val).transform.MoveAfterSibling(button.costText.transform, true);
				((TMP_Text)val.Text).fontSizeMax = 48f;
				((TMP_Text)val.Text).enableAutoSizing = true;
				((Graphic)val.Text).color = new Color(1f, 1f, 1f, ModSettingDouble.op_Implicit(TextOpacity));
			}
			if (string.IsNullOrWhiteSpace(hotkey.path) || hotkey.path.Contains("None"))
			{
				((ModHelperComponent)val).SetActive(false);
				return;
			}
			string key = hotkey.path.Split('/').Last();
			((ModHelperComponent)val).SetActive(true);
			string text;
			if ((int)hotkey.modifierKey == 0)
			{
				text = "";
			}
			else
			{
				string text3;
				if (ModSettingBool.op_Implicit(ShortenModifiers))
				{
					HotkeyModifier modifierKey = hotkey.modifierKey;
					if (1 == 0)
					{
					}
					string text2 = (modifierKey - 1) switch
					{
						2 => "^", 
						0 => "+", 
						1 => "!", 
						_ => "", 
					};
					if (1 == 0)
					{
					}
					text3 = text2;
				}
				else
				{
					text3 = ((object)hotkey.modifierKey/*cast due to .constrained prefix*/).ToString() + "+";
				}
				text = text3;
			}
			string text4 = text;
			val.SetText(text4 + HotkeyToText(key));
		}

		private static string HotkeyToText(string key)
		{
			string text = key.ToUpper();
			if (1 == 0)
			{
			}
			string result = text switch
			{
				"BACKQUOTE" => "`", 
				"MINUS" => "-", 
				"EQUALS" => "=", 
				"BACKSLASH" => "\\", 
				"LEFTBRACKET" => "[", 
				"RIGHTBRACKET" => "]", 
				"SEMICOLON" => ";", 
				"QUOTE" => "'", 
				"COMMA" => ",", 
				"PERIOD" => ".", 
				"SLASH" => "/", 
				"ALPHA0" => "0", 
				"ALPHA1" => "1", 
				"ALPHA2" => "2", 
				"ALPHA3" => "3", 
				"ALPHA4" => "4", 
				"ALPHA5" => "5", 
				"ALPHA6" => "6", 
				"ALPHA7" => "7", 
				"ALPHA8" => "8", 
				"ALPHA9" => "9", 
				"KEYPAD0" => "0", 
				"KEYPAD1" => "1", 
				"KEYPAD2" => "2", 
				"KEYPAD3" => "3", 
				"KEYPAD4" => "4", 
				"KEYPAD5" => "5", 
				"KEYPAD6" => "6", 
				"KEYPAD7" => "7", 
				"KEYPAD8" => "8", 
				"KEYPAD9" => "9", 
				"KEYPADPERIOD" => ".", 
				"KEYPADDIVIDE" => "/", 
				"KEYPADMULTIPLY" => "*", 
				"KEYPADMINUS" => "-", 
				"KEYPADPLUS" => "+", 
				"KEYPADENTER" => "ENTER", 
				"KEYPADEQUALS" => "=", 
				"SPACE" => "SPACE", 
				"RETURN" => "ENTER", 
				_ => key, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		static HotkeyDisplay()
		{
			//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_0016: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			ModSettingDouble val = new ModSettingDouble(1.0)
			{
				description = "Change how transparent the hotkey text is. 1 is fully solid, 0 is invisible."
			};
			((ModSettingNumber<double>)val).min = 0.0;
			((ModSettingNumber<double>)val).max = 1.0;
			((ModSettingNumber<double>)val).slider = true;
			val.stepSize = 0.01f;
			TextOpacity = val;
		}
	}
	public class InGameHeroSwitch : UsefulUtility
	{
		[HarmonyPatch(typeof(UnityToSimulation), "MatchReady")]
		internal static class UnityToSimulation_MatchReady
		{
			[HarmonyPostfix]
			internal static void Postfix()
			{
				RefreshShop(playSound: false);
			}
		}

		private static readonly ModSettingHotkey CycleUp = new ModSettingHotkey((KeyCode)280, (HotkeyModifier)0);

		private static readonly ModSettingHotkey CycleDown = new ModSettingHotkey((KeyCode)281, (HotkeyModifier)0);

		private const bool CycleIfPlaced = false;

		private static bool cycleDown;

		private static bool cycleUp;

		protected override bool CreateCategory => true;

		private static string CurrentHero
		{
			get
			{
				return InGame.Bridge.players[InGame.Bridge.MyPlayerNumber].hero;
			}
			set
			{
				InGame.Bridge.players[InGame.Bridge.MyPlayerNumber].hero = value;
			}
		}

		public override void OnUpdate()
		{
			Update();
		}

		public static void Update()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			if (Object.op_Implicit((Object)(object)InGame.instance) && InGame.Bridge != null && !InGame.instance.ReviewMapMode && !InGame.Bridge.IsSpectatorMode && (int)InGame.instance.GameType != 13)
			{
				if (CycleDown.JustPressed())
				{
					cycleDown = true;
				}
				if (CycleUp.JustPressed())
				{
					cycleUp = true;
				}
				if (cycleDown && cycleUp)
				{
					ChangeHero(Random.RandomRangeInt(1, ((Il2CppArrayBase<TowerDetailsModel>)(object)Game.instance.model.heroSet).Length));
				}
				else if (CycleUp.JustReleased() && cycleUp)
				{
					ChangeHero(-1);
				}
				else if (CycleDown.JustReleased() && cycleDown)
				{
					ChangeHero(1);
				}
			}
		}

		private static void ChangeHero(int delta)
		{
			cycleDown = (cycleUp = false);
			TowerModel val = default(TowerModel);
			if (string.IsNullOrEmpty(CurrentHero) || !Il2CppSystemObjectExt.Is<TowerModel>(InGame.Bridge.Model.GetTowerWithName(CurrentHero), ref val) || InGameExt.GetTowerInventory(InGame.instance).GetTowerInventoryRemaining(val) == 0)
			{
				return;
			}
			HashSet<string> unlockedHeroes = GameExt.GetPlayerProfile(Game.instance).unlockedHeroes;
			IEnumerable<HeroDetailsModel> enumerable = ((IEnumerable<TowerDetailsModel>)InGameExt.GetGameModel(InGame.instance).heroSet).Select((TowerDetailsModel tdm) => ((Il2CppObjectBase)tdm).Cast<HeroDetailsModel>());
			HeroDetailsModel[] array = (enumerable as HeroDetailsModel[]) ?? enumerable.ToArray();
			int index = ((TowerDetailsModel)array.First((HeroDetailsModel hdm) => ((TowerDetailsModel)hdm).towerId == CurrentHero)).towerIndex;
			string text = "";
			while (!unlockedHeroes.Contains(text))
			{
				index += delta;
				index = (index + array.Length) % array.Length;
				text = ((TowerDetailsModel)array.First((HeroDetailsModel hdm) => ((TowerDetailsModel)hdm).towerIndex == index)).towerId;
			}
			ResetInventory(text);
			CurrentHero = text;
			InGameExt[InGame.instance].SetSelected((Selectable)null);
		}

		private static void ResetInventory(string newHero)
		{
			TowerInventory towerInventory = InGameExt.GetTowerInventory(InGame.instance);
			HashSet<string> unlockedHeroes = GameExt.GetPlayerProfile(Game.instance).unlockedHeroes;
			Enumerator<string> enumerator = unlockedHeroes.GetEnumerator();
			while (enumerator.MoveNext())
			{
				string current = enumerator.Current;
				towerInventory.towerMaxes[current] = 0;
			}
			towerInventory.towerMaxes[newHero] = 1;
			RefreshShop(playSound: true);
		}

		private static void RefreshShop(bool playSound)
		{
			if (ShopMenuExt.instance != null)
			{
				bool disallowSelectingDifferentTowers = ShopMenuExt.instance.disallowSelectingDifferentTowers;
				ShopMenuExt.instance.disallowSelectingDifferentTowers = !playSound;
				ShopMenuExt.instance.RebuildTowerSet();
				ShopMenuExt.instance.disallowSelectingDifferentTowers = disallowSelectingDifferentTowers;
				Enumerator<ITowerPurchaseButton> enumerator = ShopMenuExt.instance.ActiveTowerButtons.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ITowerPurchaseButton current = enumerator.Current;
					((ItemPurchaseButton)((Il2CppObjectBase)current).Cast<TowerPurchaseButton>()).Update();
				}
			}
		}
	}
	public class JukeboxFolder : UsefulUtility
	{
		public class LoadJukeboxTracks : ModLoadTask
		{
			public override bool ShouldRun
			{
				get
				{
					Task loadTask = LoadTask;
					return loadTask != null && !loadTask.IsCompleted;
				}
			}

			public override bool ShowProgressBar => true;

			public override string DisplayName => "Loading Jukebox Tracks...";

			public override IEnumerator Coroutine()
			{
				List<FileJukeboxTrack> tracks = ModContent.GetContent<FileJukeboxTrack>();
				while (((ModLoadTask)this).ShouldRun)
				{
					yield return null;
					((ModLoadTask)this).Progress = (float)tracks.Count((FileJukeboxTrack track) => track.Complete) / (float)tracks.Count;
				}
				RegisterTracks(tracks);
			}
		}

		public class FileJukeboxTrack : ModJukeboxTrack
		{
			private AudioClip? audioClip;

			public sealed override string Name { get; }

			public override AudioClip? AudioClip => audioClip;

			public override string DisplayName => ((ModContent)this).Name;

			public override int RegisterPerFrame => 1;

			public string FilePath { get; }

			public bool Complete { get; private set; }

			public bool Registered { get; private set; }

			public FileJukeboxTrack(string filePath)
			{
				Name = Path.GetFileNameWithoutExtension(filePath);
				FilePath = filePath;
				((ModContent)this).mod = (BloonsMod)(object)ModContent.GetInstance<UsefulUtilitiesMod>();
				ModHelper.Msg<UsefulUtilitiesMod>((object)("Adding track \"" + ((ModContent)this).Name + "\" from " + FilePath));
			}

			public override void Register()
			{
				if (!Complete && !ModSettingBool.op_Implicit(LoadAsynchronously))
				{
					LoadTrack();
				}
				if (Complete && (Object)(object)audioClip != (Object)null)
				{
					((ModJukeboxTrack)this).Register();
					Registered = true;
				}
			}

			public void LoadTrack()
			{
				if (Complete)
				{
					return;
				}
				try
				{
					DateTime now = DateTime.Now;
					WaveStream waveStream = ResourceHandler.GetWaveStream(FilePath);
					try
					{
						if (ModSettingBool.op_Implicit(NormalizeVolume))
						{
							BloonsMod.NormalizeAudioVolume.Add(((ModContent)this).Id);
						}
						audioClip = ResourceHandler.CreateAudioClip(waveStream, ((ModContent)this).Id);
						DateTime now2 = DateTime.Now;
						if ((Object)(object)audioClip != (Object)null)
						{
							ModHelper.Msg<UsefulUtilitiesMod>((object)$"Successfully processed track {((ModContent)this).Name} duration {TimeSpan.FromSeconds(audioClip.length):g} in {(now2 - now).TotalSeconds:N1}s");
							return;
						}
					}
					finally
					{
						((IDisposable)waveStream)?.Dispose();
					}
				}
				catch (Exception ex)
				{
					ModHelper.Error<UsefulUtilitiesMod>((object)ex);
				}
				finally
				{
					Complete = true;
				}
				ModHelper.Error<UsefulUtilitiesMod>((object)("Unable to parse potential jukebox track file " + FilePath));
			}
		}

		public static readonly ModSettingFolder FolderPath;

		private static FileSystemWatcher watcher;

		public static readonly ModSettingBool LoadAsynchronously;

		public static readonly ModSettingBool NormalizeVolume;

		public static Task? LoadTask { get; private set; }

		public override IEnumerable<ModContent> Load()
		{
			IEnumerable<ModContent> first = base.Load();
			if (!Directory.Exists(ModSettingFolder.op_Implicit(FolderPath)))
			{
				Directory.CreateDirectory(ModSettingFolder.op_Implicit(FolderPath));
			}
			watcher = new FileSystemWatcher(ModSettingFolder.op_Implicit(FolderPath));
			string[] audioExtensions = ResourceHandler.AudioExtensions;
			foreach (string text in audioExtensions)
			{
				watcher.Filters.Add("*" + text);
			}
			watcher.IncludeSubdirectories = true;
			watcher.Created += delegate(object _, FileSystemEventArgs args)
			{
				TaskScheduler.ScheduleTask((Action)delegate
				{
					FileJukeboxTrack item = new FileJukeboxTrack(args.FullPath);
					AddTracks(new <>z__ReadOnlySingleElementList<FileJukeboxTrack>(item));
					LoadTracks(new <>z__ReadOnlySingleElementList<FileJukeboxTrack>(item));
					RegisterTracks(new <>z__ReadOnlySingleElementList<FileJukeboxTrack>(item));
				}, (ScheduleType)0, 1, (Func<bool>)null);
			};
			FileJukeboxTrack[] tracks = CreateTracks(ModSettingFolder.op_Implicit(FolderPath));
			if (ModSettingBool.op_Implicit(LoadAsynchronously))
			{
				LoadTask = Task.Run(delegate
				{
					LoadTracks(tracks);
				});
			}
			return first.Concat((IEnumerable<ModContent>)(object)tracks);
		}

		public static IEnumerable<string> GetFiles(string path)
		{
			return ResourceHandler.AudioExtensions.SelectMany((string extension) => Directory.EnumerateFiles(path, "*" + extension, SearchOption.AllDirectories));
		}

		public static FileJukeboxTrack[] CreateTracks(string folderPath)
		{
			return (from file in GetFiles(folderPath)
				select new FileJukeboxTrack(file)).ToArray();
		}

		public static void AddTracks([ParamCollection] IEnumerable<FileJukeboxTrack> tracks)
		{
			((ModContent)ModContent.GetInstance<JukeboxFolder>()).mod.AddContent((IEnumerable<ModContent>)tracks);
		}

		public static void LoadTracks([ParamCollection] IEnumerable<FileJukeboxTrack> tracks)
		{
			foreach (FileJukeboxTrack track in tracks)
			{
				track.LoadTrack();
			}
		}

		public static void RegisterTracks([ParamCollection] IEnumerable<FileJukeboxTrack> tracks)
		{
			foreach (FileJukeboxTrack item in tracks.Where((FileJukeboxTrack track) => !track.Registered))
			{
				((ModContent)item).Register();
				((NamedModContent)item).RegisterText(LocalizationManager.Instance.textTable);
			}
		}

		static JukeboxFolder()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0035: 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_0056: Expected O, but got Unknown
			//IL_005b: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_008e: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			ModSettingFolder val = new ModSettingFolder(Path.Combine(MelonEnvironment.GameRootDirectory, "Jukebox"))
			{
				displayName = "Jukebox Folder",
				icon = "MainMenuUiAtlas[JukeboxIcon]",
				category = UsefulUtilitiesMod.Jukebox,
				description = "Audio files you put in this folder will be automatically loaded into the BTD6 Jukebox. Can add new tracks from files without restarting the game, but can't delete them."
			};
			((ModSetting<string>)val).onSave = delegate(string newPath)
			{
				if (!(Path.GetFullPath(newPath) == Path.GetFullPath(watcher.Path)))
				{
					watcher.Path = newPath;
					TaskScheduler.ScheduleTask((Action)delegate
					{
						FileJukeboxTrack[] tracks = CreateTracks(newPath);
						AddTracks(tracks);
						LoadTracks(tracks);
						RegisterTracks(tracks);
					}, (Func<bool>)null);
				}
			};
			FolderPath = val;
			watcher = null;
			LoadAsynchronously = new ModSettingBool(true)
			{
				description = "Whether to load in tracks asynchronously on a separate thread or directly on the main thread",
				icon = "Ui[LoadingWheel]",
				category = UsefulUtilitiesMod.Jukebox
			};
			NormalizeVolume = new ModSettingBool(true)
			{
				description = "Normalizes the volume of jukebox tracks to be as load as they can be without peaking, as normal BTD6 music tends to be",
				icon = "Ui[VolumeIcon]",
				category = UsefulUtilitiesMod.Jukebox
			};
		}
	}
	public class KeepDefaultUpgradeSounds : ToggleableUtility
	{
		private static readonly Dictionary<string, List<AudioSwap>> AudioSwaps = new Dictionary<string, List<AudioSwap>>();

		protected override bool DefaultEnabled => false;

		protected override ModSettingCategory Category => UsefulUtilitiesMod.TrophyStore;

		protected override string Icon => "3b0e984ce233fd742b22aa7721e78b2a";

		public override string Description => "Makes Trophy Store upgrade effects not apply their sound changes.";

		private static bool IsEnabled => ModContent.GetInstance<KeepDefaultUpgradeSounds>().Enabled;

		public override void OnSaveSettings()
		{
			ModifyItems();
		}

		public override void OnTitleScreen()
		{
			ModifyItems();
		}

		public static void ModifyItems()
		{
			TrophyStoreItems trophyStoreItems = GameData.Instance.trophyStoreItems;
			IEnumerable<TowerAssetChange> enumerable = from data in Il2CppGenericsExt.ToList<TrophyStoreItem>(trophyStoreItems.storeItems).SelectMany((TrophyStoreItem item) => (IEnumerable<TrophyItemTypeData>)item.itemTypes)
				where (int)data.itemType == 0 && ((Object)data.itemTarget).name.EndsWith("UpgradeEffect")
				select ((Il2CppObjectBase)data.itemTarget).Cast<TowerAssetChange>();
			foreach (TowerAssetChange item in enumerable)
			{
				AudioSwaps.TryAdd(((AssetChangeItem)item).id, item.audioSwaps);
				item.audioSwaps = (IsEnabled ? new List<AudioSwap>() : AudioSwaps[((AssetChangeItem)item).id]);
			}
		}
	}
	public class MapEditorPlaceableCounts : ToggleableUtility
	{
		[HarmonyPatch]
		internal static class EditorMenuPopout_Update
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(EditorMenuPopout), "OnCategoryButtonClicked", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(EditorMenuPopout), "OnPlaceablesPlacedOrRemoved", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(EditorMenuPopout), "OnStampErasedEventTriggered", (Type[])null, (Type[])null);
			}

			[HarmonyPostfix]
			internal static void Postfix(EditorMenuPopout __instance)
			{
				UpdateTitle(__instance);
			}
		}

		protected override bool DefaultEnabled => true;

		public override string Description => "Shows the Map Editor placeable objects (props/stamps) current counts and maximum in the category title";

		protected override ModSettingCategory Category => UsefulUtilitiesMod.Sandbox;

		private static void UpdateTitle(EditorMenuPopout editorMenu)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			if (ModContent.GetInstance<MapEditorPlaceableCounts>().Enabled)
			{
				if ((int)editorMenu.selectedCategory == 2)
				{
					editorMenu.categoryTitleText.SetText($"{StringExt.Localize("Props")} ({Il2CppGenericIEnumerableExt.Count<PropToSimulation>(InGame.Bridge.GetAllProps())}/{editorMenu.EditorSettings.MaxPlaceables})");
				}
				if ((int)editorMenu.selectedCategory == 1)
				{
					editorMenu.categoryTitleText.SetText($"{StringExt.Localize("Stamps")} ({editorMenu.MapEditorSceneController.GetStampCount()}/{editorMenu.EditorSettings.MaxPlaceables})");
				}
			}
		}
	}
	public class MapEventsPauseAutoStart : UsefulUtility
	{
		[HarmonyPatch(typeof(Simulation), "RoundEnd")]
		internal static class Simulation_RoundEnd
		{
			[HarmonyPrefix]
			internal static void Prefix(Simulation __instance, int round)
			{
				int num = round + 1;
				if ((__instance.Map.mapModel.mapName == "Polyphemus" && ModSettingBool.op_Implicit(Polyphemus) && num % 10 == 5) || (__instance.Map.mapModel.mapName == "Erosion" && ModSettingBool.op_Implicit(Erosion) && ErosionRounds.Contains(num)))
				{
					__instance.pauseAutoPlay = true;
				}
			}
		}

		public static readonly ModSettingBool Polyphemus = new ModSettingBool(true)
		{
			description = "Pause auto start when the Eye closes.",
			icon = "MapImages[MapSelectPolyphemusMapButton]"
		};

		public static readonly ModSettingBool Erosion = new ModSettingBool(true)
		{
			description = "Pause auto start when the ice erodes.",
			icon = "MapImages[MapSelectErosionButton]"
		};

		private static readonly int[] ErosionRounds = new int[5] { 17, 35, 53, 71, 89 };

		protected override bool CreateCategory => true;

		public override string Description => "Pauses auto start for the rounds immediately after certain significant map events.";
	}
	public class MonkeyAutoRenamer : ToggleableUtility
	{
		[HarmonyPatch(typeof(Tower), "OnDestroy")]
		internal static class Tower_Destroy
		{
			[HarmonyPrefix]
			internal static void Prefix(Tower __instance)
			{
				if (!string.IsNullOrEmpty(__instance.namedMonkeyKey) && ModContent.GetInstance<MonkeyAutoRenamer>().Enabled)
				{
					Tower val = (from tower in (IEnumerable<Tower>)MonoLinqHelper.ToArray<Tower>