using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BTD_Mod_Helper; using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Data; using BTD_Mod_Helper.Api.ModOptions; using BTD_Mod_Helper.Api.Towers; using BTD_Mod_Helper.Extensions; using HarmonyLib; using Il2Cpp; using Il2CppAssets.Scripts; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Models.Bloons; using Il2CppAssets.Scripts.Models.Bloons.Behaviors; using Il2CppAssets.Scripts.Models.Entities; using Il2CppAssets.Scripts.Models.GenericBehaviors; using Il2CppAssets.Scripts.Models.Profile; using Il2CppAssets.Scripts.Models.SimulationBehaviors; 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.Projectiles.Behaviors; using Il2CppAssets.Scripts.Models.Towers.TowerFilters; using Il2CppAssets.Scripts.Models.Towers.Weapons; using Il2CppAssets.Scripts.Models.Towers.Weapons.Behaviors; using Il2CppAssets.Scripts.Simulation; using Il2CppAssets.Scripts.Simulation.Behaviors; using Il2CppAssets.Scripts.Simulation.Bloons; 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.TowerFilters; using Il2CppAssets.Scripts.Simulation.Towers.Weapons; using Il2CppAssets.Scripts.Simulation.Track; using Il2CppAssets.Scripts.Unity.Bridge; 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.Popups; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppNinjaKiwi.Common.ResourceUtils; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.IO; using Il2CppSystem.Linq; using MelonLoader; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TacticalTweaks; using UnityEngine; 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(TacticalTweaksMod), "Tactical Tweaks", "1.2.2", "doombubbles", null)] [assembly: MelonGame("Ninja Kiwi", "BloonsTD6")] [assembly: MelonGame("Ninja Kiwi", "BloonsTD6-Epic")] [assembly: HarmonyDontPatchAll] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("TacticalTweaks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ba6e6d2aef38cecefb394242dfbd4478c24a70de")] [assembly: AssemblyProduct("TacticalTweaks")] [assembly: AssemblyTitle("TacticalTweaks")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TacticalTweaks { public static class ModHelperData { public const string WorksOnVersion = "55.3"; public const string Version = "1.2.2"; public const string Name = "Tactical Tweaks"; public const string Description = "Adds an assortment of minor gameplay altering tweaks to BTD6, including **Buffable Paragons**!. See the Main Readme for full details.\r\n\r\nNew: Beast Handler Lone T5s, Brickell Mermonkeys, Elite Defender Target Switch, Etienne Targeting, Sticky Bomb Attack Speed, Better Laser Blasts, Better Trojan, Better Monkey City, Better Central Market, Auto Collect/Deposit Banks, Obyn Price Tweak, More Overclock Interactions, More Unfreezable Towers\r\nFormerly Useful Utilities: Dartling/Mortary/Sentry Targeting, Auto Trap Refresh\r\nOld Mods: Better Armor Piercing, Better Ezili Totem"; public const string RepoOwner = "doombubbles"; public const string PrevRepoName = "tactical-tweaks"; public const string RepoName = "TacticalTweaks"; } public abstract class TacticalTweak : NamedModContent, IModSettings, IModContent { protected virtual bool CreateCategory => false; protected virtual string Icon => ((ModContent)this).TextureExists(((ModContent)this).Name) ? ((ModContent)this).GetTextureGUID(((ModContent)this).Name) : null; protected virtual string DisableIfModPresent => ((ModContent)this).Name; protected static Instance MelonLogger => ((MelonBase)ModContent.GetInstance()).LoggerInstance; public sealed override IEnumerable Load() { if (!ModHelper.HasMod(DisableIfModPresent)) { Type[] nestedTypes = ((object)this).GetType().GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type nestedType in nestedTypes) { ((ModContent)this).mod.ApplyHarmonyPatches(nestedType); } OnLoad(); yield return (ModContent)(object)this; } } public sealed override void Register() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown TacticalTweaksMod.TacticalTweaks[((ModContent)this).Name] = this; if (CreateCategory) { ModSettingCategory category = new ModSettingCategory(((NamedModContent)this).DisplayName) { icon = Icon, collapsed = true }; foreach (ModSetting item in ((ModContent)this).mod.ModSettings.Values.Where((ModSetting setting) => (object)setting.source == this)) { item.category = category; } } OnRegister(); } public virtual void OnLoad() { } public virtual void OnRegister() { } public virtual void OnSaveSettings() { } public virtual void OnUpdate() { } public virtual void OnGameObjectsReset() { } public virtual void OnNewGameModel(GameModel gameModel) { } public virtual void OnTowerSaved(Tower tower, TowerSaveDataModel saveData) { } public virtual void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData) { } } public class TacticalTweaksMod : BloonsTD6Mod { public static readonly Dictionary TacticalTweaks = new Dictionary(); public static readonly ModSettingCategory Overclock = new ModSettingCategory("Overclock") { icon = "c101127fbd522584dbcce02cdb22afdb", order = 1 }; public static readonly ModSettingCategory Targeting = new ModSettingCategory("Targeting") { icon = "IngameUi[CamoTargetIconCross]", order = 2 }; public static readonly ModSettingBool DefaultToNewTargeting = new ModSettingBool(true) { description = "Whether to default to the new targeting options, aka setting these towers to be First by default", category = Targeting }; public static MelonPreferences_Category Preferences { get; private set; } = null; public override void OnApplicationStart() { Preferences = MelonPreferences.CreateCategory("TacticalTweaksPreferences"); CollectionExtensions.Do(from type in AccessTools.GetTypesFromAssembly(((MelonBase)this).MelonAssembly.Assembly) where !type.IsNested select type, (Action)((BloonsMod)this).ApplyHarmonyPatches); } public static void AddAllTargets(AttackModel attackModel) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown List list = AttackModelBehaviorExt.GetBehaviors(attackModel).ToList(); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetFirstModelExt.Create(new Args { isSelectable = true })); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetLastModelExt.Create(new Args { isSelectable = true })); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetCloseModelExt.Create(new Args { isSelectable = true })); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetStrongModelExt.Create(new Args { isSelectable = true })); if (!ModSettingBool.op_Implicit(DefaultToNewTargeting)) { return; } foreach (TargetSupplierModel item in list) { AttackModelBehaviorExt.RemoveBehavior(attackModel, item); AttackModelBehaviorExt.AddBehavior(attackModel, item); } } public static void UpdatePointer(AttackModel attackModel, bool? rotateTower = null) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown RotateToPointerModel behavior = AttackModelBehaviorExt.GetBehavior(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateRotateToTargetModelExt.Create(new Args { rotateOnlyOnThrow = behavior.rotateOnlyOnEmit, rotateTower = (rotateTower ?? behavior.rotateTower) })); LineEffectModel val = default(LineEffectModel); if (ModelExt.HasDescendant((Model)(object)attackModel, ref val)) { val.useRotateToPointer = false; } } public override void OnSaveSettings(JObject settings) { foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnSaveSettings(); } } public override void OnUpdate() { foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnUpdate(); } } public override void OnGameObjectsReset() { foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnGameObjectsReset(); } } public override void OnNewGameModel(GameModel gameModel) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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: Expected O, but got Unknown foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnNewGameModel(gameModel); } TowerModel heroWithNameAndLevel = gameModel.GetHeroWithNameAndLevel(TowerType.StrikerJones, 20, false); if (heroWithNameAndLevel != null) { TowerModelBehaviorExt.AddBehavior(heroWithNameAndLevel, CreateSupportRemoveFilterOutTagModelExt.Create(new Args { mutatorId = "Striker:DdtDamageModifier", removeScriptWithSupportMutatorId = "Striker:Level9BlackBuff", isGlobal = true })); } } public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData) { foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnTowerSaved(tower, saveData); } } public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData) { foreach (TacticalTweak value in TacticalTweaks.Values) { value.OnTowerLoaded(tower, saveData); } } } public abstract class ToggleableTweak : TacticalTweak { private ModSettingBool setting = null; protected abstract bool DefaultEnabled { get; } public bool Enabled => ModSettingBool.op_Implicit(setting); public abstract override string Description { get; } protected virtual ModSettingCategory Category => null; public override void OnLoad() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_005c: Expected O, but got Unknown Dictionary modSettings = ((ModContent)this).mod.ModSettings; string name = ((ModContent)this).Name; ModSettingBool val = new ModSettingBool(DefaultEnabled) { displayName = ((NamedModContent)this).DisplayName, icon = Icon, category = Category, description = ((NamedModContent)this).Description, source = (IModSettings)(object)this }; ModSettingBool value = val; setting = val; modSettings[name] = (ModSetting)(object)value; } } } namespace TacticalTweaks.Tweaks { public class AutoBloonTrapRetarget : TacticalTweak { private enum TrapRetargetSetting { Off, StartOfRound, Constantly } [HarmonyPatch(typeof(Simulation), "RoundStart")] internal static class Simulation_RoundStart { [HarmonyPostfix] internal static void Postfix(Simulation __instance) { if (ModSettingEnum.op_Implicit(AutoTrapRetarget) != TrapRetargetSetting.StartOfRound) { return; } Il2CppGenericIEnumerable.ForEach(__instance.factory.GetUncast(), (Action)delegate(TargetSelectedPoint point) { //IL_002d: 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_0035: Unknown result type (might be due to invalid IL or missing references) if (((RootBehavior)((AttackBehavior)point).attack).model.name.Contains("BloonTrap") && point.HasValidPoint) { Vector3 targetPoint = point.targetPoint; ((TargetSupplier)point).ApplyTargetTypeData(((Vector3)(ref targetPoint)).ToVector2()); } }); } } [HarmonyPatch(typeof(Weapon), "Process")] internal static class Weapon_Process { [HarmonyPostfix] internal static void Postfix(Weapon __instance) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) TargetSelectedPoint val = default(TargetSelectedPoint); if (ModSettingEnum.op_Implicit(AutoTrapRetarget) == TrapRetargetSetting.Constantly && ((RootBehavior)((AttackBehavior)__instance).attack).model.name.Contains("BloonTrap") && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)((AttackBehavior)__instance).attack.activeTargetSupplier, ref val) && __instance.IsReloadReady && val.HasValidPoint) { TargetSelectedPoint obj = val; Vector3 targetPoint = val.targetPoint; ((TargetSupplier)obj).ApplyTargetTypeData(((Vector3)(ref targetPoint)).ToVector2()); } } } private static readonly ModSettingEnum AutoTrapRetarget = new ModSettingEnum(TrapRetargetSetting.Off) { icon = "dc5d21f63f63bff40a8798a2b666a5aa", description = "For Engineers with with Bloon Trap and Larger Service Area, traps will now be automatically retargeted on the same spot to refresh them." }; } public class AutoCollectBanks : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "All Banks will auto collect when full like the XX2 Banks do."; protected override string Icon => "01a32a1a35c684d6a8d137b62d3a7f1b"; public override void OnNewGameModel(GameModel gameModel) { BankModel val = default(BankModel); foreach (TowerModel item in Il2CppGenericIEnumerable.AsIEnumerable(gameModel.GetTowersWithBaseId(TowerType.BananaFarm, false))) { if (TowerModelBehaviorExt.HasBehavior(item, ref val)) { val.autoCollect = true; } } } } public class AutoDepositBanks : ToggleableTweak { [HarmonyPatch(typeof(Bank), "Collect")] internal static class Bank_Collect { [HarmonyPrefix] internal static void Prefix(Bank __instance, ref float __state) { __state = __instance.cash; } [HarmonyPostfix] internal static void Postfix(Bank __instance, float __state) { if (ModContent.GetInstance().Enabled && TowerModelBehaviorExt.HasBehavior(((TowerBehavior)__instance).tower.towerModel) && !(__state < __instance.bankModel.capacity)) { ((RootObject)__instance).Sim.RemoveCash((double)(__state / 2f), (CashType)2, InGame.Bridge.MyPlayerNumber, (CashSource)6); __instance.DepositCash(__state / 2f); } } } protected override bool DefaultEnabled => false; public override string Description => "When making a full collection from a Monkey Bank that has Deposits enabled, half of the amount collected will be automatically deposited back."; protected override string Icon => "1728a8a7ee4434f589617ff0d2672b9c"; } public class BeastHandlerLoneT5s : ToggleableTweak { [HarmonyPatch(typeof(ContributionMutator), "Mutate")] internal static class ContributionMutator_Mutate { [HarmonyPostfix] internal static void Postfix(ContributionMutator __instance, Model model) { TowerModel val = default(TowerModel); if (ModContent.GetInstance().Enabled && __instance.towerBaseId == TowerType.Piranha && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val) && val.tier >= 5 && __instance.power < 84) { ((Model)model.GetDescendant()).GetDescendant().maxGrabBloonName = "Zomg"; } } } private class T5Description : ModTextOverride { private string Upgrade { get; init; } = null; public override string Name => Upgrade; public override string LocalizationKey => Upgrade + " Description"; public override bool Active => ModContent.GetInstance().Enabled; public override string TextValue => StringExt.RegexReplace(((ModTextOverride)this).OriginalText, " Requires.*$", ""); public override IEnumerable Load() { yield return (ModContent)(object)new T5Description { Upgrade = "Megalodon" }; yield return (ModContent)(object)new T5Description { Upgrade = "Giganotosaurus" }; yield return (ModContent)(object)new T5Description { Upgrade = "Pouakai" }; } } public override string DisplayName => "Beast Handler Lone T5s"; protected override bool DefaultEnabled => false; public override string Description => "Allows Tier 5 Beast Handlers to be purchased even without any other Beast Handlers contributing to them.\r\nMegalodon still requires 84 Beast Power to insta kill BAD Bloons."; protected override string Icon => "MonkeyIcons[BeastHandlerIcon]"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } foreach (BeastHandlerPetModel item in ((IEnumerable)MonoLinqHelper.ToArray(gameModel.GetTowersWithBaseId(TowerType.BeastHandler, false))).SelectMany((TowerModel model) => (IEnumerable)MonoLinqHelper.ToArray(((Model)model).GetDescendants())).SelectMany((TowerModel model) => (IEnumerable)MonoLinqHelper.ToArray(((Model)model).GetDescendants()))) { item.requiredCount = 0; } } } public class BetterArmorPiercingDarts : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Makes Monkey Subs with the Armor Piercing Darts upgrade to be able to pop Lead Bloons"; protected override string Icon => "89a459fa46fc4c6419f64888fb30cfa7"; public override void OnNewGameModel(GameModel gameModel) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) foreach (TowerModel item in from model in Il2CppGenericIEnumerable.AsIEnumerable(gameModel.GetTowersWithBaseId(TowerType.MonkeySub, false)) where ((Il2CppArrayBase)(object)model.appliedUpgrades).Contains("Armor Piercing Darts") select model) { DamageModel damageModel = ProjectileModelExt.GetDamageModel(TowerModelExt.GetWeapon(item).projectile); damageModel.immuneBloonProperties = (BloonProperties)(damageModel.immuneBloonProperties & -2); damageModel.immuneBloonPropertiesOriginal = (BloonProperties)(damageModel.immuneBloonPropertiesOriginal & -2); } } } public class BetterCentralMarket : ToggleableTweak { [HarmonyPatch(typeof(CentralMarketBuff), "TestTower")] internal static class CentralMarketBuff_TestTower { [HarmonyPrefix] internal static bool Prefix(CentralMarketBuff __instance, Tower testTower) { if (!ModContent.GetInstance().Enabled) { return true; } TowerModel val = default(TowerModel); if (testTower == ((TowerBehavior)__instance).tower || !Il2CppSystemObjectExt.Is(testTower.towerModel, ref val) || val.CheckSet((TowerSet)8, false)) { return false; } testTower.RemoveMutatorIncludeSubTowers((BehaviorMutator)(object)__instance.mutator); testTower.AddMutatorIncludeSubTowers((BehaviorMutator)(object)__instance.mutator, -1, true, true, false, true, -1); return false; } } [HarmonyPatch(typeof(CentralMarketBuff), "Attatched")] internal static class CentralMarketBuff_Attatched { [HarmonyPrefix] internal static void Prefix(CentralMarketBuff __instance) { if (ModContent.GetInstance().Enabled) { Enumerator enumerator = ((RootObject)__instance).Sim.factory.GetRaw().list.GetEnumerator(); while (enumerator.MoveNext()) { Tower current = enumerator.Current; __instance.TestTower(current, ((TowerBehavior)__instance).tower.towerModel, 0f, 0); } } } } [HarmonyPatch(typeof(CentralMarketMutator), "Mutate")] internal static class CentralMarketMutator_CentralMarketMutator { public class CentralMarketDescription : ModTextOverride { public override string LocalizationKey => "Central Market Description"; public override bool Active => ModContent.GetInstance().Enabled; public override string TextValue => "Earns heaps of money each round and increases income generated by all non-Support towers by 10%."; } [HarmonyPostfix] internal static void Postfix(CentralMarketBuff __instance, Model model, ref bool __result) { if (!ModContent.GetInstance().Enabled) { return; } float multiplier = __instance.centralMarketBuffModel.multiplier; float num = multiplier - 1f; foreach (CashModel item in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item.bonusMultiplier += num; __result = true; } foreach (CashPerTowerInRangeModel item2 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item2.baseCash *= multiplier; for (int i = 0; i < ((Il2CppArrayBase)(object)item2.extraCashPerTier).Count; i++) { Il2CppStructArray extraCashPerTier = item2.extraCashPerTier; int num2 = i; ((Il2CppArrayBase)(object)extraCashPerTier)[num2] = ((Il2CppArrayBase)(object)extraCashPerTier)[num2] * multiplier; } __result = true; } foreach (IncreaseBloonWorthModel item3 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { if (item3.cash > 0f) { item3.cash *= multiplier; } else { item3.cashMultiplier *= multiplier; } __result = true; } foreach (MoabTakedownModel item4 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item4.multiplier *= multiplier; __result = true; } foreach (EatBloonModel item5 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item5.rbeCashMultiplier *= multiplier; __result = true; } foreach (WallOfTreesModel item6 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item6.rbeCashMultiplier *= multiplier; __result = true; } } } protected override bool DefaultEnabled => false; public override string Description => "Makes the Central Market buff affect all non-Support towers' income generation not just Merchantmen."; protected override string Icon => "6b345ca20df5d40308baf66c662f6e33"; } public class BetterEziliTotem : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Makes Ezili's Sacrificial Totem not cost any lives"; protected override string Icon => "6316d713002ae4bfab93838017b598ee"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } for (int i = 7; i <= 20; i++) { TowerModel heroWithNameAndLevel = gameModel.GetHeroWithNameAndLevel(TowerType.Ezili, i, false); AbilityModel val = ((IEnumerable)TowerModelExt.GetAbilities(heroWithNameAndLevel)).FirstOrDefault((Func)((AbilityModel b) => ((Model)b).name.Contains("Totem"))); if (val != null) { val.livesCost = 0; } } } } public class BetterLaserBlasts : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Makes the Laser Blasts upgrade give a minor Attack Speed buff for Super Monkeys. Plasma Blasts unaffected.\r\nRates for 0/0/0, 1/0/0, 2/0/0: .045, 0.45, .03 -> .045, .04, .03"; protected override string Icon => "1e6e95d36ce3cc54ba1920cfa5378360"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } foreach (TowerModel item in ((IEnumerable)Enumerable.ToArray(gameModel.GetTowersWithBaseId(TowerType.SuperMonkey, false))).Where((TowerModel model) => ((Il2CppArrayBase)(object)model.tiers)[0] == 1)) { TowerModel tower = gameModel.GetTower(TowerType.SuperMonkey, 0, ((Il2CppArrayBase)(object)item.tiers)[1], ((Il2CppArrayBase)(object)item.tiers)[2]); TowerModel tower2 = gameModel.GetTower(TowerType.SuperMonkey, 2, ((Il2CppArrayBase)(object)item.tiers)[1], ((Il2CppArrayBase)(object)item.tiers)[2]); float rate = ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(tower).weapons)[0].Rate; float rate2 = ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(tower2).weapons)[0].Rate; ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(item).weapons)[0].Rate = (rate * 2f + rate2) / 3f; } } } public class BetterMonkeyCity : ToggleableTweak { [HarmonyPatch(typeof(MutatorTower), "Mutate")] internal static class MonkeyCityIncomeSupport_Mutate { [HarmonyPostfix] internal static void Postfix(MutatorTower __instance, Model model, ref bool __result) { if (!ModContent.GetInstance().Enabled) { return; } foreach (IncreaseBloonWorthModel item in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { if (item.cash > 0f) { item.cash *= __instance.multiplier; } else { item.cashMultiplier *= __instance.multiplier; } __result = true; } foreach (ImfLoanModel item2 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item2.amount *= __instance.multiplier; item2.imfLoanCollection.amount = item2.amount; __result = true; } foreach (MoabTakedownModel item3 in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { item3.multiplier *= __instance.multiplier; __result = true; } } } protected override bool DefaultEnabled => false; public override string Description => "Makes the Monkey City income buff affect more things, including Lead to Gold, IMF Loan, Monkey-Nomics, Monkey Pirates, and similar effects."; protected override string Icon => "92d1f357799f3407b99ac503dbf8b36f"; } public class BetterTrojan : ToggleableTweak { [HarmonyPatch(typeof(BloonWorthMutator), "Mutate")] internal static class IncreaseBloonWorthWithTierModel_BloonWorthMutator_Mutate { [HarmonyPrefix] internal static void Prefix(Model model, Model baseModel, ref int __state) { BloonModel val = default(BloonModel); BloonModel val2 = default(BloonModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val) && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)baseModel, ref val2)) { __state = val.layerNumber; val.layerNumber = (int)val2.GetTotalLayers(InGame.Bridge.Model); } } [HarmonyPostfix] internal static void Postfix(Model model, ref int __state) { BloonModel val = default(BloonModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val)) { val.layerNumber = __state; } } } protected override bool DefaultEnabled => false; public override string Description => "Makes Benjamin's Bloon Trojan use the real internal layer count for Bloons so that it no longer loses money."; protected override string Icon => "3f5b06699342a46498a873362b0aa85a"; } public class BrickellMermonkeys : ToggleableTweak { protected override bool DefaultEnabled => true; public override string Description => "Makes Brickell's effects apply to non-exclusively water based towers again."; protected override string Icon => "dc1d82f5e96b24e4bab87e09a9f47866"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } FilterTowerByPlaceableAreaModel val = default(FilterTowerByPlaceableAreaModel); foreach (TowerModel item in (Il2CppArrayBase)(object)gameModel.towers) { if (((EntityModel)item).baseId != TowerType.AdmiralBrickell) { continue; } List filters = new List(); Il2CppGenericIEnumerable.ForEach(((Model)item).GetDescendants(), (Action)delegate(Model model) { ActivateRateSupportZoneModel val2 = default(ActivateRateSupportZoneModel); if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val2)) { filters.AddRange((IEnumerable)val2.filters); } ActivatePierceSupportZoneModel val3 = default(ActivatePierceSupportZoneModel); if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val3)) { filters.AddRange((IEnumerable)val3.filters); } ActivateTowerDamageSupportZoneModel val4 = default(ActivateTowerDamageSupportZoneModel); if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val4)) { filters.AddRange((IEnumerable)val4.filters); } ActivateVisibilitySupportZoneModel val5 = default(ActivateVisibilitySupportZoneModel); if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val5)) { filters.AddRange((IEnumerable)val5.filters); } PierceSupportModel val6 = default(PierceSupportModel); if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val6)) { filters.AddRange((IEnumerable)((SupportModel)val6).filters); } }); foreach (TowerFilterModel item2 in filters) { if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)item2, ref val)) { val.exclusive = false; } } } } } public class BuffableParagons : ToggleableTweak { [HarmonyPatch(typeof(Tower), "IsParagonBased")] internal static class Tower_IsParagonBased { [HarmonyPrefix] internal static bool Prefix(ref bool __result) { if (!ModContent.GetInstance().Enabled) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ParagonTower), "Finish")] internal static class ParagonTower_Finish { [HarmonyPostfix] internal static void Postfix(ParagonTower __instance) { if (!ModContent.GetInstance().Enabled) { return; } foreach (Tower item in MonoLinqHelper.ToArray(((RootObject)__instance).Sim.towerManager.GetTowers())) { Action onSuspendedChanged = ((CommonBehaviorProxy)(object)item).onSuspendedChanged; if (onSuspendedChanged != null) { onSuspendedChanged.Invoke(); } } } } [HarmonyPatch(typeof(TapTowerAbilityBehavior), "IsBanned")] internal static class TapTowerAbilityBehavior_IsBanned { [HarmonyPrefix] internal static void Prefix(Tower tower, ref bool __state) { if (ModContent.GetInstance().Enabled) { __state = tower.towerModel.isParagon; tower.towerModel.isParagon = false; } } [HarmonyPostfix] internal static void Postfix(Tower tower, ref bool __state) { if (ModContent.GetInstance().Enabled) { tower.towerModel.isParagon = __state; } } } [HarmonyPatch(typeof(BrewTargetting), "FilterTower")] internal static class BrewTargetting_FilterTower { [HarmonyPrefix] internal static void Prefix(Tower tower, ref bool __state) { if (ModContent.GetInstance().Enabled) { __state = tower.towerModel.isParagon; tower.towerModel.isParagon = false; } } [HarmonyPostfix] internal static void Postfix(Tower tower, ref bool __state) { if (ModContent.GetInstance().Enabled) { tower.towerModel.isParagon = __state; } } } [HarmonyPatch] internal static class TargetFriendly_GetTargets { private static IEnumerable TargetMethods() { yield return MoreAccessTools.SafeGetNestedClassMethod(typeof(TargetFriendly), "GetTargets", "MoveNext", 0); } [HarmonyPrefix] internal static void Prefix(ref Tower[] __state) { if (ModContent.GetInstance().Enabled) { __state = ((IEnumerable)MonoLinqHelper.ToArray(InGame.Bridge.Simulation.factory.GetUncast())).Where((Tower tower) => tower.towerModel.isParagon).ToArray(); Tower[] array = __state; foreach (Tower val in array) { val.towerModel.isParagon = false; } } } [HarmonyPostfix] internal static void Postfix(ref Tower[] __state) { if (ModContent.GetInstance().Enabled) { Tower[] array = __state; foreach (Tower val in array) { val.towerModel.isParagon = true; } } } } [HarmonyPatch(typeof(Tower), "AddParagonMutator")] internal static class Tower_AddParagonMutator { [HarmonyPrefix] internal static bool Prefix(Tower __instance, BehaviorMutator mutator, int time, bool updateDuration, bool applyMutation, bool onlyTimeoutWhenActive, bool useRoundTime, int roundsRemaining) { if (!ModContent.GetInstance().Enabled || !__instance.towerModel.isParagon) { return true; } ((Mutable)__instance).AddMutator(mutator, time, updateDuration, applyMutation, onlyTimeoutWhenActive, useRoundTime, false, false, false, roundsRemaining, false, false); return false; } } [HarmonyPatch(typeof(Tower), "AddParagonMutatorFromParent")] internal static class Tower_AddParagonMutatorFromParent { [HarmonyPrefix] internal static bool Prefix(Tower __instance, BehaviorMutator mutator, int time, bool updateDuration, bool applyMutation, bool onlyTimeoutWhenActive, bool useRoundTime, int roundsRemaining) { if (!ModContent.GetInstance().Enabled || !__instance.towerModel.isParagon) { return true; } __instance.AddMutatorFromParent(mutator, time, updateDuration, applyMutation, onlyTimeoutWhenActive, useRoundTime, roundsRemaining); return false; } } [HarmonyPatch(typeof(Tower), "AddParagonMutatorIncludeSubTowers")] internal static class Tower_AddParagonMutatorIncludeSubTowers { [HarmonyPrefix] internal static bool Prefix(Tower __instance, BehaviorMutator mutator, int time, bool updateDuration, bool applyMutation, bool onlyTimeoutWhenActive, bool useRoundTime, int roundsRemaining) { if (!ModContent.GetInstance().Enabled || !__instance.towerModel.isParagon) { return true; } __instance.AddMutatorIncludeSubTowers(mutator, time, updateDuration, applyMutation, onlyTimeoutWhenActive, useRoundTime, roundsRemaining); return false; } } protected override float RegistrationPriority => -1f; protected override bool DefaultEnabled => false; public override string Description => "Makes Paragons able to receive buffs like normal towers."; protected override string Icon => "Ui[ParagonPip]"; public override void OnNewGameModel(GameModel gameModel) { if (base.Enabled) { Il2CppGenericIEnumerable.ForEach(((Model)gameModel.GetParagonTower(TowerType.BoomerangMonkey)).GetDescendants(), (Action)delegate(SupportModel model) { model.onlyAffectParagon = false; }); } } } public class DartlingGunnerTargeting : ToggleableTweak { [HarmonyPatch(typeof(RotateToPointer), "SetRotation")] internal static class RotateToPointer_SetRotation { [HarmonyPrefix] internal static bool Prefix(RotateToPointer __instance) { Attack attack = ((AttackBehavior)__instance).attack; TargetSupplier val = default(TargetSupplier); if (!ModContent.GetInstance().Enabled || !Il2CppSystemObjectExt.Is(attack.activeTargetSupplier, ref val)) { return true; } bool flag = false; bool flag2 = false; Enumerator enumerator = attack.attackBehaviors.GetEnumerator(); while (enumerator.MoveNext()) { AttackBehavior current = enumerator.Current; flag |= Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)current); flag2 |= Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)current); } if (!flag || !flag2) { return true; } bool flag3 = Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val); return !flag3; } } [HarmonyPatch(typeof(RotateToTarget), "ApplyRotation")] internal static class RotateToTarget_ApplyRotation { [HarmonyPrefix] internal static bool Prefix(RotateToTarget __instance) { Attack attack = ((AttackBehavior)__instance).attack; TargetSupplier val = default(TargetSupplier); if (!ModContent.GetInstance().Enabled || !Il2CppSystemObjectExt.Is(attack.activeTargetSupplier, ref val)) { return true; } bool flag = false; bool flag2 = false; Enumerator enumerator = attack.attackBehaviors.GetEnumerator(); while (enumerator.MoveNext()) { AttackBehavior current = enumerator.Current; flag |= Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)current); flag2 |= Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)current); } if (!flag || !flag2) { return true; } return Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val) || Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val); } } protected override bool DefaultEnabled => true; public override string Description => "Gives all Dartling Gunners First/Last/Close/Strong targeting"; protected override ModSettingCategory Category => TacticalTweaksMod.Targeting; protected override string Icon => "MonkeyIcons[DartlingGunnerIcon]"; protected override string DisableIfModPresent => "MegaKnowledge"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } foreach (TowerModel item in ((IEnumerable)gameModel.towers).Where((TowerModel model) => ((EntityModel)model).baseId == TowerType.DartlingGunner && !((Il2CppArrayBase)(object)model.appliedUpgrades).Contains("Bloon Area Denial System"))) { AttackModel attackModel = TowerModelExt.GetAttackModel(item); bool value = !((Il2CppArrayBase)(object)item.appliedUpgrades).Contains("Ray of Doom") && !((Il2CppArrayBase)(object)item.appliedUpgrades).Contains("Buckshot"); TacticalTweaksMod.UpdatePointer(attackModel, value); TacticalTweaksMod.AddAllTargets(attackModel); item.UpdateTargetProviders(); } } } public class EliteDefenderTargetSwitch : ToggleableTweak { [HarmonyPatch(typeof(Ability), "Activate")] internal static class Ability_Activate { [HarmonyPostfix] internal static void Postfix(Ability __instance) { if (ModContent.GetInstance().Enabled) { AbilityModel abilityModel = __instance.abilityModel; if (((abilityModel != null) ? abilityModel.displayName : null) == "Retaliation") { ((TowerBehavior)__instance).tower.SetTargetType(TargetType.first); } } } } protected override bool DefaultEnabled => false; public override string Description => "An Elite Defender will switch to First targeting after a Bloon leak activates its ability."; protected override string Icon => "c9cb42be6c73344b0bd7757d4201de65"; protected override ModSettingCategory Category => TacticalTweaksMod.Targeting; } public class EtienneTargeting : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Replaces Etienne's targeting options with the standard Fist, Last, Close Strong."; protected override string Icon => "MonkeyIcons[EtienneIcon]"; protected override ModSettingCategory Category => TacticalTweaksMod.Targeting; public override void OnNewGameModel(GameModel gameModel) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //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: Expected O, but got Unknown if (!base.Enabled) { return; } foreach (TowerModel item in Il2CppGenericIEnumerable.AsIEnumerable(gameModel.GetTowersWithBaseId(TowerType.Etienne, false))) { AttackModel attackModel = TowerModelExt.GetAttackModel(item); AttackModelBehaviorExt.RemoveBehaviors(attackModel); AttackModelBehaviorExt.RemoveBehaviors(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetLastModelExt.Create(new Args { isSelectable = true })); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetCloseModelExt.Create(new Args { isSelectable = true })); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetStrongModelExt.Create(new Args { isSelectable = true })); item.UpdateTargetProviders(); } } } public class FixIceMonkeyParagon : TacticalTweak { public override void OnNewGameModel(GameModel gameModel) { TowerModel paragonTower = gameModel.GetParagonTower(TowerType.IceMonkey); AbilityModel ability = TowerModelExt.GetAbility(paragonTower); if (ability != null) { AgeModel descendant = ((Model)ability).GetDescendant(); if (descendant != null) { descendant.rounds = 999999; } } } } public class HeroBoostDebt : ToggleableTweak { [HarmonyPatch(typeof(TowerSelectionMenu), "UpdateHeroBooster")] internal static class TowerSelectionMenu_UpdateHeroBooster { [HarmonyPostfix] internal static void Postfix(TowerSelectionMenu __instance) { if (ModContent.GetInstance().Enabled) { __instance.heroBoosterButtonText.SetText("▼$"); if (IEnumerableExt.OfIl2CppType((IEnumerable)__instance.Bridge.simulation.GetBehaviors().ToArray()).Any()) { ((Selectable)__instance.heroBoosterButton).interactable = false; } } } } [HarmonyPatch(typeof(TowerSelectionMenu), "OnHeroBoosterButtonClicked")] internal static class TowerSelectionMenu_OnHeroBoosterButtonClicked { [HarmonyPrefix] internal static bool Prefix(TowerSelectionMenu __instance) { if (!ModContent.GetInstance().Enabled) { return true; } TowerToSimulation tower = __instance.selectedTower; PopupScreen.instance.ShowPopup((Placement)0, "Hero Boost Debt", $"Do you want to boost to level {tower.hero.level + 1}?\nYou will gain a debt of ${tower.hero.costToLevelUp:N0}", ReturnCallback.op_Implicit((Action)delegate { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0074: 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_009c: Expected O, but got Unknown __instance.Bridge.UpgradeHeroToLevel(tower.Id, Action.op_Implicit((Action)delegate { }), tower.hero.level + 1); Simulation simulation = __instance.Bridge.Simulation; Args val = new Args(); ((ModelArgs)val).name = "HeroBoostDebt"; val.collectionRate = 0.5f; val.amount = tower.hero.costToLevelUp; simulation.AddBehavior((SimulationBehaviorModel)(object)CreateImfLoanCollectionModelExt.Create(val)); __instance.UpdateHeroBooster(tower); }), "Yes", ReturnCallback.op_Implicit((Action)delegate { __instance.UpdateHeroBooster(tower); }), "No", (TransitionAnim)1, (BackGround)0, false, false); return false; } } protected override bool DefaultEnabled => true; public override string Description => "Replaces the Monkey Money Hero Boost with a button that lets you purchase the next level up of the hero by going into debt."; protected override string Icon => "9419ea792c2a1344c8e538f00d4537a5"; } public class MoreUnfreezableTowers : ToggleableTweak { [HarmonyPatch(typeof(ApplyTowerFreeze), "FreezeTower")] internal static class ApplyTowerFreeze_FreezeTower { [HarmonyPrefix] internal static bool Prefix(ApplyTowerFreeze __instance, ObjectId towerID) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!ModContent.GetInstance().Enabled) { return true; } Tower towerById = ((RootObject)__instance).Sim.towerManager.GetTowerById(towerID); TowerModel towerModel = towerById.towerModel; Il2CppStringArray appliedUpgrades = towerModel.appliedUpgrades; int result; if (appliedUpgrades == null || !((Il2CppArrayBase)(object)appliedUpgrades).Contains("Ring of Fire")) { Il2CppStringArray appliedUpgrades2 = towerModel.appliedUpgrades; if (appliedUpgrades2 == null || !((Il2CppArrayBase)(object)appliedUpgrades2).Contains("Signal Flare")) { Il2CppStringArray appliedUpgrades3 = towerModel.appliedUpgrades; if (appliedUpgrades3 == null || !((Il2CppArrayBase)(object)appliedUpgrades3).Contains("Dragon's Breath")) { Il2CppStringArray appliedUpgrades4 = towerModel.appliedUpgrades; if (appliedUpgrades4 == null || !((Il2CppArrayBase)(object)appliedUpgrades4).Contains("Tidal Chill")) { Il2CppStringArray appliedUpgrades5 = towerModel.appliedUpgrades; if ((appliedUpgrades5 == null || !((Il2CppArrayBase)(object)appliedUpgrades5).Contains("The Blazing Sun")) && ((EntityModel)towerModel).baseId != TowerType.Gwendolin) { result = ((towerById.towerSkinName != "Fusty the Snowman") ? 1 : 0); goto IL_00e6; } } } } } result = 0; goto IL_00e6; IL_00e6: return (byte)result != 0; } } [HarmonyPatch(typeof(PyrotechnicsSupportFilter), "FilterTowerModel")] internal static class PyrotechnicsSupportFilter_FilterTowerModel { [HarmonyPostfix] internal static void Postfix(TowerModel towerModel, ref bool __result) { __result |= ((EntityModel)towerModel).baseId == TowerType.Desperado && (((Il2CppArrayBase)(object)towerModel.appliedUpgrades)?.Contains("The Blazing Sun") ?? false); } } protected override bool DefaultEnabled => true; public override string Description => "Fire Towers and certain other Ice Towers also no longer get frozen on Glacial Trail.\r\nThis includes: Gwen (Any Skin), Fusty the Snowman, Ring of Fire Tack Shooters, Dragon's Breath Wizards, Signal Flare Mortar Monkeys, Tidal Chill Mermonkeys, The Blazing Sun."; protected override string Icon => "MapImages[MapSelectGlacialTrailButton]"; } public class MortarMonkeyTargeting : ToggleableTweak { protected override bool DefaultEnabled => true; public override string Description => "Gives all Mortar Monkeys First/Last/Close/Strong targeting"; protected override ModSettingCategory Category => TacticalTweaksMod.Targeting; protected override string Icon => "MonkeyIcons[MortarMonkeyIcon]"; protected override string DisableIfModPresent => "MegaKnowledge"; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } foreach (TowerModel item in ((IEnumerable)gameModel.towers).Where((TowerModel model) => ((EntityModel)model).baseId == TowerType.MortarMonkey)) { AttackModel attackModel = TowerModelExt.GetAttackModel(item); TacticalTweaksMod.AddAllTargets(attackModel); item.towerSelectionMenuThemeId = "ActionButton"; item.UpdateTargetProviders(); } } } public class ObynBuffsGlobal : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Makes Obyn's buff apply to all Druids, not just ones within range."; protected override string Icon => "UiBuffIcons[BuffIconObynLevel11]"; public override void OnNewGameModel(GameModel gameModel) { foreach (TowerModel item in Il2CppGenericIEnumerable.AsIEnumerable(gameModel.GetTowersWithBaseId(TowerType.ObynGreenfoot, false))) { foreach (SupportModel behavior in TowerModelBehaviorExt.GetBehaviors(item)) { behavior.isGlobal = true; } } } } public class ObynPriceTweak : ToggleableTweak { protected override bool DefaultEnabled => false; public override string Description => "Changes Obyn's base price so that he's able to be used as a CHIMPs start like he used to be."; protected override string Icon => "MonkeyIcons[ObynGreenFootIcon]"; public override void OnNewGameModel(GameModel gameModel) { TowerModel towerWithName = gameModel.GetTowerWithName(TowerType.Sauda); foreach (TowerModel item in Il2CppGenericIEnumerable.AsIEnumerable(gameModel.GetTowersWithBaseId(TowerType.ObynGreenfoot, false))) { item.cost = towerWithName.cost; } } } public class OverclockBanks : ToggleableTweak { [HarmonyPatch(typeof(OverclockMutator), "Mutate")] internal static class OverclockMutator_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel)) { Apply(towerModel, __instance.overclockModel.rateModifier); } } } [HarmonyPatch(typeof(OverclockPermanentMutator), "Mutate")] internal static class OverclockPermanentModel_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockPermanentMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel)) { float rateModifier = 1f - (float)__instance.stacks * (1f - __instance.overclockPermanentModel.rateModifier); Apply(towerModel, rateModifier); } } } protected override bool DefaultEnabled => true; public override string Description => "Makes the Overclock buff affect the interest rates of Monkey Banks."; protected override string Icon => "01a32a1a35c684d6a8d137b62d3a7f1b"; protected override ModSettingCategory Category => TacticalTweaksMod.Overclock; public static void Apply(TowerModel towerModel, float rateModifier) { foreach (BankModel item in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item.interest /= rateModifier; } } } public class OverclockMonkeyopolis : ToggleableTweak { [HarmonyPatch(typeof(OverclockMutator), "Mutate")] internal static class OverclockMutator_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel) && !(((EntityModel)towerModel).baseId == TowerType.BananaFarm)) { Il2CppGenericIEnumerable.ForEach(model.GetDescendants(), (Action)delegate(EmissionsPerRoundFilterModel filter) { MonkeyopolisModel val = default(MonkeyopolisModel); int num = (TowerModelBehaviorExt.HasBehavior(towerModel, ref val) ? val.cratesPerRound : filter.count); filter.count = Math.CeilToInt((float)num / __instance.overclockModel.rateModifier); }); } } } [HarmonyPatch(typeof(OverclockPermanentMutator), "Mutate")] internal static class OverclockPermanentModel_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockPermanentMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel) && !(((EntityModel)towerModel).baseId == TowerType.BananaFarm)) { float rateModifier = 1f - (float)__instance.stacks * (1f - __instance.overclockPermanentModel.rateModifier); Il2CppGenericIEnumerable.ForEach(model.GetDescendants(), (Action)delegate(EmissionsPerRoundFilterModel filter) { MonkeyopolisModel val = default(MonkeyopolisModel); int num = (TowerModelBehaviorExt.HasBehavior(towerModel, ref val) ? val.cratesPerRound : filter.count); filter.count = Math.CeilToInt((float)num / rateModifier); }); } } } [HarmonyPatch(typeof(EmissionMutator), "Mutate")] internal static class EmissionMutator_Mutate { [HarmonyPrefix] internal static void Prefix(EmissionMutator __instance, Model model, ref List __state) { __state = ((IEnumerable)Enumerable.ToArray(model.GetDescendants())).Select((EmissionsPerRoundFilterModel filter) => filter.count).ToList(); } [HarmonyPostfix] internal static void Postfix(EmissionMutator __instance, Model model, ref List __state) { foreach (var (val, num) in ((IEnumerable)Enumerable.ToArray(model.GetDescendants())).Zip(__state)) { val.count = Math.Max(num, val.count); } } } protected override bool DefaultEnabled => true; public override string Description => "Makes the Overclock buff affect Monkeyopolis income in the same way it affects Banana Farms."; protected override string Icon => "6bcf8dc34ff294fe5bdf6f358a6eb62f"; protected override ModSettingCategory Category => TacticalTweaksMod.Overclock; } public class OverclockPeriodicAbilities : ToggleableTweak { [HarmonyPatch(typeof(OverclockMutator), "Mutate")] internal static class OverclockMutator_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockMutator __instance, Model model) { if (!ModContent.GetInstance().Enabled) { return; } float rateModifier = __instance.overclockModel.rateModifier; Il2CppGenericIEnumerable.ForEach(model.GetDescendants(), (Action)delegate(ActivateAbilityAfterIntervalModel i) { if (!((Model)i).name.Contains("TechBotify")) { i.interval *= rateModifier; i.intervalFrames = Math.CeilToInt((float)i.intervalFrames * rateModifier); } }); } } [HarmonyPatch(typeof(OverclockPermanentMutator), "Mutate")] internal static class OverclockPermanentModel_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockPermanentMutator __instance, Model model) { if (!ModContent.GetInstance().Enabled) { return; } float rateModifier = 1f - (float)__instance.stacks * (1f - __instance.overclockPermanentModel.rateModifier); Il2CppGenericIEnumerable.ForEach(model.GetDescendants(), (Action)delegate(ActivateAbilityAfterIntervalModel i) { if (!((Model)i).name.Contains("TechBotify")) { i.interval *= rateModifier; i.intervalFrames = Math.CeilToInt((float)i.intervalFrames * rateModifier); } }); } } protected override bool DefaultEnabled => true; public override string Description => "Makes the Overclock buff affect the frequency of periodic ability activations like Carpet of Spikes."; protected override string Icon => "beca93cfa6584443081618415fec9cb0"; protected override ModSettingCategory Category => TacticalTweaksMod.Overclock; } public class OverlockCash : ToggleableTweak { [HarmonyPatch(typeof(OverclockMutator), "Mutate")] internal static class OverclockMutator_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel)) { float rateModifier = __instance.overclockModel.rateModifier; Apply(towerModel, rateModifier); } } } [HarmonyPatch(typeof(OverclockPermanentMutator), "Mutate")] internal static class OverclockPermanentModel_Mutate { [HarmonyPostfix] internal static void Postfix(OverclockPermanentMutator __instance, Model model) { TowerModel towerModel = default(TowerModel); if (ModContent.GetInstance().Enabled && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref towerModel)) { float rateModifier = 1f - (float)__instance.stacks * (1f - __instance.overclockPermanentModel.rateModifier); Apply(towerModel, rateModifier); } } } protected override bool DefaultEnabled => true; public override string Description => "Makes the Overclock buff increase other forms of cash generation for towers such as from end of round or from abilities."; protected override string Icon => "a5a03704d4accd542a39454eba688fb5"; protected override ModSettingCategory Category => TacticalTweaksMod.Overclock; public static void Apply(TowerModel towerModel, float rateModifier) { foreach (PerRoundCashBonusTowerModel item in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item.cashPerRound /= rateModifier; item.cashRoundBonusMultiplier /= rateModifier; } foreach (ImfLoanModel item2 in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item2.amount /= rateModifier; } foreach (CashPerTowerInRangeModel item3 in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item3.baseCash /= rateModifier; for (int i = 0; i < ((Il2CppArrayBase)(object)item3.extraCashPerTier).Count; i++) { Il2CppStructArray extraCashPerTier = item3.extraCashPerTier; int num = i; ((Il2CppArrayBase)(object)extraCashPerTier)[num] = ((Il2CppArrayBase)(object)extraCashPerTier)[num] / rateModifier; } } if (!(((EntityModel)towerModel).baseId != TowerType.BananaFarm) || !(((EntityModel)towerModel).baseId != TowerType.MonkeyVillage)) { return; } foreach (CashModel item4 in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item4.bonusMultiplier += 1f / rateModifier - 1f; } } } public class ParagonSentryTargeting : ToggleableTweak { protected override bool DefaultEnabled => true; public override string Description => "Gives the Master Builder's Green Sentry First/Last/Close/Strong/Locked targeting."; protected override ModSettingCategory Category => TacticalTweaksMod.Targeting; protected override string Icon => "b22553f1b304d274d9ea350eece10cce"; public override void OnNewGameModel(GameModel gameModel) { if (base.Enabled) { TowerModel paragonTower = gameModel.GetParagonTower(TowerType.EngineerMonkey); TowerModel val = ModelExt.FindDescendant((Model)(object)paragonTower, TowerType.SentryParagonGreen); AttackModel attackModel = TowerModelExt.GetAttackModel(val); TacticalTweaksMod.UpdatePointer(attackModel, false); TacticalTweaksMod.AddAllTargets(attackModel); val.UpdateTargetProviders(); } } } public class PeriodicCooldownReduction : ToggleableTweak { [HarmonyPatch(typeof(MutatorTower), "BuffTowerModel")] internal static class AbilityCooldownScaleSupport_BuffTowerModel { [HarmonyPostfix] internal static void Postfix(MutatorTower __instance, TowerModel towerModel) { if (ModContent.GetInstance().Enabled) { Il2CppGenericIEnumerable.ForEach(((Model)towerModel).GetDescendants(), (Action)delegate(ActivateAbilityAfterIntervalModel i) { i.interval /= __instance.abilityCooldownSpeedScale; i.intervalFrames = Math.CeilToInt((float)i.intervalFrames / __instance.abilityCooldownSpeedScale); }); } } } protected override bool DefaultEnabled => true; public override string Description => "Makes ability cooldown reduction effects also apply to periodically activated abilities like Carpet of Spikes."; protected override string Icon => "beca93cfa6584443081618415fec9cb0"; } public class PursuitPathPrioritization : ToggleableTweak { [HarmonyPatch(typeof(PursuitSetting), "GetPursuitTarget")] internal static class PursuitSetting_GetPursuitTarget { [HarmonyPrefix] internal static bool Prefix(PursuitSetting __instance, ref Target? __result) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown HeliMovement heliMovement = __instance.heliMovement; if (((heliMovement != null) ? ((TowerBehavior)heliMovement).tower : null) == null || !PathSelections.TryGetValue(((RootObject)((TowerBehavior)__instance.heliMovement).tower).Id, out List value)) { return true; } Path[] currentPaths = (from p in value select ((RootObject)__instance).Sim.Map.pathManager.GetPath(p) into p where p.hasBloons || p.hasOfftrackBloons select p).ToArray(); if (!ArrayExt.Any(currentPaths)) { return true; } __result = ((IEnumerable)MonoLinqHelper.ToArray(((Il2CppObjectBase)((PathSupplierHeli)__instance).Targets(99999f)).Cast>())).FirstOrDefault((Func)delegate(Target target) { PathSegment pathSegment = target.pathSegment; object obj = ((pathSegment != null) ? pathSegment.path : null); if (obj == null) { Bloon bloon = target.bloon; obj = ((bloon != null) ? bloon.path : null); } Path val = (Path)obj; return val != null && (currentPaths.Contains(val) || val.def.pathId.Contains("Boss")); }); if (__result == null) { __result = new Target(); } return false; } } public class PursuitTsmTheme : ModTsmTheme { private TSMButton button = null; private static readonly Dictionary Dots = new Dictionary(); public override string BaseTheme => "HeliPilot"; public override void SetupTheme(BaseTSMTheme theme) { //IL_001c: 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) button = GameObjectExt.AddTSMButton(((Component)theme).gameObject, new Info("PursuitButton", 372f, -428f, 180f), "Ui[GreenBtnSquare]", "PursuitButton", ModContent.GetId()); GameObjectExt.AddImage(((Component)button).gameObject, new Info("Icon", 128f), "3d08be8876462204d9702b4259d9828e"); } public override void TowerChanged(BaseTSMTheme theme, TowerToSimulation tower) { PursuitSetting behaviorInDependants = ((RootBehavior)tower.tower).Entity.GetBehaviorInDependants(); if (behaviorInDependants == null) { ((Component)button).gameObject.SetActive(false); return; } ((Component)button).gameObject.SetActive(true); if (!Dots.Any()) { StartDrawing(); } } public override void OnDisable(BaseTSMTheme theme) { StopDrawing(); } private static void StartDrawing() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) Simulation current = SimulationExt.Current; Enumerator enumerator = current.Map.pathManager.paths.GetEnumerator(); while (enumerator.MoveNext()) { Path current2 = enumerator.Current; if (!current2.isActive || current2.def.pathId.Contains("Boss")) { continue; } foreach (PathSegment item in (Il2CppArrayBase)(object)current2.segments) { Entity val = current.factory.Create(); val.AddBehaviorFromModel((Model)(object)CreateTransformModelExt.Create(new Args { position = new Vector3(item.point.x, item.point.y, item.pointHeight) }), false); DisplayBehavior val2 = ((Il2CppObjectBase)val.AddBehaviorFromModel((Model)(object)CreateDisplayModelExt.Create(), false)).Cast(); val2.SetScaleOffset(Vector3.zero); Dots[val] = current2.def.pathId; } } } private static void StopDrawing() { foreach (Entity key in Dots.Keys) { ((RootObject)key).Destroy(); } Dots.Clear(); } public override void Update(BaseTSMTheme theme) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown if (!Dots.Any()) { return; } InputManager val = InGameExt[InGame.instance]; bool flag = ModCustomInput.ActiveInput is PursuitCustomInput; object obj; if (!flag) { obj = TowerSelectionMenuExt.instance.selectedTower; } else { CustomInput customInput = val.customInput; obj = ((customInput != null) ? customInput.tower : null); } TowerToSimulation val2 = (TowerToSimulation)obj; object obj2; if (!flag) { obj2 = null; } else { PathSegment? path = PursuitCustomInput.GetPath(val.CursorPositionWorld); if (path == null) { obj2 = null; } else { Path path2 = path.path; obj2 = ((path2 != null) ? path2.def.pathId : null); } } string text = (string)obj2; List list = ((val2 == null) ? new List() : PathSelections.GetValueOrDefault(val2.Id, new List())); foreach (KeyValuePair dot in Dots) { dot.Deconstruct(out var key, out var value); Entity val3 = key; string text2 = value; DisplayBehavior displayBehavior = val3.GetDisplayBehavior(); displayBehavior.SetScaleOffset(Vector3.one * (float)((val2 != null && (list.Contains(text2) || flag)) ? 1 : 0)); PrefabReference display = displayBehavior.displayModel.display; string text3 = ((display != null) ? display.AssetGUID : null); string text4 = "f6e4526492bc9164baac0dd1058077f2"; if (flag) { bool flag2 = text == text2; bool flag3 = list.Contains(text2); if (flag2 && flag3) { text4 = "15a96ce311133ec46b824e88f291a255"; } else if (!flag2 && !flag3) { text4 = "505654c2ff7054e49900a08b16f67bde"; } } if (text3 != text4) { displayBehavior.displayModel.display = new PrefabReference(text4); ((RootBehavior)displayBehavior).UpdatedModel((Model)(object)displayBehavior.displayModel); } } } } public class PursuitCustomInput : ModCustomInput { public override string GetHelperMessage(CustomInput customInput) { return "Prioritize pursuing specific path(s)"; } public static PathSegment? GetPath(Vector2 cursorPosWorld) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return SimulationExt.Current.map.pathManager.FirstPathSegmentInRangeOrDefault(new Vector2(cursorPosWorld), 10f, false, false, false); } public override bool IsPositionValid(CustomInput customInput, Vector2 cursorPosWorld, bool isCursorInWorld) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) return isCursorInWorld && GetPath(cursorPosWorld) != null; } public override void OnValidPositionCursorUp(CustomInput customInput, Vector2 cursorPosWorld, bool isCursorInWorld) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_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) string pathId = GetPath(cursorPosWorld).path.def.pathId; if (!PathSelections.TryGetValue(customInput.tower.Id, out List value)) { value = new List(); PathSelections.Add(customInput.tower.Id, value); } if (value.Contains(pathId)) { value.Remove(pathId); } else { value.Add(pathId); } ((ModCustomInput)this).OnValidPositionCursorUp(customInput, cursorPosWorld, isCursorInWorld); } public override void Update(CustomInput customInput, Vector3 cursorPosUnityWorld, Vector2 cursorPosWorld, bool isCursorActive) { //IL_000f: 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) if (isCursorActive) { PathSegment? path = GetPath(cursorPosWorld); string text = ((path != null) ? path.path.def.pathId : null); string text2 = ((ModCustomInput)this).GetHelperMessage(customInput); List valueOrDefault = PathSelections.GetValueOrDefault(customInput.tower.Id, new List()); if (text != null) { text2 = (valueOrDefault.Contains(text) ? ("Stop prioritizing " + text) : ("Start prioritizing " + text)); } customInput.inputManager.SetHelperMessage(text2, -1f); } } } public static readonly Dictionary> PathSelections = new Dictionary>(); protected override bool DefaultEnabled => true; protected override string Icon => "3d08be8876462204d9702b4259d9828e"; public override string Description => "Allows Heli Pilots to choose to prioritize Bloons on specific paths."; public override void OnNewGameModel(GameModel gameModel) { if (!base.Enabled) { return; } foreach (TowerModel item in ((IEnumerable)MonoLinqHelper.ToArray(gameModel.GetTowersWithBaseId(TowerType.HeliPilot, false))).Where((TowerModel model) => ((Il2CppArrayBase)(object)model.appliedUpgrades)?.Contains("Pursuit") ?? false)) { item.towerSelectionMenuThemeId = ModContent.GetId(); } } public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (PathSelections.TryGetValue(((RootObject)tower).Id, out List value)) { saveData.metaData[((ModContent)this).Id] = JsonConvert.SerializeObject((object)value); } } public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) string text = default(string); if (saveData.metaData.TryGetValue(((ModContent)this).Id, ref text)) { PathSelections[((RootObject)tower).Id] = JsonConvert.DeserializeObject>(text) ?? new List(); } } public override void OnGameObjectsReset() { PathSelections.Clear(); } } public class StickyBombAttackSpeed : ToggleableTweak { [HarmonyPatch(typeof(Tower), "OnUpgraded")] internal static class Tower_OnUpgraded { [HarmonyPostfix] internal static void Postfix(Tower __instance) { Apply(__instance); } } [HarmonyPatch(typeof(Tower), "OnPlace")] internal static class Tower_OnPlace { [HarmonyPostfix] internal static void Postfix(Tower __instance) { Apply(__instance); } } [HarmonyPatch(typeof(RateSupportMutator), "Mutate")] internal static class RateSupportMutator_Mutate { [HarmonyPrefix] internal static bool Prefix(RateSupportMutator __instance, Model baseModel, Model model, ref bool __result) { TowerModel val = default(TowerModel); TowerModel val2 = default(TowerModel); if (((BehaviorMutator)__instance).id != "StickyBombAttackSpeed" || !Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)baseModel, ref val) || !Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val2) || !ModContent.GetInstance().Enabled) { return true; } IEnumerable enumerable = Il2CppGenericIEnumerable.AsIEnumerable(((Model)val2).GetDescendants()).Where(delegate(AddBehaviorToBloonModel m) { switch (m.mutationId) { case "StickyBomb": case "MasterSticky": case "StickyBombSplash": return true; default: return false; } }); float rate = ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(val).weapons)[0].Rate; float rate2 = ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(val2).weapons)[0].Rate; float num = rate2 / rate; foreach (AddBehaviorToBloonModel item in enumerable) { item.lifespan *= num; if (item.lifespan < 0.05f) { item.lifespan = 0.05f; } item.lifespanFrames = (int)(item.lifespan * 60f); foreach (DamageOverTimeModel behavior in AddBehaviorToBloonModelBehaviorExt.GetBehaviors(item)) { behavior.Interval = item.lifespan - 0.02f; } foreach (ProjectileOverTimeModel behavior2 in AddBehaviorToBloonModelBehaviorExt.GetBehaviors(item)) { behavior2.Interval = item.lifespan - 0.02f; } } __result = true; return false; } } protected override bool DefaultEnabled => false; public override string Description => "Makes attack speed buffs cause Sticky Bombs to blow up quicker. (Also affects Master Bomber)"; protected override string Icon => "a61263630220b41b4a578114cc55cfe9"; public static void Apply(Tower? tower) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown if (((tower != null) ? tower.towerModel : null) != null && ModContent.GetInstance().Enabled) { Il2CppStringArray appliedUpgrades = tower.towerModel.appliedUpgrades; if (appliedUpgrades != null && ((Il2CppArrayBase)(object)appliedUpgrades).Contains("Sticky Bomb") && !((Mutable)tower).IsMutatedBy("StickyBombAttackSpeed")) { ((Mutable)tower).AddMutator((BehaviorMutator)new RateSupportMutator(true, "StickyBombAttackSpeed", 1f, -100, (BuffIndicatorModel)null, false, (DisplayModel)null) { cantBeAbsorbed = true }, -1, true, true, false, true, false, false, false, -1, false, false); } } } } }