Decompiled source of AbilityChoice v4.4.6

AbilityChoice.dll

Decompiled 10 hours 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 System.Text.RegularExpressions;
using AbilityChoice;
using AbilityChoice.AbilityChoices.Hero.Adora;
using AbilityChoice.AbilityChoices.Magic.WizardMonkey;
using AbilityChoice.AbilityChoices.Primary.IceMonkey;
using AbilityChoice.Descriptions;
using AbilityChoice.Displays;
using AbilityChoice.Patches;
using BTD_Mod_Helper;
using BTD_Mod_Helper.Api;
using BTD_Mod_Helper.Api.Components;
using BTD_Mod_Helper.Api.Data;
using BTD_Mod_Helper.Api.Display;
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 Il2Cpp;
using Il2CppAssets.Scripts;
using Il2CppAssets.Scripts.Data;
using Il2CppAssets.Scripts.Data.Legends;
using Il2CppAssets.Scripts.Models;
using Il2CppAssets.Scripts.Models.Artifacts;
using Il2CppAssets.Scripts.Models.Artifacts.Behaviors;
using Il2CppAssets.Scripts.Models.Audio;
using Il2CppAssets.Scripts.Models.Bloons;
using Il2CppAssets.Scripts.Models.Bloons.Behaviors;
using Il2CppAssets.Scripts.Models.CorvusSpells;
using Il2CppAssets.Scripts.Models.CorvusSpells.Continuous;
using Il2CppAssets.Scripts.Models.CorvusSpells.Instant;
using Il2CppAssets.Scripts.Models.Effects;
using Il2CppAssets.Scripts.Models.Entities;
using Il2CppAssets.Scripts.Models.GenericBehaviors;
using Il2CppAssets.Scripts.Models.GeraldoItems;
using Il2CppAssets.Scripts.Models.Map;
using Il2CppAssets.Scripts.Models.Profile;
using Il2CppAssets.Scripts.Models.TowerSets;
using Il2CppAssets.Scripts.Models.Towers;
using Il2CppAssets.Scripts.Models.Towers.Behaviors;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Abilities;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Abilities.Behaviors;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack.Behaviors;
using Il2CppAssets.Scripts.Models.Towers.Behaviors.Emissions;
using Il2CppAssets.Scripts.Models.Towers.Filters;
using Il2CppAssets.Scripts.Models.Towers.Projectiles;
using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors;
using Il2CppAssets.Scripts.Models.Towers.TowerFilters;
using Il2CppAssets.Scripts.Models.Towers.Upgrades;
using Il2CppAssets.Scripts.Models.Towers.Weapons;
using Il2CppAssets.Scripts.Models.Towers.Weapons.Behaviors;
using Il2CppAssets.Scripts.Simulation;
using Il2CppAssets.Scripts.Simulation.Bloons;
using Il2CppAssets.Scripts.Simulation.Corvus.Spells;
using Il2CppAssets.Scripts.Simulation.Corvus.Spells.Continuous;
using Il2CppAssets.Scripts.Simulation.Corvus.Spells.Instant;
using Il2CppAssets.Scripts.Simulation.Corvus.TowerManager;
using Il2CppAssets.Scripts.Simulation.GeraldoItems;
using Il2CppAssets.Scripts.Simulation.Objects;
using Il2CppAssets.Scripts.Simulation.SMath;
using Il2CppAssets.Scripts.Simulation.SimulationBehaviors;
using Il2CppAssets.Scripts.Simulation.Towers;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors.Abilities;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors.Abilities.Behaviors;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors.Attack;
using Il2CppAssets.Scripts.Simulation.Towers.Behaviors.Attack.Behaviors;
using Il2CppAssets.Scripts.Simulation.Towers.Projectiles;
using Il2CppAssets.Scripts.Simulation.Track;
using Il2CppAssets.Scripts.Unity;
using Il2CppAssets.Scripts.Unity.Bridge;
using Il2CppAssets.Scripts.Unity.Display;
using Il2CppAssets.Scripts.Unity.Menu;
using Il2CppAssets.Scripts.Unity.UI_New.HeroInGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu.TowerSelectionMenuThemes;
using Il2CppAssets.Scripts.Unity.UI_New.Legends;
using Il2CppAssets.Scripts.Unity.UI_New.Main.HeroSelect;
using Il2CppAssets.Scripts.Unity.UI_New.Popups;
using Il2CppAssets.Scripts.Unity.UI_New.Upgrade;
using Il2CppAssets.Scripts.Utils;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNinjaKiwi.Common;
using Il2CppNinjaKiwi.Common.ResourceUtils;
using Il2CppNinjaKiwi.Localization;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.IO;
using Il2CppSystem.Linq;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
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(AbilityChoiceMod), "Ability Choice", "4.4.6", "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("AbilityChoice")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6af2178126a26e4e9bdf233b0f27ec8180dddd5f")]
[assembly: AssemblyProduct("AbilityChoice")]
[assembly: AssemblyTitle("AbilityChoice")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object? IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => _items.Length;

	T IReadOnlyList<T>.this[int index] => _items[index];

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

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

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

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

	bool IList.Contains(object? value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object? value)
	{
		return ((IList)_items).IndexOf(value);
	}

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

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

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

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

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

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

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

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

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

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

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

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[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 AbilityChoice
{
	public abstract class AbilityChoice : NamedModContent
	{
		internal static int? overrideMode;

		protected MelonPreferences_Entry<int> setting;

		protected readonly HashSet<string> affectedIds = new HashSet<string>();

		protected readonly List<string> affectedOrder = new List<string>();

		public virtual string AbilityName => Regex.Replace(((ModContent)this).Name, "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z])", " $1", RegexOptions.Compiled).Trim();

		public virtual string BackUpAbilityName => null;

		public override string DisplayName => "[" + AbilityName + " Ability]";

		public bool Enabled
		{
			get
			{
				int mode = Mode;
				if ((uint)(mode - 1) <= 1u)
				{
					return true;
				}
				return false;
			}
		}

		protected bool Mode2 => Mode == 2;

		public int Mode
		{
			get
			{
				return Math.Clamp(overrideMode ?? setting?.Value ?? 0, 0, (!HasMode2) ? 1 : 2);
			}
			set
			{
				setting.Value = value;
				if (setting.Value == 2 && !HasMode2)
				{
					setting.Value = 1;
				}
			}
		}

		protected abstract bool HasMode2 { get; }

		protected override float RegistrationPriority => 25f;

		public virtual SpriteReference Icon => null;

		public override void Register()
		{
			setting = AbilityChoiceMod.AbilityChoiceSettings.CreateEntry<int>(((ModContent)this).Id, 1, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		internal void CacheAffectedIds()
		{
			affectedIds.Clear();
			affectedOrder.Clear();
			foreach (string item in from model in GetAffected(Game.instance.model)
				select ((Model)model).name)
			{
				if (affectedIds.Add(item))
				{
					affectedOrder.Add(item);
				}
			}
		}

		public void Toggle()
		{
			MelonPreferences_Entry<int> obj = setting;
			int value = obj.Value;
			obj.Value = value + 1;
			if (setting.Value > 2 || (setting.Value > 1 && !HasMode2))
			{
				setting.Value = 0;
			}
		}

		public virtual void Apply1(TowerModel model)
		{
		}

		public virtual void Apply2(TowerModel model)
		{
		}

		protected virtual void ApplyBoth(TowerModel model)
		{
		}

		public void Apply(TowerModel towerModel)
		{
			if (Mode2)
			{
				Apply2(towerModel);
			}
			else
			{
				Apply1(towerModel);
			}
			ApplyBoth(towerModel);
			RemoveAbility(towerModel);
		}

		protected virtual AbilityModel AbilityModel(TowerModel model)
		{
			return ((IEnumerable<AbilityModel>)TowerModelBehaviorExt.GetBehaviors<AbilityModel>(model)).FirstOrDefault((Func<AbilityModel, bool>)((AbilityModel abilityModel) => abilityModel.displayName == AbilityName || abilityModel.displayName == BackUpAbilityName));
		}

		protected virtual void RemoveAbility(TowerModel model)
		{
			AbilityModel val = AbilityModel(model);
			if (val != null)
			{
				TowerModelBehaviorExt.RemoveBehavior<AbilityModel>(model, val);
			}
		}

		public virtual bool AppliesTo(TowerModel towerModel)
		{
			return AbilityModel(towerModel) != null;
		}

		public virtual void Apply(GameModel gameModel)
		{
			foreach (TowerModel item in GetAffectedCached(gameModel))
			{
				Apply(item);
			}
		}

		public IEnumerable<TowerModel> GetAffectedCached(GameModel gameModel)
		{
			Dictionary<string, TowerModel> towers = ((IEnumerable<TowerModel>)gameModel.towers).Where((TowerModel model) => affectedIds.Contains(((Model)model).name)).DistinctBy((TowerModel model) => ((Model)model).name).ToDictionary((TowerModel model) => ((Model)model).name);
			return affectedOrder.Select((string s) => towers[s]).Where(AppliesTo);
		}

		public abstract IEnumerable<TowerModel> GetAffected(GameModel gameModel);

		public static float CalcAvgBonus(float uptime, float dpsMult)
		{
			return uptime * dpsMult + (1f - uptime);
		}

		internal void TechBotify(TowerModel model, AbilityModel ability = null)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0084: 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_00a8: Expected O, but got Unknown
			if (ability == null)
			{
				ability = AbilityModel(model);
			}
			ability.isHidden = true;
			string name = "TechBotify_" + ability.displayName.Replace(" ", "");
			if (IEnumerableExt.OfIl2CppType<ActivateAbilityAfterIntervalModel>((IEnumerable)((EntityModel)model).behaviors).All(delegate(ActivateAbilityAfterIntervalModel m)
			{
				AbilityModel abilityModel = m.abilityModel;
				return ((abilityModel != null) ? abilityModel.displayName : null) != ability.displayName;
			}))
			{
				Args val = new Args();
				((ModelArgs<ActivateAbilityAfterIntervalModel>)val).name = name;
				val.abilityModel = ability;
				val.interval = ability.Cooldown;
				TowerModelBehaviorExt.AddBehavior<ActivateAbilityAfterIntervalModel>(model, CreateActivateAbilityAfterIntervalModelExt.Create(val));
			}
		}
	}
	public class AbilityChoiceMod : BloonsTD6Mod
	{
		[HarmonyPatch(typeof(CosmeticHelper), "ApplyCosmeticsToGameModel")]
		internal static class CosmeticHelper_ApplyCosmeticsToGameModel
		{
			[HarmonyPostfix]
			internal static void Postfix()
			{
				GameModel rootGameModel = CosmeticHelper.rootGameModel;
				if (UseLateOnNewGameModel)
				{
					ApplyAbilityChoices(rootGameModel);
				}
			}
		}

		private static readonly ModSettingBool ApplyAfterChallengeRules = new ModSettingBool(true)
		{
			icon = "MainMenuUiAtlas[ChallengeRulesBtn]",
			description = "Makes Ability Choices calculate and apply their tower modification AFTER Challenge Rules change the cooldowns of towers rather than before"
		};

		private static readonly ModSettingButton SetAllToOff = new ModSettingButton
		{
			action = delegate
			{
				ModContent.GetContent<TowerAbilityChoice>().ForEach(delegate(TowerAbilityChoice choice)
				{
					choice.Mode = 0;
				});
			},
			icon = TowerAbilityChoice.IconForMode(0),
			description = "Sets all abilities back to their default vanilla affects.",
			buttonSprite = "Ui[YellowBtnLong]",
			buttonText = "Set All"
		};

		private static readonly ModSettingButton SetAllToMode1 = new ModSettingButton
		{
			action = delegate
			{
				ModContent.GetContent<TowerAbilityChoice>().ForEach(delegate(TowerAbilityChoice choice)
				{
					choice.Mode = 1;
				});
			},
			icon = TowerAbilityChoice.IconForMode(1),
			description = "For most towers, this is a permanent but weaker version of the ability.",
			buttonSprite = "Ui[RedBtnLong]",
			buttonText = "Set All"
		};

		private static readonly ModSettingButton SetAllToMode2 = new ModSettingButton
		{
			action = delegate
			{
				ModContent.GetContent<TowerAbilityChoice>().ForEach(delegate(TowerAbilityChoice choice)
				{
					choice.Mode = 2;
				});
			},
			icon = TowerAbilityChoice.IconForMode(2),
			description = "For the towers that have it, a different alternate affect to the ability. Towers that don'thave a second mode will be set to Mode 1.",
			buttonSprite = "Ui[BlueBtnLong]",
			buttonText = "Set All"
		};

		public static readonly ModSettingBool MoreBalanced = new ModSettingBool(true)
		{
			description = "Nerfs a few effects that were unbalanced in their initial implementation"
		};

		public static readonly ModSettingInt MagusPerfectusSwitchThreshold;

		public override bool UsesArtifactDependants => true;

		public static MelonPreferences_Category AbilityChoiceSettings { get; private set; }

		private static bool UseLateOnNewGameModel => ModSettingBool.op_Implicit(ApplyAfterChallengeRules) && !InGameData.CurrentGame.IsLegend();

		public override void OnMainMenu()
		{
			AbilityChoiceSettings.SaveToFile(false);
		}

		public override void OnTitleScreen()
		{
			foreach (AbilityChoice item in ModContent.GetContent<AbilityChoice>())
			{
				item.CacheAffectedIds();
			}
		}

		public override void OnUpdate()
		{
			//IL_008c: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			if (UnityToSimulationExt.Current != null && ModContent.GetInstance<EclipseOfFimbulwinter>().Mode == 1 && Il2CppGenericIEnumerable.Any<TowerToSimulation>(UnityToSimulationExt.Current.GetAllTowers(), (Func<TowerToSimulation, bool>)((TowerToSimulation tower) => ((tower != null) ? tower.Def : null) != null && ((EntityModel)tower.Def).baseId == TowerType.IceMonkey && tower.Def.isParagon)) && UnityToSimulationExt.Current.GetBossBloon() != null && UnityToSimulationExt.Current.GetCurrentBossSkull() == 0)
			{
				SimulationExt.Current.blockNextBossSkull = true;
			}
			if (!Input.GetMouseButtonUp(1))
			{
				return;
			}
			List<RaycastResult> val = new List<RaycastResult>();
			PointerEventData val2 = new PointerEventData(EventSystem.current)
			{
				position = Vector2.op_Implicit(Input.mousePosition)
			};
			EventSystem.current.RaycastAll(val2, val);
			Enumerator<RaycastResult> enumerator = val.GetEnumerator();
			TowerAbilityChoiceInfo towerAbilityChoiceInfo = default(TowerAbilityChoiceInfo);
			HeroAbilityChoiceInfo heroAbilityChoiceInfo = default(HeroAbilityChoiceInfo);
			while (enumerator.MoveNext())
			{
				RaycastResult current = enumerator.Current;
				if (GameObjectExt.HasComponent<TowerAbilityChoiceInfo>(current.gameObject, ref towerAbilityChoiceInfo))
				{
					towerAbilityChoiceInfo.abilityChoice.Toggle();
					towerAbilityChoiceInfo.UpdateIcon();
					towerAbilityChoiceInfo.upgradeDetails.OnPointerExit(val2);
					towerAbilityChoiceInfo.upgradeDetails.OnPointerEnter(val2);
				}
				else
				{
					if (!GameObjectExt.HasComponent<HeroAbilityChoiceInfo>(current.gameObject, ref heroAbilityChoiceInfo))
					{
						continue;
					}
					heroAbilityChoiceInfo.abilityChoice.Toggle();
					heroAbilityChoiceInfo.UpdateIcon();
					heroAbilityChoiceInfo.UpdateDescriptions();
				}
				if ((Object)(object)InGame.instance != (Object)null && !PopupScreen.instance.IsPopupActive())
				{
					PopupScreen.instance.ShowOkPopup("In order for this to take effect, you'll need to exit to the main menu and come back to the game.", (ReturnCallback)null);
				}
				else
				{
					AudioClipExtensions.Play(MenuManager.instance.buttonClickSound, "ClickSounds", 1f);
				}
			}
		}

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

		public static void ApplyAbilityChoices(GameModel gameModel)
		{
			GetRelevantArtifactEffects(out var boosts, out var towerSetChanges, out var abilityStackings);
			ReadonlyInGameData currentGame = InGameData.CurrentGame;
			if (((currentGame != null) ? currentGame.rogueData : null) != null)
			{
				RogueLegendsManager instance = RogueLegendsManager.instance;
				if (((instance != null) ? instance.RogueSaveData : null) != null)
				{
					ProcessBoosts(gameModel, boosts, towerSetChanges, abilityStackings, unapply: false);
				}
			}
			foreach (AbilityChoice item in from choice in ModContent.GetContent<AbilityChoice>()
				where choice.Enabled
				select choice)
			{
				try
				{
					item.Apply(gameModel);
				}
				catch (Exception ex)
				{
					ModHelper.Error<AbilityChoiceMod>((object)ex);
				}
			}
			ReadonlyInGameData currentGame2 = InGameData.CurrentGame;
			if (((currentGame2 != null) ? currentGame2.rogueData : null) != null)
			{
				RogueLegendsManager instance2 = RogueLegendsManager.instance;
				if (((instance2 != null) ? instance2.RogueSaveData : null) != null)
				{
					ProcessBoosts(gameModel, boosts, towerSetChanges, abilityStackings, unapply: true);
				}
			}
		}

		public override void OnNewGameModel(GameModel gameModel)
		{
			if (!UseLateOnNewGameModel)
			{
				ApplyAbilityChoices(gameModel);
			}
		}

		private static void GetRelevantArtifactEffects(out List<BoostArtifactModel> boosts, out List<CountAllCategoriesBehaviorModel> towerSetChanges, out List<AbilityStackingBehaviorModel> abilityStackings)
		{
			boosts = new List<BoostArtifactModel>();
			towerSetChanges = new List<CountAllCategoriesBehaviorModel>();
			abilityStackings = new List<AbilityStackingBehaviorModel>();
			ReadonlyInGameData currentGame = InGameData.CurrentGame;
			if (((currentGame != null) ? currentGame.rogueData : null) == null)
			{
				return;
			}
			RogueLegendsManager instance = RogueLegendsManager.instance;
			if (((instance != null) ? instance.RogueSaveData : null) == null)
			{
				return;
			}
			Enumerator<ArtifactLoot> enumerator = RogueLegendsManager.instance.RogueSaveData.artifactsInventory.GetEnumerator();
			BoostArtifactModel item = default(BoostArtifactModel);
			while (enumerator.MoveNext())
			{
				ArtifactLoot current = enumerator.Current;
				Model val = GameData.Instance.artifactsData.GetArtifactData(current.artifactName).ArtifactModel();
				if (Il2CppSystemObjectExt.Is<BoostArtifactModel>((Il2CppObjectBase)(object)val, ref item))
				{
					boosts.Add(item);
				}
				boosts.AddRange((IEnumerable<BoostArtifactModel>)MonoLinqHelper.ToArray<BoostArtifactModel>(val.GetDescendants<BoostArtifactModel>()));
				towerSetChanges.AddRange((IEnumerable<CountAllCategoriesBehaviorModel>)MonoLinqHelper.ToArray<CountAllCategoriesBehaviorModel>(val.GetDescendants<CountAllCategoriesBehaviorModel>()));
				abilityStackings.AddRange((IEnumerable<AbilityStackingBehaviorModel>)MonoLinqHelper.ToArray<AbilityStackingBehaviorModel>(val.GetDescendants<AbilityStackingBehaviorModel>()));
			}
		}

		public static void ProcessBoosts(GameModel gameModel, List<BoostArtifactModel> boosts, List<CountAllCategoriesBehaviorModel> towerSetChanges, List<AbilityStackingBehaviorModel> abilityStackings, bool unapply)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			foreach (BoostArtifactModel boost in boosts)
			{
				List<CooldownBoostBehaviorModel> cooldownBehaviors = ArtifactModelBehaviorExt.GetBehaviors<CooldownBoostBehaviorModel>(boost);
				if (!cooldownBehaviors.Any())
				{
					continue;
				}
				foreach (TowerModel tower in (Il2CppArrayBase<TowerModel>)(object)gameModel.towers)
				{
					if ((boost.towerTypes != null && ((IEnumerable<string>)boost.towerTypes).Any() && ((Il2CppArrayBase<string>)(object)boost.towerTypes).Contains(((EntityModel)tower).baseId) == boost.inverseSets) || !tower.CheckTiers(boost.tiers, boost.tiersMustBeEqual, boost.inverseTiers))
					{
						continue;
					}
					TowerSet towerSet = tower.towerSet;
					foreach (CountAllCategoriesBehaviorModel item in towerSetChanges.Where((CountAllCategoriesBehaviorModel towerSetChange) => TowerSetHelpers.ContainsFlags(towerSetChange.towerSetList, tower.towerSet)))
					{
						foreach (TowerSet item2 in (Il2CppArrayBase<TowerSet>)(object)item.alsoCountsAsList)
						{
							TowerModel obj = tower;
							obj.towerSet |= item2;
						}
					}
					bool flag = tower.CheckSet(boost.towerSet, boost.inverseSets);
					tower.towerSet = towerSet;
					if (!flag)
					{
						continue;
					}
					Il2CppGenericIEnumerable.ForEach<AbilityModel>(((Model)tower).GetDescendants<AbilityModel>(), (Action<AbilityModel>)delegate(AbilityModel ability)
					{
						using List<CooldownBoostBehaviorModel>.Enumerator enumerator9 = cooldownBehaviors.GetEnumerator();
						if (enumerator9.MoveNext())
						{
							CooldownBoostBehaviorModel current6 = enumerator9.Current;
							(bool, bool) tuple = (((BoostArtifactBehaviorModel)current6).multiplier < 1f, unapply);
							(bool, bool) tuple2 = tuple;
							if (!tuple2.Item1)
							{
								if (!tuple2.Item2)
								{
									ability.Cooldown /= ((BoostArtifactBehaviorModel)current6).multiplier;
								}
								else
								{
									ability.Cooldown *= ((BoostArtifactBehaviorModel)current6).multiplier;
								}
							}
							else if (!tuple2.Item2)
							{
								ability.Cooldown *= 2f - ((BoostArtifactBehaviorModel)current6).multiplier;
							}
							else
							{
								ability.Cooldown /= 2f - ((BoostArtifactBehaviorModel)current6).multiplier;
							}
						}
					});
				}
			}
			foreach (AbilityStackingBehaviorModel abilityStacking in abilityStackings)
			{
				foreach (TowerModel tower2 in (Il2CppArrayBase<TowerModel>)(object)gameModel.towers)
				{
					if (abilityStacking.towerTypes != null && ((IEnumerable<string>)abilityStacking.towerTypes).Any() && ((Il2CppArrayBase<string>)(object)abilityStacking.towerTypes).Contains(((EntityModel)tower2).baseId) == abilityStacking.inverseSets)
					{
						continue;
					}
					TowerSet towerSet2 = tower2.towerSet;
					foreach (CountAllCategoriesBehaviorModel item3 in towerSetChanges.Where((CountAllCategoriesBehaviorModel towerSetChange) => TowerSetHelpers.ContainsFlags(towerSetChange.towerSetList, tower2.towerSet)))
					{
						foreach (TowerSet item4 in (Il2CppArrayBase<TowerSet>)(object)item3.alsoCountsAsList)
						{
							TowerModel obj2 = tower2;
							obj2.towerSet |= item4;
						}
					}
					bool flag2 = tower2.CheckSet(abilityStacking.towerSet, abilityStacking.inverseSets);
					tower2.towerSet = towerSet2;
					if (!flag2)
					{
						continue;
					}
					Il2CppGenericIEnumerable.ForEach<AbilityModel>(((Model)tower2).GetDescendants<AbilityModel>(), (Action<AbilityModel>)delegate(AbilityModel ability)
					{
						float num = 1f + (float)abilityStacking.stackCount * 0.15f;
						if (unapply)
						{
							ability.Cooldown *= num;
						}
						else
						{
							ability.Cooldown /= num;
						}
					});
				}
			}
		}

		public override void OnRoundStart()
		{
			Syphon_OnBloonCreate.counter = 0;
		}

		public override void OnGameObjectsReset()
		{
			OverclockHandler.Dots.Clear();
			BloodSacrifice.NextSacrificeTimes.Clear();
			CorvusHandler.SpellsToReactivate.Clear();
		}

		public override bool PreBloonLeaked(Bloon bloon)
		{
			UnityToSimulation bridge = InGame.Bridge;
			int num = ((bridge != null) ? bridge.MyPlayerNumber : (-1));
			if (((RootObject)bloon).Sim.GetCorvusManagerExists(num))
			{
				CorvusManager corvusManager = ((RootObject)bloon).Sim.GetCorvusManager(num);
				if (corvusManager.CanSpellBeCast((CorvusSpellType)6) && CorvusAbilityChoice.EnabledForSpell((CorvusSpellType)6))
				{
					corvusManager.CastSpell((CorvusSpellType)6);
				}
			}
			return true;
		}

		public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (BloodSacrifice.NextSacrificeTimes.TryGetValue(((RootObject)tower).Id, out var value))
			{
				saveData.metaData["AbilityChoice-NextSacrificeTime"] = value.ToString();
			}
			TimedMutator val = default(TimedMutator);
			OverclockMutator val2 = default(OverclockMutator);
			if (Il2CppSystemObjectExt.Is<TimedMutator>(((Mutable)tower).GetMutatorById("Overclock"), ref val) && Il2CppSystemObjectExt.Is<OverclockMutator>((Il2CppObjectBase)(object)val.mutator, ref val2))
			{
				OverclockModel overclockModel = val2.overclockModel;
				if (((Model)(object)overclockModel).OverclockAbilityChoice())
				{
					saveData.metaData["OverclockAbilityChoice-rateModifier"] = overclockModel.rateModifier.ToString();
					saveData.metaData["OverclockAbilityChoice-villageRangeModifier"] = overclockModel.villageRangeModifier.ToString();
				}
			}
			TakeAimMutator val3 = default(TakeAimMutator);
			if (Il2CppSystemObjectExt.Is<TimedMutator>(((Mutable)tower).GetMutatorById("TakeAim"), ref val) && Il2CppSystemObjectExt.Is<TakeAimMutator>((Il2CppObjectBase)(object)val.mutator, ref val3))
			{
				TakeAimModel takeAimModel = val3.takeAimModel;
				if (((Model)(object)takeAimModel).OverclockAbilityChoice())
				{
					saveData.metaData["TakeAimAbilityChoice-rangeModifier"] = takeAimModel.rangeModifier.ToString();
					saveData.metaData["TakeAimAbilityChoice-spreadModifier"] = takeAimModel.spreadModifier.ToString();
				}
			}
		}

		public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			string s = default(string);
			if (saveData.metaData.TryGetValue("AbilityChoice-NextSacrificeTime", ref s))
			{
				BloodSacrifice.NextSacrificeTimes[((RootObject)tower).Id] = int.Parse(s);
			}
			TimedMutator val = default(TimedMutator);
			if (Il2CppSystemObjectExt.Is<TimedMutator>(((Mutable)tower).GetMutatorById("Overclock"), ref val))
			{
				OverclockMutator val2 = ((Il2CppObjectBase)val.mutator).Cast<OverclockMutator>();
				OverclockModel overclockModel = val2.overclockModel;
				if (((Model)(object)overclockModel).OverclockAbilityChoice())
				{
					val.totalDuration = -1;
					val.removeAt = -1;
					string s2 = default(string);
					if (saveData.metaData.TryGetValue("OverclockAbilityChoice-rateModifier", ref s2) && float.TryParse(s2, out var result))
					{
						overclockModel.rateModifier = result;
					}
					string s3 = default(string);
					if (saveData.metaData.TryGetValue("OverclockAbilityChoice-villageRangeModifier", ref s3) && float.TryParse(s3, out var result2))
					{
						overclockModel.villageRangeModifier = result2;
					}
					((BehaviorMutator)val2).resultCache.Clear();
					((Mutable)tower).ApplyMutation();
				}
			}
			if (!Il2CppSystemObjectExt.Is<TimedMutator>(((Mutable)tower).GetMutatorById("TakeAim"), ref val))
			{
				return;
			}
			TakeAimMutator val3 = ((Il2CppObjectBase)val.mutator).Cast<TakeAimMutator>();
			TakeAimModel takeAimModel = val3.takeAimModel;
			if (((Model)(object)takeAimModel).OverclockAbilityChoice())
			{
				val.totalDuration = -1;
				val.removeAt = -1;
				string s4 = default(string);
				if (saveData.metaData.TryGetValue("TakeAimAbilityChoice-rangeModifier", ref s4) && float.TryParse(s4, out var result3))
				{
					takeAimModel.rangeModifier = result3;
				}
				string s5 = default(string);
				if (saveData.metaData.TryGetValue("TakeAimAbilityChoice-spreadModifier", ref s5) && float.TryParse(s5, out var result4))
				{
					takeAimModel.spreadModifier = result4;
				}
				((BehaviorMutator)val3).resultCache.Clear();
				((Mutable)tower).ApplyMutation();
			}
		}

		static AbilityChoiceMod()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			ModSettingInt val = new ModSettingInt(0)
			{
				description = "Controls the threshold where the Magus Perfectus will switch to its mana generating attack when it drops below this amount of mana."
			};
			((ModSettingNumber<long>)val).min = 0L;
			((ModSettingNumber<long>)val).max = 100000L;
			((ModSetting)val).icon = "48e18ca7bb56c1c429c530f5d79832fe";
			MagusPerfectusSwitchThreshold = val;
		}
	}
	public class AbilityChoiceTest : ModTest
	{
		public override IEnumerator Test()
		{
			int mode;
			for (mode = 1; mode <= 2; mode++)
			{
				yield return ((ModTest)this).EnsureOnMainMenuWithNoPopUps();
				AbilityChoice.overrideMode = mode;
				yield return ((ModTest)this).LoadIntoGame((InGameData)null);
				foreach (TowerModel towerModel in (from choice in ModContent.GetContent<AbilityChoice>()
					where choice.Mode == mode
					select choice).SelectMany((AbilityChoice abilityChoice) => abilityChoice.GetAffectedCached(((ModTest)this).Bridge.Model)).Distinct())
				{
					TowerToSimulation tower = ((ModTest)this).AssertNotNull<TowerToSimulation>(ModTest.CreateTowerAt(((ModTest)this).Bridge, new Vector2(0f, 0f), towerModel, true, true, 0), ((Model)towerModel).name);
					yield return null;
					yield return null;
					yield return null;
					((ModTest)this).Bridge.SellTower(tower.Id);
				}
			}
			AbilityChoice.overrideMode = null;
		}
	}
	public class AdoraTsmTheme : ModTsmTheme
	{
		private ModHelperPanel panel;

		private ModHelperSlider slider;

		private ModHelperSlider slider20;

		public override string BaseTheme => "Default";

		public static int SacrificeAmount { get; private set; }

		public override void SetupTheme(BaseTSMTheme theme)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			panel = GameObjectExt.AddModHelperPanel(((Component)theme).gameObject, new Info("AdoraSacrificePanel", (InfoPreset)0), (string)null, (Axis?)null, 50f, 0);
			((ModHelperComponent)panel).AddImage(new Info("Icon", 372f, -75f, 120f), "de1e7961f691d41eea5aa65b821708ac");
			slider = ((ModHelperComponent)panel).AddSlider(new Info("SacrificeSlider", 0f, -75f, 550f, 75f), 0f, 0f, 150f, 5f, new Vector2(100f, 100f), UnityAction<float>.op_Implicit((Action<float>)delegate(float amount)
			{
				SacrificeAmount = (int)amount;
			}), 52f, "$/s");
			slider20 = ((ModHelperComponent)panel).AddSlider(new Info("SacrificeSliderLvl20", 0f, -75f, 550f, 75f), 0f, 0f, 33f, 1f, new Vector2(100f, 100f), UnityAction<float>.op_Implicit((Action<float>)delegate(float amount)
			{
				SacrificeAmount = (int)amount;
			}), 52f, "$/s");
			((Graphic)GameObjectExt.GetComponentInChildrenByName<Image>(((Component)slider).gameObject, "Fill")).color = new Color(1f, 1f, 0f);
			((Graphic)GameObjectExt.GetComponentInChildrenByName<Image>(((Component)slider20).gameObject, "Fill")).color = new Color(1f, 1f, 0.5f);
			((Transform)GameObjectExt.GetComponentInChildrenByName<RectTransform>(((Component)slider).gameObject, "Label")).localPosition = new Vector3(0f, -80f, 0f);
			((Transform)GameObjectExt.GetComponentInChildrenByName<RectTransform>(((Component)slider20).gameObject, "Label")).localPosition = new Vector3(0f, -80f, 0f);
			((TMP_Text)GameObjectExt.GetComponentInChildrenByName<NK_TextMeshProUGUI>(((Component)slider).gameObject, "Label")).fontStyle = (FontStyles)32;
			((TMP_Text)GameObjectExt.GetComponentInChildrenByName<NK_TextMeshProUGUI>(((Component)slider20).gameObject, "Label")).fontStyle = (FontStyles)32;
			((Component)GameObjectExt.GetComponentInChildrenByName<RectTransform>(((Component)slider).gameObject, "DefaultNotch")).gameObject.SetActive(false);
			((Component)GameObjectExt.GetComponentInChildrenByName<RectTransform>(((Component)slider20).gameObject, "DefaultNotch")).gameObject.SetActive(false);
		}

		public override void TowerChanged(BaseTSMTheme theme, TowerToSimulation tower)
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			if (tower == null || ((EntityModel)tower.Def).baseId != TowerType.Adora || tower.Def.tier < 7)
			{
				((ModHelperComponent)panel).SetActive(false);
				return;
			}
			((ModHelperComponent)panel).SetActive(true);
			if (tower.Def.tier < 20)
			{
				((ModHelperComponent)slider).SetActive(true);
				((ModHelperComponent)slider20).SetActive(false);
				slider.SetCurrentValue((float)Math.Clamp(SacrificeAmount, 0, 150), true);
			}
			else
			{
				((ModHelperComponent)slider20).SetActive(true);
				((ModHelperComponent)slider).SetActive(false);
				slider20.SetCurrentValue((float)Math.Clamp(SacrificeAmount, 0, 33), true);
				((Graphic)GameObjectExt.GetComponentInChildrenByName<Image>(((Component)slider20).gameObject, "Fill")).color = ((((Mutable)tower.tower).GetMutatorById("AdoraSunGodTransformationVengeance") != null) ? new Color(0.75f, 0f, 0f) : new Color(1f, 1f, 0.5f));
			}
		}
	}
	public abstract class CorvusAbilityChoice : HeroAbilityChoice
	{
		protected const int ContinuousFactor = 20;

		public sealed override string HeroId => TowerType.Corvus;

		protected override float RegistrationPriority => base.RegistrationPriority + 1f;

		public sealed override Dictionary<int, string> Descriptions1 => new Dictionary<int, string>();

		public sealed override Dictionary<int, string> Descriptions2 => new Dictionary<int, string>();

		public virtual string Description1 => null;

		public virtual string Description2 => null;

		public virtual string Description1Lvl20 => null;

		public virtual string Description2Lvl20 => null;

		public override SpriteReference Icon => ((TowerBasedShopItemModel)Spell(Game.instance.model.GetTowerWithName("Corvus 20"))).defaultIcon;

		public CorvusSpellType SpellType => Enum.Parse<CorvusSpellType>(((ModContent)this).Name);

		public CorvusSpellModel Spell(TowerModel model)
		{
			return ((IEnumerable<CorvusSpellModel>)TowerModelBehaviorExt.GetBehaviors<CorvusSpellModel>(model)).FirstOrDefault((Func<CorvusSpellModel, bool>)((CorvusSpellModel spellModel) => ((TowerBasedShopItemModel)spellModel).locsId == ((ModContent)this).Name));
		}

		public CorvusContinuousSpellModel ContinuousSpell(TowerModel model)
		{
			return ((IEnumerable<CorvusContinuousSpellModel>)TowerModelBehaviorExt.GetBehaviors<CorvusContinuousSpellModel>(model)).FirstOrDefault((Func<CorvusContinuousSpellModel, bool>)((CorvusContinuousSpellModel spellModel) => ((TowerBasedShopItemModel)spellModel).locsId == ((ModContent)this).Name));
		}

		public CorvusInstantSpellModel InstantSpell(TowerModel model)
		{
			return ((IEnumerable<CorvusInstantSpellModel>)TowerModelBehaviorExt.GetBehaviors<CorvusInstantSpellModel>(model)).FirstOrDefault((Func<CorvusInstantSpellModel, bool>)((CorvusInstantSpellModel spellModel) => ((TowerBasedShopItemModel)spellModel).locsId == ((ModContent)this).Name));
		}

		public override bool AppliesTo(TowerModel towerModel)
		{
			return Spell(towerModel) != null;
		}

		public static bool EnabledForSpell(CorvusSpellType spellType)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return ModContent.GetContent<CorvusAbilityChoice>().Any((CorvusAbilityChoice choice) => choice.SpellType == spellType && choice.Enabled);
		}

		public override void Apply(GameModel gameModel)
		{
			foreach (TowerModel item in GetAffected(gameModel))
			{
				if (base.Mode2)
				{
					Apply2(item);
				}
				else
				{
					Apply1(item);
				}
				ApplyBoth(item);
			}
		}

		public override IEnumerable<ModContent> Load()
		{
			yield return (ModContent)(object)this;
			if (Description1 != null)
			{
				yield return (ModContent)(object)new CorvusAbilityChoiceDescription(this, 1, Description1);
			}
			if (Description2 != null)
			{
				yield return (ModContent)(object)new CorvusAbilityChoiceDescription(this, 2, Description2);
			}
			if (Description1Lvl20 != null)
			{
				yield return (ModContent)(object)new CorvusAbilityChoiceDescription(this, 1, Description1Lvl20, lvl20: true);
			}
			if (Description2Lvl20 != null)
			{
				yield return (ModContent)(object)new CorvusAbilityChoiceDescription(this, 2, Description2Lvl20, lvl20: true);
			}
		}
	}
	public static class CorvusHandler
	{
		[HarmonyPatch(typeof(CorvusManager), "ConsumeContinuousSpellMana")]
		internal static class CorvusManager_ConsumeContinuousSpellMana
		{
			[HarmonyPrefix]
			internal static void Prefix(CorvusManager __instance, ref List<CorvusContinuousSpell> __state)
			{
				__state = Il2CppSystemDictionaryExt.Keys<CorvusContinuousSpell, CorvusContinuousSpellTiming>(__instance.activeContinuousSpells).ToList();
			}

			[HarmonyPostfix]
			internal static void Postfix(CorvusManager __instance, CorvusContinuousSpell spell, ref List<CorvusContinuousSpell> __state)
			{
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				if (__instance.IsSpellActive((CorvusSpell)(object)spell))
				{
					return;
				}
				SpellsToReactivate.TryAdd(__instance.owner, new HashSet<CorvusSpellType>());
				HashSet<CorvusSpellType> hashSet = SpellsToReactivate[__instance.owner];
				foreach (CorvusContinuousSpell item in __state.Where((CorvusContinuousSpell s) => CorvusAbilityChoice.EnabledForSpell(((CorvusSpell)s).SpellType)))
				{
					hashSet.Add(((CorvusSpell)item).SpellType);
				}
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "Process")]
		internal static class CorvusManager_Process
		{
			[HarmonyPostfix]
			internal static void Postfix(CorvusManager __instance)
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Invalid comparison between Unknown and I4
				//IL_0141: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_0148: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Invalid comparison between Unknown and I4
				//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_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Invalid comparison between Unknown and I4
				//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_0150: Unknown result type (might be due to invalid IL or missing references)
				//IL_0154: Invalid comparison between Unknown and I4
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Invalid comparison between Unknown and I4
				//IL_018d: Unknown result type (might be due to invalid IL or missing references)
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0216: Unknown result type (might be due to invalid IL or missing references)
				//IL_021f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0231: Unknown result type (might be due to invalid IL or missing references)
				SpellsToReactivate.TryAdd(__instance.owner, new HashSet<CorvusSpellType>());
				CorvusSpellType[] array = (CorvusSpellType[])(object)new CorvusSpellType[2]
				{
					(CorvusSpellType)9,
					(CorvusSpellType)13
				};
				List<CorvusSpellType> val2 = default(List<CorvusSpellType>);
				foreach (CorvusSpellType val in array)
				{
					if (CorvusAbilityChoice.EnabledForSpell(val) && __instance.spellRestrictions.TryGetValue(val, ref val2))
					{
						val2.Clear();
					}
				}
				foreach (CorvusInstantSpell item in Il2CppSystemDictionaryExt.Keys<CorvusInstantSpell, CorvusInstantSpellTiming>(__instance.activeInstantSpells).ToList())
				{
					CorvusInstantSpellTiming val3 = __instance.activeInstantSpells[item];
					if (!CorvusAbilityChoice.EnabledForSpell(((CorvusSpell)item).SpellType) || val3.FramesRemainingActive > 1 || (int)((CorvusSpell)item).SpellType == 6)
					{
						continue;
					}
					if (__instance.TryConsumeMana(((CorvusSpellModel)item.SpellModel).initialManaCost))
					{
						val3.totalFramesActive += (int)(item.SpellModel.duration * 60f);
						CorvusSpellType spellType = ((CorvusSpell)item).SpellType;
						if (((int)spellType == 9 || spellType - 13 <= 1) ? true : false)
						{
							item.Cast();
						}
					}
					else
					{
						CorvusSpellType spellType = ((CorvusSpell)item).SpellType;
						if (((int)spellType != 9 && (int)spellType != 14) || 1 == 0)
						{
							__instance.CancelInstantSpell(((CorvusSpell)item).SpellType);
						}
						SpellsToReactivate[__instance.owner].Add(((CorvusSpell)item).SpellType);
					}
				}
				foreach (CorvusSpellType item2 in SpellsToReactivate[__instance.owner].ToList())
				{
					if (__instance.CanSpellBeCast(item2) && __instance.HasEnoughManaForSpell(__instance.LookupSpellByType(item2)))
					{
						SpellsToReactivate[__instance.owner].Remove(item2);
						if (!__instance.IsSpellActive(item2))
						{
							__instance.CastSpell(item2);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "GetSpellStatus")]
		internal static class CorvusManager_GetSpellStatus
		{
			[HarmonyPostfix]
			internal static void Postfix(CorvusSpellType spellType, ref CorvusSpellStatus __result)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if (CorvusAbilityChoice.EnabledForSpell(spellType) && (int)spellType != 6)
				{
					__result = new CorvusSpellStatus(spellType, __result.isActive, __result.canSpellBeCast, 0f, 0f);
				}
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "IsManaDraining")]
		internal static class CorvusManager_IsManaDraining
		{
			[HarmonyPostfix]
			internal static void Postfix(CorvusManager __instance, ref bool __result)
			{
				__result |= Il2CppSystemDictionaryExt.Keys<CorvusInstantSpell, CorvusInstantSpellTiming>(__instance.activeInstantSpells).Any((CorvusInstantSpell spell) => CorvusAbilityChoice.EnabledForSpell(((CorvusSpell)spell).SpellType));
			}
		}

		[HarmonyPatch(typeof(CorvusSpellbookUi), "UpdateDeactivateButton")]
		internal static class CorvusSpellbookUi_UpdateDeactivateButton
		{
			[HarmonyPostfix]
			internal static bool Prefix(CorvusSpellbookUi __instance)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				CorvusInstantSpellModel val = default(CorvusInstantSpellModel);
				if (!TowerSelectionMenuExt.instance.IsSecondarySelectionMenuVisible() || !Il2CppSystemObjectExt.Is<CorvusInstantSpellModel>((Il2CppObjectBase)(object)((SecondarySelectionMenuUi)__instance).TowerBasedShopItemModel, ref val) || !CorvusAbilityChoice.EnabledForSpell(((CorvusSpellModel)val).spellType))
				{
					return true;
				}
				CorvusSpellStatus corvusSpellStatus = InGame.Bridge.GetCorvusSpellStatus(((CorvusSpellModel)val).spellType, InGame.Bridge.MyPlayerNumber);
				((Component)__instance.deactivateButton).gameObject.SetActive(corvusSpellStatus.isActive);
				return false;
			}
		}

		[HarmonyPatch(typeof(CorvusSpellbookUi), "DeactivateSelectedSpell")]
		internal static class CorvusSpellbookUi_DeactivateSelectedSpell
		{
			[HarmonyPrefix]
			internal static bool Prefix(CorvusSpellbookUi __instance)
			{
				//IL_0011: 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)
				CorvusInstantSpellModel val = default(CorvusInstantSpellModel);
				if (!Il2CppSystemObjectExt.Is<CorvusInstantSpellModel>((Il2CppObjectBase)(object)((SecondarySelectionMenuUi)__instance).TowerBasedShopItemModel, ref val) || !CorvusAbilityChoice.EnabledForSpell(((CorvusSpellModel)val).spellType))
				{
					return true;
				}
				InGame.Bridge.Simulation.GetCorvusManager(InGame.Bridge.MyPlayerNumber).CancelInstantSpell(((CorvusSpellModel)val).spellType);
				return false;
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "TriggerCorvusToReleaseSpirit")]
		internal static class CorvusManager_TriggerCorvusToReleaseSpirit
		{
			public static bool releasing;

			[HarmonyPrefix]
			internal static void Prefix(CorvusManager __instance)
			{
				releasing = true;
			}

			[HarmonyPostfix]
			internal static void Postfix(CorvusManager __instance)
			{
				releasing = false;
				if (CorvusAbilityChoice.EnabledForSpell((CorvusSpellType)12) && __instance.IsSpellActive((CorvusSpellType)12) && __instance.duplicateSpiritSubTower == null)
				{
					((Il2CppObjectBase)__instance.LookupSpellByType((CorvusSpellType)12)).Cast<Echo>().CreateDuplicateSpirit();
				}
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "GetSaveMetaData")]
		internal static class CorvusManager_GetSaveMetaData
		{
			[HarmonyPostfix]
			internal unsafe static void Postfix(CorvusManager __instance, Dictionary<string, string> metaData)
			{
				if (SpellsToReactivate.TryGetValue(__instance.owner, out var value))
				{
					metaData.Add("CorvusMetadata_SpellsToReactivate" + __instance.owner, GeneralExtensions.Join<string>(value.Select((CorvusSpellType type) => ((object)(*(CorvusSpellType*)(&type))/*cast due to .constrained prefix*/).ToString()), (Func<string, string>)null, ","));
				}
			}
		}

		[HarmonyPatch(typeof(CorvusManager), "SetSaveMetaData")]
		internal static class CorvusManager_SetSaveMetaData
		{
			[HarmonyPostfix]
			internal static void Postfix(CorvusManager __instance, Dictionary<string, string> metaData)
			{
				string text = default(string);
				if (metaData.TryGetValue("CorvusMetadata_SpellsToReactivate" + __instance.owner, ref text))
				{
					SpellsToReactivate[__instance.owner] = text.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(Enum.Parse<CorvusSpellType>).ToHashSet();
				}
			}
		}

		public static readonly Dictionary<int, HashSet<CorvusSpellType>> SpellsToReactivate = new Dictionary<int, HashSet<CorvusSpellType>>();
	}
	public abstract class GeraldoAbilityChioce : HeroAbilityChoice
	{
		public sealed override string HeroId => TowerType.Geraldo;

		protected abstract int CostMult { get; }

		protected sealed override bool HasMode2 => false;

		public abstract override Dictionary<int, string> Descriptions2 { get; }

		public override SpriteReference Icon => ((TowerBasedShopItemModel)GeraldoItem()).defaultIcon;

		public GeraldoItemModel GeraldoItem(GameModel gameModel = null)
		{
			return (gameModel ?? Game.instance.model).GetGeraldoItemWithName(((ModContent)this).Name);
		}

		public override bool AppliesTo(TowerModel towerModel)
		{
			return Math.Clamp(GeraldoItem().levelUnlockedAt, 1, 20) == towerModel.tier;
		}

		public override IEnumerable<ModContent> Load()
		{
			yield return (ModContent)(object)this;
			int key;
			string value;
			foreach (KeyValuePair<int, string> item in Descriptions1)
			{
				item.Deconstruct(out key, out value);
				int level = key;
				string description = value;
				yield return (ModContent)(object)new HeroAbilityChoiceDescription(this, level, 1, description);
			}
			foreach (KeyValuePair<int, string> item2 in Descriptions2)
			{
				item2.Deconstruct(out key, out value);
				int level2 = key;
				string description2 = value;
				yield return (ModContent)(object)new GeraldoAbilityChoiceDescription(this, level2, description2);
			}
		}

		public sealed override void Apply1(TowerModel model)
		{
		}

		public sealed override void Apply2(TowerModel model)
		{
		}

		public override void Apply(GameModel gameModel)
		{
			GeraldoItemModel val = GeraldoItem(gameModel);
			val.cost *= CostMult;
			Apply(val);
		}

		protected abstract void Apply(GeraldoItemModel geraldoItem);
	}
	public abstract class HeroAbilityChoice : AbilityChoice
	{
		public static readonly Dictionary<string, AbilityChoice> Cache = new Dictionary<string, AbilityChoice>();

		public abstract string HeroId { get; }

		public sealed override string Description => ((NamedModContent)this).Description;

		public abstract Dictionary<int, string> Descriptions1 { get; }

		public virtual Dictionary<int, string> Descriptions2 { get; }

		protected override bool HasMode2 => Descriptions2 != null;

		public override IEnumerable<ModContent> Load()
		{
			yield return (ModContent)(object)this;
			foreach (int level in Descriptions1.Keys)
			{
				yield return (ModContent)(object)new HeroAbilityChoiceDescription(this, level, 1, $"[{((ModContent)this).Id} Description1 {level}]");
			}
			if (!HasMode2)
			{
				yield break;
			}
			foreach (int level2 in Descriptions2.Keys)
			{
				yield return (ModContent)(object)new HeroAbilityChoiceDescription(this, level2, 2, $"[{((ModContent)this).Id} Description2 {level2}]");
			}
		}

		public override void Register()
		{
			base.Register();
			Cache[((ModContent)this).Id] = this;
		}

		public override IEnumerable<TowerModel> GetAffected(GameModel gameModel)
		{
			return from model in Il2CppGenericIEnumerable.AsIEnumerable<TowerModel>(gameModel.GetTowersWithBaseId(HeroId, false)).Where(AppliesTo)
				orderby model.tier
				select model;
		}

		public static string IconForMode(int mode)
		{
			if (1 == 0)
			{
			}
			string result = mode switch
			{
				1 => "Ui[RedBtnSquare]", 
				2 => "Ui[BlueBtnSquare]", 
				_ => "Ui[YellowBtnSquare]", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public override void RegisterText(Dictionary<string, string> textTable)
		{
			textTable[((ModContent)this).Id] = ((NamedModContent)this).DisplayName;
			int key;
			string value;
			foreach (KeyValuePair<int, string> item in Descriptions1)
			{
				item.Deconstruct(out key, out value);
				int value2 = key;
				string text = value;
				textTable[$"{((ModContent)this).Id} Description1 {value2}"] = text;
			}
			if (!HasMode2)
			{
				return;
			}
			foreach (KeyValuePair<int, string> item2 in Descriptions2)
			{
				item2.Deconstruct(out key, out value);
				int value3 = key;
				string text2 = value;
				textTable[$"{((ModContent)this).Id} Description2 {value3}"] = text2;
			}
		}
	}
	[RegisterTypeInIl2Cpp(false)]
	public class HeroAbilityChoiceInfo : MonoBehaviour
	{
		public HeroAbilityChoice abilityChoice;

		public Il2CppReferenceArray<HeroUpgradeButton> buttons;

		public GameObject container;

		public Image abilityIcon;

		public Image background;

		public int index;

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

		public void UpdateIcon()
		{
			ImageExt.SetSprite(background, HeroAbilityChoice.IconForMode(abilityChoice?.Mode ?? 0));
			if (abilityChoice != null)
			{
				container.SetActive(true);
				SpriteReference icon = abilityChoice.Icon;
				if (icon != null)
				{
					ImageExt.SetSprite(abilityIcon, icon);
				}
			}
		}

		public void UpdateDescriptions()
		{
			foreach (HeroUpgradeButton item in (Il2CppArrayBase<HeroUpgradeButton>)(object)buttons)
			{
				UpdateDescription(abilityChoice.HeroId, item);
			}
		}

		public static void UpdateDescription(string heroId, HeroUpgradeButton button)
		{
			string text = $"{heroId} Level {button.HeroIndex} Description";
			button.descriptions.SetText(LocalizationManager.Instance.GetText(text));
		}

		public static void Setup(string selectedHero, Il2CppReferenceArray<HeroUpgradeButton> buttons)
		{
			Il2CppArrayBase<TowerModel> source = Enumerable.ToArray<TowerModel>(Game.instance.model.GetTowersWithBaseId(selectedHero, false));
			List<HeroAbilityChoice> list = (from choice in ModContent.GetContent<HeroAbilityChoice>()
				where choice.HeroId == selectedHero
				select choice).ToList();
			foreach (HeroUpgradeButton item in (Il2CppArrayBase<HeroUpgradeButton>)(object)buttons)
			{
				foreach (HeroAbilityChoiceInfo componentsInChild in ((Component)((Component)item).transform).GetComponentsInChildren<HeroAbilityChoiceInfo>(true))
				{
					componentsInChild.abilityChoice = null;
					if (componentsInChild.index > 0)
					{
						componentsInChild.container.SetActive(false);
					}
				}
			}
			foreach (HeroAbilityChoice abilityChoice in list)
			{
				TowerModel towerModel = ((IEnumerable<TowerModel>)source).First((TowerModel towerModel2) => abilityChoice.AppliesTo(towerModel2));
				HeroUpgradeButton val = ((IEnumerable<HeroUpgradeButton>)buttons).First((HeroUpgradeButton upgradeButton) => upgradeButton.HeroIndex == towerModel.tier);
				HeroAbilityChoiceInfo heroAbilityChoiceInfo = GameObjectExtensions.GetComponentOrAdd<HeroAbilityChoiceInfo>(val.abilityIconContainer);
				if (heroAbilityChoiceInfo.abilityChoice != null)
				{
					Il2CppArrayBase<HeroAbilityChoiceInfo> componentsInChildren = ((Component)((Component)val).transform).GetComponentsInChildren<HeroAbilityChoiceInfo>(true);
					if (!Il2CppSystemObjectExt.Is<HeroAbilityChoiceInfo>(((IEnumerable<HeroAbilityChoiceInfo>)componentsInChildren).FirstOrDefault((HeroAbilityChoiceInfo i) => i.abilityChoice == null), ref heroAbilityChoiceInfo))
					{
						int length = componentsInChildren.Length;
						GameObject val2 = Object.Instantiate<GameObject>(val.abilityIconContainer, val.abilityIconContainer.transform.parent);
						((Object)val2).name = ((Object)val2).name.Replace("(Clone)", length.ToString());
						heroAbilityChoiceInfo = val2.GetComponent<HeroAbilityChoiceInfo>();
						heroAbilityChoiceInfo.container = val2;
						heroAbilityChoiceInfo.index = length;
					}
				}
				else
				{
					heroAbilityChoiceInfo.container = val.abilityIconContainer;
				}
				heroAbilityChoiceInfo.container.SetActive(true);
				heroAbilityChoiceInfo.abilityChoice = abilityChoice;
				heroAbilityChoiceInfo.buttons = buttons;
				heroAbilityChoiceInfo.abilityIcon = GameObjectExt.GetComponentInChildrenByName<Image>(((Component)heroAbilityChoiceInfo).gameObject, "Icon");
				heroAbilityChoiceInfo.background = GameObjectExt.GetComponentInChildrenByName<Image>(((Component)heroAbilityChoiceInfo).gameObject, "Bg");
				GameObjectExtensions.GetComponentOrAdd<Text>(heroAbilityChoiceInfo.container);
			}
			foreach (HeroUpgradeButton item2 in (Il2CppArrayBase<HeroUpgradeButton>)(object)buttons)
			{
				foreach (HeroAbilityChoiceInfo componentsInChild2 in ((Component)((Component)item2).transform).GetComponentsInChildren<HeroAbilityChoiceInfo>())
				{
					componentsInChild2.UpdateIcon();
				}
			}
		}
	}
	internal static class MagusPerfectusManager
	{
		[HarmonyPatch(typeof(MagusPerfectusGraveyardStateManager), "TriggerManaExplosion")]
		internal static class MagusPerfectusGraveyardStateManager_TriggerManaExplosion
		{
			[HarmonyPrefix]
			internal static bool Prefix(MagusPerfectusGraveyardStateManager __instance, ref int __result)
			{
				if (activatingPhoenixRebirth)
				{
					__instance.explosionRemainingFrames = 450;
					NecroData paragonNecroData = __instance.ParagonNecroData;
					if (paragonNecroData != null)
					{
						__result = paragonNecroData.RbePool() / 4;
						if (paragonNecroData.RbePool() - __result < 1000)
						{
							__result = paragonNecroData.RbePool();
						}
						__instance.ConsumeMana(__result, false);
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(PhoenixRebirth), "Activate")]
		internal static class PhoenixRebirth_Activate
		{
			[HarmonyPrefix]
			internal static void Prefix(PhoenixRebirth __instance, ref int __state)
			{
				activatingPhoenixRebirth = ((AbilityBehavior)__instance).ability.abilityModel.isHidden;
			}

			[HarmonyPostfix]
			internal static void Postfix(PhoenixRebirth __instance)
			{
				activatingPhoenixRebirth = false;
			}
		}

		[HarmonyPatch(typeof(PhoenixRebirth), "SpawnZombieZOMGs")]
		internal static class PhoenixRebirth_SpawnZombieZOMGs
		{
			[HarmonyPostfix]
			internal static void Postfix(PhoenixRebirth __instance, int manaConsumed)
			{
				if (!spawningBfbs)
				{
					spawningBfbs = true;
					int num = manaConsumed % __instance.behaviourModel.manaPerZombieZOMG;
					ProjectileModel projectileZOMG = __instance.behaviourModel.projectileZOMG;
					__instance.behaviourModel.projectileZOMG = __instance.behaviourModel.projectileBFB;
					PhoenixRebirthModel behaviourModel = __instance.behaviourModel;
					behaviourModel.manaPerZombieZOMG /= 4;
					__instance.SpawnZombieZOMGs(num);
					__instance.behaviourModel.projectileZOMG = projectileZOMG;
					PhoenixRebirthModel behaviourModel2 = __instance.behaviourModel;
					behaviourModel2.manaPerZombieZOMG *= 4;
					spawningBfbs = false;
				}
			}
		}

		[HarmonyPatch(typeof(PhoenixRebirth), "CanUseAbility")]
		internal static class PhoenixRebirth_CanUseAbility
		{
			[HarmonyPrefix]
			internal static bool Prefix(PhoenixRebirth __instance, ref bool __result)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Invalid comparison between Unknown and I4
				if (((AbilityBehavior)__instance).ability.abilityModel.isHidden && (int)((MagusPerfectusAbilityBehavior)__instance).GraveyardManager.graveyardManaState == 1)
				{
					__result = false;
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(MagusPerfectusGraveyardStateManager), "Process")]
		internal static class MagusPerfectusGraveyardStateManager_Process
		{
			[HarmonyPostfix]
			internal static void Postfix(MagusPerfectusGraveyardStateManager __instance)
			{
				NecroData paragonNecroData = __instance.ParagonNecroData;
				if (paragonNecroData != null)
				{
					int num = paragonNecroData.RbePool();
					if (PreviousMana.TryGetValue(__instance.registeredNecroIdx, out var value) && value > ModSettingInt.op_Implicit(AbilityChoiceMod.MagusPerfectusSwitchThreshold) && num <= ModSettingInt.op_Implicit(AbilityChoiceMod.MagusPerfectusSwitchThreshold))
					{
						__instance.SwitchGraveyardManaState((GraveyardManaState)1);
					}
					PreviousMana[__instance.registeredNecroIdx] = num;
				}
			}
		}

		[HarmonyPatch(typeof(ArcaneMetamorphosis), "Process")]
		internal static class ArcaneMeta_Process
		{
			[HarmonyPrefix]
			internal static void Prefix(ArcaneMetamorphosis __instance)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if (ModContent.GetInstance<ArcaneMetamorphosis>().Mode == 1)
				{
					__instance.isCurrentlyMorphed = (int)((MagusPerfectusAbilityBehavior)__instance).GraveyardManager.graveyardManaState == 0 && ((IEnumerable<List<Attack>>)Il2CppSystemDictionaryExt.GetValues<GraveyardManaState, List<Attack>>(((MagusPerfectusAbilityBehavior)__instance).GraveyardManager.graveyardStateAttacks).ToArray()).SelectMany((List<Attack> list) => (IEnumerable<Attack>)list.ToArray()).Any((Attack attack) => attack.HasValidTarget());
				}
			}
		}

		private static bool activatingPhoenixRebirth;

		private static bool spawningBfbs;

		private static readonly Dictionary<int, int> PreviousMana = new Dictionary<int, int>();
	}
	internal static class ModHelperData
	{
		public const string WorksOnVersion = "55.2";

		public const string Version = "4.4.6";

		public const string Name = "Ability Choice";

		public const string Description = "Adds in new choices for towers with abilities that you can pick instead of having an active ability. Selected in the Upgrades menu for the tower by Right-Clicking on the Upgrade to switch.\r\n\r\nYellow Icon: Default Effect\r\nRed Icon: Permanent but weaker effect of the ability\r\nBlue Icon: A new effect based on the theme of the upgrade path";

		public const string RepoOwner = "doombubbles";

		public const string PrevRepoName = "ability-choice";

		public const string RepoName = "AbilityChoice";
	}
	internal static class OverclockHandler
	{
		[HarmonyPatch]
		internal static class TapTowerAbilityBehavior_Activate
		{
			internal static IEnumerable<MethodInfo> TargetMethods()
			{
				return new <>z__ReadOnlyArray<MethodInfo>(new MethodInfo[2]
				{
					AccessTools.Method(typeof(Overclock), "Activate", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(TakeAim), "Activate", (Type[])null, (Type[])null)
				});
			}

			[HarmonyPostfix]
			internal static void Postfix(TapTowerAbilityBehavior __instance)
			{
				if (__instance.OverclockAbilityChoice() && __instance.selectedTower != null && !__instance.IsBanned(__instance.selectedTower))
				{
					ApplyOverclock(((TowerBehavior)((AbilityBehavior)__instance).ability).tower, __instance.selectedTower, __instance);
				}
			}
		}

		[HarmonyPatch(typeof(Ability), "Process")]
		internal static class Ability_Process
		{
			[HarmonyPostfix]
			internal static void Postfix(Ability __instance)
			{
				//IL_0101: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_012d: Unknown result type (might be due to invalid IL or missing references)
				OverclockPermanentModel val = default(OverclockPermanentModel);
				Overclock val2 = default(Overclock);
				TimedMutator val3 = default(TimedMutator);
				OverclockPermanentMutator val4 = default(OverclockPermanentMutator);
				if (__instance.CooldownRemaining == 0f && __instance.abilityModel.OverclockAbilityChoice() && Il2CppSystemObjectExt.Is<OverclockPermanentModel>(AbilityModelBehaviorExt.GetBehavior<OverclockPermanentModel>(__instance.abilityModel), ref val) && Il2CppSystemObjectExt.Is<Overclock>(((RootBehavior)__instance).entity.GetBehaviorInDependants<Overclock>(), ref val2) && ((TapTowerAbilityBehavior)val2).selectedTower != null && (!Il2CppSystemObjectExt.Is<TimedMutator>(((Mutable)((TapTowerAbilityBehavior)val2).selectedTower).GetMutatorById(OverclockPermanentModel.MutatorId), ref val3) || !Il2CppSystemObjectExt.Is<OverclockPermanentMutator>((Il2CppObjectBase)(object)val3.mutator, ref val4) || val4.stacks < val.maxStacks))
				{
					__instance.Activate(false);
					__instance.CooldownRemaining = __instance.abilityModel.cooldownFrames;
				}
				TapTowerAbilityBehavior val5 = default(TapTowerAbilityBehavior);
				if (!__instance.abilityModel.OverclockAbilityChoice() || !Il2CppSystemObjectExt.Is<TapTowerAbilityBehavior>(((RootBehavior)__instance).entity.GetBehaviorInDependants<TapTowerAbilityBehavior>(), ref val5))
				{
					return;
				}
				TechBotLink fakeTechBotLink = GetFakeTechBotLink(__instance);
				if (val5.selectedTower != null)
				{
					TowerToSimulation selectedTower = TowerSelectionMenuExt.instance.selectedTower;
					ObjectId? val6 = ((selectedTower != null) ? new ObjectId?(selectedTower.Id) : ((ObjectId?)null));
					ObjectId id = ((RootObject)((TowerBehavior)__instance).tower).Id;
					if (val6.HasValue && val6.GetValueOrDefault() == id)
					{
						fakeTechBotLink.PlotPointsToLinkedTower(val5.selectedTower);
						return;
					}
				}
				fakeTechBotLink.RemoveDots();
			}
		}

		[HarmonyPatch(typeof(Ability), "OnDestroy")]
		internal static class Ability_OnDestroy
		{
			[HarmonyPrefix]
			internal static void Prefix(Ability __instance)
			{
				if (__instance.abilityModel.OverclockAbilityChoice())
				{
					TechBotLink fakeTechBotLink = GetFakeTechBotLink(__instance);
					fakeTechBotLink.RemoveDots();
				}
			}
		}

		[HarmonyPatch(typeof(OverclockPermanent), "ApplyToTower")]
		internal static class OverclockPermanent_ApplyToTower
		{
			[HarmonyPrefix]
			internal static bool Prefix(OverclockPermanent __instance)
			{
				if (!((AbilityBehavior)__instance).ability.abilityModel.OverclockAbilityChoice())
				{
					return true;
				}
				return ((AbilityBehavior)__instance).ability.CooldownRemaining == 0f;
			}
		}

		[HarmonyPatch(typeof(TapTowerAbilityBehavior), "GetCustomInputData")]
		internal static class TapTowerAbilityBehavior_GetCustomInputData
		{
			[HarmonyPostfix]
			internal static void Postfix(TapTowerAbilityBehavior __instance, ref Object __result)
			{
				OverclockCIData val = default(OverclockCIData);
				if (__instance.OverclockAbilityChoice() && Il2CppSystemObjectExt.Is<OverclockCIData>((Il2CppObjectBase)(object)__result, ref val))
				{
					val.validTowerIds.RemoveAll(Predicate<ObjectId>.op_Implicit((Func<ObjectId, bool>)delegate(ObjectId id)
					{
						//IL_0000: Unknown result type (might be due to invalid IL or missing references)
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_001c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0033: Unknown result type (might be due to invalid IL or missing references)
						//IL_0036: Unknown result type (might be due to invalid IL or missing references)
						Tower selectedTower = __instance.selectedTower;
						ObjectId? val2 = ((selectedTower != null) ? new ObjectId?(((RootObject)selectedTower).Id) : ((ObjectId?)null));
						return val2.HasValue && id == val2.GetValueOrDefault();
					}));
				}
			}
		}

		[HarmonyPatch(typeof(TapTowerAbilityBehavior), "OnTowerUpgraded")]
		internal static class TapTowerAbilityBehavior_OnTowerUpgraded
		{
			[HarmonyPostfix]
			internal static void Postfix(TapTowerAbilityBehavior __instance, Tower tower)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				if (__instance.OverclockAbilityChoice())
				{
					ObjectId id = ((RootObject)tower).Id;
					Tower selectedTower = __instance.selectedTower;
					ObjectId? val = ((selectedTower != null) ? new ObjectId?(((RootObject)selectedTower).Id) : ((ObjectId?)null));
					if (val.HasValue && id == val.GetValueOrDefault() && !__instance.IsBanned(tower))
					{
						ApplyOverclock(((TowerBehavior)((AbilityBehavior)__instance).ability).tower, tower, __instance);
					}
					if (((RootObject)tower).Id == ((RootObject)((TowerBehavior)((AbilityBehavior)__instance).ability).tower).Id && __instance.selectedTower != null && ((RootBehavior)((AbilityBehavior)__instance).ability).entity.GetBehavior<OverclockPermanent>() != null && ((Mutable)__instance.selectedTower).GetMutatorById(OverclockPermanentModel.MutatorId) == null)
					{
						((AbilityBehavior)__instance).ability.ClearCooldown();
						((AbilityBehavior)__instance).ability.Activate(false);
					}
				}
			}
		}

		[HarmonyPatch(typeof(TapTowerAbilityBehavior), "OnDestroy")]
		internal static class TapTowerAbilityBehavior_OnDestroy
		{
			[HarmonyPrefix]
			internal static void Prefix(TapTowerAbilityBehavior __instance)
			{
				if (__instance.OverclockAbilityChoice() && __instance.selectedTower != null)
				{
					((Mutable)__instance.selectedTower).RemoveMutatorsById(__instance.MutatorId());
				}
			}
		}

		[HarmonyPatch]
		internal static class TapTowerAbilityBehavior_ApplyCustomInputData
		{
			internal static IEnumerable<MethodInfo> TargetMethods()
			{
				return new <>z__ReadOnlyArray<MethodInfo>(new MethodInfo[2]
				{
					AccessTools.Method(typeof(Overclock), "ApplyCustomInputData", (Type[])null, (Type[])null),
					AccessTools.Method(typeof(TakeAim), "ApplyCustomInputData", (Type[])null, (Type[])null)
				});
			}

			[HarmonyPrefix]
			internal static void Prefix(TapTowerAbilityBehavior __instance, CustomInputData data)
			{
				//IL_0017: 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)
				if (__instance.OverclockAbilityChoice() && __instance.selectedTower != null && ((RootObject)__instance.selectedTower).Id != data.objectIdValue)
				{
					((Mutable)__instance.selectedTower).RemoveMutatorsById(__instance.MutatorId());
				}
			}
		}

		[HarmonyPatch(typeof(Ability), "IsReady")]
		internal static class Ability_IsReady
		{
			[HarmonyPrefix]
			internal static void Prefix(Ability __instance, ref bool ignoreCooldown)
			{
				if (__instance.abilityModel.OverclockAbilityChoice())
				{
					ignoreCooldown = true;
				}
			}
		}

		[HarmonyPatch(typeof(Ability), "Activate")]
		internal static class Ability_Activate
		{
			[HarmonyPrefix]
			internal static void Prefix(Ability __instance, ref bool ignoreCooldown)
			{
				if (__instance.abilityModel.OverclockAbilityChoice())
				{
					ignoreCooldown = true;
				}
			}
		}

		[HarmonyPatch(typeof(UnityToSimulation), "GetAllAbilities")]
		internal static class UnityToSimulation_GetAllAbilities
		{
			[HarmonyPostfix]
			internal static void Postfix(ref List<AbilityToSimulation> __result)
			{
				List<AbilityToSimulation> obj = __result;
				__result = ((obj != null) ? Il2CppGenerics.Where<AbilityToSimulation>(obj, (Func<AbilityToSimulation, bool>)((AbilityToSimulation a) => a == null || !a.model.OverclockAbilityChoice())) : null);
			}
		}

		[HarmonyPatch(typeof(MapSaveLoader), "LoadMapSaveData")]
		internal static class MapSaveLoader_LoadMapSaveData
		{
			[HarmonyPostfix]
			internal static void Postfix(Simulation sim, MapSaveDataModel mapData)
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if (mapData == null)
				{
					return;
				}
				Enumerator<TowerSaveDataModel> enumerator = mapData.placedTowers.GetEnumerator();
				while (enumerator.MoveNext())
				{
					TowerSaveDataModel current = enumerator.Current;
					if (current != null)
					{
						Tower towerById = sim.towerManager.GetTowerById(current.IdLastSave);
						((BloonsTD6Mod)ModHelper.GetMod<AbilityChoiceMod>()).OnTowerLoaded(towerById, current);
					}
				}
			}
		}

		[HarmonyPatch(typeof(OverclockMutator), "Mutate")]
		internal static class OverclockMutator_Mutate
		{
			[HarmonyPostfix]
			internal static void Postfix(OverclockMutator __instance, Model model)
			{
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Expected O, but got Unknown
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Expected O, but got Unknown
				TowerModel val = default(TowerModel);
				if (Il2CppSystemObjectExt.Is<TowerModel>((Il2CppObjectBase)(object)model, ref val) && ((Model)(object)__instance.overclockModel).OverclockAbilityChoice() && __instance.overclockModel.isParagonMode)
				{
					OverclockModel overclockModel = __instance.overclockModel;
					float uptime = (float)overclockModel.paragonZoneLifespanFrames / (float)overclockModel.lifespanFrames;
					float multiplier = 1f / AbilityChoice.CalcAvgBonus(uptime, 1f / overclockModel.rateModifier);
					float additive = AbilityChoice.CalcAvgBonus(uptime, overclockModel.villageRangeModifier);
					TowerModel obj = val;
					Args val2 = new Args();
					((ModelArgs<RangeSupportModel>)val2).name = "Overclock";
					val2.isUnique = true;
					val2.multiplier = multiplier;
					val2.additive = additive;
					val2.mutatorId = overclockModel.mutatorId;
					val2.buffLocsName = overclockModel.buffLocsName;
					val2.buffIconName = overclockModel.buffIconName;
					val2.showBuffIcon = true;
					val2.isCustomRadius = true;
					val2.customRadius = overclockModel.paragonZoneRange;
					TowerModelBehaviorExt.AddBehavior<RangeSupportModel>(obj, CreateRangeSupportModelExt.Create(val2));
				}
			}
		}

		[HarmonyPatch(typeof(MutatorTower), "Mutate")]
		internal static class RangeSupport_Mutate
		{
			[HarmonyPrefix]
			internal static bool Prefix(MutatorTower __instance, Model baseModel, Model model, ref bool __result)
			{
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: 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_00aa: Expected O, but got Unknown
				if (((BehaviorMutator)__instance).id != "Overclock")
				{
					return true;
				}
				OverclockModel val = ModelExt.Duplicate<OverclockModel>(((Model)Game.instance.model.GetTower(TowerType.EngineerMonkey, 0, 4, 0)).GetDescendant<OverclockModel>());
				val.rateModifier = __instance.multiplier;
				val.villageRangeModifier = __instance.additive;
				val.buffIconName = ((BehaviorMutator)__instance).buffIndicator.iconName;
				val.buffLocsName = ((BehaviorMutator)__instance).buffIndicator.buffName;
				OverclockMutator val2 = new OverclockMutator(val)
				{
					resultCache = ((BehaviorMutator)__instance).resultCache,
					limiters = ((BehaviorMutator)__instance).limiters,
					mutated = ((BehaviorMutator)__instance).mutated
				};
				__result = ((BehaviorMutator)val2).Mutate(baseModel, model);
				return false;
			}
		}

		public const string Enabled = "AbilityChoiceEnabled";

		internal static readonly Dictionary<ObjectId, List<Entity>> Dots = new Dictionary<ObjectId, List<Entity>>();

		public static BehaviorMutator GetMutator(TapTowerAbilityBehavior behavior, int tier)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			Ability ability = ((AbilityBehavior)behavior).ability;
			float num = (float)ability.abilityModel.cooldownFrames * (1f - ability.abilityModel.CooldownSpeedScale);
			Overclock val = default(Overclock);
			if (Il2CppSystemObjectExt.Is<Overclock>((Il2CppObjectBase)(object)behavior, ref val))
			{
				OverclockModel val2 = ModelExt.Duplicate<OverclockModel>(val.overclockModel);
				tier = Math.Clamp(tier, 0, ((Il2CppArrayBase<float>)(object)val2.tierBasedDurationMultiplier).Count - 1);
				float uptime = ((Il2CppArrayBase<float>)(object)val2.tierBasedDurationMultiplier)[tier] * (float)val2.lifespanFrames / num;
				val2.rateModifier = 1f / AbilityChoice.CalcAvgBonus(uptime, 1f / val2.rateModifier);
				val2.villageRangeModifier = AbilityChoice.CalcAvgBonus(uptime, val2.villageRangeModifier);
				return (BehaviorMutator)new OverclockMutator(val2);
			}
			TakeAim val3 = default(TakeAim);
			if (Il2CppSystemObjectExt.Is<TakeAim>((Il2CppObjectBase)(object)behavior, ref val3))
			{
				TakeAimModel val4 = ModelExt.Duplicate<TakeAimModel>(val3.takeAimModel);
				float uptime2 = (float)val4.lifespanFrames / num;
				val4.rangeModifier = AbilityChoice.CalcAvgBonus(uptime2, val4.rangeModifier);
				val4.spreadModifier = 1f / AbilityChoice.CalcAvgBonus(uptime2, 1f / val4.spreadModifier);
				return (BehaviorMutator)new TakeAimMutator(val4);
			}
			return null;
		}

		public static void ApplyOverclock(Tower from, Tower to, TapTowerAbilityBehavior behavior)
		{
			if (((IEnumerable<TapTowerAbilityBehavior>)MonoLinqHelper.ToArray<TapTowerAbilityBehavior>(((RootObject)from).Sim.factory.GetUncast<TapTowerAbilityBehavior>())).Count(delegate(TapTowerAbilityBehavior o)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				Tower selectedTower = o.selectedTower;
				ObjectId? val = ((selectedTower != null) ? new ObjectId?(((RootObject)selectedTower).Id) : ((ObjectId?)null));
				ObjectId id = ((RootObject)to).Id;
				return val.HasValue && val.GetValueOrDefault() == id;
			}) <= 1)
			{
				((Mutable)to).RemoveMutatorsById(behavior.MutatorId());
			}
			int num = to.towerModel.tier;
			if (to.towerModel.IsHero())
			{
				num = (num - 1) / 4;
			}
			((Mutable)to).AddMutator(GetMutator(behavior, num), -1, true, true, false, true, false, false, false, -1, from.IsParagonBased(), true);
		}

		internal static bool OverclockAbilityChoice(this TapTowerAbilityBehavior overclock)
		{
			return ((RootBehavior)overclock).model.OverclockAbilityChoice();
		}

		internal static bool OverclockAbilityChoice(this AbilityModel abilityModel)
		{
			OverclockModel overclockModel = default(OverclockModel);
			TakeAimModel overclockModel2 = default(TakeAimModel);
			return (ModelExt.HasDescendant<OverclockModel>((Model)(object)abilityModel, ref overclockModel) && ((Model)(object)overclockModel).OverclockAbilityChoice()) || (ModelExt.HasDescendant<TakeAimModel>((Model)(object)abilityModel, ref overclockModel2) && ((Model)(object)overclockModel2).OverclockAbilityChoice());
		}

		internal static bool OverclockAbilityChoice(this Model overclockModel)
		{
			return overclockModel.name.Contains("AbilityChoiceEnabled");
		}

		private static string MutatorId(this TapTowerAbilityBehavior instance)
		{
			return ((MemberInfo)((Object)instance).GetIl2CppType()).Name;
		}

		private static TechBotLink GetFakeTechBotLink(Ability __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			TapTowerAbilityBehavior behaviorInDependants = ((RootBehavior)__instance).entity.GetBehaviorInDependants<TapTowerAbilityBehavior>();
			List<Entity> lineDotDisplays = default(List<Entity>);
			if (!Dots.TryGetValue(((RootObject)((TowerBehavior)__instance).tower).Id, ref lineDotDisplays))
			{
				List<Entity> val = (Dots[((RootObject)((TowerBehavior)__instance).tower).Id] = new List<Entity>());
				lineDotDisplays = val;
			}
			TechBotLinkModel descendant = ((Model)Game.instance.model.GetPowerWithId(TowerType.TechBot).tower).GetDescendant<TechBotLinkModel>();
			TechBotLink val3 = new TechBotLink();
			((AbilityBehavior)val3).ability = __instance;
			((RootBehavior)val3).entity = ((RootBehavior)__instance).entity;
			((RootObject)val3).Sim = ((RootObject)__instance).Sim;
			Tower selectedTower = behaviorInDependants.selectedTower;
			val3.selectedTowerId = (ObjectId)((selectedTower != null) ? ((RootObject)selectedTower).Id : default(ObjectId));
			val3.linkedTowers = ArrayExt.ToIl2CppList<Tower>((Tower[])(object)new Tower[1] { behaviorInDependants.selectedTower });
			((RootBehavior)val3).model = (Model)(object)descendant;
			val3.techBotLinkModel = descendant;
			val3.lineDotDisplays = lineDotDisplays;
			return val3;
		}
	}
	public abstract class TowerAbilityChoice : AbilityChoice
	{
		public static readonly Dictionary<string, TowerAbilityChoice> Cache = new Dictionary<string, TowerAbilityChoice>();

		public abstract string Description1 { get; }

		public virtual string Description2 => "";

		public abstract string UpgradeId { get; }

		protected string DefaultDescription { get; private set; }

		protected TowerModel BaseTowerModel { get; private set; }

		protected sealed override bool HasMode2 => !string.IsNullOrEmpty(Description2);

		public sealed override IEnumerable<ModContent> Load()
		{
			yield return (ModContent)(object)this;
			yield return (ModContent)(object)new TowerAbilityChoiceDescription(this, 1, "[" + ((ModContent)this).Id + " Description1]");
			if (HasMode2)
			{
				yield return (ModContent)(object)new TowerAbilityChoiceDescription(this, 2, "[" + ((ModContent)this).Id + " Description2]");
			}
		}

		public override void Register()
		{
			base.Register();
			BaseTowerModel = GetAffected(Game.instance.model).First();
			Cache[UpgradeId] = this;
			DefaultDescription = LocalizationManager.Instance.textTable[UpgradeId + " Description"];
		}

		public override IEnumerable<TowerModel> GetAffected(GameModel gameModel)
		{
			return from model in ((IEnumerable<TowerModel>)gameModel.towers).Where((TowerModel model) => ((Il2CppArrayBase<string>)(object)model.appliedUpgrades)?.Contains(UpgradeId) ?? false).Where(AppliesTo)
				orderby ((Il2CppArrayBase<string>)(object)model.appliedUpgrades).Length
				select model;
		}

		public static string IconForMode(int mode)
		{
			if (1 == 0)
			{
			}
			string result = mode switch
			{
				1 => "Ui[NotifyRed]", 
				2 => "Ui[NotifyBlue]", 
				_ => "Ui[NotificationYellow]", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public override void RegisterText(Dictionary<string, string> textTable)
		{
			if (!string.IsNullOrEmpty(((NamedModContent)this).DisplayName))
			{
				textTable[((ModContent)this).Id] = ((NamedModContent)this).DisplayName;
			}
			if (!string.IsNullOrEmpty(Description1))
			{
				textTable[((ModContent)this).Id + " Description1"] = Description1;
			}
			if (!string.IsNullOrEmpty(Description2))
			{
				textTable[((ModContent)this).Id + " Description2"] = Description2;
			}
		}
	}
	public class TowerAbilityChoiceDescription : AbilityChoiceDescription<TowerAbilityChoice>
	{
		public override string LocalizationKey => abilityChoice.UpgradeId + " Description";

		public TowerAbilityChoiceDescription(TowerAbilityChoice abilityChoice, int mode, string description)
			: base(abilityChoice, mode, description)
		{
		}
	}
	[RegisterTypeInIl2Cpp(false)]
	public class TowerAbilityChoiceInfo : MonoBehaviour
	{
		public UpgradeDetails upgradeDetails;

		public TowerAbilityChoice abilityChoice;

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

		public void UpdateIcon()
		{
			GameObject abilityObject = upgradeDetails.abilityObject;
			Image component = abilityObject.GetComponent<Image>();
			if (abilityChoice != null)
			{
				abilityObject.SetActive(true);
				ImageExt.SetSprite(component, TowerAbilityChoice.IconForMode(abilityChoice.Mode));
			}
			else
			{
				ImageExt.SetSprite(component, TowerAbilityChoice.IconForMode(0));
			}
		}

		public static void Setup(params UpgradeDetails[] pathUpgrades)
		{
			foreach (UpgradeDetails val in pathUpgrades)
			{
				if (!((Behaviour)val).isActiveAndEnabled)
				{
					break;
				}
				TowerAbilityChoiceInfo towerAbilityChoiceInfo = ((Component)val.GetButton()).gameObject.GetComponent<TowerAbilityChoiceInfo>();
				if ((Object)(object)towerAbilityChoiceInfo != (Object)null)
				{
					towerAbilityChoiceInfo.abilityChoice = null;
				}
				UpgradeModel upgrade = val.upgrade;
				string key = ((upgrade != null) ? ((Model)upgrade).name : null) ?? "";
				if (TowerAbilityChoice.Cache.TryGetValue(key, out var value))
				{
					if ((Object)(object)towerAbilityChoiceInfo == (Object)null)
					{
						towerAbilityChoiceInfo = ((Component)val.GetButton()).gameObject.AddComponent<TowerAbilityChoiceInfo>();
					}
					towerAbilityChoiceInfo.abilityChoice = value;
					towerAbilityChoiceInfo.upgradeDetails = val;
				}
				if ((Object)(object)towerAbilityChoiceInfo != (Object)null)
				{
					towerAbilityChoiceInfo.UpdateIcon();
				}
			}
		}
	}
}
namespace AbilityChoice.Patches
{
	[HarmonyPatch(typeof(MutatorTower), "BuffTowerModel")]
	internal static class AbilityCooldownScaleSupport_BuffTowerModel
	{
		[HarmonyPostfix]
		internal static void Postfix(MutatorTower __instance, TowerModel towerModel)
		{
			Il2CppGenericIEnumerable.ForEach<ActivateAbilityAfterIntervalModel>(((Model)towerModel).GetDescendants<ActivateAbilityAfterIntervalModel>(), (Action<ActivateAbilityAfterIntervalModel>)delegate(ActivateAbilityAfterIntervalModel i)
			{
				i.interval /= __instance.abilityCooldownSpeedScale;
				i.intervalFrames = Math.CeilToInt((float)i.intervalFrames / __instance.abilityCooldownSpeedScale);
			});
		}
	}
	[HarmonyPatch(typeof(ActivateAbilityAfterInterval), "Initialise")]
	internal static class ActivateAbilityAfterInterval_Initialise
	{
		[HarmonyPostfix]
		internal static void Postfix(ActivateAbilityAfterInterval __instance)
		{
			if (((RootBehavior)__instance).model.name.Contains("TechBotify"))
			{
				Ability ability = __instance.GetAbility();
				if (ability != null && !ability.abilityModel.startOffCooldown)
				{
					__instance.lastActivatedAt = ((RootObject)__instance).Sim.roundTime.elapsed;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ActivateAbilityAfterInterval), "Process")]
	internal static class ActivateAbilityAfterInterval_Process
	{
		[HarmonyPrefix]
		internal static void Prefix(ActivateAbilityAfterInterval __instance)
		{
			if (((EntityBehavior)__instance).Model.name.Contains("TechBotify"))
			{
				Ability ability = __instance.GetAbility();
				if (ability != null)
				{
					float num = ability.abilityModel.Cooldown * (1f - ability.abilityModel.CooldownSpeedScale);
					ActivateAbilityAfterIntervalModel activateAbilityAfterIntervalModel = __instance.activateAbilityAfterIntervalModel;
					activateAbilityAfterIntervalModel.interval = Math.Min(activateAbilityAfterIntervalModel.interval, num);
					activateAbilityAfterIntervalModel.intervalFrames = Math.Min(activateAbilityAfterIntervalModel.intervalFrames, (int)Math.Round(num * 60f));
				}
			}
		}
	}
	[HarmonyPatch(typeof(DarkMutator), "Mutate")]
	internal static class AdoraSunGodTransformationModel_DarkMutator_Mutate
	{
		[HarmonyPostfix]
		private static void Postfix(Model model)
		{
			TowerModel newBall = model.GetDescendant<AbilityCreateTowerModel>().towerModel;
			Il2CppGenericIEnumerable.ForEach<TowerCreateTowerModel>(model.GetDescendants<TowerCreateTowerModel>(), (Action<TowerCreateTowerModel>)delegate(TowerCreateTowerModel createTower)
			{
				createTower.towerModel = newBall;
				((Model)createTower).name = ((Model)createTower).name + "Dark";
			});
		}
	}
	[HarmonyPatch(typeof(Mutator), "Mutate")]
	internal static class AdoraSunGodTransformationModel_Mutator_Mutate
	{
		[HarmonyPostfix]
		private static void Postfix(Model model)
		{
			TowerModel newBall = model.GetDescendant<AbilityCreateTowerModel>().towerModel;
			Il2CppGenericIEnumerable.ForEach<TowerCreateTowerModel>(model.GetDescendants<TowerCreateTowerModel>(), (Action<TowerCreateTowerModel>)delegate(TowerCreateTowerModel createTower)
			{
				createTower.towerModel = newBall;
				((Model)createTower).name = ((Model)createTower).name + "SunGod";
			});
		}
	}
	[HarmonyPatch(typeof(BottleHotSauceBehavior), "Activate")]
	internal static class BottleHotSauceBehavior_Activate
	{
		[HarmonyPrefix]
		private static bool Prefix(BottleHotSauceBehavior __instance, Vector2 location, int inputId)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			ISelectable selection = ((GeraldoItemBehavior)__instance).sim.Map.GetSelection(location, 20f);
			Tower val = default(Tower);
			if (Il2CppSystemObjectExt.Is<Tower>((Il2CppObjectBase)(object)selection, ref val) && ((Mutable)val).IsMutatedBy("BottleHotSauce"))
			{
				((Mutable)val).RemoveMutatorsById("BottleHotSauce");
				Il2CppGenericIEnumerable.ForEach<Tower>(((GeraldoItemBehavior)__instance).sim.towerManager.GetChildTowers(val), (Action<Tower>)delegate(Tower t)
				{
					if (((EntityModel)t.towerModel).baseId == TowerType.HotSauceCreature)
					{
						((GeraldoItemBehavior)__instance).sim.towerManager.DestroyTower(t, inputId);
					}
				});
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(BottleHotSauceBehavior), "IsPositionValid")]
	internal static class BottleHotSauceBehavior_IsPositionValid
	{
		public static bool CurrentlyChecking { get; private set; }

		[HarmonyPrefix]
		private static void Prefix(BottleHotSauceBehavior __instance)
		{
			CurrentlyChecking = true;
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			CurrentlyChecking = false;
		}
	}
	[HarmonyPatch(typeof(Mutable), "IsMutatedBy", new Type[] { typeof(string) })]
	internal static class Mutable_IsMutatedBy
	{
		[HarmonyPrefix]
		private static bool Prefix(string id, ref bool __result)
		{
			if (BottleHotSauceBehavior_IsPositionValid.CurrentlyChecking && id == "BottleHotSauce")
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MutatorTower), "Mutate")]
	internal static class DamageSupport_Mutate
	{
		[HarmonyPrefix]
		internal static bool Prefix(MutatorTower __instance, Model model, ref bool __result)
		{
			if ((double)__instance.increase < 0.99)
			{
				float mult = __instance.increase + 1f;
				Il2CppGenericIEnumerable.ForEach<DamageModel>(model.GetDescendants<DamageModel>(), (Action<DamageModel>)delegate(DamageModel damageModel)
				{
					damageModel.damage = (float)Math.Ceiling(damageModel.damage * mult);
				});
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(HeroInGameScreen), "Open")]
	internal static class HeroInGameScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(HeroInGameScreen __instance)
		{
			HeroAbilityChoiceInfo.Setup(__instance.heroId, __instance.heroUpgrades);
		}
	}
	[HarmonyPatch(typeof(HeroUpgradeDetails), "BindHeroDetails")]
	internal static class HeroUpgradeDetails_BindDetails
	{
		[HarmonyPostfix]
		private static void Postfix(HeroUpgradeDetails __instance)
		{
			HeroAbilityChoiceInfo.Setup(__instance.DisplayedHeroId, __instance.heroUpgrades);
		}
	}
	[HarmonyPatch(typeof(SelectPointInput), "IsPositionValid")]
	internal static class SelectPointInput_IsPositionValid
	{
		[HarmonyPostfix]
		private static void Postfix(SelectPointInput __instance, Vector2 cursorPosWorld, ref bool __result)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Invalid comparison between Unknown and I4
			SelectTargetCIData cii = __instance.cii;
			object obj;
			if (cii == null)
			{
				obj = null;
			}
			else
			{
				PrefabReference targetInvalidImageId = cii.targetInvalidImageId;
				obj = ((targetInvalidImageId != null) ? targetInvalidImageId.AssetGUID : null);
			}
			if ((string?)obj == ModContent.GetDisplayGUID<MegaMineInvalid>())
			{
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(cursorPosWorld);
				bool num = __result;
				Area areaAtPoint = InGame.instance.bridge.Simulation.Map.GetAreaAtPoint(val, (Area)null, false, false);
				int num2;
				if (areaAtPoint == null)
				{
					num2 = 0;
				}
				else
				{
					AreaModel areaModel = areaAtPoint.areaModel;
					num2 = (((int)((areaModel != null) ? new AreaType?(areaModel.type) : ((AreaType?)null)).GetValueOrDefault() == 1) ? 1 : 0);
				}
				__result = (byte)((num ? 1u : 0u) & (uint)num2) != 0;
			}
		}
	}
	[HarmonyPatch(typeof(SwordCharge), "HideTower")]
	internal static class SwordCharge_HideTower
	{
		[HarmonyPrefix]
		private static bool Prefix(SwordCharge __instance)
		{
			return __instance.swordChargeModel.effectAtEndModel != null;
		}
	}
	[HarmonyPatch(typeof(Syphon), "OnBloonCreate")]
	internal static class Syphon_OnBloonCreate
	{
		public static int counter;

		[HarmonyPrefix]
		private static void Prefix(Syphon __instance, Bloon bloon)
		{
			SyphonFunding behavior = ((RootBehavior)__instance).entity.GetBehavior<SyphonFunding>();
			if (behavior != null && !((IEnumerable<string>)__instance.syphonM