Decompiled source of PathsPlusPlus v1.2.3

PathsPlusPlus.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BTD_Mod_Helper;
using BTD_Mod_Helper.Api;
using BTD_Mod_Helper.Api.Components;
using BTD_Mod_Helper.Api.Enums;
using BTD_Mod_Helper.Api.ModOptions;
using BTD_Mod_Helper.Api.Testing;
using BTD_Mod_Helper.Api.Towers;
using BTD_Mod_Helper.Extensions;
using HarmonyLib;
using Il2CppAssets.Scripts;
using Il2CppAssets.Scripts.Models;
using Il2CppAssets.Scripts.Models.Entities;
using Il2CppAssets.Scripts.Models.Profile;
using Il2CppAssets.Scripts.Models.TowerSets;
using Il2CppAssets.Scripts.Models.Towers;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Abilities;
using Il2CppAssets.Scripts.Models.Towers.Upgrades;
using Il2CppAssets.Scripts.Simulation.GeraldoItems;
using Il2CppAssets.Scripts.Simulation.Input;
using Il2CppAssets.Scripts.Simulation.Objects;
using Il2CppAssets.Scripts.Simulation.Towers;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors;
using Il2CppAssets.Scripts.Simulation.Tracking;
using Il2CppAssets.Scripts.Unity;
using Il2CppAssets.Scripts.Unity.Bridge;
using Il2CppAssets.Scripts.Unity.Menu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu;
using Il2CppAssets.Scripts.Unity.UI_New.Popups;
using Il2CppAssets.Scripts.Unity.UI_New.Upgrade;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNinjaKiwi.Common;
using Il2CppNinjaKiwi.Common.ResourceUtils;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PathsPlusPlus;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(PathsPlusPlusMod), "Paths++", "1.2.3", "doombubbles", null)]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6")]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6-Epic")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("PathsPlusPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8647110bce21da0eed5be39d5307cffe48c6acf4")]
[assembly: AssemblyProduct("PathsPlusPlus")]
[assembly: AssemblyTitle("PathsPlusPlus")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PathsPlusPlus
{
	internal static class ModHelperData
	{
		public const string WorksOnVersion = "55.2";

		public const string Version = "1.2.3";

		public const string Name = "Paths++";

		public const string Description = "A helper mod allowing additional upgrade paths and tiers to be made for towers.\n\nToggle 'Balanced Mode' to switch from being still only able to get up to max upgrades in any one path and 2 in another, vs getting all vanilla upgrades you normally can as well as any/all available Paths++ upgrades.\n\nToggling off Balanced Mode can also function well with Ultimate Crosspathing (assuming the Mod Creators were keeping it in mind while coding).";

		public const string RepoOwner = "doombubbles";

		public const string PrevRepoName = "paths-plus-plus";

		public const string RepoName = "PathsPlusPlus";
	}
	public abstract class MultiPathPlusPlus : PathPlusPlus
	{
		private string tower = null;

		public override string Name => ((ModContent)this).Name + "-" + Tower;

		public sealed override string Tower => tower ?? throw new ArgumentException("Tower was null for MultiPathPlusPlus " + ((ModContent)this).Name);

		public abstract IEnumerable<string> Towers { get; }

		public Dictionary<string, MultiPathPlusPlus> PathsByTower { get; private set; } = new Dictionary<string, MultiPathPlusPlus>();

		public override IEnumerable<ModContent> Load()
		{
			return (IEnumerable<ModContent>)Towers.Select(delegate(string t)
			{
				MultiPathPlusPlus multiPathPlusPlus = (MultiPathPlusPlus)Activator.CreateInstance(((object)this).GetType());
				multiPathPlusPlus.tower = t;
				PathsByTower[t] = multiPathPlusPlus;
				multiPathPlusPlus.PathsByTower = PathsByTower;
				return multiPathPlusPlus;
			});
		}

		public override int GetTier(Tower t)
		{
			MultiPathPlusPlus value;
			return PathsByTower.TryGetValue(((EntityModel)t.towerModel).baseId, out value) ? value.GetTier(t) : 0;
		}
	}
	public abstract class MultiUpgradePlusPlus : UpgradePlusPlus
	{
		private string tower = null;

		public override string Name => ((ModContent)this).Name + "-" + tower;

		public string Tower => tower ?? throw new ArgumentException("Tower was null for MultiUpgradePlusPlus " + ((ModContent)this).Name);

		public override MultiPathPlusPlus Path => BasePath.PathsByTower[Tower];

		private protected abstract MultiPathPlusPlus BasePath { get; }

		public override string Icon => ((object)this).GetType().Name;

		public override string DisplayName => StringExt.Spaced(((object)this).GetType().Name);

		public override IEnumerable<ModContent> Load()
		{
			return (IEnumerable<ModContent>)BasePath.Towers.Select(delegate(string t)
			{
				MultiUpgradePlusPlus multiUpgradePlusPlus = (MultiUpgradePlusPlus)Activator.CreateInstance(((object)this).GetType());
				multiUpgradePlusPlus.tower = t;
				return multiUpgradePlusPlus;
			});
		}
	}
	public abstract class MultiUpgradePlusPlus<T> : MultiUpgradePlusPlus where T : MultiPathPlusPlus
	{
		private protected sealed override MultiPathPlusPlus BasePath => ModContent.GetInstance<T>();
	}
	public abstract class PathPlusPlus : NamedModContent, IHasDefaultTest
	{
		protected internal const int Top = 0;

		protected internal const int Middle = 1;

		protected internal const int Bottom = 2;

		public readonly SortedDictionary<int, UpgradePlusPlus> Upgrades = new SortedDictionary<int, UpgradePlusPlus>();

		[CompilerGenerated]
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private PathPlusPlusMutator <Mutator>k__BackingField;

		protected sealed override float RegistrationPriority => 11f;

		internal int StartTier => (ExtendVanillaPath >= 0) ? Upgrades.Keys.DefaultIfEmpty(5).Min() : 0;

		public abstract string Tower { get; }

		public virtual int UpgradeCount => StartTier + Upgrades.Count;

		public int Path { get; private set; }

		public virtual int ExtendVanillaPath => -1;

		public virtual bool ShowInMenu => true;

		public virtual bool UseUpgradedTowerModels => false;

		public virtual bool UseDefaultTest => true;

		public PathPlusPlusMutator Mutator => <Mutator>k__BackingField ?? (<Mutator>k__BackingField = new PathPlusPlusMutator(this));

		public virtual int Priority => 100 - ((ModContent)this).Order;

		public virtual bool ValidTiers(int[] tiers)
		{
			return DefaultValidTiers(tiers);
		}

		public static bool DefaultValidTiers(int[] tiers)
		{
			return ModHelper.HasMod("UltimateCrosspathing") || (tiers.Count((int i) => i > 2) <= 1 && tiers.Count((int i) => i > 0) <= 2);
		}

		public override void Register()
		{
			int num = Upgrades.Values.Select((UpgradePlusPlus upgrade) => upgrade.Tier).DefaultIfEmpty(0).Max();
			if (ExtendVanillaPath >= 0 && num < 5)
			{
				num = 5;
			}
			for (int num2 = StartTier; num2 < num; num2++)
			{
				if (!Upgrades.ContainsKey(num2))
				{
					throw new Exception($"Path {((ModContent)this).Id} is missing Upgrade for tier {num2 + 1}");
				}
			}
			PathsPlusPlusMod.PathsById[((ModContent)this).Id] = this;
			int extendVanillaPath = ExtendVanillaPath;
			if (extendVanillaPath >= 0 && extendVanillaPath <= 2)
			{
				Path = ExtendVanillaPath;
				Dictionary<int, List<PathPlusPlus>> orAdd = PathsPlusPlusMod.ExtendedPathsByTower.GetOrAdd(Tower, new Dictionary<int, List<PathPlusPlus>>());
				List<PathPlusPlus> orAdd2 = orAdd.GetOrAdd(Path, new List<PathPlusPlus>());
				orAdd2.Add(this);
			}
			else
			{
				List<PathPlusPlus> orAdd3 = PathsPlusPlusMod.PathsByTower.GetOrAdd(Tower, new List<PathPlusPlus>());
				Path = 3 + orAdd3.Count;
				orAdd3.Add(this);
			}
			foreach (UpgradePlusPlus value in Upgrades.Values)
			{
				GameModelExt.AddUpgrade(Game.instance.model, value.GetUpgradeModel());
			}
		}

		public override IEnumerable<ModContent> Load()
		{
			yield return (ModContent)(object)this;
			yield return (ModContent)(object)Mutator;
		}

		public virtual void OnUpgraded(Tower tower, int tier)
		{
		}

		public virtual void OnAttached(Tower tower, int tier)
		{
		}

		public void Apply(TowerModel tower, int tier)
		{
			if (tower.isParagon || ((EntityModel)tower).baseId != Tower)
			{
				return;
			}
			tower.tier = Math.Max(tower.tier, Math.Min(5, tier));
			List<string> list = ((IEnumerable<string>)tower.appliedUpgrades).ToList();
			if (ExtendVanillaPath >= 0 && StartTier < 5)
			{
				if (UseUpgradedTowerModels)
				{
					foreach (UpgradeModel item in ((IEnumerable<string>)tower.appliedUpgrades).Select((Func<string, UpgradeModel>)GameModelExt.Current.GetUpgrade))
					{
						if (item.path == Path && item.tier >= StartTier)
						{
							list.Remove(((Model)item).name);
						}
					}
				}
				else if (tier > 0)
				{
					string oldValue = GeneralExtensions.Join<int>((IEnumerable<int>)tower.tiers, (Func<int, string>)null, "");
					((Il2CppArrayBase<int>)(object)tower.tiers)[ExtendVanillaPath] = Math.Clamp(tier, 0, 5);
					((Model)tower).name = ((Model)tower).name.Replace(oldValue, GeneralExtensions.Join<int>((IEnumerable<int>)tower.tiers, (Func<int, string>)null, ""));
				}
			}
			List<UpgradePlusPlus> list2 = new List<UpgradePlusPlus>();
			for (int i = 0; i < tier; i++)
			{
				if (Upgrades.TryGetValue(i, out UpgradePlusPlus value) && !list.Contains(((ModContent)value).Id))
				{
					list2.Add(value);
					value.ApplyUpgrade(tower);
					value.ApplyUpgrade(tower, tier);
					if (value.IsHighestUpgrade(tower, highestOrEqual: true) && value.PortraitReference != null)
					{
						tower.portrait = value.PortraitReference;
					}
					list.Add(((ModContent)value).Id);
				}
			}
			tower.appliedUpgrades = Il2CppStringArray.op_Implicit(list.ToArray());
			foreach (UpgradePlusPlus item2 in list2)
			{
				item2.LateApplyUpgrade(tower);
				item2.LateApplyUpgrade(tower, tier);
			}
		}

		public virtual int GetTier(Tower tower)
		{
			BehaviorMutator mutator = GetMutator(tower);
			return (mutator != null) ? Mutator.Tier(mutator) : 0;
		}

		public BehaviorMutator? GetMutator(Tower tower)
		{
			TimedMutator mutatorById = ((Mutable)tower).GetMutatorById(((ModContent)this).Id);
			return (mutatorById != null) ? mutatorById.mutator : null;
		}

		public void SetTier(Tower tower, int tier, bool onUpgrade = false)
		{
			((Mutable)tower).RemoveMutatorsById(((ModContent)this).Id);
			((Mutable)tower).AddMutator(((ModMutator)Mutator).Create(JToken.op_Implicit(tier)), -1, true, true, false, true, false, false, false, -1, false, false);
			for (int i = 0; i < tier; i++)
			{
				if (Upgrades.TryGetValue(i, out UpgradePlusPlus value))
				{
					OnAttached(tower, tier);
					value.OnAttached(tower);
					value.currentlyAppliedOn.Add(tower);
				}
			}
			if (onUpgrade && Upgrades.TryGetValue(tier - 1, out UpgradePlusPlus value2))
			{
				OnUpgraded(tower, tier);
				value2.OnUpgraded(tower);
				BloonsMod mod = ((ModContent)this).mod;
				BloonsTD6Mod val = (BloonsTD6Mod)(object)((mod is BloonsTD6Mod) ? mod : null);
				if (val != null)
				{
					val.OnTowerUpgraded(tower, ((ModContent)value2).Name, ((Il2CppObjectBase)((Mutable)tower).rootModel).Cast<TowerModel>());
				}
			}
		}

		[Obsolete("Should pass in an actual Tower object now")]
		public static PathPlusPlus? GetPath(string tower, int path)
		{
			List<PathPlusPlus> value;
			Dictionary<int, List<PathPlusPlus>> value2;
			List<PathPlusPlus> value3;
			return (path >= 3) ? (PathsPlusPlusMod.PathsByTower.TryGetValue(tower, out value) ? value.FirstOrDefault((PathPlusPlus plus) => plus.Path == path) : null) : ((!PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(tower, out value2)) ? null : (value2.TryGetValue(path, out value3) ? value3.First() : null));
		}

		public static IList<PathPlusPlus> GetPaths(string tower, int path)
		{
			List<PathPlusPlus> value;
			if (path >= 3)
			{
				return PathsPlusPlusMod.PathsByTower.TryGetValue(tower, out value) ? value.Where((PathPlusPlus p) => p.Path == path).ToArray() : Array.Empty<PathPlusPlus>();
			}
			if (!PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(tower, out Dictionary<int, List<PathPlusPlus>> value2))
			{
				return new List<PathPlusPlus>();
			}
			if (!value2.TryGetValue(path, out var value3))
			{
				return new List<PathPlusPlus>();
			}
			return value3;
		}

		public static IList<PathPlusPlus> GetPaths(Tower tower, int path)
		{
			IList<PathPlusPlus> paths = GetPaths(((EntityModel)tower.towerModel).baseId, path);
			if (path >= 3)
			{
				return paths;
			}
			foreach (PathPlusPlus item in paths)
			{
				if (item.GetTier(tower) > 0)
				{
					return new List<PathPlusPlus>(1) { item };
				}
			}
			return paths.Where((PathPlusPlus p) => ((Il2CppArrayBase<int>)(object)tower.towerModel.tiers)[path] <= p.StartTier).ToArray();
		}

		public static PathPlusPlus? GetPath(Tower tower, int path)
		{
			IList<PathPlusPlus> paths = GetPaths(tower, path);
			if (path >= 3)
			{
				return paths.FirstOrDefault();
			}
			foreach (PathPlusPlus item in paths)
			{
				if (item.GetMutator(tower) != null)
				{
					return item;
				}
			}
			return null;
		}

		public static PathPlusPlus? GetPath(Tower tower, int path, int tier)
		{
			if (path >= 3)
			{
				return GetPath(tower, path);
			}
			IList<PathPlusPlus> paths = GetPaths(((EntityModel)tower.towerModel).baseId, path);
			foreach (PathPlusPlus item in paths)
			{
				if (item.GetTier(tower) > 0)
				{
					return item;
				}
			}
			paths = paths.Where((PathPlusPlus p) => p.StartTier >= tier - 1).ToArray();
			foreach (PathPlusPlus item2 in paths)
			{
				if (item2.GetMutator(tower) != null)
				{
					return item2;
				}
			}
			paths = paths.Where((PathPlusPlus p) => p.StartTier == tier - 1).ToArray();
			if (tier >= 6 && paths.Any())
			{
				return paths.First();
			}
			return null;
		}

		[Obsolete("Should pass in an actual Tower object now")]
		public static bool TryGetPath(string tower, int path, out PathPlusPlus pathPlusPlus)
		{
			return (pathPlusPlus = GetPath(tower, path)) != null;
		}

		public static bool TryGetPath(Tower tower, int path, out PathPlusPlus pathPlusPlus)
		{
			return (pathPlusPlus = GetPath(tower, path)) != null;
		}

		public static bool TryGetPath(Tower tower, int path, int tier, out PathPlusPlus pathPlusPlus)
		{
			return (pathPlusPlus = GetPath(tower, path, tier)) != null;
		}
	}
	public abstract class PathPlusPlus<T> : PathPlusPlus where T : ModTower
	{
		public sealed override string Tower => ((ModContent)(object)ModContent.GetInstance<T>()).Id;
	}
	public static class PathPlusPlusExtensions
	{
		public static int GetTier(this Tower tower, string pathId)
		{
			int result;
			if (PathsPlusPlusMod.PathsById.TryGetValue(pathId, out PathPlusPlus value))
			{
				int tier = value.GetTier(tower);
				if (tier >= 0)
				{
					result = tier;
					goto IL_001f;
				}
			}
			result = 0;
			goto IL_001f;
			IL_001f:
			return result;
		}

		public static int GetTier(this Tower tower, int path)
		{
			int result;
			if (PathPlusPlus.TryGetPath(tower, path, out PathPlusPlus pathPlusPlus))
			{
				int tier = pathPlusPlus.GetTier(tower);
				if (tier >= 0)
				{
					result = tier;
					goto IL_0032;
				}
			}
			result = ((path < 3) ? ((Il2CppArrayBase<int>)(object)tower.towerModel.tiers)[path] : 0);
			goto IL_0032;
			IL_0032:
			return result;
		}

		public static int GetTier(this Tower tower, PathPlusPlus path)
		{
			return path.GetTier(tower);
		}

		public static int GetTier<T>(this Tower tower) where T : PathPlusPlus
		{
			return tower.GetTier(ModContent.GetInstance<T>());
		}

		public static bool HasUpgrade<T>(this Tower tower) where T : UpgradePlusPlus
		{
			return ((Il2CppArrayBase<string>)(object)tower.towerModel.appliedUpgrades).Contains(((ModContent)ModContent.GetInstance<T>()).Id);
		}

		public static Dictionary<PathPlusPlus, int> GetTiers(this Tower tower)
		{
			List<PathPlusPlus> value;
			return PathsPlusPlusMod.PathsByTower.TryGetValue(((EntityModel)tower.towerModel).baseId, out value) ? value.ToDictionary((PathPlusPlus path) => path, (PathPlusPlus path) => tower.GetTier(((ModContent)path).Id)) : new Dictionary<PathPlusPlus, int>();
		}

		private static int[] GetExtendedTiers(this Tower tower)
		{
			return new int[3]
			{
				tower.GetTier(0),
				tower.GetTier(1),
				tower.GetTier(2)
			};
		}

		public static List<int> GetAllTiers(this Tower tower)
		{
			return tower.GetExtendedTiers().Concat(from kvp in tower.GetTiers()
				orderby kvp.Key.Path
				select kvp.Value).ToList();
		}

		public static void SetTier(this Tower tower, string pathId, int tier, bool onUpgrade = false)
		{
			if (!PathsPlusPlusMod.PathsById.TryGetValue(pathId, out PathPlusPlus value))
			{
				ModHelper.Warning<PathsPlusPlusMod>((object)("No path found with id " + pathId));
			}
			else
			{
				value.SetTier(tower, tier, onUpgrade);
			}
		}

		public static void SetTier(this Tower tower, int path, int tier, bool onUpgrade = false)
		{
			if (PathPlusPlus.TryGetPath(tower, path, out PathPlusPlus pathPlusPlus))
			{
				pathPlusPlus.SetTier(tower, tier, onUpgrade);
			}
		}

		public static Dictionary<PathPlusPlus, int> GetTiers(this TowerModel towerModel)
		{
			return (from upgrade in ((IEnumerable<string>)towerModel.appliedUpgrades).Select(((IReadOnlyDictionary<string, UpgradePlusPlus>)PathsPlusPlusMod.UpgradesById).GetValueOrDefault<string, UpgradePlusPlus>)
				where upgrade?.Path.Tower == ((EntityModel)towerModel).baseId
				group upgrade by upgrade.Path).ToDictionary((IGrouping<PathPlusPlus, UpgradePlusPlus> grouping) => grouping.Key, (IGrouping<PathPlusPlus, UpgradePlusPlus> grouping) => grouping.DefaultIfEmpty().Max((UpgradePlusPlus plus) => plus?.Tier ?? 0));
		}

		public static List<int> GetAllTiers(this TowerModel towerModel)
		{
			return ((IEnumerable<int>)towerModel.tiers).Concat(towerModel.GetTiers().Values).ToList();
		}

		internal static PathPlusPlus? GetPath(this UpgradeObjectPlusPlus upgradePlusPlus)
		{
			return string.IsNullOrEmpty(upgradePlusPlus.pathId) ? null : PathsPlusPlusMod.PathsById.GetValueOrDefault(upgradePlusPlus.pathId, null);
		}

		internal static TV GetOrAdd<TK, TV>(this Dictionary<TK, TV> dict, TK key, TV defaultValue) where TK : notnull
		{
			TV result;
			if (!dict.TryGetValue(key, out TV value))
			{
				TV val = (dict[key] = defaultValue);
				result = val;
			}
			else
			{
				result = value;
			}
			return result;
		}
	}
	public class PathPlusPlusMutator(PathPlusPlus path) : ModMutator()
	{
		public override int Priority => path.Priority;

		public override string Name => ((ModContent)path).Name;

		public override bool CantBeAbsorbed => true;

		public override bool Saved => false;

		public override string MutatorId => ((ModContent)path).Id;

		public override bool Mutate(Model baseModel, Model model, JToken data)
		{
			TowerModel tower = ((Il2CppObjectBase)model).Cast<TowerModel>();
			int tier = Extensions.Value<int>((IEnumerable<JToken>)data);
			path.Apply(tower, tier);
			return true;
		}

		public int Tier(BehaviorMutator behaviorMutator)
		{
			return Extensions.Value<int>((IEnumerable<JToken>)((ModMutator)this).GetData(behaviorMutator));
		}
	}
	public class PathPlusPlusTest : ModContentDefaultTest<PathPlusPlus>
	{
		private PathPlusPlus Path => base.Content;

		public override IEnumerator Test()
		{
			yield return ((ModTest)this).EnsureOnMainMenuWithNoPopUps();
			yield return ((ModTest)this).LoadIntoGame((InGameData)null);
			TowerModel towerModel = ((ModTest)this).Bridge.Model.GetTowerWithName(Path.Tower);
			TowerToSimulation tower = ((ModTest)this).AssertNotNull<TowerToSimulation>(ModTest.CreateTowerAt(((ModTest)this).Bridge, new Vector2(0f, 0f), towerModel, true, true, -1), "");
			Path.SetTier(tower.tower, -1);
			for (int i = 0; i < Path.UpgradeCount; i++)
			{
				((ModTest)this).Assert(ModTest.UpgradeTower(((ModTest)this).Bridge, tower, Path.Path), "");
			}
		}
	}
	[RegisterTypeInIl2Cpp(false)]
	internal class PathsPlusPlusController : MonoBehaviour
	{
		public TowerSelectionMenu menu = null;

		public ScrollRect scrollRect = null;

		public List<UpgradeObjectPlusPlus> moreUpgradeButtons = null;

		public PathsPlusPlusController(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			if (menu.selectedTower == null || PopupScreen.instance.IsPopupActive())
			{
				return;
			}
			foreach (var (num2, val2) in PathsPlusPlusMod.HotKeysByPath)
			{
				if (!val2.JustPressed() || num2 >= ((Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons).Length)
				{
					continue;
				}
				UpgradeObject val3 = ((Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons)[num2];
				if (!((Object)(object)val3 == (Object)null) && ((Behaviour)val3).isActiveAndEnabled)
				{
					int tier = val3.tier;
					val3.OnUpgrade();
					if (val3.tier > tier)
					{
						val3.WobbleUpgrade();
					}
				}
			}
		}

		public static PathsPlusPlusController? Create(TowerSelectionMenu menu)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			GameObject towerDetails = menu.towerDetails;
			GameObject gameObject = ((Component)towerDetails.transform.parent).gameObject;
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			PathsPlusPlusController pathsPlusPlusController = gameObject.AddComponent<PathsPlusPlusController>();
			pathsPlusPlusController.menu = menu;
			pathsPlusPlusController.moreUpgradeButtons = new List<UpgradeObjectPlusPlus>();
			Mask val = gameObject.AddComponent<Mask>();
			val.showMaskGraphic = false;
			gameObject.AddComponent<Image>();
			ScrollRect val2 = (pathsPlusPlusController.scrollRect = gameObject.AddComponent<ScrollRect>());
			RectTransform val3 = ((Il2CppObjectBase)towerDetails.transform).Cast<RectTransform>();
			val3.pivot = new Vector2(0.5f, 1f);
			val2.content = val3;
			RectTransform viewport = ((Il2CppObjectBase)gameObject.transform).Cast<RectTransform>();
			val2.viewport = viewport;
			val2.horizontal = false;
			val2.scrollSensitivity = 165f;
			val2.inertia = false;
			val2.movementType = (MovementType)2;
			foreach (UpgradeObject item in (Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons)
			{
				ModifyDefaultUpgradeObject(item);
			}
			VerticalLayoutGroup val4 = towerDetails.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val4).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)val4).childForceExpandWidth = false;
			((LayoutGroup)val4).childAlignment = (TextAnchor)1;
			((LayoutGroup)val4).padding = new RectOffset
			{
				bottom = 25,
				top = 25
			};
			((HorizontalOrVerticalLayoutGroup)val4).spacing = 15f;
			ContentSizeFitter val5 = towerDetails.AddComponent<ContentSizeFitter>();
			val5.verticalFit = (FitMode)2;
			for (int i = 0; i < ((Il2CppArrayBase<UpgradeInfoPopup>)(object)menu.upgradeInfoPopups).Count; i++)
			{
				UpgradeInfoPopup val6 = ((Il2CppArrayBase<UpgradeInfoPopup>)(object)menu.upgradeInfoPopups)[i];
				PopUpFixer popUpFixer = ((Component)val6).gameObject.AddComponent<PopUpFixer>();
				popUpFixer.upgradeObj = ((Component)((Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons)[i]).gameObject;
			}
			return pathsPlusPlusController;
		}

		public void SetMode(bool hasMorePaths)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			GameObject towerDetails = menu.towerDetails;
			GameObject gameObject = ((Component)towerDetails.transform.parent).gameObject;
			RectTransform val = ((Il2CppObjectBase)gameObject.transform).Cast<RectTransform>();
			val.sizeDelta = new Vector2(-50f, (float)(hasMorePaths ? (-1046) : (-1106)));
			scrollRect.vertical = hasMorePaths;
			scrollRect.verticalNormalizedPosition = 1f;
			((HorizontalOrVerticalLayoutGroup)towerDetails.GetComponent<VerticalLayoutGroup>()).spacing = (hasMorePaths ? 15 : 20);
			((Behaviour)gameObject.GetComponent<Mask>()).enabled = hasMorePaths;
			((Behaviour)gameObject.GetComponent<Image>()).enabled = hasMorePaths;
			TaskScheduler.ScheduleTask((Action)delegate
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: 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)
				for (int i = 3; i < ((Il2CppArrayBase<UpgradeInfoPopup>)(object)menu.upgradeInfoPopups).Count; i++)
				{
					Transform parent = ((Component)((Il2CppArrayBase<UpgradeInfoPopup>)(object)menu.upgradeInfoPopups)[i]).transform.parent;
					Vector3 localPosition = parent.localPosition;
					Vector3 localPosition2 = localPosition;
					localPosition2.x = Math.Abs(localPosition.x) * (float)(menu.IsOpenedRight() ? 1 : (-1));
					parent.localPosition = localPosition2;
				}
			}, (Func<bool>)null);
		}

		private void AddNewUpgradeObject()
		{
			UpgradeObject val = ((Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons)[0];
			int num = 3 + moreUpgradeButtons.Count;
			GameObject val2 = GameObjectExt.Duplicate<GameObject>(((Component)val).gameObject, menu.towerDetails.transform);
			UpgradeObjectPlusPlus component = val2.GetComponent<UpgradeObjectPlusPlus>();
			component.upgradeObject = val2.GetComponent<UpgradeObject>();
			((Object)val2).name = "UpgradeObject_" + (num + 1);
			UpgradeObject upgradeObject = component.upgradeObject;
			upgradeObject.upgradeButton.row = num;
			((BaseUpgrade)upgradeObject.currentUpgrade).row = num;
			upgradeObject.buttonID = num;
			upgradeObject.upgradeButton.background = ((Component)upgradeObject.upgradeButton).GetComponent<Image>();
			moreUpgradeButtons.Add(component);
			menu.upgradeButtons = Il2CppReferenceArrayExt.AddTo<UpgradeObject>(menu.upgradeButtons, upgradeObject);
			Transform parent = ((Component)((Il2CppArrayBase<UpgradeInfoPopup>)(object)menu.upgradeInfoPopups)[0]).transform.parent.parent;
			Transform val3 = GameObjectExt.Duplicate<Transform>(parent, ((Component)parent).transform.parent);
			((Object)val3).name = "Upgrade_" + (num + 1);
			UpgradeInfoPopup componentInChildren = ((Component)val3).GetComponentInChildren<UpgradeInfoPopup>();
			PopUpFixer componentOrAdd = GameObjectExtensions.GetComponentOrAdd<PopUpFixer>(((Component)componentInChildren).gameObject);
			componentOrAdd.upgradeObj = val2;
			menu.upgradeInfoPopups = Il2CppReferenceArrayExt.AddTo<UpgradeInfoPopup>(menu.upgradeInfoPopups, componentInChildren);
			scrollRect.verticalNormalizedPosition = 1f;
		}

		private static void ModifyDefaultUpgradeObject(UpgradeObject upgradeObject)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			LayoutElement val = ((Component)upgradeObject).gameObject.AddComponent<LayoutElement>();
			Vector2 sizeDelta = ((Il2CppObjectBase)((Component)upgradeObject).transform).Cast<RectTransform>().sizeDelta;
			float preferredWidth = (val.minWidth = sizeDelta.x);
			val.preferredWidth = preferredWidth;
			preferredWidth = (val.minHeight = sizeDelta.y);
			val.preferredHeight = preferredWidth;
			((Il2CppObjectBase)upgradeObject.locked.transform).Cast<RectTransform>().sizeDelta = new Vector2(900f, 350f);
			Transform parent = ((Component)((Il2CppArrayBase<TierObject>)(object)upgradeObject.tiers)[0]).transform.parent;
			ComponentExt.TranslateScaled((Component)(object)parent, new Vector3(13f, 0f, 0f));
			GridLayoutGroup component = ((Component)parent).GetComponent<GridLayoutGroup>();
			component.constraint = (Constraint)2;
			component.constraintCount = 5;
			component.startAxis = (Axis)1;
			((LayoutGroup)component).childAlignment = (TextAnchor)6;
			component.spacing = new Vector2(4f, 4f);
			UpgradeObjectPlusPlus upgradeObjectPlusPlus = ((Component)upgradeObject).gameObject.AddComponent<UpgradeObjectPlusPlus>();
			upgradeObjectPlusPlus.upgradeObject = upgradeObject;
		}

		public void InitUpgradeButtons()
		{
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			TowerToSimulation selectedTower = menu.selectedTower;
			if (selectedTower == null || selectedTower.hero != null)
			{
				return;
			}
			Tower tower = selectedTower.tower;
			if (tower == null)
			{
				return;
			}
			TowerModel towerModel = tower.towerModel;
			if (towerModel == null || towerModel.isParagon)
			{
				return;
			}
			if (!PathsPlusPlusMod.PathsByTower.TryGetValue(((EntityModel)selectedTower.Def).baseId, out List<PathPlusPlus> value))
			{
				value = new List<PathPlusPlus>();
			}
			while (value.Count > moreUpgradeButtons.Count)
			{
				AddNewUpgradeObject();
			}
			for (int i = 0; i < 3; i++)
			{
				UpgradeObject upgradeButton = ((Il2CppArrayBase<UpgradeObject>)(object)menu.upgradeButtons)[i];
				UpgradeObjectPlusPlus component = ((Component)upgradeButton).GetComponent<UpgradeObjectPlusPlus>();
				if ((Object)(object)component == (Object)null || !((Behaviour)component).isActiveAndEnabled)
				{
					continue;
				}
				if (PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(((EntityModel)selectedTower.Def).baseId, out Dictionary<int, List<PathPlusPlus>> _))
				{
					int tier = upgradeButton.tier;
					PathPlusPlus path = PathPlusPlus.GetPath(selectedTower.tower, i, tier + 1);
					if (path == null)
					{
						component.pathId = null;
					}
					else
					{
						component.InitForTower(selectedTower, ((ModContent)path).Id);
						upgradeButton.UpdateVisuals(path.Path, false);
					}
					List<PathPlusPlus> list = (from p in PathPlusPlus.GetPaths(selectedTower.tower, i)
						where p.StartTier == upgradeButton.tier
						select p).ToList();
					component.CycleShowing(list.Count > ((tier >= 5 && !TowerSelectionMenuUtils.CanUpgradeToParagon(selectedTower, true)) ? 1 : 0) && !menu.IsUpgradePathClosed(i), Il2CppStringArray.op_Implicit(list.Select((PathPlusPlus plus) => ((ModContent)plus).Id).ToArray()));
				}
				else
				{
					component.CycleShowing(showing: false, new Il2CppStringArray(0L));
				}
			}
			Il2CppArrayBase<PopUpFixer> componentsInChildren = ((Component)((Component)menu).transform).GetComponentsInChildren<PopUpFixer>(true);
			for (int num = 0; num < moreUpgradeButtons.Count; num++)
			{
				UpgradeObjectPlusPlus button = Il2CppGenericsExt.Get<UpgradeObjectPlusPlus>(moreUpgradeButtons, num);
				UpgradeInfoPopup component2 = ((Component)((IEnumerable<PopUpFixer>)componentsInChildren).First((PopUpFixer fixer) => (Object)(object)fixer.upgradeObj == (Object)(object)((Component)button.upgradeObject).gameObject)).GetComponent<UpgradeInfoPopup>();
				if (num < value.Count)
				{
					PathPlusPlus pathPlusPlus = value[num];
					((Component)button).gameObject.SetActive(true);
					((Behaviour)button.upgradeObject).enabled = true;
					button.InitForTower(selectedTower, ((ModContent)pathPlusPlus).Id);
					((Behaviour)component2).enabled = true;
					((Component)component2).gameObject.SetActive(true);
				}
				else
				{
					button.upgradeObject.tts = null;
					((Behaviour)button.upgradeObject).enabled = false;
					((Component)button).gameObject.SetActive(false);
					((Behaviour)component2).enabled = false;
					((Component)component2).gameObject.SetActive(false);
				}
			}
			menu.upgradeButtons = Il2CppReferenceArray<UpgradeObject>.op_Implicit(((IEnumerable<UpgradeObject>)((Component)((Component)menu).transform).GetComponentsInChildren<UpgradeObject>(false)).ToArray());
			menu.upgradeInfoPopups = Il2CppReferenceArray<UpgradeInfoPopup>.op_Implicit(((IEnumerable<UpgradeInfoPopup>)((Component)((Component)menu).transform).GetComponentsInChildren<UpgradeInfoPopup>(false)).ToArray());
			UpdateVisuals();
		}

		public void UpdateVisuals()
		{
			TowerToSimulation selectedTower = menu.selectedTower;
			if (selectedTower == null || selectedTower.hero != null)
			{
				return;
			}
			Tower tower = selectedTower.tower;
			if (tower == null)
			{
				return;
			}
			TowerModel towerModel = tower.towerModel;
			if (towerModel == null || towerModel.isParagon)
			{
				return;
			}
			Enumerator<UpgradeObjectPlusPlus> enumerator = moreUpgradeButtons.GetEnumerator();
			while (enumerator.MoveNext())
			{
				UpgradeObjectPlusPlus current = enumerator.Current;
				if (((Component)current).gameObject.active)
				{
					current.upgradeObject.UpdateVisuals(current.upgradeObject.path, false);
				}
			}
		}

		public void UpdateCosts()
		{
			TowerToSimulation selectedTower = menu.selectedTower;
			if (selectedTower == null || selectedTower.hero != null)
			{
				return;
			}
			Tower tower = selectedTower.tower;
			if (tower == null)
			{
				return;
			}
			TowerModel towerModel = tower.towerModel;
			if (towerModel == null || towerModel.isParagon)
			{
				return;
			}
			Enumerator<UpgradeObjectPlusPlus> enumerator = moreUpgradeButtons.GetEnumerator();
			while (enumerator.MoveNext())
			{
				UpgradeObjectPlusPlus current = enumerator.Current;
				if (((Component)current).gameObject.active)
				{
					current.upgradeObject.UpdateCost();
				}
			}
			CheckCash();
		}

		public void CheckCash()
		{
			TowerToSimulation selectedTower = menu.selectedTower;
			if (selectedTower == null || selectedTower.hero != null)
			{
				return;
			}
			Tower tower = selectedTower.tower;
			if (tower == null)
			{
				return;
			}
			TowerModel towerModel = tower.towerModel;
			if (towerModel == null || towerModel.isParagon)
			{
				return;
			}
			Enumerator<UpgradeObjectPlusPlus> enumerator = moreUpgradeButtons.GetEnumerator();
			while (enumerator.MoveNext())
			{
				UpgradeObjectPlusPlus current = enumerator.Current;
				if (((Component)current).gameObject.active)
				{
					current.upgradeObject.CheckCash();
				}
			}
		}
	}
	public class PathsPlusPlusMod : BloonsTD6Mod
	{
		public static readonly Dictionary<string, PathPlusPlus> PathsById = new Dictionary<string, PathPlusPlus>();

		public static readonly Dictionary<string, List<PathPlusPlus>> PathsByTower = new Dictionary<string, List<PathPlusPlus>>();

		public static readonly Dictionary<string, UpgradePlusPlus> UpgradesById = new Dictionary<string, UpgradePlusPlus>();

		public static readonly Dictionary<string, Dictionary<int, List<PathPlusPlus>>> ExtendedPathsByTower = new Dictionary<string, Dictionary<int, List<PathPlusPlus>>>();

		public static readonly Dictionary<string, string?[]> DefaultExtendedPaths = new Dictionary<string, string[]>();

		public static readonly ModSettingBool BalancedMode = new ModSettingBool(true)
		{
			description = "Restricts upgrading across all paths to be the standard 5 in one path, 2 in another, 0 in the rest. When disabled, vanilla upgrade paths work as normal and you can additionally use any/all Paths++ upgrade.",
			icon = "441a882ac2a1fce42854bcceb07f8ae4",
			button = true,
			enabledText = "On",
			disabledText = "Off"
		};

		internal static readonly ModSettingCategory Hotkeys = new ModSettingCategory("Hotkeys");

		internal static readonly ModSettingHotkey UpgradePath4 = new ModSettingHotkey((KeyCode)44, (HotkeyModifier)1)
		{
			category = Hotkeys,
			displayName = "Upgrade Fourth Path"
		};

		internal static readonly ModSettingHotkey UpgradePath5 = new ModSettingHotkey((KeyCode)46, (HotkeyModifier)1)
		{
			category = Hotkeys,
			displayName = "Upgrade Fifth Path"
		};

		internal static readonly ModSettingHotkey UpgradePath6 = new ModSettingHotkey((KeyCode)47, (HotkeyModifier)1)
		{
			category = Hotkeys,
			displayName = "Upgrade Sixth Path"
		};

		internal static readonly ModSettingHotkey UpgradePath7 = new ModSettingHotkey((KeyCode)44, (HotkeyModifier)3)
		{
			category = Hotkeys,
			displayName = "Upgrade Seventh Path"
		};

		internal static readonly ModSettingHotkey UpgradePath8 = new ModSettingHotkey((KeyCode)46, (HotkeyModifier)3)
		{
			category = Hotkeys,
			displayName = "Upgrade Eighth Path"
		};

		internal static readonly ModSettingHotkey UpgradePath9 = new ModSettingHotkey((KeyCode)47, (HotkeyModifier)3)
		{
			category = Hotkeys,
			displayName = "Upgrade Ninth Path"
		};

		internal static readonly Dictionary<int, ModSettingHotkey> HotKeysByPath = new Dictionary<int, ModSettingHotkey>
		{
			{ 3, UpgradePath4 },
			{ 4, UpgradePath5 },
			{ 5, UpgradePath6 },
			{ 6, UpgradePath7 },
			{ 7, UpgradePath8 },
			{ 8, UpgradePath9 }
		};

		private static readonly Dictionary<PathPlusPlus, int> Clipboard = new Dictionary<PathPlusPlus, int>();

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

		public override void OnApplicationStart()
		{
			Preferences = MelonPreferences.CreateCategory("PathsPlusPlusPreferences");
		}

		public override void OnNewGameModel(GameModel gameModel)
		{
			Clipboard.Clear();
			foreach (ShopTowerDetailsModel item in IEnumerableExt.OfIl2CppType<ShopTowerDetailsModel>((IEnumerable)gameModel.towerSet))
			{
				if (!ExtendedPathsByTower.TryGetValue(((TowerDetailsModel)item).towerId, out Dictionary<int, List<PathPlusPlus>> value))
				{
					continue;
				}
				if (item.pathOneMax == 5 && value.TryGetValue(0, out var value2))
				{
					item.pathOneMax = value2.Max((PathPlusPlus p) => p.UpgradeCount);
				}
				if (item.pathTwoMax == 5 && value.TryGetValue(1, out var value3))
				{
					item.pathTwoMax = value3.Max((PathPlusPlus p) => p.UpgradeCount);
				}
				if (item.pathThreeMax == 5 && value.TryGetValue(2, out var value4))
				{
					item.pathThreeMax = value4.Max((PathPlusPlus p) => p.UpgradeCount);
				}
			}
		}

		public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData)
		{
			foreach (string key in PathsById.Keys)
			{
				int tier = tower.GetTier(key);
				if (tier > 0)
				{
					saveData.metaData[key] = tier.ToString();
				}
			}
		}

		public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData)
		{
			foreach (string key in PathsById.Keys)
			{
				if (saveData.metaData.ContainsKey(key) && int.TryParse(saveData.metaData[key], out var result))
				{
					tower.SetTier(key, result);
				}
			}
		}

		public override void OnProfileLoaded(ProfileModel profile)
		{
			foreach (UpgradePlusPlus item in ModContent.GetContent<UpgradePlusPlus>())
			{
				profile.acquiredUpgrades.AddIfNotPresent(((ModContent)item).Id);
			}
		}

		public override void PreCleanProfile(ProfileModel profile)
		{
			string[] ids = (from upgrade in ModContent.GetContent<UpgradePlusPlus>()
				select ((ModContent)upgrade).Id).ToArray();
			profile.acquiredUpgrades.RemoveWhere(Predicate<string>.op_Implicit((Func<string, bool>)((string s) => ((ReadOnlySpan<string>)ids).Contains(s))));
		}

		public override void PostCleanProfile(ProfileModel profile)
		{
			((BloonsTD6Mod)this).OnProfileLoaded(profile);
		}

		public override void OnTowerDestroyed(Tower tower)
		{
			foreach (UpgradePlusPlus item in ModContent.GetContent<UpgradePlusPlus>())
			{
				item.currentlyAppliedOn.Remove(tower);
			}
		}

		public override void OnGameObjectsReset()
		{
			foreach (UpgradePlusPlus item in ModContent.GetContent<UpgradePlusPlus>())
			{
				item.currentlyAppliedOn.Clear();
			}
		}

		public override void OnSaveSettings(JObject settings)
		{
			settings["DefaultExtendedPaths"] = (JToken)(object)JObject.FromObject((object)DefaultExtendedPaths);
		}

		public override void OnLoadSettings(JObject settings)
		{
			JToken obj = settings["DefaultExtendedPaths"];
			Dictionary<string, string[]> dictionary = ((obj != null) ? obj.ToObject<Dictionary<string, string[]>>() : null);
			if (dictionary == null)
			{
				return;
			}
			foreach (var (key, value) in dictionary)
			{
				DefaultExtendedPaths[key] = value;
			}
		}

		public override void OnTowerCreated(Tower tower, Entity target, Model modelToUse)
		{
			if (!DefaultExtendedPaths.TryGetValue(((EntityModel)tower.towerModel).baseId, out string[] value))
			{
				return;
			}
			foreach (PathPlusPlus item in from pathId in value
				where pathId != null && PathsById.ContainsKey(pathId)
				select PathsById[pathId])
			{
				item.SetTier(tower, -1);
			}
		}

		public override object? Call(string operation, params object[] parameters)
		{
			switch (operation)
			{
			case "OnTowerCopied":
			{
				Tower tower5 = default(Tower);
				if (!ArrayExt.CheckTypes<Tower>(parameters, ref tower5))
				{
					break;
				}
				Clipboard.Clear();
				foreach (PathPlusPlus value in PathsById.Values)
				{
					int tier = value.GetTier(tower5);
					if (tier > 0)
					{
						Clipboard[value] = tier;
					}
				}
				break;
			}
			case "OnTowerPasted":
			{
				Tower tower4 = default(Tower);
				bool flag = default(bool);
				if (!ArrayExt.CheckTypes<Tower, bool>(parameters, ref tower4, ref flag))
				{
					break;
				}
				foreach (var (pathPlusPlus2, num2) in Clipboard)
				{
					pathPlusPlus2.SetTier(tower4, flag ? (-1) : num2);
				}
				break;
			}
			case "OnClipboardCleared":
				Clipboard.Clear();
				break;
			case "GetPathIds":
				return PathsById.Keys;
			case "GetTiers":
			{
				Tower tower3 = default(Tower);
				if (!ArrayExt.CheckTypes<Tower>(parameters, ref tower3))
				{
					break;
				}
				return tower3.GetAllTiers();
			}
			case "ValidTiers":
			{
				string tower6 = default(string);
				int path5 = default(int);
				int[] tiers = default(int[]);
				if (ArrayExt.CheckTypes<string, int, int[]>(parameters, ref tower6, ref path5, ref tiers))
				{
					PathPlusPlus pathPlusPlus3;
					return !PathPlusPlus.TryGetPath(tower6, path5, out pathPlusPlus3) || pathPlusPlus3.ValidTiers(tiers);
				}
				Tower tower7 = default(Tower);
				int path6 = default(int);
				int[] tiers2 = default(int[]);
				if (!ArrayExt.CheckTypes<Tower, int, int[]>(parameters, ref tower7, ref path6, ref tiers2))
				{
					break;
				}
				PathPlusPlus pathPlusPlus4;
				return !PathPlusPlus.TryGetPath(tower7, path6, out pathPlusPlus4) || pathPlusPlus4.ValidTiers(tiers2);
			}
			case "GetUpgrade":
			{
				string tower = default(string);
				int path = default(int);
				int key = default(int);
				if (ArrayExt.CheckTypes<string, int, int>(parameters, ref tower, ref path, ref key))
				{
					PathPlusPlus? path2 = PathPlusPlus.GetPath(tower, path);
					object result;
					if (path2 == null)
					{
						result = null;
					}
					else
					{
						UpgradePlusPlus? valueOrDefault = path2.Upgrades.GetValueOrDefault(key);
						result = ((valueOrDefault != null) ? ((ModContent)valueOrDefault).Id : null);
					}
					return result;
				}
				Tower tower2 = default(Tower);
				int path3 = default(int);
				int key2 = default(int);
				if (!ArrayExt.CheckTypes<Tower, int, int>(parameters, ref tower2, ref path3, ref key2))
				{
					break;
				}
				PathPlusPlus? path4 = PathPlusPlus.GetPath(tower2, path3);
				object result2;
				if (path4 == null)
				{
					result2 = null;
				}
				else
				{
					UpgradePlusPlus? valueOrDefault2 = path4.Upgrades.GetValueOrDefault(key2);
					result2 = ((valueOrDefault2 != null) ? ((ModContent)valueOrDefault2).Id : null);
				}
				return result2;
			}
			}
			return ((BloonsMod)this).Call(operation, parameters);
		}
	}
	[RegisterTypeInIl2Cpp(false)]
	internal class PopUpFixer : MonoBehaviour
	{
		public GameObject upgradeObj = null;

		public PopUpFixer(IntPtr ptr)
			: base(ptr)
		{
		}

		private void LateUpdate()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				UpgradeInfoPopup component = ((Component)this).GetComponent<UpgradeInfoPopup>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)upgradeObj == (Object)null))
				{
					Transform transform = ((Component)component).transform;
					Vector3 position = transform.position;
					position.y = upgradeObj.transform.position.y;
					transform.position = position;
				}
			}
			catch (Exception ex)
			{
				ModHelper.Warning<PathsPlusPlusMod>((object)ex);
			}
		}
	}
	[RegisterTypeInIl2Cpp(false)]
	internal class UpgradeObjectPlusPlus : MonoBehaviour
	{
		public UpgradeObject upgradeObject = null;

		public string? pathId;

		public bool overrideParagon;

		public ModHelperButton? cycle;

		public Il2CppStringArray? cyclePathIds;

		private int delay;

		public bool IsExtra
		{
			get
			{
				PathPlusPlus pathPlusPlus;
				return upgradeObject.path >= 3 || (PathPlusPlus.TryGetPath(upgradeObject.towerSelectionMenu.selectedTower.tower, upgradeObject.path, upgradeObject.tier + 1, out pathPlusPlus) && upgradeObject.tier >= pathPlusPlus.StartTier);
			}
		}

		public UpgradeObjectPlusPlus(IntPtr ptr)
			: base(ptr)
		{
		}

		public void InitForTower(TowerToSimulation tts, string path)
		{
			PathPlusPlus pathPlusPlus = PathsPlusPlusMod.PathsById[path];
			pathId = ((ModContent)pathPlusPlus).Id;
			upgradeObject.path = pathPlusPlus.Path;
			upgradeObject.tts = tts;
			upgradeObject.upgradeButton.tts = tts;
			int tier = tts.tower.GetTier(path);
			if (tier > upgradeObject.tier)
			{
				upgradeObject.tier = tier;
			}
			try
			{
				if (IsExtra)
				{
					upgradeObject.LoadUpgrades();
				}
			}
			catch (Exception ex)
			{
				ModHelper.Warning<PathsPlusPlusMod>((object)ex);
			}
		}

		public void CycleShowing(bool showing, Il2CppStringArray pathIds)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_003c: 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)
			cyclePathIds = pathIds;
			if (showing)
			{
				if ((Object)(object)cycle == (Object)null)
				{
					cycle = ModHelperButton.Create(new Info("Cycle", 150f, 150f, new Vector2(0.55f, 0.5f)), "Ui[RestartIcon]", (Action)null);
					((Component)cycle).transform.Rotate(0f, 0f, 180f);
					((ModHelperComponent)cycle).SetParent(((Component)upgradeObject).transform);
				}
				((Component)cycle).gameObject.SetActive(true);
				ButtonExt.SetOnClick(cycle.Button, new Function(CycleUpgrade));
			}
			else if ((Object)(object)cycle != (Object)null)
			{
				((Component)cycle).gameObject.SetActive(false);
			}
		}

		public void CycleUpgrade()
		{
			if (cyclePathIds == null || !((IEnumerable<string>)cyclePathIds).Any() || (Object)(object)cycle == (Object)null)
			{
				return;
			}
			AudioClipExtensions.Play(MenuManager.instance.buttonClick3Sound, "FX", 1f);
			List<PathPlusPlus> list = ((IEnumerable<string>)cyclePathIds).Select((string s) => PathsPlusPlusMod.PathsById[s]).ToList();
			int tier = upgradeObject.tier;
			TowerToSimulation tts = upgradeObject.tts;
			int path = upgradeObject.path;
			bool flag = TowerSelectionMenuUtils.CanUpgradeToParagon(tts, true) && tier >= 5;
			PathPlusPlus path2 = PathPlusPlus.GetPath(tts.tower, path, tier + 1);
			PathPlusPlus pathPlusPlus;
			if (!overrideParagon && flag)
			{
				overrideParagon = true;
				pathPlusPlus = list.First();
			}
			else if (overrideParagon && path2 == list.Last() && flag)
			{
				overrideParagon = false;
				pathPlusPlus = null;
			}
			else if (path2 == null)
			{
				pathPlusPlus = list.First();
			}
			else
			{
				int num = list.IndexOf(path2) + 1;
				pathPlusPlus = ((num >= list.Count) ? null : list[num]);
			}
			foreach (PathPlusPlus item in list)
			{
				((Mutable)tts.tower).RemoveMutatorsById(((ModContent)item).Id);
			}
			pathPlusPlus?.SetTier(tts.tower, -1);
			pathId = ((pathPlusPlus != null) ? ((ModContent)pathPlusPlus).Id : null);
			upgradeObject.LoadUpgrades();
		}

		private void Update()
		{
			if (delay > 0)
			{
				delay--;
			}
			else if (Input.GetKeyDown((KeyCode)325))
			{
				delay = 30;
				CycleUpgrade();
			}
		}
	}
	public abstract class UpgradePlusPlus : NamedModContent
	{
		internal readonly HashSet<Tower> currentlyAppliedOn = new HashSet<Tower>();

		private UpgradeModel? upgradeModel;

		protected sealed override float RegistrationPriority => 10f;

		public abstract PathPlusPlus Path { get; }

		public virtual string Icon => ((ModContent)this).Name;

		public virtual SpriteReference IconReference => ((ModContent)this).GetSpriteReferenceOrDefault(Icon);

		public abstract int Cost { get; }

		public virtual bool Ability => false;

		public abstract int Tier { get; }

		public virtual string? Portrait => null;

		public virtual int MaxAtOnce
		{
			get
			{
				if (Tier < 5)
				{
					goto IL_003d;
				}
				BloonsMod val = default(BloonsMod);
				if (ModHelper.HasMod("Unlimited5thTiers", ref val) && val.ModSettings.TryGetValue("AllowUnlimited5thTiers", out var value))
				{
					ModSettingBool val2 = (ModSettingBool)(object)((value is ModSettingBool) ? value : null);
					if (val2 != null && ModSettingBool.op_Implicit(val2))
					{
						goto IL_003d;
					}
				}
				int result = 1;
				goto IL_0045;
				IL_003d:
				result = 999999999;
				goto IL_0045;
				IL_0045:
				return result;
			}
		}

		public virtual SpriteReference? PortraitReference => (!string.IsNullOrEmpty(Portrait)) ? ((ModContent)this).GetSpriteReferenceOrDefault(Portrait) : (((ModContent)this).GetSpriteReferenceOrNull(((ModContent)Path).Name) ?? ((ModContent)this).GetSpriteReferenceOrNull(((ModContent)Path).Name + Tier) ?? ModContent.CreateSpriteReference(VanillaSprites.ByName.GetValueOrDefault(VanillaPortrait)));

		private string VanillaPortrait
		{
			get
			{
				string text = Path.Tower.Replace(TowerType.WizardMonkey, "Wizard");
				for (int i = 0; i <= 2; i++)
				{
					text = ((Path.Path != i || Tier >= 6) ? (text + "0") : (text + Tier));
				}
				return text;
			}
		}

		public virtual string? Container => null;

		public virtual SpriteReference? ContainerReference => string.IsNullOrEmpty(Container) ? null : ((ModContent)this).GetSpriteReferenceOrDefault(Container);

		public virtual bool NeedsConfirmation => false;

		public virtual string? ConfirmationTitle => null;

		public virtual string? ConfirmationBody => null;

		protected static string UpgradeContainerPlatinum => ModContent.GetTextureGUID<PathsPlusPlusMod>("UpgradeContainerPlatinum");

		protected static string UpgradeContainerDiamond => ModContent.GetTextureGUID<PathsPlusPlusMod>("UpgradeContainerDiamond");

		protected static string UpgradeContainerRainbow => ModContent.GetTextureGUID<PathsPlusPlusMod>("UpgradeContainerRainbow");

		public override void Register()
		{
			if (Tier <= 0)
			{
				throw new Exception($"Tier of {((ModContent)this).Id} must be greater than {0}");
			}
			if (!Path.Upgrades.TryAdd(Tier - 1, this))
			{
				throw new Exception($"Tier {Tier} of {((ModContent)Path).Id} is used by both {((ModContent)this).Id} and {((ModContent)Path.Upgrades[Tier - 1]).Id}");
			}
			PathsPlusPlusMod.UpgradesById[((ModContent)this).Id] = this;
		}

		public override void RegisterText(Dictionary<string, string> textTable)
		{
			((NamedModContent)this).RegisterText(textTable);
			if (NeedsConfirmation)
			{
				if (ConfirmationTitle != null)
				{
					textTable[((ModContent)this).Id + " Title"] = ConfirmationTitle;
				}
				if (ConfirmationBody != null)
				{
					textTable[((ModContent)this).Id + " Body"] = ConfirmationBody;
				}
			}
		}

		public UpgradeModel GetUpgradeModel()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0058: Expected O, but got Unknown
			UpgradeModel obj = upgradeModel;
			if (obj == null)
			{
				UpgradeModel val = new UpgradeModel(((ModContent)this).Id, Cost, 0, IconReference, Path.Path, Tier - 1, 0, NeedsConfirmation ? ((ModContent)this).Id : "", "");
				UpgradeModel val2 = val;
				upgradeModel = val;
				obj = val2;
			}
			return obj;
		}

		public bool IsHighestUpgrade(TowerModel towerModel, bool highestOrEqual = false)
		{
			return towerModel.GetAllTiers().All((int t) => highestOrEqual ? (Tier >= t) : (Tier > t));
		}

		public virtual void ApplyUpgrade(TowerModel towerModel)
		{
		}

		public virtual void ApplyUpgrade(TowerModel towerModel, int tier)
		{
		}

		public virtual void OnUpgraded(Tower tower)
		{
		}

		public virtual void OnAttached(Tower tower)
		{
		}

		public virtual void LateApplyUpgrade(TowerModel towerModel)
		{
		}

		public virtual void LateApplyUpgrade(TowerModel towerModel, int tier)
		{
		}
	}
	public abstract class UpgradePlusPlus<T> : UpgradePlusPlus where T : PathPlusPlus
	{
		public sealed override PathPlusPlus Path => ModContent.GetInstance<T>();
	}
	[RegisterTypeInIl2Cpp(false)]
	internal class UpgradeScreenPlusPlus : MonoBehaviour
	{
		[HarmonyPatch(typeof(UpgradeScreen), "UpdateUi")]
		internal static class UpgradeScreen_UpdateUi
		{
			[HarmonyPostfix]
			private static void Postfix(UpgradeScreen __instance)
			{
				UpgradeScreenPlusPlus upgradeScreenPlusPlus = ((Component)__instance).GetComponentInChildren<UpgradeScreenPlusPlus>();
				if ((Object)(object)upgradeScreenPlusPlus == (Object)null)
				{
					upgradeScreenPlusPlus = Setup(__instance);
				}
				upgradeScreenPlusPlus.UpdateUi(__instance.currTowerId);
			}
		}

		[HarmonyPatch(typeof(UpgradeScreen), "Open")]
		internal static class UpgradeScreen_Open
		{
			[HarmonyPostfix]
			private static void Postfix(UpgradeScreen __instance)
			{
				lastDefaults = JsonConvert.SerializeObject((object)PathsPlusPlusMod.DefaultExtendedPaths);
				foreach (KeyValuePair<string, string[]> defaultExtendedPath in PathsPlusPlusMod.DefaultExtendedPaths)
				{
					defaultExtendedPath.Deconstruct(out var _, out var value);
					string[] array = value;
					for (int i = 0; i < array.Length; i++)
					{
						string text = array[i];
						if (text != null && !PathsPlusPlusMod.PathsById.ContainsKey(text))
						{
							array[i] = null;
						}
					}
				}
				Animator val = default(Animator);
				foreach (UpgradeDetails componentsInChild in ((Component)__instance).GetComponentsInChildren<UpgradeDetails>())
				{
					if (GameObjectExt.HasComponent<Animator>(((Component)componentsInChild).gameObject, ref val))
					{
						val.speed = 0.75f;
						val.Play("PopupScaleIn");
					}
					((Behaviour)((Component)componentsInChild).GetComponentInChildren<EventTrigger>(true)).enabled = false;
				}
			}
		}

		[HarmonyPatch(typeof(UpgradeScreen), "Close")]
		internal static class UpgradeScreen_Close
		{
			[HarmonyPostfix]
			private static void Postfix(UpgradeScreen __instance)
			{
				Animator val = default(Animator);
				foreach (UpgradeDetails componentsInChild in ((Component)__instance).GetComponentsInChildren<UpgradeDetails>())
				{
					if (GameObjectExt.HasComponent<Animator>(((Component)componentsInChild).gameObject, ref val))
					{
						val.speed = 1f;
						val.Play("PopupScaleOut");
					}
				}
				if (JsonConvert.SerializeObject((object)PathsPlusPlusMod.DefaultExtendedPaths) != lastDefaults)
				{
					((BloonsMod)ModContent.GetInstance<PathsPlusPlusMod>()).SaveModSettings();
				}
			}
		}

		private const int TopBarHeight = 345;

		private const int LeftSideWidth16X9 = 1240;

		private const int LeftSideWidth16X10 = 1010;

		private const int LeftSideWidth4X3 = 849;

		private const int PathsSpacing = 525;

		private const int UpgradeSpacing = 490;

		public UpgradeScreen upgradeScreen = null;

		public ModHelperScrollPanel scrollPanel = null;

		public RectTransform upgradePaths = null;

		public RectTransform scrollContent = null;

		private float paragonOffset;

		public readonly List<GameObject> createdUpgradePaths = new List<GameObject>();

		public readonly List<UpgradeDetails>[] extraUpgradeDetails = new List<UpgradeDetails>[3]
		{
			new List<UpgradeDetails>(),
			new List<UpgradeDetails>(),
			new List<UpgradeDetails>()
		};

		private static string lastDefaults;

		public UpgradeScreenPlusPlus(IntPtr ptr)
			: base(ptr)
		{
		}

		public void UpdateUi(string towerId)
		{
			//IL_0aa2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab3: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a29: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a33: Expected O, but got Unknown
			//IL_09a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<GameObject> enumerator = createdUpgradePaths.GetEnumerator();
			while (enumerator.MoveNext())
			{
				GameObject current = enumerator.Current;
				current.gameObject.SetActive(false);
			}
			foreach (UpgradeDetails item in extraUpgradeDetails.SelectMany((List<UpgradeDetails> val8) => (IEnumerable<UpgradeDetails>)val8.ToArray()))
			{
				((Component)item).gameObject.SetActive(false);
			}
			List<PathPlusPlus> value;
			List<PathPlusPlus> list = (PathsPlusPlusMod.PathsByTower.TryGetValue(towerId, out value) ? value.Where((PathPlusPlus path) => path?.ShowInMenu ?? false).ToList() : new List<PathPlusPlus>());
			Dictionary<int, List<PathPlusPlus>> value2;
			Dictionary<int, List<PathPlusPlus>> dictionary = (PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(towerId, out value2) ? value2 : new Dictionary<int, List<PathPlusPlus>>());
			List<PathPlusPlus> list2 = new List<PathPlusPlus>();
			for (int num = 0; num <= 2; num++)
			{
				if (!dictionary.TryGetValue(num, out var value3))
				{
					continue;
				}
				if (PathsPlusPlusMod.DefaultExtendedPaths.TryGetValue(towerId, out string[] value4) && value4.Length == 3)
				{
					string d = value4[num];
					if (d != null && PathsPlusPlusMod.PathsById.ContainsKey(d))
					{
						list2.Add(value3.Single((PathPlusPlus plus) => ((ModContent)plus).Id == d));
						continue;
					}
				}
				using IEnumerator<PathPlusPlus> enumerator3 = value3.Where((PathPlusPlus path) => path.StartTier >= 5).GetEnumerator();
				if (enumerator3.MoveNext())
				{
					PathPlusPlus current3 = enumerator3.Current;
					list2.Add(current3);
				}
			}
			PathPlusPlus[] array = list.Concat(list2).ToArray();
			Transform transform = upgradeScreen.paragonPanel.transform;
			foreach (Button item2 in ((IEnumerable<Button>)((Component)upgradeScreen).GetComponentsInChildren<Button>(true)).Where((Button button) => ((Object)button).name == "Cycle"))
			{
				((Component)item2).gameObject.SetActive(false);
			}
			ScrollRect scrollRect = scrollPanel.ScrollRect;
			if (array.Length == 0 && dictionary.Count == 0)
			{
				scrollRect.horizontal = false;
				scrollRect.vertical = false;
				TaskScheduler.ScheduleTask((Action)delegate
				{
					scrollRect.SetHorizontalNormalizedPosition(0f);
					scrollRect.SetVerticalNormalizedPosition(1f);
				}, (Func<bool>)null);
				transform.localPosition = Vector3.zero;
				paragonOffset = 0f;
				return;
			}
			int num2 = ((array.Length == 0) ? 5 : array.Max((PathPlusPlus path) => path.UpgradeCount));
			int num3 = (upgradeScreen.ShowParagonPanel() ? 6 : 7);
			scrollRect.horizontal = num2 >= num3;
			scrollRect.vertical = list.Any();
			TaskScheduler.ScheduleTask((Action)delegate
			{
				if (!scrollRect.horizontal)
				{
					scrollRect.SetHorizontalNormalizedPosition(0f);
				}
				if (!scrollRect.vertical)
				{
					scrollRect.SetVerticalNormalizedPosition(1f);
				}
			}, (Func<bool>)null);
			Vector3 localPosition = ((Transform)upgradePaths).localPosition;
			float num4 = 0f;
			float num5 = 0f;
			for (int num6 = 0; num6 < list.Count; num6++)
			{
				PathPlusPlus pathPlusPlus = list[num6];
				num4 += 525f;
				num5 = Math.Max(num5, (pathPlusPlus.UpgradeCount - 5) * 490);
				GameObject val;
				if (num6 >= createdUpgradePaths.Count)
				{
					val = Object.Instantiate<GameObject>(upgradeScreen.path3Container, (Transform)(object)upgradePaths);
					((Object)val).name = $"Path {pathPlusPlus.Path + 1} Upgrades";
					ComponentExt.TranslateScaled((Component)(object)val.transform, new Vector3(0f, 0f - num4, 0f));
					for (int num7 = 0; num7 < val.transform.childCount; num7++)
					{
						Animator val2 = ((Component)val.transform.GetChild(num7)).gameObject.AddComponent<Animator>();
						val2.runtimeAnimatorController = Animations.PopupAnim;
						val2.updateMode = (AnimatorUpdateMode)2;
					}
					createdUpgradePaths.Add(val);
				}
				else
				{
					val = Il2CppGenericsExt.Get<GameObject>(createdUpgradePaths, num6);
				}
				val.SetActive(true);
				Il2CppArrayBase<UpgradeDetails> componentsInChildren = val.GetComponentsInChildren<UpgradeDetails>();
				for (int num8 = 0; num8 < pathPlusPlus.Upgrades.Count; num8++)
				{
					try
					{
						if (num8 >= componentsInChildren.Length)
						{
							UpgradeDetails val3 = Object.Instantiate<UpgradeDetails>(componentsInChildren[num8 - 1], val.transform);
							((Object)((Component)val3).gameObject).name = "Upgrade(Clone)";
							componentsInChildren = val.GetComponentsInChildren<UpgradeDetails>();
						}
						UpgradeDetails upgrade = componentsInChildren[num8];
						UpgradePlusPlus upgradePlusPlus = pathPlusPlus.Upgrades[num8];
						if (upgradePlusPlus != null)
						{
							SetUpgrade(upgrade, upgradePlusPlus);
						}
					}
					catch (Exception ex)
					{
						ModHelper.Warning<PathsPlusPlusMod>((object)ex);
					}
				}
				for (int num9 = pathPlusPlus.Upgrades.Count; num9 < componentsInChildren.Length; num9++)
				{
					((Component)componentsInChildren[num9]).gameObject.SetActive(false);
				}
				upgradeScreen.ResetUpgradeUnlocks(IEnumerableExt.ToIl2CppReferenceArray<UpgradeDetails>(((IEnumerable<UpgradeDetails>)componentsInChildren).Take(pathPlusPlus.Upgrades.Count)), (UpgradeDetails)null);
				foreach (UpgradeDetails item3 in componentsInChildren)
				{
					item3.SetUpgradeScreen(upgradeScreen);
				}
			}
			foreach (PathPlusPlus item4 in list2)
			{
				num5 = Math.Max(num5, (item4.UpgradeCount - 5) * 490);
				Il2CppReferenceArray<UpgradeDetails> upgrades = GetUpgrades(item4.ExtendVanillaPath);
				List<UpgradeDetails> val4 = extraUpgradeDetails[item4.ExtendVanillaPath];
				GameObject container = GetContainer(item4.ExtendVanillaPath);
				foreach (UpgradePlusPlus value7 in item4.Upgrades.Values)
				{
					try
					{
						if (value7.Tier > ((Il2CppArrayBase<UpgradeDetails>)(object)upgrades).Count + val4.Count)
						{
							UpgradeDetails val5 = Object.Instantiate<UpgradeDetails>(((IEnumerable<UpgradeDetails>)upgrades).Last(), container.transform);
							((Object)((Component)val5).gameObject).name = "Upgrade(Clone)";
							val4.Add(val5);
						}
						UpgradeDetails[] array2 = ((IEnumerable<UpgradeDetails>)upgrades).Concat((IEnumerable<UpgradeDetails>)val4.ToArray()).ToArray();
						UpgradeDetails upgrade2 = array2[value7.Tier - 1];
						SetUpgrade(upgrade2, value7);
					}
					catch (Exception ex2)
					{
						ModHelper.Warning<PathsPlusPlusMod>((object)ex2);
					}
				}
				upgradeScreen.ResetUpgradeUnlocks(Il2CppGenericsExt.ToIl2CppReferenceArray<UpgradeDetails>(Il2CppGenerics.Where<UpgradeDetails>(val4, (Func<UpgradeDetails, bool>)((UpgradeDetails details) => ((Component)details).gameObject.active))), (UpgradeDetails)null);
				Enumerator<UpgradeDetails> enumerator8 = val4.GetEnumerator();
				while (enumerator8.MoveNext())
				{
					UpgradeDetails current8 = enumerator8.Current;
					current8.SetUpgradeScreen(upgradeScreen);
				}
			}
			for (int num10 = 0; num10 <= 2; num10++)
			{
				if (!dictionary.TryGetValue(num10, out var value5))
				{
					continue;
				}
				UpgradeDetails[] array3 = ((IEnumerable<UpgradeDetails>)GetUpgrades(num10)).Concat((IEnumerable<UpgradeDetails>)extraUpgradeDetails[num10].ToArray()).ToArray();
				string[] value6;
				string text = (PathsPlusPlusMod.DefaultExtendedPaths.TryGetValue(towerId, out value6) ? value6[num10] : null);
				for (int tier = 0; tier <= 5; tier++)
				{
					List<string> list3 = (from path in value5
						where path.StartTier == tier
						select ((ModContent)path).Id).ToList();
					if (list3.Count > ((tier == 5) ? 1 : 0))
					{
						UpgradeDetails upgrade3 = array3[tier];
						Button val6 = ((IEnumerable<Button>)((Component)((Component)upgrade3).transform).GetComponentsInChildren<Button>(true)).FirstOrDefault((Func<Button, bool>)((Button button) => ((Object)button).name == "Cycle"));
						if ((Object)(object)val6 == (Object)null)
						{
							ModHelperButton val7 = ModHelperButton.Create(new Info("Cycle", 150f, 150f, new Vector2(0f, 0.5f)), "Ui[RestartIcon]", (Action)null);
							((Component)val7).transform.Rotate(0f, 0f, 180f);
							((ModHelperComponent)val7).SetParent(((Component)upgrade3).transform);
							val6 = val7.Button;
						}
						((Component)val6).gameObject.SetActive(true);
						int finalP = num10;
						int finalTier = tier;
						ButtonExt.SetOnClick(val6, (Function)delegate
						{
							CycleExtendedPath(towerId, finalP, finalTier, upgrade3);
						});
						if (text != null && list3.Contains(text))
						{
							break;
						}
					}
				}
			}
			paragonOffset = num5;
			scrollContent.sizeDelta = new Vector2(num5, num4);
			((Transform)upgradePaths).localPosition = localPosition;
		}

		private Il2CppReferenceArray<UpgradeDetails> GetUpgrades(int path)
		{
			if (1 == 0)
			{
			}
			Il2CppReferenceArray<UpgradeDetails> result = (Il2CppReferenceArray<UpgradeDetails>)(path switch
			{
				0 => upgradeScreen.path1Upgrades, 
				1 => upgradeScreen.path2Upgrades, 
				2 => upgradeScreen.path3Upgrades, 
				_ => throw new IndexOutOfRangeException(), 
			});
			if (1 == 0)
			{
			}
			return result;
		}

		private GameObject GetContainer(int path)
		{
			if (1 == 0)
			{
			}
			GameObject result = (GameObject)(path switch
			{
				0 => upgradeScreen.path1Container, 
				1 => upgradeScreen.path2Container, 
				2 => upgradeScreen.path3Container, 
				_ => throw new IndexOutOfRangeException(), 
			});
			if (1 == 0)
			{
			}
			return result;
		}

		private static void SetUpgrade(UpgradeDetails upgrade, UpgradePlusPlus upgradePlusPlus)
		{
			((Component)upgrade).gameObject.SetActive(true);
			upgrade.SetUpgrade(upgrade.baseTowerID, upgradePlusPlus.GetUpgradeModel(), ((Il2CppObjectBase)new List<AbilityModel>()).Cast<ICollection<AbilityModel>>(), upgradePlusPlus.Path.Path, upgradePlusPlus.PortraitReference);
			((Component)upgrade.icon).gameObject.SetActive(true);
			upgrade.abilityObject.SetActive(upgradePlusPlus.Ability);
			UpgradeDetailsTheme val = ((upgradePlusPlus.Tier >= 5) ? upgrade.tier5Theme : upgrade.standardTheme);
			upgrade.theme = ((Il2CppObjectBase)((Object)val).MemberwiseClone()).Cast<UpgradeDetailsTheme>();
			if (upgradePlusPlus.ContainerReference != null)
			{
				UpgradeDetailsTheme theme = upgrade.theme;
				SpriteReference owned = (upgrade.theme.paragonPurchased = upgradePlusPlus.ContainerReference);
				theme.owned = owned;
			}
		}

		public static UpgradeScreenPlusPlus Setup(UpgradeScreen upgradeScreen)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			UpgradeScreenPlusPlus upgradeScreenPlusPlus = ((Component)upgradeScreen).gameObject.AddComponent<UpgradeScreenPlusPlus>();
			upgradeScreenPlusPlus.upgradeScreen = upgradeScreen;
			ModHelperScrollPanel val = (upgradeScreenPlusPlus.scrollPanel = GameObjectExt.AddModHelperScrollPanel(((Component)upgradeScreen).gameObject, new Info("UpgradesScroll", (InfoPreset)0), (Axis?)null, (string)null, 0f, 0));
			((Component)val).GetComponent<Mask>().showMaskGraphic = false;
			((ModHelperComponent)val).AddComponent<Image>();
			val.ScrollRect.horizontal = false;
			((ModHelperComponent)val.ScrollContent).AddComponent<Text>();
			RectTransform val2 = (upgradeScreenPlusPlus.scrollContent = ((Il2CppObjectBase)((Component)val.ScrollContent).transform).Cast<RectTransform>());
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			RectTransform val3 = (upgradeScreenPlusPlus.upgradePaths = ((Il2CppObjectBase)((Component)ComponentExt.GetComponentFromChildrenByName<LayoutElement>((Component)(object)upgradeScreen, "UpgradePaths")).transform).Cast<RectTransform>());
			((Transform)val3).SetParent(((Component)val.ScrollContent).transform);
			val3.sizeDelta = Vector2.zero;
			val2.pivot = new Vector2(0f, 1f);
			Rect rect = ((Il2CppObjectBase)((Component)upgradeScreen).transform).Cast<RectTransform>().rect;
			float num = ((Rect)(ref rect)).width / ((Rect)(ref rect)).height;
			if (1 == 0)
			{
			}
			int num2 = ((num < 1.5f) ? 849 : ((!(num < 1.7f)) ? 1240 : 1010));
			if (1 == 0)
			{
			}
			int num3 = num2;
			Vector3 localPosition = ((Transform)val3).localPosition;
			((ModHelperComponent)val).RectTransform.pivot = new Vector2(1f, 0f);
			((ModHelperComponent)val).RectTransform.sizeDelta = new Vector2((float)(-num3), -345f);
			((Transform)val3).localPosition = localPosition + new Vector3((float)(-num3), 345f, 0f);
			((Component)val).transform.SetSiblingIndex(4);
			return upgradeScreenPlusPlus;
		}

		private void LateUpdate()
		{
			//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_0027: 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)
			RectTransform val = ((Il2CppObjectBase)upgradeScreen.paragonPanel.transform).Cast<RectTransform>();
			Vector2 anchoredPosition = val.anchoredPosition;
			anchoredPosition.x = scrollContent.anchoredPosition.x + paragonOffset;
			val.anchoredPosition = anchoredPosition;
		}

		[HideFromIl2Cpp]
		private void CycleExtendedPath(string towerId, int path, int tier, UpgradeDetails upgradeDetails)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			AudioClipExtensions.Play(MenuManager.instance.buttonClick3Sound, "FX", 1f);
			Vector3 localPosition = ((Component)scrollPanel.ScrollContent).transform.localPosition;
			string[] value;
			string current = (PathsPlusPlusMod.DefaultExtendedPaths.TryGetValue(towerId, out value) ? value[path] : null);
			List<PathPlusPlus> list = PathsPlusPlusMod.ExtendedPathsByTower[towerId][path].Where((PathPlusPlus p) => p.StartTier == tier).ToList();
			int num = list.FindIndex((PathPlusPlus p) => ((ModContent)p).Id == current);
			if (tier >= 5 && num < 0)
			{
				num = 0;
			}
			num++;
			PathPlusPlus pathPlusPlus = ((num >= list.Count) ? null : list[num]);
			if (!PathsPlusPlusMod.DefaultExtendedPaths.TryGetValue(towerId, out string[] value2))
			{
				string[] array = (PathsPlusPlusMod.DefaultExtendedPaths[towerId] = new string[3]);
				value2 = array;
			}
			value2[path] = ((pathPlusPlus != null) ? ((ModContent)pathPlusPlus).Id : null);
			UpgradeDetails selectedDetails = upgradeScreen.selectedDetails;
			upgradeScreen.PopulatePaths(Game.instance.model.GetTower(towerId, 0, 0, 0), false, "");
			UpdateUi(towerId);
			((Component)scrollPanel.ScrollContent).transform.localPosition = localPosition;
			upgradeDetails.OnPointerExit((PointerEventData)null);
			upgradeDetails.OnPointerEnter((PointerEventData)null);
			if ((Object)(object)selectedDetails != (Object)null && ((Component)selectedDetails).gameObject.activeInHierarchy)
			{
				upgradeScreen.SelectUpgrade(selectedDetails, true);
			}
		}
	}
}
namespace PathsPlusPlus.Patches
{
	[HarmonyPatch(typeof(UnityToSimulation), "UpgradeTower_Impl")]
	internal static class UnityToSimulation_UpgradeTower_Impl
	{
		[HarmonyPrefix]
		private static bool Prefix(UnityToSimulation __instance, ObjectId id, int pathIndex, int callbackId, int inputId, double nonUpgradeCashInvestment)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			TowerManager towerManager = __instance.simulation.towerManager;
			Tower towerById = towerManager.GetTowerById(id);
			List<int> allTiers = towerById.GetAllTiers();
			int num = ++allTiers[pathIndex];
			if (!PathPlusPlus.TryGetPath(towerById, pathIndex, num, out PathPlusPlus pathPlusPlus) || num <= pathPlusPlus.StartTier)
			{
				return true;
			}
			Action<bool> val = __instance.UnregisterCallback(callbackId, inputId);
			float num2 = 100000000f;
			if (towerManager.CanUpgradeTower(towerById, pathIndex, num, inputId, ref num2, false))
			{
				TowerModel val2 = ((Il2CppObjectBase)((Mutable)towerById).rootModel).Cast<TowerModel>();
				if (pathPlusPlus != null && pathPlusPlus.ExtendVanillaPath >= 0 && pathPlusPlus.StartTier < 5 && pathPlusPlus.UseUpgradedTowerModels && num <= 5)
				{
					val2 = __instance.Model.GetTower(((EntityModel)val2).baseId, allTiers[0], allTiers[1], allTiers[2]);
				}
				towerManager.UpgradeTower(inputId, towerById, val2, pathIndex, num2, 1f, true, true, true, false, false, 0, nonUpgradeCashInvestment);
			}
			if ((Delegate)(object)val != (Delegate)null)
			{
				val.Invoke(true);
			}
			UpgradeButton.upgradeCashOffset = 0f;
			return false;
		}
	}
	[HarmonyPatch(typeof(TowerManager), "GetTowerUpgradeCost")]
	internal static class TowerManager_GetTowerUpgradeCost
	{
		private static void Prefix(Tower? tower, int path, int tier, ref Il2CppReferenceArray<UpgradePathModel>? __state)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			if (tower != null)
			{
				TowerModel towerModel = tower.towerModel;
				TowerModel val = default(TowerModel);
				if (((towerModel != null) ? new bool?(Il2CppSystemObjectExt.Is<TowerModel>(towerModel, ref val)) : ((bool?)null)) == true && path >= 0 && PathPlusPlus.TryGetPath(tower, path, tier, out PathPlusPlus pathPlusPlus) && pathPlusPlus.Upgrades.TryGetValue(tier - 1, out UpgradePlusPlus value))
				{
					__state = val.upgrades;
					val.upgrades = Il2CppReferenceArray<UpgradePathModel>.op_Implicit((UpgradePathModel[])(object)new UpgradePathModel[1]
					{
						new UpgradePathModel(((ModContent)value).Id, ((Model)val).name)
					});
				}
			}
		}

		[HarmonyPostfix]
		private static void Postfix(Tower tower, ref Il2CppReferenceArray<UpgradePathModel>? __state)
		{
			if (__state != null)
			{
				tower.towerModel.upgrades = __state;
			}
		}
	}
	[HarmonyPatch(typeof(TowerManager), "UpgradeTower")]
	internal static class TowerManager_UpgradeTower
	{
		[HarmonyPrefix]
		internal static void Prefix(Tower tower, int pathIndex, bool isParagon, ref int __state)
		{
			if (!isParagon)
			{
				__state = tower.GetAllTiers()[pathIndex] + 1;
			}
		}

		[HarmonyPostfix]
		internal static void Postfix(Tower tower, int pathIndex, bool isParagon, ref int __state)
		{
			if (!isParagon)
			{
				List<int> allTiers = tower.GetAllTiers();
				if (pathIndex >= 0 && pathIndex < allTiers.Count && PathPlusPlus.TryGetPath(tower, pathIndex, __state, out PathPlusPlus pathPlusPlus) && __state > pathPlusPlus.StartTier)
				{
					pathPlusPlus.SetTier(tower, __state, onUpgrade: true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(TowerManager), "IsTowerPathTierLocked")]
	internal static class TowerManager_IsTowerPathTierLocked
	{
		[HarmonyPrefix]
		private static bool Prefix(Tower tower, int path, int tier, ref bool __result)
		{
			if (path < 3 && tier <= 5)
			{
				return true;
			}
			int[] array = tower.GetAllTiers().ToArray();
			array[path] = tier;
			int num;
			if (PathsPlusPlusMod.PathsByTower.TryGetValue(((EntityModel)tower.towerModel).baseId, out List<PathPlusPlus> value))
			{
				PathPlusPlus pathPlusPlus = value.FirstOrDefault((PathPlusPlus plus) => plus.Path == path);
				if (pathPlusPlus != null && pathPlusPlus.Upgrades.TryGetValue(tier - 1, out UpgradePlusPlus value2) && value2.currentlyAppliedOn.Count >= value2.MaxAtOnce)
				{
					num = (pathPlusPlus.ValidTiers(array) ? 1 : 0);
					goto IL_00a2;
				}
			}
			num = 0;
			goto IL_00a2;
			IL_00a2:
			__result = (byte)num != 0;
			return false;
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "IsUpgradePathClosed")]
	internal static class TowerSelectionMenu_IsUpgradePathClosed
	{
		[HarmonyPrefix]
		private static bool Prefix(TowerSelectionMenu __instance, int path, ref bool __result)
		{
			if (!ModSettingBool.op_Implicit(PathsPlusPlusMod.BalancedMode))
			{
				__result = false;
				return false;
			}
			Tower tower = __instance.selectedTower.tower;
			string baseId = ((EntityModel)tower.towerModel).baseId;
			List<int> tiers = tower.GetAllTiers();
			if (PathPlusPlus.TryGetPath(tower, path, ++tiers[path], out PathPlusPlus pathPlusPlus))
			{
				__result = !pathPlusPlus.ValidTiers(tiers.ToArray());
				return false;
			}
			if (PathsPlusPlusMod.PathsByTower.TryGetValue(baseId, out List<PathPlusPlus> value))
			{
				__result = !PathPlusPlus.DefaultValidTiers(tiers.Take(3).ToArray()) || value.Any((PathPlusPlus p) => !p.ValidTiers(tiers.ToArray()));
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(UpgradeButton), "IsUpgradeBlocked")]
	internal static class UpgradeButton_IsUpgradeBlocked
	{
		[HarmonyPrefix]
		private static bool Prefix(UpgradeButton __instance, ref string? __result)
		{
			if (__instance.row < 3)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(TowerInventory), "IsPathTierLocked")]
	internal static class TowerInventory_IsPathTierLocked
	{
		[HarmonyPrefix]
		private static bool Prefix(int path, ref bool __result)
		{
			if (path < 3)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(TowerToSimulation), "GetMaxTierForPath")]
	internal static class TowerToSimulation_GetMaxTierForPath
	{
		[HarmonyPrefix]
		private static bool Prefix(TowerToSimulation __instance, int path, ref int __result)
		{
			__result = 5;
			foreach (PathPlusPlus path2 in PathPlusPlus.GetPaths(__instance.tower, path))
			{
				if (path2.UpgradeCount > __result)
				{
					__result = path2.UpgradeCount;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(UpgradeObject), "CheckRestrictedPath")]
	internal static class UpgradeObject_CheckRestrictedPath
	{
		[HarmonyPrefix]
		private static bool Prefix(UpgradeObject __instance, ref int __result)
		{
			if (__instance.path < 3)
			{
				return true;
			}
			__result = 5;
			return false;
		}
	}
	[HarmonyPatch(typeof(UpgradeButton), "CheckDcLocked")]
	internal static class UpgradeButton_CheckDcLocked
	{
		[HarmonyPrefix]
		private static bool Prefix(int path, ref bool __result)
		{
			if (path < 3)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(UpgradeButton), "UpdateBeastHandlerUI")]
	internal static class UpgradeButton_UpdateBeastHandlerUI
	{
		[HarmonyPrefix]
		private static bool Prefix(int path)
		{
			return path < 3;
		}
	}
	[HarmonyPatch(typeof(Tower), "AddMutator")]
	internal static class Tower_AddMutator
	{
		[HarmonyPrefix]
		private static bool Prefix(Tower __instance, BehaviorMutator mutator)
		{
			return !__instance.towerModel.isSubTower || !PathsPlusPlusMod.PathsById.ContainsKey(mutator.id);
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class UpgradeModel_IsParagon
	{
		[HarmonyPrefix]
		private static bool Prefix(UpgradeModel __instance, ref bool __result)
		{
			if (PathsPlusPlusMod.UpgradesById.ContainsKey(((Model)__instance).name))
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(UpgradeObject), "PostSimUpgrade")]
	internal static class UpgradeObject_PostSimUpgrade
	{
		[HarmonyPrefix]
		private static bool Prefix(UpgradeObject __instance)
		{
			return ((Behaviour)__instance).isActiveAndEnabled;
		}
	}
	[HarmonyPatch(typeof(BeastHandlerUpgradeLock), "IsUpgradeBlocked")]
	internal static class BeastHandlerUpgradeLock_IsUpgradeBlocked
	{
		[HarmonyPrefix]
		private static bool Prefix(BeastHandlerUpgradeLock __instance, int path, ref bool __result)
		{
			if (path >= 3)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(UpgradeButton), "UpdateMergeButton")]
	internal static class UpgradeButton_UpdateMergeButton
	{
		[HarmonyPrefix]
		internal static bool Prefix(UpgradeButton __instance)
		{
			return __instance.row < 3;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class UpgradeButton_IsBeastHandlerContributionUpgradeAvailable
	{
		[HarmonyPrefix]
		internal static bool Prefix(UpgradeButton __instance)
		{
			return __instance.row < 3;
		}
	}
	[HarmonyPatch(typeof(CurrentUpgrade), "UpdateBeastHandlerDisplay")]
	internal static class CurrentUpgrade_UpdateBeastHandlerDisplay
	{
		[HarmonyPrefix]
		internal static bool Prefix(CurrentUpgrade __instance)
		{
			return ((BaseUpgrade)__instance).row < 3;
		}
	}
	[HarmonyPatch(typeof(AnalyticsTrackerSim), "OnTowerUpgraded")]
	internal static class AnalyticsTrackerSim_OnTowerUpgraded
	{
		[HarmonyPrefix]
		internal static bool Prefix(Tower tower, int pathUpgraded, bool isParagon)
		{
			if (isParagon)
			{
				return true;
			}
			if (pathUpgraded >= 3)
			{
				return false;
			}
			List<int> allTiers = tower.GetAllTiers();
			int num = allTiers[pathUpgraded];
			return num < 6;
		}
	}
	[HarmonyPatch(typeof(GeraldoChangeTowerBehavior), "Activate")]
	internal static class GeraldoChangeTowerBehavior_Activate
	{
		[HarmonyPrefix]
		internal static void Prefix(GeraldoChangeTowerBehavior __instance)
		{
			__instance.mutatorBanList = Il2CppStringArray.op_Implicit(((IEnumerable<string>)__instance.mutatorBanList).Concat(from path in ModContent.GetContent<PathPlusPlus>()
				select ((ModContent)path).Id).Distinct().ToArray());
		}
	}
	[HarmonyPatch(typeof(RotateToDefaultPositionTower), "OnUpgraded")]
	internal static class RotateToDefaultPositionTower_OnUpgraded
	{
		[HarmonyPrefix]
		internal static bool Prefix(int pathUpgraded)
		{
			return pathUpgraded < 3;
		}
	}
	[HarmonyPatch]
	internal static class TowerSelectionMenu_Show
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(TowerSelectionMenu), "Show", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(TowerSelectionMenu), "UpdateTower", (Type[])null, (Type[])null);
		}

		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				componentInChildren = PathsPlusPlusController.Create(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "SelectTower")]
	internal static class TowerSelectionMenu_SelectTower
	{
		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance, TowerToSimulation? tower)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>(false);
			if ((Object)(object)componentInChildren != (Object)null && tower != null && tower.Def != null)
			{
				componentInChildren.SetMode(PathsPlusPlusMod.PathsByTower.ContainsKey(((EntityModel)tower.Def).baseId));
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "InitUpgradeButtons")]
	internal static class TowerSelectionMenu_InitUpgradeButtons
	{
		[HarmonyPrefix]
		private static void Prefix(TowerSelectionMenu __instance)
		{
			if ((Object)(object)__instance.sheriffDetails != (Object)null && __instance.sheriffDetails.active)
			{
				return;
			}
			UpgradeObjectPlusPlus upgradeObjectPlusPlus = default(UpgradeObjectPlusPlus);
			foreach (UpgradeObject item in (Il2CppArrayBase<UpgradeObject>)(object)__instance.upgradeButtons)
			{
				if (GameObjectExt.HasComponent<UpgradeObjectPlusPlus>(((Component)item).gameObject, ref upgradeObjectPlusPlus))
				{
					upgradeObjectPlusPlus.pathId = null;
				}
				item.tier = 0;
			}
			if (((Il2CppArrayBase<UpgradeObject>)(object)__instance.upgradeButtons).Length > 3)
			{
				foreach (UpgradeObject item2 in ((IEnumerable<UpgradeObject>)__instance.upgradeButtons).Skip(3))
				{
					((Component)item2).gameObject.SetActive(false);
				}
				__instance.upgradeButtons = Il2CppReferenceArray<UpgradeObject>.op_Implicit(((IEnumerable<UpgradeObject>)__instance.upgradeButtons).Take(3).ToArray());
			}
			if (((Il2CppArrayBase<UpgradeInfoPopup>)(object)__instance.upgradeInfoPopups).Length > 3)
			{
				__instance.upgradeInfoPopups = Il2CppReferenceArray<UpgradeInfoPopup>.op_Implicit(((IEnumerable<UpgradeInfoPopup>)__instance.upgradeInfoPopups).Take(3).ToArray());
			}
		}

		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			if (!((Object)(object)__instance.sheriffDetails != (Object)null) || !__instance.sheriffDetails.active)
			{
				PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>();
				if ((Object)(object)componentInChildren != (Object)null && !__instance.powerProDetails.activeSelf)
				{
					componentInChildren.InitUpgradeButtons();
				}
			}
		}
	}
	[HarmonyPatch(typeof(UpgradeObject), "LoadUpgrades")]
	internal static class UpgradeObject_LoadUpgrades
	{
		[HarmonyPostfix]
		private static void Postfix(UpgradeObject __instance)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			UpgradeObjectPlusPlus upgradeObjectPlusPlus = default(UpgradeObjectPlusPlus);
			if (Il2CppSystemObjectExt.Is<PowerProUpgradeObject>((Il2CppObjectBase)(object)__instance) || !GameObjectExt.HasComponent<UpgradeObjectPlusPlus>(((Component)__instance).gameObject, ref upgradeObjectPlusPlus))
			{
				return;
			}
			PathPlusPlus path = upgradeObjectPlusPlus.GetPath();
			if (path != null && upgradeObjectPlusPlus.IsExtra)
			{
				Tower tower = __instance.tts.tower;
				UpgradeModel val = null;
				if (__instance.tier < path.UpgradeCount && !InGame.Bridge.IsUpgradeLocked(((RootObject)tower).Id, __instance.path, __instance.tier + 1))
				{
					val = InGame.Bridge.Model.GetUpgrade(((ModContent)path.Upgrades[__instance.tier]).Id);
				}
				if (TowerSelectionMenuUtils.CanUpgradeToParagon(__instance.tts, true) && __instance.tier >= 5 && (!upgradeObjectPlusPlus.overrideParagon || __instance.tier == path.UpgradeCount))
				{
					val = InGame.Bridge.Model.GetUpgrade(__instance.tts.Def.paragonUpgrade.upgrade);
				}
				if (val != null)
				{
					UpgradeButton upgradeButton = __instance.upgradeButton;
					upgradeButton.SetUpgradeModel(val);
					upgradeButton.UpdateVisuals(__instance.path, val.tier + 1, false);
				}
				if (__instance.tier > 0 && (__instance.path > 2 || __instance.tier > path.StartTier) && path.Upgrades.ContainsKey(__instance.tier - 1))
				{
					__instance.currentUpgradeModel = InGame.Bridge.Model.GetUpgrade(((ModContent)path.Upgrades[__instance.tier - 1]).Id);
					__instance.currentUpgrade.SetUpgradeModel(__instance.currentUpgradeModel, __instance.tts);
				}
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "OnUpdateUpgradeVisuals")]
	internal static class TowerSelectionMenu_OnUpdateUpgradeVisuals
	{
		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.UpdateVisuals();
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "CheckUpgradeCosts")]
	internal static class TowerSelectionMenu_CheckUpgradeCosts
	{
		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.UpdateCosts();
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "OnUpgradePricesChanged")]
	internal static class TowerSelectionMenu_OnUpgradePricesChanged
	{
		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.UpdateCosts();
				componentInChildren.UpdateVisuals();
			}
		}
	}
	[HarmonyPatch(typeof(TowerSelectionMenu), "CashChanged")]
	internal static class TowerSelectionMenu_CashChanged
	{
		[HarmonyPostfix]
		private static void Postfix(TowerSelectionMenu __instance)
		{
			PathsPlusPlusController componentInChildren = ((Component)__instance).GetComponentInChildren<PathsPlusPlusController>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.CheckCash();
			}
		}
	}
	[HarmonyPatch(typeof(Tower), "GetUpgrade")]
	internal static class Tower_GetUpgrade
	{
		[HarmonyPrefix]
		private static bool Prefix(Tower __instance, int path, ref UpgradeModel? __result)
		{
			if (PathPlusPlus.TryGetPath(__instance, path, out PathPlusPlus pathPlusPlus))
			{
				int num = __instance.GetTier(((ModContent)pathPlusPlus).Id);
				if (path < 3)
				{
					num = Math.Max(((Il2CppArrayBase<int>)(object)__instance.towerModel.tiers)[path], num);
				}
				if (path < 3 && num < pathPlusPlus.StartTier)
				{
					return true;
				}
				__result = ((num < pathPlusPlus.UpgradeCount) ? ((RootObject)__instance).Sim.model.GetUpgrade(((ModContent)pathPlusPlus.Upgrades[num]).Id) : null);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(UpgradeObject), "CheckBlockedPath")]
	internal class UpgradeObject_CheckBlockedPath
	{
		[HarmonyPrefix]
		private static bool Prefix(UpgradeObject __instance, ref int __result)
		{
			if (!((Behaviour)__instance).isActiveAndEnabled)
			{
				return false;
			}
			if (Il2CppSystemObjectExt.Is<PowerProUpgradeObject>((Il2CppObjectBase)(object)__instance))
			{
				return true;
			}
			Tower tower = __instance.towerSelectionMenu.selectedTower.tower;
			int path = __instance.path;
			List<PathPlusPlus> list = PathPlusPlus.GetPaths(tower, path).ToList();
			int num = list.Select((PathPlusPlus plus) => plus.UpgradeCount).DefaultIfEmpty(5).Max();
			if (!ModSettingBool.op_Implicit(PathsPlusPlusMod.BalancedMode) && list.Any())
			{
				__result = num;
				return false;
			}
			if (!list.Any() && (!ModSettingBool.op_Implicit(PathsPlusPlusMod.BalancedMode) || (path < 3 && ModHelper.HasMod("UltimateCrosspathing"))))
			{
				return true;
			}
			List<int> tiers = tower.GetAllTiers();
			int num2 = tiers[path];
			for (int num3 = num2; num3 <= num; num3++)
			{
				__result = num3;
				tiers[path] = num3 + 1;
				if (list.Any())
				{
					list.RemoveAll((PathPlusPlus plus) => !plus.ValidTiers(tiers.ToArray()));
					if (!list.Any())
					{
						break;
					}
				}
				else if (!PathPlusPlus.DefaultValidTiers(tiers.Take(3).ToArray()) || list.Any((PathPlusPlus p) => !p.ValidTiers(tiers.ToArray())))
				{
					break;
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class TowerSelectionMenu_DisplayClass_UpgradeTower
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return typeof(TowerSelectionMenu).GetNestedTypes().SelectMany((Type type) => TypeExt.GetMethods(type, "_UpgradeTower_b__0")).Single((MethodInfo info) => ArrayExt.Any<ParameterInfo>(info.GetParameters(), (Func<ParameterInfo, bool>)((ParameterInfo param) => param.Name == "isUpgraded")));
		}

		[HarmonyPrefix]
		private static bool Prefix(Object __instance, bool isUpgraded)
		{
			int num = ((Il2CppObjectBase)__instance.GetIl2CppType().GetField("path").GetValue(__instance)).Unbox<int>();
			if (num < 3)
			{
				return true;
			}
			TowerSelectionMenu val = ((Il2CppObjectBase)__instance.GetIl2CppType().GetField("<>4__this").GetValue(__instance)).Cast<TowerSelectionMenu>();
			UpgradeObject val2 = ((Il2CppArrayBase<UpgradeObject>)(object)val.upgradeButtons)[num];
			if (!((Behaviour)val2).isActiveAndEnabled)
			{
				return false;
			}
			if (!isUpgraded)
			{
				val2.tier = val.selectedTower.tower.GetTier(num);
				val2.LoadUpgrades();
				val.OnUpdateUpgradeVisuals(false);
			}
			val2.PostSimUpgrade();
			return false;
		}
	}
	[HarmonyPatch(typeof(UpgradeObject), "SetTier", new Type[]
	{
		typeof(int),
		typeof(int),
		typeof(int)
	})]
	internal static class UpgradeObject_SetTier
	{
		[HarmonyPrefix]
		private static void Prefix(UpgradeObject __instance, ref int tier, ref int maxTier, ref int maxTierRestricted)
		{
			if (Il2CppSystemObjectExt.Is<PowerProUpgradeObject>((Il2CppObjectBase)(object)__instance))
			{
				return;
			}
			List<TierObject> list = Il2CppReferenceArrayExt.ToList<TierObject>(__instance.tiers);
			TierObject val = list[0];
			int num = Math.Max(maxTier, 5);
			UpgradeObjectPlusPlus upgradePlusPlus = default(UpgradeObjectPlusPlus);
			if (GameObjectExt.HasComponent<UpgradeObjectPlusPlus>(((Component)__instance).gameObject, ref upgradePlusPlus))
			{
				num = Math.Max(num, upgradePlusPlus.GetPath()?.UpgradeCount ?? num);
				if (maxTier == 5)
				{
					maxTier = Math.Max(5, num);
				}
				if (maxTierRestricted == 5)
				{
					maxTierRestricted = Math.Max(5, num);
				}
			}
			while (num > list.Count)
			{
				TierObject val2 = GameObjectExt.Duplicate<TierObject>(val, ((Component)val).transform.parent);
				list.Add(val2);
				((Object)val2).name = "Tier " + list.Count;
			}
			if (list.Count > ((Il2CppArrayBase<TierObject>)(object)__instance.tiers).Length)
			{
				__instance.tiers = Il2CppReferenceArray<TierObject>.op_Implicit(list.ToArray());
			}
			for (int i = 0; i < num; i++)
			{
				((Component)list[i]).gameObject.SetActive(true);
			}
			for (int j = num; j < list.Count; j++)
			{
				((Component)list[j]).gameObject.SetActive(false);
			}
		}
	}
	[HarmonyPatch(typeof(UpgradeButton), "OnPointerDown")]
	internal static class UpgradeButton_OnPointerDown
	{
		[HarmonyPostfix]
		private static void Postfix(UpgradeButton __instance, PointerEventData eventData)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)eventData.button == 1)
			{
				GameObjectExt.Exists<UpgradeObjectPlusPlus>(((Component)__instance).GetComponentInParent<UpgradeObjectPlusPlus>())?.CycleUpgrade();
			}
		}
	}
}