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.Data; using BTD_Mod_Helper.Api.Helpers; using BTD_Mod_Helper.Api.ModOptions; using BTD_Mod_Helper.Api.Towers; using BTD_Mod_Helper.Extensions; using HarmonyLib; using Il2Cpp; using Il2CppAssets.Scripts.Data; using Il2CppAssets.Scripts.Data.Cosmetics; using Il2CppAssets.Scripts.Data.Cosmetics.PowerAssetChanges; using Il2CppAssets.Scripts.Data.TrophyStore; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Models.Entities; using Il2CppAssets.Scripts.Models.Gameplay.Mods; using Il2CppAssets.Scripts.Models.Powers; using Il2CppAssets.Scripts.Models.Profile; using Il2CppAssets.Scripts.Models.TowerSets; using Il2CppAssets.Scripts.Models.Towers; using Il2CppAssets.Scripts.Models.Towers.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Projectiles; using Il2CppAssets.Scripts.Models.Towers.Upgrades; using Il2CppAssets.Scripts.Simulation; using Il2CppAssets.Scripts.Simulation.Input; using Il2CppAssets.Scripts.Simulation.Objects; using Il2CppAssets.Scripts.Simulation.SMath; using Il2CppAssets.Scripts.Simulation.Towers; using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.Bridge; using Il2CppAssets.Scripts.Unity.Player; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.RightMenu; using Il2CppAssets.Scripts.Unity.UI_New.InGame.RightMenu.Powers; using Il2CppAssets.Scripts.Unity.UI_New.InGame.StoreMenu; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu.TowerSelectionMenuThemes; using Il2CppAssets.Scripts.Unity.UI_New.Upgrade; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppNinjaKiwi.Common.ResourceUtils; using Il2CppNinjaKiwi.LiNK.Client; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using MelonLoader; using Microsoft.CodeAnalysis; using Newtonsoft.Json.Linq; using PowersInShop; using PowersInShop.Towers; 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(PowersInShopMod), "Powers in Shop", "3.1.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("PowersInShop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+faaf826a5c9731e6693b3dd23aa3fa05252814fa")] [assembly: AssemblyProduct("PowersInShop")] [assembly: AssemblyTitle("PowersInShop")] [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 PowersInShop { public interface IPowerTower { string Id { get; } string Name { get; } string DisplayName { get; } SpriteReference IconReference { get; } int BaseCost { get; } ModSettingInt _cost { get; set; } void LoadImpl() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0044: Expected O, but got Unknown _cost = new ModSettingInt(BaseCost) { category = PowersInShopMod.Costs, displayName = DisplayName, description = "In Game Cost for " + DisplayName + ". Set to a negative number to disable the buff." }; ((BloonsMod)ModContent.GetInstance()).ModSettings[Name + "Cost"] = (ModSetting)(object)_cost; } void RegisterImpl() { PowersInShopMod.PowersByName[Name] = this; PowersInShopMod.PowersById[Id] = this; ((ModSetting)_cost).icon = IconReference.AssetGUID; } } public static class ModHelperData { public const string WorksOnVersion = "55.0"; public const string Version = "3.1.1"; public const string RepoOwner = "doombubbles"; public const string PrevRepoName = "powers-in-shop"; public const string RepoName = "PowersInShop"; public const string Name = "Powers in Shop"; public const string Description = "Adds many of the Monkey Money Powers to the in-game shop for purchase with normal currency."; public const string Icon = "Powers-Button.png"; } public abstract class ModInstantPower : ModFakeTower, IPowerTower { public override bool DontAddToShop => ((ModTower)this).Cost < 0; public override string DisplayName => "[" + ((ModContent)this).Name + "]"; public sealed override string Description => "[" + ((ModContent)this).Name + " Description]"; public override string Icon => SpriteResizer.Scaled(PowerModel.icon.AssetGUID, 0.75f, true); public abstract int BaseCost { get; } public ModSettingInt _cost { get; set; } = null; public sealed override int Cost => ModSettingInt.op_Implicit(_cost); protected IPowerTower This => this; public static Simulation Sim => InGame.Bridge.Simulation; public static GameModel GameModel => ((Object)(object)InGame.instance == (Object)null) ? Game.instance.model : Sim.model; public PowerModel PowerModel => GameModel.GetPowerWithId(((ModContent)this).Name); public override IEnumerable Load() { This.LoadImpl(); return ((ModContent)this).Load(); } public override void Register() { This.RegisterImpl(); ((ModTower)this).Register(); } public override bool CanPlaceAt(Vector2 at, Tower hoveredTower, ref string helperMessage) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (TimeManager.inBetweenRounds && !PowerModel.canBeActivatedBetweenRounds) { helperMessage = "Can only be used when a round is active."; return false; } return InGame.Bridge.CheckPowerLocation(at, PowerModel); } public override void ModifyBaseTowerModel(TowerModel towerModel) { ((ModFakeTower)this).ModifyBaseTowerModel(towerModel); if (((EntityModel)towerModel).behaviors == null) { Il2CppReferenceArray val = (((EntityModel)towerModel).behaviors = new Il2CppReferenceArray(0L)); } } public override void ModifyTowerModelForMatch(TowerModel towerModel, GameModel gameModel) { PowerModel powerWithId = gameModel.GetPowerWithId(((ModContent)this).Name); if (ModSettingBool.op_Implicit(PowersInShopMod.ChangeIconsForSkins)) { towerModel.icon.guidRef = SpriteResizer.Scaled(powerWithId.icon.AssetGUID, 0.75f, true); } towerModel.portrait = towerModel.icon; } public sealed override void OnPlace(Vector2 at, TowerModel towerModelFake, Tower hoveredTower, float cost) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) ActivatePower(new Vector2(at), PowerModel); } public virtual void ActivatePower(Vector2 at, PowerModel powerModel) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Sim.powerManager.Activate(at, ref powerModel, InGame.Bridge.MyPlayerNumber); } string IPowerTower.get_Id() { return ((ModContent)this).Id; } } public abstract class ModPowerTower : ModPowerTowerBase { public sealed override int TopPathUpgrades => 0; public sealed override int MiddlePathUpgrades => 0; public sealed override int BottomPathUpgrades => 0; public sealed override string Description => "[" + ((ModContent)this).Name + " Description]"; } public abstract class ModPowerTowerBase : ModTower, IPowerTower, IModSettings, IModContent { public override bool DontAddToShop => !Application.isBatchMode && ((ModTower)this).Cost < 0; public override string DisplayName => "[" + ((ModContent)this).Name + "]"; public abstract int BaseCost { get; } public ModSettingInt _cost { get; set; } = null; public sealed override int Cost => ModSettingInt.op_Implicit(_cost); protected IPowerTower This => this; public override string BaseTower => ((ModContent)this).Name; public PowerModel PowerModel => Game.instance.model.GetPowerWithId(((ModContent)this).Name); public sealed override SpriteReference IconReference => ((ModTower)this).PortraitReference; public sealed override SpriteReference PortraitReference { get { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown SpriteReference portrait = PowerModel.tower.portrait; object obj = ((portrait != null) ? portrait.AssetGUID : null); if (obj == null) { SpriteReference icon = PowerModel.tower.icon; obj = ((icon != null) ? icon.AssetGUID : null) ?? PowerModel.icon.AssetGUID; } return new SpriteReference((string)obj); } } public sealed override bool IncludeInMonkeyTeams => false; public override TowerModel GetBaseTowerModel(params int[] tiers) { return TowerModelExt.MakeCopy(PowerModel.tower, ((ModContent)this).Id, false, (string)null); } public override void ModifyBaseTowerModel(TowerModel towerModel) { } public override IEnumerable Load() { This.LoadImpl(); return ((ModContent)this).Load(); } public override void Register() { This.RegisterImpl(); ((ModTower)this).Register(); } public override void ModifyTowerModelForMatch(TowerModel towerModel, GameModel gameModel) { TowerModel tower = gameModel.GetPowerWithId(((ModContent)this).Name).tower; string baseId = ((EntityModel)towerModel).baseId; string name = ((Model)towerModel).name; float cost = towerModel.cost; SpriteReference icon = towerModel.icon; towerModel.CopyFrom(tower, false); ((EntityModel)towerModel).baseId = baseId; ((Model)towerModel).name = name; towerModel.cost = cost; towerModel.icon = (ModSettingBool.op_Implicit(PowersInShopMod.ChangeIconsForSkins) ? towerModel.portrait : icon); towerModel.powerName = null; } public virtual void MutateTower(TowerModel towerModel) { } string IPowerTower.get_Id() { return ((ModContent)this).Id; } } public abstract class ModPowerTowerPro : ModPowerTowerBase { public static readonly Dictionary ByName = new Dictionary(); public static readonly Dictionary ById = new Dictionary(); public static readonly Dictionary Upgrades = new Dictionary(); public sealed override int TopPathUpgrades => 3; public sealed override int MiddlePathUpgrades => 3; public sealed override int BottomPathUpgrades => 3; public override bool DontApplyModUpgrades => true; public sealed override string Description => "[" + ((ModContent)this).Name + "Power Description]"; public override bool IsValidCrosspath(params int[] tiers) { return tiers.Count((int tier) => tier > 0) <= 1; } public override void ModifyBaseTowerModel(TowerModel towerModel) { base.ModifyBaseTowerModel(towerModel); foreach (string item in (Il2CppArrayBase)(object)towerModel.appliedUpgrades) { Upgrades.TryAdd(item, ((ModContent)this).Name); } } public override void Register() { base.Register(); ById[((ModContent)this).Id] = this; ByName[((ModContent)this).Name] = this; foreach (IGrouping item in from pair in Upgrades where pair.Value == ((ModContent)this).Name select Game.instance.model.GetPowerProUpgrade(pair.Key) into model group model by ((UpgradeModel)model).tier) { int xpCost = item.Max((PowerProUpgradeModel model) => ((UpgradeModel)model).xpCost); foreach (PowerProUpgradeModel item2 in item) { ((UpgradeModel)item2).xpCost = xpCost; } } } public override TowerModel GetBaseTowerModel(params int[] tiers) { return TowerModelExt.MakeCopy(((IEnumerable)Game.instance.model.GetPowerProModel(((ModContent)this).Name).towerModels).First((TowerModel model) => model.CheckTiersAreEqual(tiers[0], tiers[1], tiers[2])), ((ModContent)this).Id, false, (string)null); } public override int? MaxUpgradePips(TowerToSimulation tower, int path, int defaultMax) { return Math.Min(3, defaultMax); } } public abstract class ModTrackPower : ModInstantPower { private ModSettingInt pierce = null; protected abstract int BasePierce { get; } public override IEnumerable Load() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_002a: Expected O, but got Unknown ModSettingInt val = new ModSettingInt(BasePierce) { category = PowersInShopMod.Properties }; ((ModSettingNumber)val).min = 0L; pierce = val; return base.Load(); } public override void Register() { base.Register(); ((ModSetting)pierce).icon = ((ModTower)this).IconReference.AssetGUID; } public override void ActivatePower(Vector2 at, PowerModel powerModel) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) ProjectileModel descendant = ((Model)Game.instance.model.GetPowerWithId(((ModContent)this).Name)).GetDescendant(); powerModel = ModelExt.Duplicate(powerModel); ProjectileModel descendant2 = ((Model)powerModel).GetDescendant(); descendant2.pierce *= (float)ModSettingInt.op_Implicit(pierce) / descendant.pierce; base.ActivatePower(at, powerModel); } } public class Powers : ModTowerSet { public override bool AllowInRestrictedModes => ModSettingBool.op_Implicit(PowersInShopMod.AllowInRestrictedModes); public override int GetTowerSetIndex(List towerSets) { return towerSets.IndexOf((TowerSet)8) + 1; } } public class PowersInShopMod : BloonsTD6Mod { public const string MutatorId = "PowersInShop"; public static readonly Dictionary PowersByName = new Dictionary(); public static readonly Dictionary PowersById = new Dictionary(); private static readonly ModSettingBool AllowInChimps = new ModSettingBool(false) { icon = "3f868bbf2f43344a78ddff2450dfa493" }; public static readonly ModSettingBool AllowInRestrictedModes = new ModSettingBool(true) { description = "Determines whether power towers will be usable in Primary Only, Military Only and Magic Only game modes.", icon = "MainMenuUiAtlas[MagicBtn]", requiresRestart = true }; public static readonly ModSettingBool OverrideHotkeys = new ModSettingBool(true) { description = "Disables the hotkeys for activating real powers, and assigns them to the shop ones instead.", icon = "Ui[HotkeysIcon]" }; public static readonly ModSettingBool ChangeIconsForSkins = new ModSettingBool(false) { description = "Whether to change the icons in the shop to reflect the power skin being used.", icon = "95f6bb31750d2f64d90b44cc452d8ec8" }; public static readonly ModSettingCategory Costs = ModSettingCategory.op_Implicit("Costs"); public static readonly ModSettingCategory RechargeCosts = ModSettingCategory.op_Implicit("Recharge Costs"); public static readonly ModSettingCategory Properties = ModSettingCategory.op_Implicit("Properties"); private static bool clipboardIsPowerFromShop; public override void OnTitleScreen() { HandleChimps(); } public override void OnSaveSettings(JObject settings) { foreach (ModTower item in from tower in ModContent.GetContent() where tower is IPowerTower select tower) { foreach (TowerModel item2 in Il2CppGenericIEnumerable.AsIEnumerable(Game.instance.model.GetTowersWithBaseId(((ModContent)item).Id, false))) { item2.cost = item.Cost; } item.AddOrRemoveFromShop(); } HandleChimps(); } public static void HandleChimps() { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown ModModel val = ((IEnumerable)GameData.Instance.mods).FirstOrDefault((Func)((ModModel model) => ((Model)model).name == "Clicks")); if (val == null) { return; } List chimpsMutators = Il2CppReferenceArrayExt.ToList(val.mutatorMods); Dictionary dictionary = (from tower in ModContent.GetContent() where tower is IPowerTower select tower).ToDictionary((ModTower tower) => ((ModContent)tower).Id, (ModTower tower) => chimpsMutators.OfType().FirstOrDefault((Func)((LockTowerModModel model) => model.towerToLock == ((ModContent)tower).Id))); if (ModSettingBool.op_Implicit(AllowInChimps)) { foreach (LockTowerModModel item in dictionary.Values.Where((LockTowerModModel lockTowerModel) => lockTowerModel != null)) { chimpsMutators.Remove((MutatorModModel)(object)item); } } else { foreach (var (text2, val3) in dictionary) { if (val3 == null) { chimpsMutators.Add((MutatorModModel)new LockTowerModModel("", text2)); } } } val.mutatorMods = ListExt.ToIl2CppReferenceArray(chimpsMutators); } public static void MarkAsPowerFromShop(Tower tower) { MutableExt.AddMutator((Mutable)(object)tower, (JToken)null, -1, true, true, false, true, false, false, false, -1, false, false); } public static bool IsPowerFromShop(Tower tower) { return MutableExt.IsMutatedBy((Mutable)(object)tower); } public override void OnTowerSaved(Tower tower, TowerSaveDataModel saveData) { if (IsPowerFromShop(tower)) { saveData.metaData["PowersInShop"] = "true"; } } public override void OnTowerLoaded(Tower tower, TowerSaveDataModel saveData) { if (saveData.metaData.ContainsKey("PowersInShop")) { MarkAsPowerFromShop(tower); } } public static void SyncInventoryCounts(TowerInventory ti, PowerInventory pi, string powerName, Func operation) { string id = ModContent.GetId(powerName); ModTower val = default(ModTower); if (!ModContent.TryFind(id, ref val)) { return; } int num2 = default(int); int num3 = default(int); int num = operation(ti.towerCounts.TryGetValue(((ModContent)val).Id, ref num2) ? num2 : 0, pi.powerCounts.TryGetValue(((ModContent)val).Name, ref num3) ? num3 : 0); ti.towerCounts[((ModContent)val).Id] = num; pi.powerCounts[((ModContent)val).Name] = num; ShopMenu instance = ShopMenuExt.instance; if (instance != null) { Transform towerButtonFromBaseId = instance.GetTowerButtonFromBaseId(id); if (towerButtonFromBaseId != null) { ((Object)towerButtonFromBaseId).MarkDirty(); } } } public override object? Call(string operation, params object[] parameters) { switch (operation) { case "OnTowerCopied": { Tower tower2 = default(Tower); if (ArrayExt.CheckTypes(parameters, ref tower2)) { clipboardIsPowerFromShop = IsPowerFromShop(tower2); } break; } case "OnTowerPasted": { Tower tower = default(Tower); if (ArrayExt.CheckTypes(parameters, ref tower) && clipboardIsPowerFromShop) { MarkAsPowerFromShop(tower); } break; } case "OnClipboardCleared": clipboardIsPowerFromShop = false; break; case "ModifyClipboardCost": { Tower val = default(Tower); if (!ArrayExt.CheckTypes(parameters, ref val)) { break; } if (IsPowerFromShop(val) && ModPowerTowerPro.ByName.TryGetValue(((EntityModel)val.towerModel).baseId, out ModPowerTowerPro value)) { return InGame.Bridge.Model.GetTower(((ModContent)value).Id, 0, 0, 0).cost; } return 0; } } return null; } } public class PowersInShopMutator : ModMutator { public override bool Saved => false; public override int Priority => 10; public override bool Mutate(Model baseModel, Model model, JToken data) { TowerModel val = default(TowerModel); if (!Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)model, ref val) || !PowersInShopMod.PowersByName.TryGetValue(((EntityModel)val).baseId, out IPowerTower value) || !(value is ModPowerTowerBase modPowerTowerBase)) { return true; } modPowerTowerBase.MutateTower(val); return true; } } } namespace PowersInShop.Towers { public class BananaFarmer : ModPowerTower { public override int BaseCost => 500; protected override int Order => 5; } public class BananaFarmerPro : ModPowerTowerPro { public override string BaseTower => TowerType.BananaFarmerPro; protected override int Order => 15; public override int BaseCost => 1000; } public class CamoTrap : ModTrackPower { protected override int BasePierce => 500; protected override int Order => 4; public override int BaseCost => 600; } public class CaveMonkey : ModPowerTower { public override int BaseCost => 750; protected override int Order => 14; } public class DartTime : ModInstantPower { public override int BaseCost => -1; protected override int Order => 13; } public class EnergisingTotem : ModPowerTower { public static readonly ModSettingDouble TotemAttackSpeed; public static readonly ModSettingInt TotemRechargeCost; public override string BaseTower => TowerType.EnergisingTotem; protected override int Order => 7; public override int BaseCost => 1000; public override void MutateTower(TowerModel towerModel) { TowerModelBehaviorExt.GetBehavior(towerModel).multiplier = 1f / (1f + ModSettingDouble.op_Implicit(TotemAttackSpeed)); } static EnergisingTotem() { //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_0019: 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_0038: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0085: Expected O, but got Unknown ModSettingDouble val = new ModSettingDouble(0.15) { description = ".15 = 15%, down by default from the normal 25% boost so it isn't as blatantly overpowered", category = PowersInShopMod.Properties }; ((ModSettingNumber)val).min = 0.0; ((ModSetting)val).icon = "PowerIcons[EnergisingTotemIcon]"; TotemAttackSpeed = val; ModSettingInt val2 = new ModSettingInt(500) { description = "In in-game cash, not monkey money", category = PowersInShopMod.RechargeCosts, icon = "PowerIcons[EnergisingTotemIcon]" }; ((ModSettingNumber)val2).min = 0L; TotemRechargeCost = val2; } } public class GlueTrap : ModTrackPower { protected override int BasePierce => 300; protected override int Order => 3; public override int BaseCost => 500; } public class MoabMine : ModTrackPower { protected override int BasePierce => 1; protected override int Order => 2; public override int BaseCost => 2000; } public class MonkeyBoost : ModInstantPower { public override int BaseCost => -1; protected override int Order => 11; } public class MonkeyBoostPro : ModPowerTowerPro { public static readonly ModSettingInt HypeRechargeCost = new ModSettingInt(1000) { description = "In in-game cash, not monkey money", icon = "acf8fc839c349344e940ffb014577a0c", category = PowersInShopMod.RechargeCosts }; public override string BaseTower => "MonkeyBoostPro"; protected override int Order => 17; public override int BaseCost => 4000; public override void MutateTower(TowerModel towerModel) { base.MutateTower(towerModel); if (towerModel.towerSelectionMenuThemeId == "Default") { towerModel.towerSelectionMenuThemeId = "SuperMonkeyBeacon"; } } } public class Pontoon : ModPowerTower { protected override int Order => 8; public override int BaseCost => 450; } public class PortableLake : ModPowerTower { protected override int Order => 9; public override int BaseCost => 500; } public class RoadSpikes : ModTrackPower { protected override int BasePierce => 20; protected override int Order => 1; public override int BaseCost => 50; } public class SuperMonkeyBeacon : ModPowerTowerPro { public static readonly ModSettingInt BeaconRechargeCost = new ModSettingInt(2000) { description = "In in-game cash, not monkey money", icon = "24ec1eea1a05c1b47975e8d2fd57513b", category = PowersInShopMod.RechargeCosts }; protected override int Order => 16; public override int BaseCost => 4000; } public class SuperMonkeyStorm : ModInstantPower { public override int BaseCost => -1; protected override int Order => 10; } public class TechBot : ModPowerTower { protected override int Order => 6; public override int BaseCost => 375; } public class TechBotPrime : ModPowerTowerPro { public override string BaseTower => TowerType.TechBotPrime; protected override int Order => 18; public override int BaseCost => 1000; } public class Thrive : ModInstantPower { public override int BaseCost => -1; protected override int Order => 12; } } namespace PowersInShop.Patches { [HarmonyPatch(typeof(Hotkeys), "Setup")] internal static class Hotkeys_Setup { [HarmonyPostfix] private static void Postfix(Hotkeys __instance) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown if (!ModSettingBool.op_Implicit(PowersInShopMod.OverrideHotkeys)) { return; } Dictionary dictionary = ((IEnumerable)__instance.powerHotkeys.ToArray()).Where((PowerHotkeyInfo info) => PowersInShopMod.PowersByName.ContainsKey(((Model)((PowerButton)info.standardPowerButton).powerModel).name)).DistinctBy((PowerHotkeyInfo info) => ((Model)((PowerButton)info.standardPowerButton).powerModel).name).ToDictionary((PowerHotkeyInfo info) => ((Model)((PowerButton)info.standardPowerButton).powerModel).name); Enumerator enumerator = ShopMenuExt.instance.ActiveTowerButtons.GetEnumerator(); while (enumerator.MoveNext()) { ITowerPurchaseButton current = enumerator.Current; string baseId = ((EntityModel)current.TowerModel).baseId; if (PowersInShopMod.PowersById.TryGetValue(baseId, out IPowerTower value)) { HotkeyButton hotkeyButton; if (dictionary.TryGetValue(value.Name, out var value2)) { __instance.powerHotkeys.Remove(value2); hotkeyButton = value2.hotkeyButton; } else { hotkeyButton = __instance.hotKeyButtonSet.GetButton(value.Name); } __instance.towerHotkeys.Add(new TowerHotkeyInfo { towerBaseId = baseId, hotkeyButton = hotkeyButton, towerPurchaseButton = current }); } } } } [HarmonyPatch(typeof(InputManager), "CreatePlacementTower")] internal static class InputManager_CreatePlacementTower { [HarmonyPatch(typeof(Tower), "OnPlace")] internal static class Tower_OnPlace { [HarmonyPostfix] internal static void Postfix(Tower __instance) { if (nextPlace != null && !(((Model)__instance.towerModel).name != ((Model)nextPlace).name)) { __instance.worth = nextCost; PowersInShopMod.MarkAsPowerFromShop(__instance); nextPlace = null; nextCost = 0f; } } } internal static TowerModel? nextPlace; internal static float nextCost; [HarmonyPrefix] internal static void Prefix(InputManager __instance, Vector2 pos) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (TowerModelExt.GetModTower(__instance.placementModel) is ModPowerTowerBase modPowerTowerBase) { TowerModel placementModel = ModelExt.Duplicate(__instance.Bridge.Model.GetPowerWithId(((ModContent)modPowerTowerBase).Name).tower); int myPlayerNumber = InGame.Bridge.MyPlayerNumber; Simulation simulation = InGame.Bridge.Simulation; float terrainHeight = simulation.Map.GetTerrainHeight(new Vector2(pos), false, false); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(pos.x, pos.y, terrainHeight); TowerInventory towerInventory = simulation.GetTowerInventory(myPlayerNumber); float towerCost = simulation.towerManager.GetTowerCost(__instance.placementModel, val, towerInventory, myPlayerNumber); simulation.RemoveCash((double)towerCost, (CashType)0, myPlayerNumber, (CashSource)4); __instance.placementModel = placementModel; nextCost = towerCost; nextPlace = placementModel; } } } [HarmonyPatch(typeof(Simulation), "StockStandardPowerInventory")] internal static class Simulation_StockStandardPowerInventory { [HarmonyPostfix] internal static void Postfix(Simulation __instance, PowerInventory pi) { int item = Il2CppSystemDictionaryExt.Entries(__instance.powerInventories).First<(int, PowerInventory)>(((int key, PowerInventory value) tuple) => tuple.value == pi).Item1; TowerInventory val = __instance.towerInventories[item]; int num2 = default(int); int num3 = default(int); foreach (IPowerTower item2 in ModContent.GetContent().OfType()) { int num = Math.Min(val.towerMaxes.TryGetValue(item2.Id, ref num2) ? num2 : int.MaxValue, pi.powerMaxes.TryGetValue(item2.Name, ref num3) ? num3 : int.MaxValue); val.towerMaxes[item2.Id] = num; pi.powerMaxes[item2.Name] = num; } } } [HarmonyPatch(typeof(Tower), "OnPlace")] internal static class Tower_OnPlace { [HarmonyPostfix] internal static void Postfix(Tower __instance) { if (__instance.towerModel.isPowerTower) { Simulation sim = ((RootObject)__instance).Sim; PowerInventory pi = sim.powerInventories[__instance.owner]; TowerInventory ti = sim.towerInventories[__instance.owner]; PowersInShopMod.SyncInventoryCounts(ti, pi, __instance.towerModel.powerName, Math.Max); } } } [HarmonyPatch(typeof(Tower), "OnDestroy")] internal static class Tower_OnDestroy { [HarmonyPostfix] internal static void Postfix(Tower __instance) { if (__instance.towerModel.isPowerTower) { Simulation sim = ((RootObject)__instance).Sim; PowerInventory val = sim.powerInventories[__instance.owner]; TowerInventory ti = sim.towerInventories[__instance.owner]; Dictionary powerCounts = val.powerCounts; string powerName = __instance.towerModel.powerName; int num = powerCounts[powerName]; powerCounts[powerName] = num - 1; PowersInShopMod.SyncInventoryCounts(ti, val, __instance.towerModel.powerName, Math.Min); } } } [HarmonyPatch] public class TSMThemeRecharge_OnButtonPress { private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(TSMThemeEnergisingTotem), "OnButtonPress", new Type[2] { typeof(TowerToSimulation), typeof(TSMButton) }, (Type[])null); yield return AccessTools.Method(typeof(TSMThemeSuperMonkeyBeacon), "OnButtonPress", new Type[2] { typeof(TowerToSimulation), typeof(TSMButton) }, (Type[])null); } [HarmonyPrefix] public static bool Prefix(TSMThemeDefault __instance, TowerToSimulation tower, TSMButton button) { if (!PowersInShopMod.IsPowerFromShop(tower.tower)) { return true; } int num; if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)__instance)) { num = ModSettingInt.op_Implicit(EnergisingTotem.TotemRechargeCost); } else { if (!Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)__instance)) { return true; } num = ModSettingInt.op_Implicit((((EntityModel)tower.tower.towerModel).baseId == TowerType.SuperMonkeyBeacon) ? SuperMonkeyBeacon.BeaconRechargeCost : MonkeyBoostPro.HypeRechargeCost); } int num2 = CostHelper.CostForDifficulty(num, InGame.instance); double cash = InGame.Bridge.GetCash(-1); if (cash < (double)num2) { return false; } InGame.Bridge.Simulation.RemoveCash((double)num2, (CashType)1, tower.owner, (CashSource)0); tower.PerformCustomUIAction(button.buttonId); return false; } } [HarmonyPatch] internal static class TSMThemeRecharge_Selected { private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(TSMThemeEnergisingTotem), "Selected", new Type[2] { typeof(TowerToSimulation), typeof(bool) }, (Type[])null); yield return AccessTools.Method(typeof(TSMThemeSuperMonkeyBeacon), "Selected", new Type[2] { typeof(TowerToSimulation), typeof(bool) }, (Type[])null); } [HarmonyPostfix] internal static void Postfix(TSMThemeDefault __instance, TowerToSimulation tower) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) bool flag = PowersInShopMod.IsPowerFromShop(tower.tower); TSMThemeEnergisingTotem val = default(TSMThemeEnergisingTotem); GameObject gameObject; int num; if (Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)__instance, ref val)) { gameObject = ((Component)val.rechargeButton).gameObject; num = ModSettingInt.op_Implicit(EnergisingTotem.TotemRechargeCost); } else { TSMThemeSuperMonkeyBeacon val2 = default(TSMThemeSuperMonkeyBeacon); if (!Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)__instance, ref val2)) { return; } gameObject = ((Component)val2.rechargeButton).gameObject; num = ModSettingInt.op_Implicit((((EntityModel)tower.tower.towerModel).baseId == TowerType.SuperMonkeyBeacon) ? SuperMonkeyBeacon.BeaconRechargeCost : MonkeyBoostPro.HypeRechargeCost); } int value = CostHelper.CostForDifficulty(num, InGame.instance); NK_TextMeshProUGUI componentInChildrenByName = GameObjectExt.GetComponentInChildrenByName(gameObject, "Text"); ((Behaviour)componentInChildrenByName).enabled = true; ((TMP_Text)componentInChildrenByName).text = $"${value:N0}"; ((TMP_Text)componentInChildrenByName).margin = new Vector4(0f, 25f, 0f, 0f); ((Component)componentInChildrenByName).gameObject.SetActive(flag); ((Behaviour)GameObjectExt.GetComponentInChildrenByName(gameObject, "MmIcon")).enabled = !flag; ((Behaviour)GameObjectExt.GetComponentInChildrenByName(gameObject, "TextCount")).enabled = !flag; } } [HarmonyPatch(typeof(CosmeticHelper), "ApplyAssetChangesToPowerModel")] internal static class CosmeticHelper_ApplyAssetChangesToPowerModel { [HarmonyPostfix] internal static void Postfix(PowerModel pm, PowerAssetChange pac) { //IL_0094: 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) //IL_009c: Expected O, but got Unknown //IL_00a1: Expected O, but got Unknown if (!ModSettingBool.op_Implicit(PowersInShopMod.ChangeIconsForSkins) || !PowersInShopMod.PowersByName.TryGetValue(((Model)pm).name, out IPowerTower value) || !(value is ModTrackPower modTrackPower)) { return; } TrophyStoreItem val = Il2CppGenerics.First(GameData.Instance.trophyStoreItems.GetAllItems(), (Func)((TrophyStoreItem storeItem) => Il2CppReferenceArray.Any(storeItem.itemTypes, (Func)((TrophyItemTypeData data) => data.itemTarget.id == ((AssetChangeItem)pac).id)))); TowerModel towerWithName = CosmeticHelper.rootGameModel.GetTowerWithName(((ModContent)modTrackPower).Id); SpriteReference val2 = new SpriteReference(SpriteResizer.Scaled(val.icon.AssetGUID, 0.75f, true)); SpriteReference portrait = val2; towerWithName.icon = val2; towerWithName.portrait = portrait; } } [HarmonyPatch(typeof(Btd6Player), "HasUnlockedTower")] internal static class Btd6Player_HasUnlockedTower { [HarmonyPrefix] internal static bool Prefix(Btd6Player __instance, string? towerId, ref bool __result) { if (towerId != null && ModPowerTowerPro.ById.TryGetValue(towerId, out ModPowerTowerPro value)) { PowersProSaveData powersProSaveData = ((Player)(object)__instance).Data.powersProSaveData; PowersProPowerSaveData val = default(PowersProPowerSaveData); __result = powersProSaveData != null && powersProSaveData.dataByPower?.TryGetValue(((ModContent)value).Name, ref val) == true && val.seenUnlockPro.ValueBool; return false; } return true; } } [HarmonyPatch(typeof(Btd6Player), "HasUpgrade")] internal static class Btd6Player_HasUpgrade { [HarmonyPrefix] internal static bool Prefix(Btd6Player __instance, string upgradeId, ref bool __result) { if (ModPowerTowerPro.Upgrades.TryGetValue(upgradeId, out string value)) { PowerProUpgradeModel powerProUpgrade = ((Player)(object)__instance).Data.Model.GetPowerProUpgrade(upgradeId); PowersProSaveData powersProSaveData = ((Player)(object)__instance).Data.powersProSaveData; PowersProPowerSaveData val = default(PowersProPowerSaveData); __result = powersProSaveData != null && powersProSaveData.dataByPower?.TryGetValue(value, ref val) == true && val.unlockedTier.ValueInt > ((UpgradeModel)powerProUpgrade).tier; return false; } return true; } } [HarmonyPatch(typeof(SelectedUpgrade), "UpdateButtonState")] internal static class SelectedUpgrade_UpdateButtonState { [HarmonyPostfix] internal static void Postfix(SelectedUpgrade __instance) { GameObject gameObject = ((Component)((Component)__instance.aquireButton).transform.parent).gameObject; UpgradeDetails selectedDetails = __instance.SelectedDetails; int active; if (selectedDetails == null) { active = 1; } else { UpgradeModel upgrade = selectedDetails.upgrade; active = ((((upgrade != null) ? new bool?(Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)upgrade)) : ((bool?)null)) != true) ? 1 : 0); } gameObject.SetActive((byte)active != 0); } } [HarmonyPatch(typeof(UpgradeScreen), "ResetUpgradeUnlocks")] internal static class UpgradeScreen_ResetUpgradeUnlocks { [HarmonyPostfix] internal static void Postfix(Il2CppReferenceArray upgrades) { foreach (UpgradeDetails item in ((IEnumerable)upgrades).Where(delegate(UpgradeDetails upgrade) { UpgradeModel upgrade2 = upgrade.upgrade; return upgrade2 != null && Il2CppSystemObjectExt.Is((Il2CppObjectBase)(object)upgrade2) && !upgrade.hasUpgrade; })) { item.SetLocked(); } } } [HarmonyPatch(typeof(InGame), "ShowUpgradeTree", new Type[] { typeof(PlayerContext) })] internal static class InGame_ShowUpgradeTree1 { public static bool Active { get; private set; } [HarmonyPrefix] internal static void Prefix() { Active = true; } [HarmonyPostfix] internal static void Postfix() { Active = false; } } [HarmonyPatch(typeof(InGame), "ShowUpgradeTree", new Type[] { typeof(TowerModel), typeof(Context), typeof(bool) })] internal static class InGame_ShowUpgradeTree2 { public static bool Active { get; private set; } [HarmonyPrefix] internal static void Prefix() { Active = true; } [HarmonyPostfix] internal static void Postfix() { Active = false; } } [HarmonyPatch(typeof(ReadonlyInGameData), "ArePowersAllowed")] internal static class ReadonlyInGameData_ArePowersAllowed { [HarmonyPrefix] internal static bool Prefix(ref bool __result) { if (InGame_ShowUpgradeTree1.Active || InGame_ShowUpgradeTree2.Active) { __result = true; return false; } return true; } } }