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.Extensions; using HarmonyLib; using Il2Cpp; using Il2CppAssets.Scripts; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Models.Entities; using Il2CppAssets.Scripts.Models.Powers; using Il2CppAssets.Scripts.Models.Profile; using Il2CppAssets.Scripts.Models.Towers; using Il2CppAssets.Scripts.Models.Towers.Upgrades; using Il2CppAssets.Scripts.Simulation.Objects; using Il2CppAssets.Scripts.Simulation.Towers; using Il2CppAssets.Scripts.Simulation.Towers.Behaviors; using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.Player; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.RightMenu.Powers; using Il2CppAssets.Scripts.Unity.UI_New.InGame.StoreMenu; using Il2CppAssets.Scripts.Unity.UI_New.Popups; using Il2CppInterop.Runtime.InteropTypes; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using InstaMonkeyRework; using MelonLoader; using Microsoft.CodeAnalysis; 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(InstaMonkeyReworkMod), "Insta Monkey Rework", "1.1.9", "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("InstaMonkeyRework")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c2b9ae02cbeb07e1ac9b2988764878542a69459a")] [assembly: AssemblyProduct("InstaMonkeyRework")] [assembly: AssemblyTitle("InstaMonkeyRework")] [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 InstaMonkeyRework { public class InstaMonkeyReworkMod : BloonsTD6Mod { [HarmonyPatch(typeof(InputManager), "TryPlace")] internal class InputManager_TryPlace { [HarmonyPrefix] internal static bool Prefix() { return !((Object)(object)PopupScreen.instance != (Object)null) || !PopupScreen.instance.IsPopupActive(); } } [HarmonyPatch(typeof(InputManager), "ExitInstaMode")] internal class InputManager_ExitInstaMode { [HarmonyPostfix] internal static void Postfix(InputManager __instance) { InInstaMode = false; } } [HarmonyPatch(typeof(Btd6Player), "ConsumeInstaTower")] internal class Btd6Player_ConsumeInstaTower { [HarmonyPrefix] internal static bool Prefix() { if (ActuallyConsumeInsta) { ActuallyConsumeInsta = false; return true; } return false; } } [HarmonyPatch(typeof(Tower), "OnPlace")] internal static class Tower_OnPlace { [HarmonyPrefix] private static void Prefix(Tower __instance) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) TowerModel towerModel = __instance.towerModel; Warned = false; if (__instance.worth != 0f) { return; } string name = ((Model)towerModel).name; TowerModel? instaModel = InstaModel; if (name == ((instaModel != null) ? ((Model)instaModel).name : null) && (!InGame.instance.IsCoop || __instance.owner == GameExt.GetNkGI(Game.instance).PeerID)) { int costForThing = GetCostForThing(__instance); if (InGameExt.GetCash(InGame.instance) >= (double)costForThing) { costForThing = GetCostForThing(__instance); InGameExt.AddCash(InGame.instance, (double)(-costForThing)); __instance.worth = costForThing; Dictionary savedPlacedInstas = SavedPlacedInstas; ObjectId id = ((RootObject)__instance).Id; savedPlacedInstas[((ObjectId)(ref id)).Id] = ((Model)towerModel).name; } else { ActuallyConsumeInsta = true; GameExt.GetBtd6Player(Game.instance).ConsumeInstaTower(((EntityModel)towerModel).baseId, towerModel.tiers); } InstaModel = null; } } } [HarmonyPatch(typeof(StandardInstaTowerButton), "UpdateUseCount")] internal class StandardInstaTowerButton_UpdateUseCount { [HarmonyPostfix] internal static void Postfix(StandardInstaTowerButton __instance, int useCount) { int num = useCount - GetTotalPlaced(((Model)__instance.instaTowerModel).name); ((StandardPowerButton)__instance).powerCountText.SetText(num + "/" + useCount); } } [HarmonyPatch(typeof(StandardInstaTowerButton), "SetPower")] internal class StandardInstaTowerButton_SetPower { [HarmonyPostfix] internal static void Postfix(StandardInstaTowerButton __instance, PowerModel powerModel, bool isInsta) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI val = ((IEnumerable)((Component)__instance).GetComponentsInChildren()).FirstOrDefault((Func)((TextMeshProUGUI text) => ((Object)text).name == "Cost")); float num = ((TMP_Text)__instance.tiers).fontSize / 3f; if ((Object)(object)val == (Object)null) { val = (TextMeshProUGUI)(object)Object.Instantiate(__instance.tiers, ((TMP_Text)__instance.tiers).transform.parent, true); ((Object)val).name = "Cost"; ((TMP_Text)val).transform.Translate(0f, num, 0f); ((Graphic)val).color = Color.red; } int costForThing = GetCostForThing(powerModel.tower); ((TMP_Text)val).SetText($"${costForThing:n0}"); int tier = __instance.instaTowerModel.tier; TextMeshProUGUI val2 = ((IEnumerable)((Component)__instance).GetComponentsInChildren()).FirstOrDefault((Func)((TextMeshProUGUI text) => ((Object)text).name == "Discount")); if ((Object)(object)val2 == (Object)null) { val2 = (TextMeshProUGUI)(object)Object.Instantiate(((StandardPowerButton)__instance).powerCountText, ((TMP_Text)((StandardPowerButton)__instance).powerCountText).transform.parent, true); ((Object)val2).name = "Discount"; ((TMP_Text)val2).transform.Translate(num * 3f, 0f, 0f); ((Graphic)val2).color = Color.green; } if (tier > 0) { ((TMP_Text)val2).SetText("-" + tier * 5 + "%"); } else { ((TMP_Text)val2).SetText(""); } } } [HarmonyPatch(typeof(TowerPurchaseButton), "ButtonActivated")] internal class TowerPurchaseButton_OnPointerClick { [HarmonyPrefix] internal static bool Prefix(TowerPurchaseButton __instance) { if (Input.GetMouseButton(1) && __instance.towerModel.IsBaseTower && !__instance.IsHero && InGameData.CurrentGame.ArePowersAllowed()) { Context val = Il2CppGenerics.First(InGame.instance.playerContexts); val.rightMenu.ShowPowersMenu(); PowersMenu powersMenu = ((Il2CppObjectBase)val.powersMenu).Cast(); powersMenu.ShowInstaMonkeys(); InGameExt[InGame.instance].ExitTowerMode(); TaskScheduler.ScheduleTask((Action)delegate { powersMenu.instaTowersMenu.Show(__instance.towerModel); }, (Func)null); return false; } return true; } } public static bool ActuallyConsumeInsta; public static bool InInstaMode; public static TowerModel? InstaModel; public static bool Warned; public static Dictionary SavedPlacedInstas; public override void OnMainMenu() { SavedPlacedInstas = new Dictionary(); } public override void OnRestart() { SavedPlacedInstas = new Dictionary(); } public static int GetCostForThing(TowerModel towerModel) { float num = Game.instance.model.GetTowerFromId(((Model)towerModel).name).cost + (float)TowerModelExt.GetAppliedUpgrades(towerModel).Sum((UpgradeModel model) => model.cost); switch (InGame.instance.SelectedDifficulty) { case "Easy": num *= 0.85f; break; case "Hard": num *= 1.08f; break; case "Impoppable": num *= 1.2f; break; } num *= 1f - 0.05f * (float)towerModel.tier; return (int)(5.0 * Math.Round(num / 5f)); } public static int GetCostForThing(Tower tower) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) float cost = Game.instance.model.GetTowerFromId(((Model)tower.towerModel).name).cost; TowerManager towerManager = InGameExt.GetTowerManager(InGame.instance); Dictionary> zoneDiscount = towerManager.GetZoneDiscount(tower.towerModel, ((CommonBehaviorProxy)(object)tower).Position.ToVector3(), 0, 0, tower.owner, ""); float discountMultiplier = towerManager.GetDiscountMultiplier(zoneDiscount); cost *= 1f - discountMultiplier; foreach (UpgradeModel appliedUpgrade in TowerModelExt.GetAppliedUpgrades(tower.towerModel)) { float num = appliedUpgrade.cost; zoneDiscount = towerManager.GetZoneDiscount(tower.towerModel, ((CommonBehaviorProxy)(object)tower).Position.ToVector3(), appliedUpgrade.path, appliedUpgrade.tier, tower.owner, ((Model)appliedUpgrade).name); discountMultiplier = towerManager.GetDiscountMultiplier(zoneDiscount); num *= 1f - discountMultiplier; cost += num; } switch (InGame.instance.SelectedDifficulty) { case "Easy": cost *= 0.85f; break; case "Hard": cost *= 1.08f; break; case "Impoppable": cost *= 1.2f; break; } cost *= 1f - 0.05f * (float)tower.towerModel.tier; return (int)(5.0 * Math.Round(cost / 5f)); } public static int GetTotalPlaced(string name) { return SavedPlacedInstas.Values.Count((string value) => value == name); } public override void OnUpdate() { //IL_0121: 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_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)InGame.instance == (Object)null || InGame.instance.bridge == null) { return; } InGame instance = InGame.instance; if (instance != null) { List playerContexts = instance.playerContexts; bool? obj; PowersMenu val = default(PowersMenu); if (playerContexts == null) { obj = null; } else { Context obj2 = Il2CppGenerics.FirstOrDefault(playerContexts); if (obj2 == null) { obj = null; } else { BasePowersMenu powersMenu = obj2.powersMenu; obj = ((powersMenu != null) ? new bool?(Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)powersMenu, ref val)) : ((bool?)null)); } } bool? flag = obj; InstaTowersMenu val2 = default(InstaTowersMenu); if (flag == true && Il2CppSystemObjectExt.Is(val.instaTowersMenu, ref val2)) { foreach (StandardInstaTowerButton componentsInChild in ((Component)val2).GetComponentsInChildren()) { TextMeshProUGUI val3 = ((IEnumerable)((Component)componentsInChild).GetComponentsInChildren()).FirstOrDefault((Func)((TextMeshProUGUI text) => ((Object)text).name == "Cost")); if (!((Object)(object)val3 == (Object)null)) { int num = TextToInt(val3); ((Graphic)val3).color = ((InGameExt.GetCash(InGame.instance) >= (double)num) ? Color.white : Color.red); int useCount = ((StandardPowerButton)componentsInChild).GetUseCount(); int totalPlaced = GetTotalPlaced(((Model)componentsInChild.instaTowerModel).name); TextMeshProUGUI val4 = ((IEnumerable)((Component)componentsInChild).GetComponentsInChildren()).First((TextMeshProUGUI text) => ((Object)text).name == "Discount"); if (totalPlaced >= useCount) { ((Behaviour)val3).enabled = false; ((Behaviour)val4).enabled = false; ((Graphic)((StandardPowerButton)componentsInChild).powerCountText).color = Color.red; } else { ((Behaviour)val3).enabled = true; ((Behaviour)val4).enabled = true; ((Graphic)((StandardPowerButton)componentsInChild).powerCountText).color = Color.white; } } } } } InputManager val5 = InGameExt[InGame.instance]; if (val5 == null || !val5.inInstaMode || InInstaMode) { return; } int useCount2 = ((StandardPowerButton)val5.instaButton).GetUseCount(); int totalPlaced2 = GetTotalPlaced(((Model)val5.instaModel).name); int costForThing = GetCostForThing(val5.instaModel); if (!Warned && (totalPlaced2 >= useCount2 || (double)costForThing > InGameExt.GetCash(InGame.instance))) { PopupScreen.instance.ShowPopup((Placement)0, "Real Insta Warning", "You are placing an actual Insta Monkey, and doing so will remove it from your inventory. Are you sure you want to continue?", ReturnCallback.op_Implicit((Action)delegate { Warned = true; }), "Yes", ReturnCallback.op_Implicit((Action)val5.CancelAllPlacementActions), "No", (TransitionAnim)1, (BackGround)1, false, false); } InInstaMode = true; InstaModel = val5.instaModel; } public static int TextToInt(TextMeshProUGUI textMeshProUGUI) { return int.Parse(((TMP_Text)textMeshProUGUI).text.Substring(1).Replace(",", "")); } public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Dictionary savedPlacedInstas = SavedPlacedInstas; ObjectId id = ((RootObject)tower).Id; if (savedPlacedInstas.ContainsKey(((ObjectId)(ref id)).Id)) { Dictionary metaData = saveData.metaData; Dictionary savedPlacedInstas2 = SavedPlacedInstas; id = ((RootObject)tower).Id; metaData["InstaMonkeyRework"] = savedPlacedInstas2[((ObjectId)(ref id)).Id]; } } public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (saveData.metaData.ContainsKey("InstaMonkeyRework")) { Dictionary savedPlacedInstas = SavedPlacedInstas; ObjectId id = ((RootObject)tower).Id; savedPlacedInstas[((ObjectId)(ref id)).Id] = saveData.metaData["InstaMonkeyRework"]; } } public override void OnTowerDestroyed(Tower tower) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0029: Unknown result type (might be due to invalid IL or missing references) Dictionary savedPlacedInstas = SavedPlacedInstas; ObjectId id = ((RootObject)tower).Id; if (savedPlacedInstas.ContainsKey(((ObjectId)(ref id)).Id)) { Dictionary savedPlacedInstas2 = SavedPlacedInstas; id = ((RootObject)tower).Id; savedPlacedInstas2.Remove(((ObjectId)(ref id)).Id); } } } public static class ModHelperData { public const string WorksOnVersion = "54.0"; public const string Version = "1.1.9"; public const string Name = "Insta Monkey Rework"; public const string Description = "Adds a new way to use insta monkeys: Instead of being one-time use only, you can optionally spend in-game cash for instas and they won't be removed from your collection. Price is discounted from the full amount based on the tier of the insta."; public const string RepoOwner = "doombubbles"; public const string PrevRepoName = "insta-monkey-rework"; public const string RepoName = "InstaMonkeyRework"; } }