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.ModOptions; using BTD_Mod_Helper.Extensions; using HarmonyLib; using Il2CppAssets.Scripts.Models.TowerSets; using Il2CppAssets.Scripts.Models.Towers; using Il2CppAssets.Scripts.Simulation.Input; using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.Bridge; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.StoreMenu; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using InGameHeroSwitch; using MelonLoader; using Microsoft.CodeAnalysis; 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(InGameHeroSwitchMod), "In-Game Hero Switch", "1.1.7", "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("InGameHeroSwitch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c355a042dea528d33be8a455c600de9a65d65280")] [assembly: AssemblyProduct("InGameHeroSwitch")] [assembly: AssemblyTitle("InGameHeroSwitch")] [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 InGameHeroSwitch { public class InGameHeroSwitchMod : BloonsTD6Mod { public static readonly ModSettingBool CycleIfPlaced = new ModSettingBool(false) { description = "Whether to still allow cycling to different heroes if one is already placed down.", button = true }; public static readonly ModSettingHotkey CycleUp = new ModSettingHotkey((KeyCode)280, (HotkeyModifier)0); public static readonly ModSettingHotkey CycleDown = new ModSettingHotkey((KeyCode)281, (HotkeyModifier)0); public override void OnUpdate() { InGameHeroSwitchUtility.Update(); } } public class InGameHeroSwitchUtility { [HarmonyPatch(typeof(UnityToSimulation), "MatchReady")] internal static class UnityToSimulation_MatchReady { [HarmonyPostfix] internal static void Postfix() { RefreshShop(playSound: false); } } private static bool cycleDown; private static bool cycleUp; private static string CurrentHero { get { return InGame.Bridge.players[InGame.Bridge.GetInputId()].hero; } set { InGame.Bridge.players[InGame.Bridge.GetInputId()].hero = value; } } public static void Update() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)InGame.instance) && InGame.Bridge != null && !InGame.instance.ReviewMapMode && !InGame.Bridge.IsSpectatorMode && (int)InGame.instance.GameType != 13) { if (InGameHeroSwitchMod.CycleDown.JustPressed()) { cycleDown = true; } if (InGameHeroSwitchMod.CycleUp.JustPressed()) { cycleUp = true; } if (cycleDown && cycleUp) { ChangeHero(Random.RandomRangeInt(1, ((Il2CppArrayBase)(object)Game.instance.model.heroSet).Length)); } else if (InGameHeroSwitchMod.CycleUp.JustReleased() && cycleUp) { ChangeHero(-1); } else if (InGameHeroSwitchMod.CycleDown.JustReleased() && cycleDown) { ChangeHero(1); } } } private static void ChangeHero(int delta) { cycleDown = (cycleUp = false); TowerModel val = default(TowerModel); if (string.IsNullOrEmpty(CurrentHero) || !Il2CppSystemObjectExt.Is(InGame.Bridge.Model.GetTowerWithName(CurrentHero), ref val) || (InGameExt.GetTowerInventory(InGame.instance).GetTowerInventoryRemaining(val) == 0 && !ModSettingBool.op_Implicit(InGameHeroSwitchMod.CycleIfPlaced))) { return; } HashSet unlockedHeroes = GameExt.GetPlayerProfile(Game.instance).unlockedHeroes; IEnumerable enumerable = ((IEnumerable)InGameExt.GetGameModel(InGame.instance).heroSet).Select((TowerDetailsModel tdm) => ((Il2CppObjectBase)tdm).Cast()); HeroDetailsModel[] array = (enumerable as HeroDetailsModel[]) ?? enumerable.ToArray(); int index = ((TowerDetailsModel)array.First((HeroDetailsModel hdm) => ((TowerDetailsModel)hdm).towerId == CurrentHero)).towerIndex; string text = ""; while (!unlockedHeroes.Contains(text)) { index += delta; index = (index + array.Length) % array.Length; text = ((TowerDetailsModel)array.First((HeroDetailsModel hdm) => ((TowerDetailsModel)hdm).towerIndex == index)).towerId; } ResetInventory(text); CurrentHero = text; InGameExt[InGame.instance].SetSelected((Selectable)null); } private static void ResetInventory(string newHero) { TowerInventory towerInventory = InGameExt.GetTowerInventory(InGame.instance); HashSet unlockedHeroes = GameExt.GetPlayerProfile(Game.instance).unlockedHeroes; Enumerator enumerator = unlockedHeroes.GetEnumerator(); while (enumerator.MoveNext()) { string current = enumerator.Current; towerInventory.towerMaxes[current] = 0; } towerInventory.towerMaxes[newHero] = 1; RefreshShop(playSound: true); } private static void RefreshShop(bool playSound) { bool disallowSelectingDifferentTowers = ShopMenuExt.instance.disallowSelectingDifferentTowers; ShopMenuExt.instance.disallowSelectingDifferentTowers = !playSound; ShopMenuExt.instance.RebuildTowerSet(); ShopMenuExt.instance.disallowSelectingDifferentTowers = disallowSelectingDifferentTowers; Enumerator enumerator = ShopMenuExt.instance.ActiveTowerButtons.GetEnumerator(); while (enumerator.MoveNext()) { ITowerPurchaseButton current = enumerator.Current; ((ItemPurchaseButton)((Il2CppObjectBase)current).Cast()).Update(); } } } public static class ModHelperData { public const string WorksOnVersion = "56.0"; public const string Version = "1.1.7"; public const string Name = "In-Game Hero Switch"; public const string Description = "Lets you press the PageUp and PageDown keys (configurable) to cycle your hero while in a game."; public const string RepoOwner = "doombubbles"; public const string PrevRepoName = "in-game-hero-switch"; public const string RepoName = "InGameHeroSwitch"; } }