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 Towers { get; } public Dictionary PathsByTower { get; private set; } = new Dictionary(); public override IEnumerable Load() { return (IEnumerable)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 Load() { return (IEnumerable)BasePath.Towers.Select(delegate(string t) { MultiUpgradePlusPlus multiUpgradePlusPlus = (MultiUpgradePlusPlus)Activator.CreateInstance(((object)this).GetType()); multiUpgradePlusPlus.tower = t; return multiUpgradePlusPlus; }); } } public abstract class MultiUpgradePlusPlus : MultiUpgradePlusPlus where T : MultiPathPlusPlus { private protected sealed override MultiPathPlusPlus BasePath => ModContent.GetInstance(); } 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 Upgrades = new SortedDictionary(); [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private PathPlusPlusMutator 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 => k__BackingField ?? (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> orAdd = PathsPlusPlusMod.ExtendedPathsByTower.GetOrAdd(Tower, new Dictionary>()); List orAdd2 = orAdd.GetOrAdd(Path, new List()); orAdd2.Add(this); } else { List orAdd3 = PathsPlusPlusMod.PathsByTower.GetOrAdd(Tower, new List()); Path = 3 + orAdd3.Count; orAdd3.Add(this); } foreach (UpgradePlusPlus value in Upgrades.Values) { GameModelExt.AddUpgrade(Game.instance.model, value.GetUpgradeModel()); } } public override IEnumerable 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 list = ((IEnumerable)tower.appliedUpgrades).ToList(); if (ExtendVanillaPath >= 0 && StartTier < 5) { if (UseUpgradedTowerModels) { foreach (UpgradeModel item in ((IEnumerable)tower.appliedUpgrades).Select((Func)GameModelExt.Current.GetUpgrade)) { if (item.path == Path && item.tier >= StartTier) { list.Remove(((Model)item).name); } } } else if (tier > 0) { string oldValue = GeneralExtensions.Join((IEnumerable)tower.tiers, (Func)null, ""); ((Il2CppArrayBase)(object)tower.tiers)[ExtendVanillaPath] = Math.Clamp(tier, 0, 5); ((Model)tower).name = ((Model)tower).name.Replace(oldValue, GeneralExtensions.Join((IEnumerable)tower.tiers, (Func)null, "")); } } List list2 = new List(); 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()); } } } [Obsolete("Should pass in an actual Tower object now")] public static PathPlusPlus? GetPath(string tower, int path) { List value; Dictionary> value2; List 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 GetPaths(string tower, int path) { List value; if (path >= 3) { return PathsPlusPlusMod.PathsByTower.TryGetValue(tower, out value) ? value.Where((PathPlusPlus p) => p.Path == path).ToArray() : Array.Empty(); } if (!PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(tower, out Dictionary> value2)) { return new List(); } if (!value2.TryGetValue(path, out var value3)) { return new List(); } return value3; } public static IList GetPaths(Tower tower, int path) { IList 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(1) { item }; } } return paths.Where((PathPlusPlus p) => ((Il2CppArrayBase)(object)tower.towerModel.tiers)[path] <= p.StartTier).ToArray(); } public static PathPlusPlus? GetPath(Tower tower, int path) { IList 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 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 : PathPlusPlus where T : ModTower { public sealed override string Tower => ((ModContent)(object)ModContent.GetInstance()).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)(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(this Tower tower) where T : PathPlusPlus { return tower.GetTier(ModContent.GetInstance()); } public static bool HasUpgrade(this Tower tower) where T : UpgradePlusPlus { return ((Il2CppArrayBase)(object)tower.towerModel.appliedUpgrades).Contains(((ModContent)ModContent.GetInstance()).Id); } public static Dictionary GetTiers(this Tower tower) { List 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(); } private static int[] GetExtendedTiers(this Tower tower) { return new int[3] { tower.GetTier(0), tower.GetTier(1), tower.GetTier(2) }; } public static List 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((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 GetTiers(this TowerModel towerModel) { return (from upgrade in ((IEnumerable)towerModel.appliedUpgrades).Select(((IReadOnlyDictionary)PathsPlusPlusMod.UpgradesById).GetValueOrDefault) where upgrade?.Path.Tower == ((EntityModel)towerModel).baseId group upgrade by upgrade.Path).ToDictionary((IGrouping grouping) => grouping.Key, (IGrouping grouping) => grouping.DefaultIfEmpty().Max((UpgradePlusPlus plus) => plus?.Tier ?? 0)); } public static List GetAllTiers(this TowerModel towerModel) { return ((IEnumerable)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(this Dictionary 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(); int tier = Extensions.Value((IEnumerable)data); path.Apply(tower, tier); return true; } public int Tier(BehaviorMutator behaviorMutator) { return Extensions.Value((IEnumerable)((ModMutator)this).GetData(behaviorMutator)); } } public class PathPlusPlusTest : ModContentDefaultTest { 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(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 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)(object)menu.upgradeButtons).Length) { continue; } UpgradeObject val3 = ((Il2CppArrayBase)(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.menu = menu; pathsPlusPlusController.moreUpgradeButtons = new List(); Mask val = gameObject.AddComponent(); val.showMaskGraphic = false; gameObject.AddComponent(); ScrollRect val2 = (pathsPlusPlusController.scrollRect = gameObject.AddComponent()); RectTransform val3 = ((Il2CppObjectBase)towerDetails.transform).Cast(); val3.pivot = new Vector2(0.5f, 1f); val2.content = val3; RectTransform viewport = ((Il2CppObjectBase)gameObject.transform).Cast(); val2.viewport = viewport; val2.horizontal = false; val2.scrollSensitivity = 165f; val2.inertia = false; val2.movementType = (MovementType)2; foreach (UpgradeObject item in (Il2CppArrayBase)(object)menu.upgradeButtons) { ModifyDefaultUpgradeObject(item); } VerticalLayoutGroup val4 = towerDetails.AddComponent(); ((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(); val5.verticalFit = (FitMode)2; for (int i = 0; i < ((Il2CppArrayBase)(object)menu.upgradeInfoPopups).Count; i++) { UpgradeInfoPopup val6 = ((Il2CppArrayBase)(object)menu.upgradeInfoPopups)[i]; PopUpFixer popUpFixer = ((Component)val6).gameObject.AddComponent(); popUpFixer.upgradeObj = ((Component)((Il2CppArrayBase)(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(); val.sizeDelta = new Vector2(-50f, (float)(hasMorePaths ? (-1046) : (-1106))); scrollRect.vertical = hasMorePaths; scrollRect.verticalNormalizedPosition = 1f; ((HorizontalOrVerticalLayoutGroup)towerDetails.GetComponent()).spacing = (hasMorePaths ? 15 : 20); ((Behaviour)gameObject.GetComponent()).enabled = hasMorePaths; ((Behaviour)gameObject.GetComponent()).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)(object)menu.upgradeInfoPopups).Count; i++) { Transform parent = ((Component)((Il2CppArrayBase)(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)null); } private void AddNewUpgradeObject() { UpgradeObject val = ((Il2CppArrayBase)(object)menu.upgradeButtons)[0]; int num = 3 + moreUpgradeButtons.Count; GameObject val2 = GameObjectExt.Duplicate(((Component)val).gameObject, menu.towerDetails.transform); UpgradeObjectPlusPlus component = val2.GetComponent(); component.upgradeObject = val2.GetComponent(); ((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(); moreUpgradeButtons.Add(component); menu.upgradeButtons = Il2CppReferenceArrayExt.AddTo(menu.upgradeButtons, upgradeObject); Transform parent = ((Component)((Il2CppArrayBase)(object)menu.upgradeInfoPopups)[0]).transform.parent.parent; Transform val3 = GameObjectExt.Duplicate(parent, ((Component)parent).transform.parent); ((Object)val3).name = "Upgrade_" + (num + 1); UpgradeInfoPopup componentInChildren = ((Component)val3).GetComponentInChildren(); PopUpFixer componentOrAdd = GameObjectExtensions.GetComponentOrAdd(((Component)componentInChildren).gameObject); componentOrAdd.upgradeObj = val2; menu.upgradeInfoPopups = Il2CppReferenceArrayExt.AddTo(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(); Vector2 sizeDelta = ((Il2CppObjectBase)((Component)upgradeObject).transform).Cast().sizeDelta; float preferredWidth = (val.minWidth = sizeDelta.x); val.preferredWidth = preferredWidth; preferredWidth = (val.minHeight = sizeDelta.y); val.preferredHeight = preferredWidth; ((Il2CppObjectBase)upgradeObject.locked.transform).Cast().sizeDelta = new Vector2(900f, 350f); Transform parent = ((Component)((Il2CppArrayBase)(object)upgradeObject.tiers)[0]).transform.parent; ComponentExt.TranslateScaled((Component)(object)parent, new Vector3(13f, 0f, 0f)); GridLayoutGroup component = ((Component)parent).GetComponent(); 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.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 value)) { value = new List(); } while (value.Count > moreUpgradeButtons.Count) { AddNewUpgradeObject(); } for (int i = 0; i < 3; i++) { UpgradeObject upgradeButton = ((Il2CppArrayBase)(object)menu.upgradeButtons)[i]; UpgradeObjectPlusPlus component = ((Component)upgradeButton).GetComponent(); if ((Object)(object)component == (Object)null || !((Behaviour)component).isActiveAndEnabled) { continue; } if (PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(((EntityModel)selectedTower.Def).baseId, out Dictionary> _)) { 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 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 componentsInChildren = ((Component)((Component)menu).transform).GetComponentsInChildren(true); for (int num = 0; num < moreUpgradeButtons.Count; num++) { UpgradeObjectPlusPlus button = Il2CppGenericsExt.Get(moreUpgradeButtons, num); UpgradeInfoPopup component2 = ((Component)((IEnumerable)componentsInChildren).First((PopUpFixer fixer) => (Object)(object)fixer.upgradeObj == (Object)(object)((Component)button.upgradeObject).gameObject)).GetComponent(); 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.op_Implicit(((IEnumerable)((Component)((Component)menu).transform).GetComponentsInChildren(false)).ToArray()); menu.upgradeInfoPopups = Il2CppReferenceArray.op_Implicit(((IEnumerable)((Component)((Component)menu).transform).GetComponentsInChildren(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 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 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 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 PathsById = new Dictionary(); public static readonly Dictionary> PathsByTower = new Dictionary>(); public static readonly Dictionary UpgradesById = new Dictionary(); public static readonly Dictionary>> ExtendedPathsByTower = new Dictionary>>(); public static readonly Dictionary DefaultExtendedPaths = new Dictionary(); 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 HotKeysByPath = new Dictionary { { 3, UpgradePath4 }, { 4, UpgradePath5 }, { 5, UpgradePath6 }, { 6, UpgradePath7 }, { 7, UpgradePath8 }, { 8, UpgradePath9 } }; private static readonly Dictionary Clipboard = new Dictionary(); 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((IEnumerable)gameModel.towerSet)) { if (!ExtendedPathsByTower.TryGetValue(((TowerDetailsModel)item).towerId, out Dictionary> 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()) { profile.acquiredUpgrades.AddIfNotPresent(((ModContent)item).Id); } } public override void PreCleanProfile(ProfileModel profile) { string[] ids = (from upgrade in ModContent.GetContent() select ((ModContent)upgrade).Id).ToArray(); profile.acquiredUpgrades.RemoveWhere(Predicate.op_Implicit((Func)((string s) => ((ReadOnlySpan)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()) { item.currentlyAppliedOn.Remove(tower); } } public override void OnGameObjectsReset() { foreach (UpgradePlusPlus item in ModContent.GetContent()) { 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 dictionary = ((obj != null) ? obj.ToObject>() : 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(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(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(parameters, ref tower3)) { break; } return tower3.GetAllTiers(); } case "ValidTiers": { string tower6 = default(string); int path5 = default(int); int[] tiers = default(int[]); if (ArrayExt.CheckTypes(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(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(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(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(); 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((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((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)cyclePathIds).Any() || (Object)(object)cycle == (Object)null) { return; } AudioClipExtensions.Play(MenuManager.instance.buttonClick3Sound, "FX", 1f); List list = ((IEnumerable)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 currentlyAppliedOn = new HashSet(); 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("UpgradeContainerPlatinum"); protected static string UpgradeContainerDiamond => ModContent.GetTextureGUID("UpgradeContainerDiamond"); protected static string UpgradeContainerRainbow => ModContent.GetTextureGUID("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 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 : UpgradePlusPlus where T : PathPlusPlus { public sealed override PathPlusPlus Path => ModContent.GetInstance(); } [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(); 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 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()) { if (GameObjectExt.HasComponent(((Component)componentsInChild).gameObject, ref val)) { val.speed = 0.75f; val.Play("PopupScaleIn"); } ((Behaviour)((Component)componentsInChild).GetComponentInChildren(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()) { if (GameObjectExt.HasComponent(((Component)componentsInChild).gameObject, ref val)) { val.speed = 1f; val.Play("PopupScaleOut"); } } if (JsonConvert.SerializeObject((object)PathsPlusPlusMod.DefaultExtendedPaths) != lastDefaults) { ((BloonsMod)ModContent.GetInstance()).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 createdUpgradePaths = new List(); public readonly List[] extraUpgradeDetails = new List[3] { new List(), new List(), new List() }; 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 enumerator = createdUpgradePaths.GetEnumerator(); while (enumerator.MoveNext()) { GameObject current = enumerator.Current; current.gameObject.SetActive(false); } foreach (UpgradeDetails item in extraUpgradeDetails.SelectMany((List val8) => (IEnumerable)val8.ToArray())) { ((Component)item).gameObject.SetActive(false); } List value; List list = (PathsPlusPlusMod.PathsByTower.TryGetValue(towerId, out value) ? value.Where((PathPlusPlus path) => path?.ShowInMenu ?? false).ToList() : new List()); Dictionary> value2; Dictionary> dictionary = (PathsPlusPlusMod.ExtendedPathsByTower.TryGetValue(towerId, out value2) ? value2 : new Dictionary>()); List list2 = new List(); 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 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