using System; 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.Display; using BTD_Mod_Helper.Api.ModOptions; using BTD_Mod_Helper.Api.Towers; using BTD_Mod_Helper.Extensions; using HarmonyLib; using Il2Cpp; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Models.GenericBehaviors; using Il2CppAssets.Scripts.Models.Towers; using Il2CppAssets.Scripts.Models.Towers.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.Behaviors.Emissions.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Projectiles; using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Weapons; using Il2CppAssets.Scripts.Models.Towers.Weapons.Behaviors; using Il2CppAssets.Scripts.Simulation.Objects; using Il2CppAssets.Scripts.Simulation.SMath; using Il2CppAssets.Scripts.Simulation.Towers; using Il2CppAssets.Scripts.Simulation.Towers.Behaviors.Attack; using Il2CppAssets.Scripts.Simulation.Towers.Projectiles; using Il2CppAssets.Scripts.Simulation.Towers.Projectiles.Behaviors; using Il2CppAssets.Scripts.Simulation.Towers.Weapons; using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.Bridge; using Il2CppAssets.Scripts.Unity.Display; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu.TowerSelectionMenuThemes; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppNinjaKiwi.Common.ResourceUtils; using Il2CppSystem.IO; using MelonLoader; using Microsoft.CodeAnalysis; using MiniCrosspaths; using MiniCrosspaths.DoubleRangaBoomers; using Newtonsoft.Json.Linq; using PathsPlusPlus; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(MiniCrosspathsMod), "Mini Crosspaths", "1.0.1", "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("MiniCrosspaths")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a7b4adbcd1f2cd99c8f71c4efde5806cafe0863a")] [assembly: AssemblyProduct("MiniCrosspaths")] [assembly: AssemblyTitle("MiniCrosspaths")] [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 MiniCrosspaths { public class MiniCrosspathsMod : BloonsTD6Mod { } public static class ModHelperData { public const string WorksOnVersion = "55.0"; public const string Version = "1.0.1"; public const string Name = "Mini Crosspaths"; public const string Description = "Adds a number of mini two-upgrade Paths++ paths for towers. \nMany are based on old BTD game features / my favorite features that I've implemented in other mods such as Mega Knowledge or Rogue Remix, others are brand new.\nThis makes them available in a balanced way in regular games, making you pay a fair price and consider the crosspathing tradeoffs (unless you have Paths++ Balanced Mode turned off)."; public const string RepoOwner = "doombubbles"; public const string PrevRepoName = "mini-crosspaths"; public const string RepoName = "MiniCrosspaths"; public const string Dependencies = "doombubbles/PathsPlusPlus"; } } namespace MiniCrosspaths.SplodeyDartMonkeys { public class HeatTippedArrow : HeatTippedDisplay { public override int Tier => 3; } public class HeatTippedBolt : HeatTippedDisplay { public override int Tier => 4; } public class HeatTippedDart : HeatTippedDisplay { public override int Tier => 0; } public class HeatTippedDarts : UpgradePlusPlus { public override int Cost => 125; public override int Tier => 1; public override string Description => "Heat tipped darts allow the Dart Monkey to pop Frozen and Lead Bloons."; public override void ApplyUpgrade(TowerModel towerModel) { Il2CppGenericIEnumerable.ForEach(((Model)towerModel).GetDescendants(), (Action)delegate(DamageModel damage) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0033: 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) damage.immuneBloonProperties = (BloonProperties)(damage.immuneBloonProperties & -17); damage.immuneBloonProperties = (BloonProperties)(damage.immuneBloonProperties & -2); damage.immuneBloonPropertiesOriginal = (BloonProperties)(damage.immuneBloonPropertiesOriginal & -17); damage.immuneBloonPropertiesOriginal = (BloonProperties)(damage.immuneBloonPropertiesOriginal & -2); }); ProjectileModel dart = ((Model)towerModel).GetDescendant(); foreach (HeatTippedDisplay item in from heatTippedDisplay in ModContent.GetContent() where dart.display == ((ModDisplay)heatTippedDisplay).BaseDisplayReference select heatTippedDisplay) { ((ModDisplay)item).Apply(dart); } } } public abstract class HeatTippedDisplay : ModDisplay { public abstract int Tier { get; } public override PrefabReference BaseDisplayReference => ((Model)Game.instance.model.GetTower(TowerType.DartMonkey, 0, 0, Tier)).GetDescendant().display; public override void ModifyDisplayNode(UnityDisplayNode node) { UnityDisplayNodeExt.GetSpriteRenderer(node, 0, true).sprite = ((ModContent)this).GetSprite(((ModContent)this).Name, 10f); } } public class SplodeyDartMonkeysPath : PathPlusPlus { public override string Tower => TowerType.DartMonkey; } public class SplodeyDarts : UpgradePlusPlus { public override int Cost => 400; public override int Tier => 2; public override string Description => "Projectiles will create a small explosion the first time they collide with a Bloon."; public override string DetailedDescription => "Explosions have the same pierce as the projectile, and the same base damage (but unaffected by damage modifiers)."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown //IL_0181: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_01b5: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_01d7: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Expected O, but got Unknown //IL_01f9: Expected O, but got Unknown //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected O, but got Unknown //IL_021b: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Expected O, but got Unknown //IL_023d: Expected O, but got Unknown //IL_0248: Expected O, but got Unknown ((UpgradePlusPlus)this).ApplyUpgrade(towerModel); DamageModel val = default(DamageModel); foreach (ProjectileModel item in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { if (ProjectileModelBehaviorExt.HasBehavior(item) && ProjectileModelBehaviorExt.HasBehavior(item, ref val)) { Args val2 = new Args(); ((ModelArgs)(object)val2).name = "SplodeyDarts"; val2.emission = (EmissionModel)(object)CreateSingleEmissionModelExt.Create(); Args val3 = new Args(); ((ModelArgs)(object)val3).name = "Splosion"; val3.pierce = item.pierce; val3.radius = 10f; val3.ignoreBlockers = true; val3.behaviors = (Model[])(object)new Model[2] { (Model)CreateDamageModelExt.Create(new Args { damage = val.damage, maxDamage = val.damage, immuneBloons = (BloonProperties)((towerModel.tier != 5) ? 2 : 0) }), (Model)CreateAgeModelExt.Create(new Args { lifespan = 0.1f }) }; val3.CanHitCamo = ((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("Enhanced Eyesight"); val2.projectile = CreateProjectileModelExt.Create(val3); ProjectileModelBehaviorExt.AddBehavior(item, CreateCreateProjectileOnContactModelExt.Create(val2)); Args val4 = new Args(); ((ModelArgs)val4).name = "SplodeyDarts"; val4.effectModel = CreateEffectModelExt.Create(new Args { assetId = new PrefabReference("6d84b13b7622d2744b8e8369565bc058"), lifespan = 2f }); ProjectileModelBehaviorExt.AddBehavior(item, CreateCreateEffectOnContactModelExt.Create(val4)); Args val5 = new Args(); ((ModelArgs)val5).name = "SplodeyDarts"; val5.sound1 = CreateSoundModelExt.Create(new Args { assetId = new AudioClipReference("ec9a5a7531a750e4c82bf8429e0812e4") }); val5.sound2 = CreateSoundModelExt.Create(new Args { assetId = new AudioClipReference("57fac571daa668140b0674eb515f9586") }); val5.sound3 = CreateSoundModelExt.Create(new Args { assetId = new AudioClipReference("5b1ee796433122141a0db034af251f15") }); val5.sound4 = CreateSoundModelExt.Create(new Args { assetId = new AudioClipReference("f5f616027b9887c4db5b1341a614b352") }); val5.sound5 = CreateSoundModelExt.Create(new Args { assetId = new AudioClipReference("9a36e64ca09a7ef42bd4af49c1cf4ef6") }); ProjectileModelBehaviorExt.AddBehavior(item, CreateCreateSoundOnProjectileCollisionModelExt.Create(val5)); } } } } [HarmonyPatch] internal static class CreateProjectileOnContact_Collide { private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(CreateProjectileOnContact), "Collide", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(CreateProjectileOnContact), "CollideMap", (Type[])null, (Type[])null); } [HarmonyPrefix] internal static bool Prefix(CreateProjectileOnContact __instance) { return ((ProjectileBehavior)__instance).projectile == null || !((Model)__instance.createProjectileOnContactModel).name.Contains("SplodeyDarts") || ((ProjectileBehavior)__instance).projectile.collidedWith.Count <= 1; } } [HarmonyPatch] internal static class CreateEffectOnContact_Collide { private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(CreateEffectOnContact), "Collide", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(CreateEffectOnContact), "CollideMap", (Type[])null, (Type[])null); } [HarmonyPrefix] internal static bool Prefix(CreateEffectOnContact __instance) { return ((ProjectileBehavior)__instance).projectile == null || !((Model)__instance.createEffectOnContactModel).name.Contains("SplodeyDarts") || ((ProjectileBehavior)__instance).projectile.collidedWith.Count <= 1; } } [HarmonyPatch] internal static class CreateSoundOnProjectileCollision_ { private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(CreateSoundOnProjectileCollision), "Collide", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(CreateSoundOnProjectileCollision), "CollideMap", (Type[])null, (Type[])null); } [HarmonyPrefix] internal static bool Prefix(CreateSoundOnProjectileCollision __instance) { return ((ProjectileBehavior)__instance).projectile == null || !((Model)__instance.createSoundOnProjectileCollisionModel).name.Contains("SplodeyDarts") || ((ProjectileBehavior)__instance).projectile.collidedWith.Count <= 1; } } } namespace MiniCrosspaths.LaserRangBoomers { public class LaserRangBoomersPath : PathPlusPlus { public override string Tower => TowerType.BoomerangMonkey; } public class LaserRangs : UpgradePlusPlus { public override int Cost => 250; public override int Tier => 1; public override string Description => "Now throws Laser-Rangs, gaining increased pierce and projectile speed."; public override string DetailedDescription => "Projectiles can longer pop Purple Bloons, but travel 25% faster and have pierce increased by +4 or x1.5, whichever is higher, with MOAB press getting a flat +60."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) ProjectileModel descendant = ((Model)TowerModelExt.GetAttackModel(towerModel)).GetDescendant(); foreach (ProjectileModel item in MonoLinqHelper.ToArray(((Model)towerModel).GetDescendants())) { if (ProjectileModelBehaviorExt.HasBehavior(item)) { item.pierce = Math.Max(item.pierce + 4f, (int)(item.pierce * 1.5f)); } } DamageModel damageModel = ProjectileModelExt.GetDamageModel(descendant); if (towerModel.tier < 5) { damageModel.immuneBloonProperties = (BloonProperties)(damageModel.immuneBloonProperties | 8); damageModel.immuneBloonPropertiesOriginal = (BloonProperties)(damageModel.immuneBloonPropertiesOriginal | 8); } FollowPathModel val = default(FollowPathModel); TravelStraitModel val2 = default(TravelStraitModel); if (ProjectileModelBehaviorExt.HasBehavior(descendant, ref val)) { FollowPathModel obj = val; obj.Speed *= 1.25f; } else if (ProjectileModelBehaviorExt.HasBehavior(descendant, ref val2)) { TravelStraitModel obj2 = val2; obj2.Speed *= 1.25f; } if (((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("MOAB Press")) { ProjectileModel descendant2 = ((Model)TowerModelExt.GetAttackModel(towerModel, "MOABPress")).GetDescendant(); descendant2.pierce += 60f; } PrefabReference display = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.SuperMonkey, 1, 0, ((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("Glaives") ? 4 : 3))).GetDescendant().display; ProjectileModelExt.SetDisplay(descendant, display); OrbitModel val3 = default(OrbitModel); if (TowerModelBehaviorExt.HasBehavior(towerModel, ref val3)) { ProjectileModelExt.ApplyDisplay(val3.projectile); } AddBehaviorToBloonModel val4 = default(AddBehaviorToBloonModel); if (ModelExt.HasDescendant((Model)(object)towerModel, ref val4)) { val4.parentDamageModel = null; ((Model)val4).RemoveChildDependant(val4.parentDamageModel); } } } public class LaserOrbit : ModDisplay { private static readonly int TintColor = Shader.PropertyToID("_TintColor"); public override PrefabReference BaseDisplayReference => TowerModelBehaviorExt.GetBehavior(Game.instance.model.GetTower(TowerType.BoomerangMonkey, 5, 0, 0)).projectile.display; public override void ModifyDisplayNodeAsync(UnityDisplayNode node, Action onComplete) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) ((Renderer)((Component)node).GetComponentInChildren()).material.SetColor(TintColor, new Color(1f, 0.10980392f, 0f, 0.5f)); PrefabReference display = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.SuperMonkey, 1, 0, 4))).GetDescendant().display; ((ModDisplay)this).UseNode(display.AssetGUID, (Action)delegate(UnityDisplayNode displayNode) { UnityDisplayNodeExt.GetRenderer(node, true).sprite = UnityDisplayNodeExt.GetRenderer(displayNode, true).sprite; node.RecalculateGenericRenderers(); onComplete(); }); } } public class PlasmaRangs : UpgradePlusPlus { public override int Cost => 350; public override int Tier => 2; public override string Description => "Upgrades to Plasma-Rangs, attacking even faster."; public override string DetailedDescription => "Can pop Frozen and Lead Bloons. Fire rate for all weapons is 50% faster, including Glaive-Lord orbital damage."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_011a: 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_012b: Unknown result type (might be due to invalid IL or missing references) ProjectileModel descendant = ((Model)TowerModelExt.GetAttackModel(towerModel)).GetDescendant(); DamageModel damageModel = ProjectileModelExt.GetDamageModel(descendant); damageModel.immuneBloonProperties = (BloonProperties)(damageModel.immuneBloonProperties & -18); damageModel.immuneBloonPropertiesOriginal = (BloonProperties)(damageModel.immuneBloonPropertiesOriginal & -18); foreach (WeaponModel item in DoubleRangaBoomersPath.BoomerAttacks(towerModel).SelectMany((AttackModel attack) => (IEnumerable)attack.weapons)) { item.Rate /= 1.5f; } PrefabReference display = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.SuperMonkey, 2, 0, ((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("Glaives") ? 4 : 3))).GetDescendant().display; ProjectileModelExt.SetDisplay(descendant, display); OrbitModel val = default(OrbitModel); if (TowerModelBehaviorExt.HasBehavior(towerModel, ref val)) { ProjectileModelExt.ApplyDisplay(val.projectile); DamageModel descendant2 = ((Model)TowerModelExt.GetAttackModel(towerModel, "Orbit")).GetDescendant(); descendant2.immuneBloonProperties = (BloonProperties)(descendant2.immuneBloonProperties & -18); descendant2.immuneBloonPropertiesOriginal = (BloonProperties)(descendant2.immuneBloonPropertiesOriginal & -18); } } } public class PlasmaOrbit : ModDisplay { private static readonly int TintColor = Shader.PropertyToID("_TintColor"); public override PrefabReference BaseDisplayReference => TowerModelBehaviorExt.GetBehavior(Game.instance.model.GetTower(TowerType.BoomerangMonkey, 5, 0, 0)).projectile.display; public override void ModifyDisplayNodeAsync(UnityDisplayNode node, Action onComplete) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) ((Renderer)((Component)node).GetComponentInChildren()).material.SetColor(TintColor, new Color(77f / 85f, 0f, 1f, 0.5f)); PrefabReference display = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.SuperMonkey, 2, 0, 4))).GetDescendant().display; ((ModDisplay)this).UseNode(display.AssetGUID, (Action)delegate(UnityDisplayNode displayNode) { UnityDisplayNodeExt.GetRenderer(node, true).sprite = UnityDisplayNodeExt.GetRenderer(displayNode, true).sprite; node.RecalculateGenericRenderers(); onComplete(); }); } } } namespace MiniCrosspaths.InstantBombShooters { public class InstantBombShootersPath : PathPlusPlus { public override string Tower => TowerType.BombShooter; } public class PrecisionMunition : UpgradePlusPlus { [HarmonyPatch(typeof(Weapon), "CalcRateFrames")] internal static class Weapon_CalcRateFrames { [HarmonyPostfix] internal static void Postfix(Weapon __instance) { //IL_003b: 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_0049: Unknown result type (might be due to invalid IL or missing references) if (!((Model)__instance.weaponModel).name.Contains("PrecisionMunition")) { return; } Projectile val = Il2CppGenerics.FirstOrDefault(__instance.newProjectiles); if (val != null && ((CommonBehaviorProxy)(object)val).target != null) { Vector3 ejectPosition = __instance.GetEjectPosition(true); float num = ((Vector3)(ref ejectPosition)).Distance(((CommonBehaviorProxy)(object)val).target.Position); if (num / ((TowerBehavior)((AttackBehavior)__instance).attack).tower.towerModel.range > 2f) { __instance.rateFrames = (int)((float)__instance.rateFrames * 1.3f); } } } } public override int Cost => 500; public override int Tier => 2; public override string Description => "Can hit Bloons it can see anywhere on screen. Attacks 30% slower for very far away Bloons."; public override string DetailedDescription => "Gains global effective range. If Bloons are further than twice the original displayed range, attacks 30% slower."; public override void ApplyUpgrade(TowerModel towerModel) { towerModel.isGlobalRange = true; } } public class QuantumPayload : UpgradePlusPlus { public override int Cost => 150; public override int Tier => 1; public override string Description => "Bombs explode instantly at the target's location with no travel time."; public override void ApplyUpgrade(TowerModel towerModel, int tier) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown AlternateProjectileModel val3 = default(AlternateProjectileModel); foreach (AttackModel item in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { WeaponModel val = ((Il2CppArrayBase)(object)item.weapons)[0]; ProjectileModel val2 = ((val != null) ? val.projectile : null); if (val != null && val2 != null && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)val.emission) && ProjectileModelBehaviorExt.HasBehavior(val2) && Mathf.Approximately(val2.maxPierce, 1f)) { if (tier > 1) { item.range = 999999f; ModelExt.SetName(val, ((Model)val).name + "_PrecisionMunition"); } WeaponModelExt.SetEmission(val, (EmissionModel)(object)CreateInstantDamageEmissionModelExt.Create()); ProjectileModelBehaviorExt.RemoveBehavior(val2); ProjectileModelBehaviorExt.RemoveBehavior(val2); ProjectileModelBehaviorExt.AddBehavior(val2, CreateInstantModelExt.Create()); ProjectileModelBehaviorExt.AddBehavior(val2, CreateAgeModelExt.Create(new Args { lifespan = 0.1f })); if (Il2CppSystemObjectExt.Is(WeaponModelBehaviorExt.GetBehavior(val), ref val3)) { ((Model)val3).RemoveChildDependant(val3.emissionModel); val3.emissionModel = (EmissionModel)(object)CreateInstantDamageEmissionModelExt.Create(); ((Model)val3).AddChildDependant(val3.emissionModel); ProjectileModelBehaviorExt.RemoveBehavior(val3.projectile); ProjectileModelBehaviorExt.RemoveBehavior(val3.projectile); ProjectileModelBehaviorExt.AddBehavior(val2, CreateInstantModelExt.Create()); ProjectileModelBehaviorExt.AddBehavior(val2, CreateAgeModelExt.Create(new Args { lifespan = 0.1f })); } } } } } } namespace MiniCrosspaths.HoverPlaneAces { public class HoverPlane : UpgradePlusPlus { public override int Cost => 600; public override int Tier => 1; public override string Description => "Now longer flies in paths, instead hovering wherever you direct it."; public override string DetailedDescription => "Replaces all default movement with Heli Pilot style movement."; public override void ApplyUpgrade(TowerModel towerModel, int tier) { if (ModelExt.HasDescendant((Model)(object)towerModel)) { return; } TowerModel tower = Game.instance.model.GetTower(TowerType.HeliPilot, 0, 0, 0); TowerModel tower2 = Game.instance.model.GetTower(TowerType.HeliPilot, 2, 0, 0); AirUnitModel behavior = TowerModelBehaviorExt.GetBehavior(towerModel); List behaviors = TowerModelBehaviorExt.GetBehaviors(towerModel); HeliMovementModel val = ModelExt.Duplicate(((Model)tower).GetDescendant()); val.maxSpeed = AirUnitModelBehaviorExt.GetBehavior(behavior).speed; val.tiltAngle = 0f; AirUnitModelBehaviorExt.RemoveBehavior(behavior); AirUnitModelBehaviorExt.AddBehavior(behavior, val); bool flag = true; bool flag2 = tier > 1; PursuitSettingModel val2 = default(PursuitSettingModel); foreach (AttackModel item in behaviors.OrderBy((AttackModel model) => ((Model)model).name.Length)) { item.fireWithoutTarget = false; item.range = 99999f; foreach (WeaponModel item2 in (Il2CppArrayBase)(object)item.weapons) { item2.fireWithoutTarget = false; } AttackModelBehaviorExt.RemoveBehaviors(item); AttackModelBehaviorExt.RemoveBehaviors(item); AttackModelBehaviorExt.RemoveBehaviors(item); AttackModelBehaviorExt.RemoveBehaviors(item); AttackModel attackModel = TowerModelExt.GetAttackModel(flag2 ? tower2 : tower); AttackModelBehaviorExt.AddBehavior(item, ModelExt.Duplicate(AttackModelBehaviorExt.GetBehavior(attackModel))); Il2CppGenericIEnumerable.ForEach(((Model)item).GetDescendants(), (Action)delegate(ArcEmissionModel arc) { arc.useAirUnitRotation = true; }); if (!flag) { continue; } flag = false; foreach (TargetSupplierModel behavior2 in AttackModelBehaviorExt.GetBehaviors(attackModel)) { AttackModelBehaviorExt.AddBehavior(item, ModelExt.Duplicate(behavior2, ((ModContent)this).Name)); } if (AttackModelBehaviorExt.HasBehavior(item, ref val2)) { val2.pursuitDistance = (((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("Spectre") ? 45 : 15); } } towerModel.UpdateTargetProviders(); BloonsMod val3 = default(BloonsMod); if (ModHelper.HasMod("TacticalTweaks", ref val3) && val3.ModSettings.TryGetValue("PursuitPathPrioritization", out var value)) { ModSettingBool val4 = (ModSettingBool)(object)((value is ModSettingBool) ? value : null); if (val4 != null && ModSettingBool.op_Implicit(val4)) { towerModel.towerSelectionMenuThemeId = "TacticalTweaks-PursuitTsmTheme"; return; } } towerModel.towerSelectionMenuThemeId = "Default"; } } public class HoverPlaneAcesPath : PathPlusPlus { public override string Tower => TowerType.MonkeyAce; } public class Pursuit : UpgradePlusPlus { public override int Cost => 500; public override int Tier => 2; public override string Description => "A new targeting option enables Monkey Ace to seek and pursue the Bloons automatically."; public override string DetailedDescription => "Gains the Pursuit targeting option like Heli Pilots."; public override void ApplyUpgrade(TowerModel towerModel) { } } } namespace MiniCrosspaths.DreadnoughtBoats { public class Dreadnought : UpgradePlusPlus { public override int Tier => 1; public override int Cost => 600; public override string Description => "Shoots molten cannonballs instead of darts/grapes that deal extra damage and can pop all Bloon types."; public override string DetailedDescription => "Projectiles can hit all Bloon types, and their base damage and additive bonuses are all increased by +1 or x1.3, whichever is higher."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) PrefabReference display = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.WizardMonkey, 0, 1, 0), "Fireball")).GetDescendant().display; PrefabReference display2 = ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.TackShooter, 5, 0, 0), "Meteor")).GetDescendant().display; PrefabReference display3 = ((Model)Game.instance.model.GetTower(TowerType.BombShooter, 3, 0, 0)).GetDescendant().display; IEnumerable source = Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants()).Prepend(towerModel); IEnumerable enumerable = source.SelectMany((TowerModel t) => Il2CppGenericIEnumerable.AsIEnumerable(((Model)t).GetDescendants())); DamageModel val = default(DamageModel); foreach (ProjectileModel item in enumerable) { if (ProjectileModelBehaviorExt.HasBehavior(item, ref val)) { DamageModel obj = val; DamageModel obj2 = val; BloonProperties immuneBloonProperties = (BloonProperties)0; obj2.immuneBloonPropertiesOriginal = (BloonProperties)0; obj.immuneBloonProperties = immuneBloonProperties; val.damage = Math.Max(val.damage + 1f, val.damage * 1.3f); foreach (DamageModifierForTagModel behavior in ProjectileModelBehaviorExt.GetBehaviors(item)) { behavior.damageAddative = Math.Max(behavior.damageAddative + 1f, behavior.damageAddative * 1.3f); } } if (!ProjectileModelBehaviorExt.HasBehavior(item)) { break; } ProjectileModelExt.SetDisplay(item); if (ProjectileModelBehaviorExt.GetBehaviors(item).Count < 1) { item.scale = ((item.radius > 3f) ? 0.7f : 0.5f); } } } } public class MoltenCannonBall : ModDisplay { public override PrefabReference BaseDisplayReference => ((Model)TowerModelExt.GetAttackModel(Game.instance.model.GetTower(TowerType.TackShooter, 5, 0, 0), "Meteor")).GetDescendant().display; public override void ModifyDisplayNode(UnityDisplayNode node) { ((Component)UnityDisplayNodeExt.GetRenderer(node, "Head", true)).gameObject.SetActive(false); ((Component)UnityDisplayNodeExt.GetRenderer(node, "Tail", true)).gameObject.SetActive(false); } } public class DreadnoughtBoatsPath : PathPlusPlus { public override string Tower => TowerType.MonkeyBuccaneer; } public class Privateer : UpgradePlusPlus { public override int Cost => 800; public override int Tier => 2; public override string Description => "Earns 50% more cash from Bloons popped / hooked. Merchantman income is increased by 10%."; public override string DetailedDescription => "Cash from Bloons is 1.5x, Merchantman income is +10% after other additive bonuses like Trade Empire."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown Args val = new Args(); ((ModelArgs)val).name = ((ModContent)this).Name; val.multiplier = 1.5f; TowerModelBehaviorExt.AddBehavior(towerModel, CreateCashIncreaseModelExt.Create(val)); PerRoundCashBonusTowerModel val2 = default(PerRoundCashBonusTowerModel); if (ModelExt.HasDescendant((Model)(object)towerModel, ref val2)) { PerRoundCashBonusTowerModel obj = val2; obj.cashRoundBonusMultiplier += 0.1f; } } } } namespace MiniCrosspaths.DoubleRangaBoomers { public class DoubleRanga : UpgradePlusPlus { public override int Cost => 400; public override int Tier => 2; public override string Description => "Throws 2 Boomerangs at a time, but not as frequently."; public override string DetailedDescription => "Main boomerangs, MOAB Press Boomerangs, and orbiting glaives have double projectile count but two thirds attack speed."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_0050: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown foreach (WeaponModel item in DoubleRangaBoomersPath.BoomerAttacks(towerModel).SelectMany((AttackModel attack) => (IEnumerable)attack.weapons)) { item.Rate *= 1.5f; WeaponModelExt.SetEmission(item, (EmissionModel)(object)CreateArcEmissionModelExt.Create(new Args { angle = 30f, count = 2 })); } OrbitModel val = default(OrbitModel); if (TowerModelBehaviorExt.HasBehavior(towerModel, ref val)) { OrbitModel obj = val; obj.count *= 2; WeaponModel obj2 = ((Il2CppArrayBase)(object)TowerModelExt.GetAttackModel(towerModel, "Orbit").weapons)[0]; obj2.Rate *= 0.75f; } } } public class DoubleRangaBoomersPath : PathPlusPlus { public override string Tower => TowerType.BoomerangMonkey; public static List BoomerAttacks(TowerModel towerModel) { List list = new List { TowerModelExt.GetAttackModel(towerModel) }; if (((Il2CppArrayBase)(object)towerModel.appliedUpgrades).Contains("MOAB Press")) { list.Add(TowerModelExt.GetAttackModel(towerModel, "MOABPress")); } return list; } } public class SonicBoom : UpgradePlusPlus { public override int Cost => 100; public override int Tier => 1; public override string Description => "Boomerangs can smash through Frozen Bloons for extra damage."; public override string DetailedDescription => "All projectiles can pop Frozen bloons, gaining a damage bonus equal to the projectile's base damage."; public override void ApplyUpgrade(TowerModel towerModel, int tier) { Il2CppGenericIEnumerable.ForEach(((Model)towerModel).GetDescendants(), (Action)delegate(ProjectileModel proj) { //IL_0014: 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_0024: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0044: 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_005c: 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 DamageModel val2 = default(DamageModel); if (ProjectileModelBehaviorExt.HasBehavior(proj, ref val2)) { DamageModel obj = val2; obj.immuneBloonPropertiesOriginal = (BloonProperties)(obj.immuneBloonPropertiesOriginal & -17); DamageModel obj2 = val2; obj2.immuneBloonProperties = (BloonProperties)(obj2.immuneBloonProperties & -17); Args val3 = new Args(); ((ModelArgs)val3).name = "Frozen"; val3.bloonState = "Ice"; val3.damageMultiplier = 1f; val3.damageAdditive = val2.damage; val3.mustBeModified = true; ProjectileModelBehaviorExt.AddBehavior(proj, CreateDamageModifierForBloonStateModelExt.Create(val3)); proj.hasDamageModifiers = true; } }); AddBehaviorToBloonModel val = default(AddBehaviorToBloonModel); if (ModelExt.HasDescendant((Model)(object)towerModel, ref val)) { val.parentDamageModel = null; ((Model)val).RemoveChildDependant(val.parentDamageModel); } } } } namespace MiniCrosspaths.CrystalBallWizards { public class CrystalBall : UpgradePlusPlus { public override int Cost => 1000; public override int Tier => 2; public override string Description => "Gains a toggle to allow long range targeting of Bloons in radius of your other towers. Loses Guided Magic's obstacle ignoring behavior while active."; public override string DetailedDescription => "Toggle Advanced Intel style targeting at the cost of giving up Guided Magic ignoring blockers, if you have it. Projectiles will always use Guided Magic homing to hit targets."; public override void ApplyUpgrade(TowerModel towerModel) { //IL_003b: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0089: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown towerModel.towerSelectionMenuThemeId = ModContent.GetId(); foreach (AttackModel attackModel in TowerModelExt.GetAttackModels(towerModel)) { if (AttackModelBehaviorExt.HasBehavior(attackModel)) { AttackModelBehaviorExt.RemoveBehavior(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetFirstSharedRangeModelExt.Create(new Args { isSelectable = true, isSharedRangeEnabled = false })); } if (AttackModelBehaviorExt.HasBehavior(attackModel)) { AttackModelBehaviorExt.RemoveBehavior(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetLastSharedRangeModelExt.Create(new Args { isSelectable = true, isSharedRangeEnabled = false })); } if (AttackModelBehaviorExt.HasBehavior(attackModel)) { AttackModelBehaviorExt.RemoveBehavior(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetCloseSharedRangeModelExt.Create(new Args { isSelectable = true, isSharedRangeEnabled = false })); } if (AttackModelBehaviorExt.HasBehavior(attackModel)) { AttackModelBehaviorExt.RemoveBehavior(attackModel); AttackModelBehaviorExt.AddBehavior(attackModel, CreateTargetStrongSharedRangeModelExt.Create(new Args { isSelectable = true, isSharedRangeEnabled = false })); } attackModel.attackThroughWalls = false; } foreach (WeaponModel weapon in TowerModelExt.GetWeapons(towerModel)) { EmissionModelBehaviorExt.AddBehavior(weapon.emission, CreateEmissionCamoIfTargetIsCamoModelExt.Create()); } } public override void OnUpgraded(Tower tower) { MutableExt.AddMutator((Mutable)(object)tower, (JToken)null, -1, true, true, false, true, false, false, false, -1, false, false); } } public class CrystalBallMutator : ModMutator { public override bool CantBeAbsorbed => true; public override bool Saved => true; public override int Priority => 5; public override bool Mutate(Model baseModel, Model model, JToken data) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown TowerModel val = default(TowerModel); if (!Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val)) { return false; } val.ignoreBlockers = false; TargetFirstSharedRangeModel val2 = default(TargetFirstSharedRangeModel); TargetLastSharedRangeModel val3 = default(TargetLastSharedRangeModel); TargetCloseSharedRangeModel val4 = default(TargetCloseSharedRangeModel); TargetStrongSharedRangeModel val5 = default(TargetStrongSharedRangeModel); foreach (AttackModel attackModel in TowerModelExt.GetAttackModels(val)) { if (AttackModelBehaviorExt.HasBehavior(attackModel, ref val2)) { val2.isSharedRangeEnabled = true; } if (AttackModelBehaviorExt.HasBehavior(attackModel, ref val3)) { val3.isSharedRangeEnabled = true; } if (AttackModelBehaviorExt.HasBehavior(attackModel, ref val4)) { val4.isSharedRangeEnabled = true; } if (AttackModelBehaviorExt.HasBehavior(attackModel, ref val5)) { val5.isSharedRangeEnabled = true; } attackModel.attackThroughWalls = false; } foreach (ProjectileModel item in Il2CppGenericIEnumerable.AsIEnumerable(model.GetDescendants())) { TravelStraitModel behavior = ProjectileModelBehaviorExt.GetBehavior(item); if (behavior != null) { if (ProjectileModelBehaviorExt.GetBehavior(item) == null) { ProjectileModelBehaviorExt.AddBehavior(item, CreateTrackTargetModelExt.Create(new Args { distance = 80f, trackNewTargets = true, maxSeekAngle = 360f, turnRate = 360f })); } item.ignoreBlockers = false; } } return true; } } public class CrystalBallTSM : ModTsmTheme { public override string BaseTheme => "SelectPointInput"; public TSMButton ToggleCrystalBall { get; private set; } = null; public ModHelperImage Icon { get; private set; } = null; public override void SetupTheme(BaseTSMTheme theme) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) ToggleCrystalBall = GameObjectExt.AddTSMButton(((Component)theme).gameObject, new Info("ToggleCrystalBall", 372f, -428f, 180f), "Ui[TwitchBtnSquare]", "ToggleCrystalBall", (string)null); Icon = GameObjectExt.AddImage(((Component)ToggleCrystalBall).gameObject, new Info("Icon", 128f), ""); } public override void TowerChanged(BaseTSMTheme theme, TowerToSimulation tower) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) ImageExt.SetSprite(Icon.Image, MutableExt.IsMutatedBy((Mutable)(object)tower.tower) ? ((ModContent)this).GetSpriteReference("CrystalBall").AssetGUID : "1c4a4709378c343e0a7234bb2faa2d81"); ((Component)ToggleCrystalBall).gameObject.SetActive(((Il2CppArrayBase)(object)tower.Def.appliedUpgrades).Contains("Guided Magic")); RectTransform component = ((Component)ToggleCrystalBall).GetComponent(); Il2CppStringArray appliedUpgrades = tower.Def.appliedUpgrades; int num; if (appliedUpgrades != null && ((Il2CppArrayBase)(object)appliedUpgrades).Contains("Wall of Fire")) { Il2CppStringArray appliedUpgrades2 = tower.Def.appliedUpgrades; if (appliedUpgrades2 != null && ((Il2CppArrayBase)(object)appliedUpgrades2).Contains("Guided Magic")) { num = 198; goto IL_00b5; } } num = 0; goto IL_00b5; IL_00b5: component.anchoredPosition = new Vector2(372f, (float)(-428 + num)); } public override void OnButtonPressed(BaseTSMTheme theme, TowerToSimulation tower, string buttonId) { if (!(buttonId != "ToggleCrystalBall")) { if (MutableExt.IsMutatedBy((Mutable)(object)tower.tower)) { MutableExt.RemoveMutator((Mutable)(object)tower.tower); } else { MutableExt.AddMutator((Mutable)(object)tower.tower, (JToken)null, -1, true, true, false, true, false, false, false, -1, false, false); } } } } public class CrystalBallWizardsPath : PathPlusPlus { public override string Tower => TowerType.WizardMonkey; } public class MonkeyApprentice : UpgradePlusPlus { public override int Cost => 75; public override int Tier => 1; public override string Description => "Further study makes all Wizard projectiles travel much further."; public override string DetailedDescription => "All projectiles that travel in a straight line have doubled lifespan."; public override void ApplyUpgrade(TowerModel towerModel) { foreach (TravelStraitModel item in Il2CppGenericIEnumerable.AsIEnumerable(((Model)towerModel).GetDescendants())) { item.Lifespan *= 2f; } } } }